Line data Source code
1 : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2 : * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Brian Bruns
3 : * Copyright (C) 2004-2015 Ziglio Frediano
4 : *
5 : * This library is free software; you can redistribute it and/or
6 : * modify it under the terms of the GNU Library General Public
7 : * License as published by the Free Software Foundation; either
8 : * version 2 of the License, or (at your option) any later version.
9 : *
10 : * This library is distributed in the hope that it will be useful,
11 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 : * Library General Public License for more details.
14 : *
15 : * You should have received a copy of the GNU Library General Public
16 : * License along with this library; if not, write to the
17 : * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 : * Boston, MA 02111-1307, USA.
19 : */
20 :
21 : #include <config.h>
22 :
23 : #include <stdarg.h>
24 : #include <stdio.h>
25 :
26 : #include <freetds/time.h>
27 :
28 : #if HAVE_SYS_TYPES_H
29 : #include <sys/types.h>
30 : #endif /* HAVE_SYS_TYPES_H */
31 :
32 : #if HAVE_ERRNO_H
33 : #include <errno.h>
34 : #endif /* HAVE_ERRNO_H */
35 :
36 : #if HAVE_UNISTD_H
37 : #include <unistd.h>
38 : #endif /* HAVE_UNISTD_H */
39 :
40 : #if HAVE_STDLIB_H
41 : #include <stdlib.h>
42 : #endif /* HAVE_STDLIB_H */
43 :
44 : #if HAVE_STRING_H
45 : #include <string.h>
46 : #endif /* HAVE_STRING_H */
47 :
48 : #if HAVE_SYS_SOCKET_H
49 : #include <sys/socket.h>
50 : #endif /* HAVE_SYS_SOCKET_H */
51 :
52 : #if HAVE_NETINET_IN_H
53 : #include <netinet/in.h>
54 : #endif /* HAVE_NETINET_IN_H */
55 :
56 : #if HAVE_NETINET_TCP_H
57 : #include <netinet/tcp.h>
58 : #endif /* HAVE_NETINET_TCP_H */
59 :
60 : #if HAVE_ARPA_INET_H
61 : #include <arpa/inet.h>
62 : #endif /* HAVE_ARPA_INET_H */
63 :
64 : #if HAVE_SYS_IOCTL_H
65 : #include <sys/ioctl.h>
66 : #endif /* HAVE_SYS_IOCTL_H */
67 :
68 : #if HAVE_SELECT_H
69 : #include <sys/select.h>
70 : #endif /* HAVE_SELECT_H */
71 :
72 : #if HAVE_FCNTL_H
73 : #include <fcntl.h>
74 : #endif /* HAVE_FCNTL_H */
75 :
76 : #ifdef HAVE_SYS_EVENTFD_H
77 : #include <sys/eventfd.h>
78 : #endif /* HAVE_SYS_EVENTFD_H */
79 :
80 : #ifdef _WIN32
81 : #include <winsock2.h>
82 : #include <ws2tcpip.h>
83 : #include <mstcpip.h>
84 : #endif
85 :
86 : #include <freetds/tds.h>
87 : #include <freetds/utils/string.h>
88 : #include <freetds/utils/nosigpipe.h>
89 : #include <freetds/tds/tls.h>
90 : #include <freetds/replacements.h>
91 :
92 : #include <signal.h>
93 : #include <assert.h>
94 :
95 : /* error is always returned */
96 : #define TDSSELERR 0
97 : #define TDSPOLLURG 0x8000u
98 :
99 : #if ENABLE_ODBC_MARS
100 : static void tds_check_cancel(TDSCONNECTION *conn);
101 : #endif
102 :
103 :
104 : /**
105 : * \addtogroup network
106 : * @{
107 : */
108 :
109 : #if !defined(SOL_TCP) && (defined(IPPROTO_TCP) || defined(_WIN32))
110 : /* fix incompatibility between MS headers */
111 : # ifndef IPPROTO_TCP
112 : # define IPPROTO_TCP IPPROTO_TCP
113 : # endif
114 : # define SOL_TCP IPPROTO_TCP
115 : #endif
116 :
117 : /* Optimize the way we send packets */
118 : #undef USE_CORK
119 : #undef USE_NODELAY
120 : /* On early Linux use TCP_CORK if available */
121 : #if defined(__linux__) && defined(TCP_CORK)
122 : #define USE_CORK 1
123 : /* On *BSD try to use TCP_CORK */
124 : /*
125 : * NOPUSH flag do not behave in the same way
126 : * cf ML "FreeBSD 5.0 performance problems with TCP_NOPUSH"
127 : */
128 : #elif (defined(__FreeBSD__) || defined(__GNU_FreeBSD__) || defined(__OpenBSD__)) && defined(TCP_CORK)
129 : #define USE_CORK 1
130 : /* otherwise use NODELAY */
131 : #elif defined(TCP_NODELAY) && defined(SOL_TCP)
132 : #define USE_NODELAY 1
133 : /* under VMS we have to define TCP_NODELAY */
134 : #elif defined(__VMS)
135 : #define TCP_NODELAY 1
136 : #define USE_NODELAY 1
137 : #endif
138 :
139 : /**
140 : * Set socket to non-blocking
141 : * @param sock socket to set
142 : * @return 0 on success or error code
143 : */
144 : int
145 4759 : tds_socket_set_nonblocking(TDS_SYS_SOCKET sock)
146 : {
147 : #if !defined(_WIN32)
148 4759 : unsigned int ioctl_nonblocking = 1;
149 : #else
150 : u_long ioctl_nonblocking = 1;
151 : #endif
152 :
153 4759 : if (IOCTLSOCKET(sock, FIONBIO, &ioctl_nonblocking) >= 0)
154 : return 0;
155 0 : return sock_errno;
156 : }
157 :
158 : static void
159 3971 : tds_addrinfo_set_port(struct addrinfo *addr, unsigned int port)
160 : {
161 3971 : assert(addr != NULL);
162 :
163 3971 : switch(addr->ai_family) {
164 3971 : case AF_INET:
165 3971 : ((struct sockaddr_in *) addr->ai_addr)->sin_port = htons(port);
166 3971 : break;
167 :
168 : #ifdef AF_INET6
169 0 : case AF_INET6:
170 0 : ((struct sockaddr_in6 *) addr->ai_addr)->sin6_port = htons(port);
171 0 : break;
172 : #endif
173 : }
174 3971 : }
175 :
176 : const char*
177 34 : tds_addrinfo2str(struct addrinfo *addr, char *name, int namemax)
178 : {
179 : #ifndef NI_NUMERICHOST
180 : #define NI_NUMERICHOST 0
181 : #endif
182 34 : struct sockaddr *sa = (struct sockaddr *) addr->ai_addr;
183 :
184 34 : if (!name || namemax <= 0)
185 : return "";
186 : #ifdef __VMS /* OpenVMS TCPIP v5.7 getnameinfo() is buggy */
187 : if (addr->ai_family == AF_INET && inet_ntop(AF_INET, &((struct sockaddr_in *) sa)->sin_addr, name, namemax))
188 : return name;
189 : #ifdef AF_INET6
190 : if (addr->ai_family == AF_INET6 && inet_ntop(AF_INET6, &((struct sockaddr_in6 *) sa)->sin6_addr, name, namemax)) {
191 : uint32_t scope_id = ((struct sockaddr_in6 *) sa)->sin6_scope_id;
192 :
193 : if (scope_id) {
194 : size_t len = strlen(name);
195 :
196 : snprintf(name + len, (size_t) namemax - len, "%%%u", scope_id);
197 : }
198 : return name;
199 : }
200 : #endif
201 : #else
202 34 : if (getnameinfo(sa, addr->ai_addrlen, name, namemax, NULL, 0, NI_NUMERICHOST) == 0)
203 : return name;
204 : #endif
205 0 : return "";
206 : }
207 :
208 : typedef struct
209 : {
210 : char ipaddr[128];
211 : } addrinfo2str_res;
212 :
213 : static addrinfo2str_res
214 : addrinfo2str(struct addrinfo *addr)
215 : {
216 : addrinfo2str_res res;
217 :
218 4 : res.ipaddr[0] = 0;
219 4 : tds_addrinfo2str(addr, res.ipaddr, sizeof(res.ipaddr));
220 4 : return res;
221 : }
222 :
223 : #define addrinfo2str(addr) (addrinfo2str(addr).ipaddr)
224 :
225 : /**
226 : * Returns error stored in the socket
227 : */
228 : static int
229 3969 : tds_get_socket_error(TDS_SYS_SOCKET sock)
230 : {
231 : int err;
232 3969 : SOCKLEN_T optlen = sizeof(err);
233 : char *errstr;
234 :
235 : /* check socket error */
236 3969 : if (tds_getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *) &err, &optlen) != 0) {
237 0 : err = sock_errno;
238 0 : errstr = sock_strerror(err);
239 0 : tdsdump_log(TDS_DBG_ERROR, "getsockopt(2) failed: %s\n", errstr);
240 : sock_strerror_free(errstr);
241 3969 : } else if (err != 0) {
242 0 : errstr = sock_strerror(err);
243 0 : tdsdump_log(TDS_DBG_ERROR, "getsockopt(2) reported: %s\n", errstr);
244 : sock_strerror_free(errstr);
245 : }
246 3969 : return err;
247 : }
248 :
249 : /**
250 : * Setup the socket and attempt a connection.
251 : * Function allocate the socket in *p_sock and try to start a connection.
252 : * @param p_sock where returned socket is stored. Socket is stored even on error.
253 : * Can be INVALID_SOCKET.
254 : * @param addr address to use for attempting the connection
255 : * @param port port to connect to
256 : * @param p_oserr where system error is returned
257 : * @returns TDSEOK is success, TDSEINPROGRESS if connection attempt is started
258 : * or any other error.
259 : */
260 : static TDSERRNO
261 3969 : tds_setup_socket(TDS_SYS_SOCKET *p_sock, struct addrinfo *addr, unsigned int port, int *p_oserr)
262 : {
263 : enum {
264 : TDS_SOCKET_KEEPALIVE_IDLE = 40,
265 : TDS_SOCKET_KEEPALIVE_INTERVAL = 2
266 : };
267 : TDS_SYS_SOCKET sock;
268 : int retval, len, err;
269 : char *errstr;
270 : #if defined(_WIN32)
271 : struct tcp_keepalive keepalive = {
272 : TRUE,
273 : TDS_SOCKET_KEEPALIVE_IDLE * 1000,
274 : TDS_SOCKET_KEEPALIVE_INTERVAL * 1000
275 : };
276 : DWORD written;
277 : #endif
278 :
279 3969 : *p_oserr = 0;
280 :
281 3969 : tds_addrinfo_set_port(addr, port);
282 :
283 3969 : *p_sock = sock = socket(addr->ai_family, SOCK_STREAM, 0);
284 3969 : if (TDS_IS_SOCKET_INVALID(sock)) {
285 0 : errstr = sock_strerror(*p_oserr = sock_errno);
286 0 : tdsdump_log(TDS_DBG_ERROR, "socket creation error: %s\n", errstr);
287 : sock_strerror_free(errstr);
288 : return TDSESOCK;
289 : }
290 :
291 : #ifdef SO_KEEPALIVE
292 3969 : len = 1;
293 3969 : setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (const void *) &len, sizeof(len));
294 : #endif
295 :
296 : #if defined(_WIN32)
297 : if (WSAIoctl(sock, SIO_KEEPALIVE_VALS, &keepalive, sizeof(keepalive),
298 : NULL, 0, &written, NULL, NULL) != 0) {
299 : errstr = sock_strerror(*p_oserr = sock_errno);
300 : tdsdump_log(TDS_DBG_ERROR, "error setting keepalive: %s\n", errstr);
301 : sock_strerror_free(errstr);
302 : }
303 : #elif defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL)
304 3969 : len = TDS_SOCKET_KEEPALIVE_IDLE;
305 3969 : setsockopt(sock, SOL_TCP, TCP_KEEPIDLE, (const void *) &len, sizeof(len));
306 3969 : len = TDS_SOCKET_KEEPALIVE_INTERVAL;
307 3969 : setsockopt(sock, SOL_TCP, TCP_KEEPINTVL, (const void *) &len, sizeof(len));
308 : #endif
309 :
310 : #if defined(SO_NOSIGPIPE)
311 : len = 1;
312 : if (setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (const void *) &len, sizeof(len))) {
313 : *p_oserr = sock_errno;
314 : return TDSESOCK;
315 : }
316 : #endif
317 :
318 3969 : len = 1;
319 : #if defined(USE_NODELAY)
320 : setsockopt(sock, SOL_TCP, TCP_NODELAY, (const void *) &len, sizeof(len));
321 : #elif defined(USE_CORK)
322 3969 : setsockopt(sock, SOL_TCP, TCP_NODELAY, (const void *) &len, sizeof(len));
323 3969 : setsockopt(sock, SOL_TCP, TCP_CORK, (const void *) &len, sizeof(len));
324 : #else
325 : #error One should be defined
326 : #endif
327 :
328 3973 : tdsdump_log(TDS_DBG_INFO1, "Connecting to %s port %d\n", addrinfo2str(addr), port);
329 :
330 : #ifdef DOS32X /* the other connection doesn't work on WATTCP32 */
331 : if (connect(sock, addr->ai_addr, addr->ai_addrlen) < 0) {
332 : *p_oserr = sock_errno;
333 : tdsdump_log(TDS_DBG_ERROR, "tds_setup_socket(): %s:%d", addrinfo2str(addr), port);
334 : return TDSECONN;
335 : }
336 : return TDSEOK;
337 : #else
338 3969 : if ((*p_oserr = tds_socket_set_nonblocking(sock)) != 0) {
339 : return TDSEUSCT; /* close enough: "Unable to set communications timer" */
340 : }
341 3969 : retval = connect(sock, addr->ai_addr, addr->ai_addrlen);
342 3969 : if (retval == 0) {
343 0 : tdsdump_log(TDS_DBG_INFO2, "connection established\n");
344 : return TDSEOK;
345 : }
346 :
347 : /* got some kind of error */
348 3969 : err = *p_oserr = sock_errno;
349 3969 : errstr = sock_strerror(err);
350 3969 : tdsdump_log(TDS_DBG_ERROR, "tds_setup_socket: connect(2) returned \"%s\"\n", errstr);
351 : sock_strerror_free(errstr);
352 :
353 : /* connection attempt started */
354 3969 : if (err == TDSSOCK_EINPROGRESS)
355 : return TDSEINPROGRESS;
356 :
357 : #if DEBUGGING_CONNECTING_PROBLEM
358 : if (err != ECONNREFUSED && err != ENETUNREACH) {
359 : tdsdump_dump_buf(TDS_DBG_ERROR, "Contents of sockaddr_in", addr->ai_addr, addr->ai_addrlen);
360 : tdsdump_log(TDS_DBG_ERROR, " sockaddr_in:\t"
361 : "%s = %x\n"
362 : "\t\t\t%s = %x\n"
363 : "\t\t\t%s = %s\n"
364 : , "sin_family", addr->ai_family
365 : , "port", port
366 : , "address", addrinfo2str(addr)
367 : );
368 : }
369 : #endif
370 0 : return TDSECONN;
371 : #endif /* not DOS32X */
372 : }
373 :
374 : typedef struct {
375 : struct addrinfo *addr;
376 : unsigned next_retry_time;
377 : unsigned retry_count;
378 : } retry_addr;
379 :
380 : TDSERRNO
381 3969 : tds_open_socket(TDSSOCKET *tds, struct addrinfo *addr, unsigned int port, int timeout, int *p_oserr)
382 : {
383 3969 : TDSCONNECTION *conn = tds->conn;
384 : size_t len, i;
385 : int oserr;
386 : TDSERRNO tds_error;
387 : struct addrinfo *curr_addr;
388 : struct pollfd *fds;
389 : retry_addr *addresses;
390 : unsigned curr_time, start_time;
391 : typedef struct {
392 : retry_addr retry;
393 : struct pollfd fd;
394 : } alloc_addr;
395 : enum { MAX_RETRY = 10 };
396 :
397 3969 : *p_oserr = 0;
398 :
399 3969 : if (!addr)
400 : return TDSECONN;
401 :
402 3969 : tdsdump_log(TDS_DBG_INFO1, "Connecting with protocol version %d.%d\n",
403 : TDS_MAJOR(conn), TDS_MINOR(conn));
404 :
405 7938 : for (len = 0, curr_addr = addr; curr_addr != NULL; curr_addr = curr_addr->ai_next)
406 3969 : ++len;
407 :
408 3969 : addresses = (retry_addr *) tds_new0(alloc_addr, len);
409 3969 : if (!addresses)
410 : return TDSEMEM;
411 3969 : fds = (struct pollfd *) &addresses[len];
412 :
413 3969 : tds_error = TDSECONN;
414 :
415 : /* fill all structures */
416 3969 : curr_time = start_time = tds_gettime_ms();
417 7938 : for (i = 0, curr_addr = addr; i < len; curr_addr = curr_addr->ai_next) {
418 3969 : fds[i].fd = INVALID_SOCKET;
419 3969 : addresses[i].addr = curr_addr;
420 3969 : addresses[i].next_retry_time = curr_time;
421 3969 : addresses[i].retry_count = 0;
422 3969 : ++i;
423 : }
424 :
425 : /* if we have only one address means that availability groups feature is not
426 : * present, avoid to check the addresses multiple times */
427 3969 : if (len == 1)
428 3969 : addresses[0].retry_count = MAX_RETRY;
429 :
430 3969 : timeout *= 1000;
431 3969 : if (!timeout) {
432 : /* A timeout of zero means wait forever */
433 0 : timeout = -1;
434 : }
435 :
436 : /* now the list is full with sockets trying to connect */
437 3969 : while (len) {
438 3969 : int rc, poll_timeout = timeout;
439 :
440 : /* timeout */
441 3969 : if (poll_timeout >= 0) {
442 3969 : if (curr_time - start_time > (unsigned) poll_timeout) {
443 0 : *p_oserr = TDSSOCK_ETIMEDOUT;
444 : goto exit;
445 : }
446 3969 : poll_timeout -= curr_time - start_time;
447 : }
448 :
449 : /* try again if needed */
450 3969 : for (i = 0; i < len; ++i) {
451 : int time_left;
452 :
453 3969 : if (!TDS_IS_SOCKET_INVALID(fds[i].fd))
454 0 : continue;
455 3969 : time_left = addresses[i].next_retry_time - curr_time;
456 3969 : if (time_left <= 0) {
457 : TDS_SYS_SOCKET sock;
458 3969 : tds_error = tds_setup_socket(&sock, addresses[i].addr, port, p_oserr);
459 3969 : switch (tds_error) {
460 0 : case TDSEOK:
461 : /* connected! */
462 : /* free other sockets and continue with this one */
463 0 : conn->s = sock;
464 0 : tds_error = TDSEOK;
465 0 : goto exit;
466 3969 : case TDSEINPROGRESS:
467 : /* save socket in the list */
468 3969 : fds[i].fd = sock;
469 : break;
470 0 : default:
471 : /* error, continue with other addresses */
472 0 : if (!TDS_IS_SOCKET_INVALID(sock))
473 0 : CLOSESOCKET(sock);
474 0 : --len;
475 0 : fds[i] = fds[len];
476 0 : addresses[i] = addresses[len];
477 0 : --i;
478 0 : continue;
479 : }
480 : } else {
481 : /* update timeout */
482 0 : if (time_left < poll_timeout || poll_timeout < 0)
483 0 : poll_timeout = time_left;
484 : }
485 : }
486 :
487 : /* wait activities on file descriptors */
488 3969 : for (i = 0; i < len; ++i) {
489 3969 : fds[i].revents = 0;
490 3969 : fds[i].events = TDSSELWRITE|TDSSELERR;
491 : }
492 3969 : tds_error = TDSECONN;
493 3969 : rc = poll(fds, len, poll_timeout);
494 3969 : oserr = sock_errno; /* save to avoid overrides */
495 3969 : curr_time = tds_gettime_ms();
496 :
497 : /* error */
498 3969 : if (rc < 0) {
499 0 : *p_oserr = oserr;
500 0 : if (*p_oserr == TDSSOCK_EINTR)
501 0 : continue;
502 : goto exit;
503 : }
504 :
505 : /* got some event on file descriptors */
506 0 : for (i = 0; i < len; ++i) {
507 3969 : if (TDS_IS_SOCKET_INVALID(fds[i].fd))
508 0 : continue;
509 3969 : if (!fds[i].revents)
510 0 : continue;
511 3969 : *p_oserr = tds_get_socket_error(fds[i].fd);
512 3969 : if (*p_oserr || (fds[i].revents & POLLERR) != 0) {
513 : /* error, remove from list and possibly make
514 : * the loop exit */
515 0 : CLOSESOCKET(fds[i].fd);
516 0 : fds[i].fd = INVALID_SOCKET;
517 0 : addresses[i].next_retry_time = curr_time + 1000;
518 0 : if (++addresses[i].retry_count >= MAX_RETRY || len == 1) {
519 0 : --len;
520 0 : fds[i] = fds[len];
521 0 : addresses[i] = addresses[len];
522 0 : --i;
523 : }
524 0 : continue;
525 : }
526 3969 : if (fds[i].revents & POLLOUT) {
527 3969 : conn->s = fds[i].fd;
528 3969 : fds[i].fd = INVALID_SOCKET;
529 3969 : tds_error = TDSEOK;
530 : goto exit;
531 : }
532 : }
533 : }
534 :
535 0 : exit:
536 : if (tds_error != TDSEOK) {
537 0 : tdsdump_log(TDS_DBG_ERROR, "tds_open_socket() failed\n");
538 : } else {
539 3969 : tdsdump_log(TDS_DBG_INFO2, "tds_open_socket() succeeded\n");
540 3969 : tds->state = TDS_IDLE;
541 : }
542 :
543 7938 : while (len > 0) {
544 3969 : --len;
545 3969 : if (!TDS_IS_SOCKET_INVALID(fds[len].fd))
546 0 : CLOSESOCKET(fds[len].fd);
547 : }
548 3969 : free(addresses);
549 3969 : return tds_error;
550 : }
551 :
552 : /**
553 : * Close current socket.
554 : * For last socket close entire connection.
555 : * For MARS send FIN request.
556 : * This attempts a graceful disconnection, for ungraceful call
557 : * tds_connection_close.
558 : */
559 : void
560 5497 : tds_close_socket(TDSSOCKET * tds)
561 : {
562 5497 : if (!IS_TDSDEAD(tds)) {
563 : #if ENABLE_ODBC_MARS
564 1953 : TDSCONNECTION *conn = tds->conn;
565 1953 : unsigned n = 0, count = 0;
566 1953 : tds_mutex_lock(&conn->list_mtx);
567 126945 : for (; n < conn->num_sessions; ++n)
568 124992 : if (TDSSOCKET_VALID(conn->sessions[n]))
569 1953 : ++count;
570 1953 : if (count > 1)
571 0 : tds_append_fin(tds);
572 1953 : tds_mutex_unlock(&conn->list_mtx);
573 1953 : if (count <= 1) {
574 1953 : tds_disconnect(tds);
575 1953 : tds_connection_close(conn);
576 : } else {
577 0 : tds_set_state(tds, TDS_DEAD);
578 : }
579 : #else
580 1952 : tds_disconnect(tds);
581 1952 : if (!TDS_IS_SOCKET_INVALID(tds_get_s(tds)) && CLOSESOCKET(tds_get_s(tds)) == -1)
582 0 : tdserror(tds_get_ctx(tds), tds, TDSECLOS, sock_errno);
583 1952 : tds_set_s(tds, INVALID_SOCKET);
584 1952 : tds_set_state(tds, TDS_DEAD);
585 : #endif
586 : }
587 5497 : }
588 :
589 : void
590 7150 : tds_connection_close(TDSCONNECTION *conn)
591 : {
592 : #if ENABLE_ODBC_MARS
593 4623 : unsigned n = 0;
594 : #endif
595 :
596 7150 : if (!TDS_IS_SOCKET_INVALID(conn->s)) {
597 : /* TODO check error ?? how to return it ?? */
598 2955 : CLOSESOCKET(conn->s);
599 2955 : conn->s = INVALID_SOCKET;
600 : }
601 :
602 : #if ENABLE_ODBC_MARS
603 4623 : tds_mutex_lock(&conn->list_mtx);
604 300495 : for (; n < conn->num_sessions; ++n)
605 295872 : if (TDSSOCKET_VALID(conn->sessions[n]))
606 2108 : tds_set_state(conn->sessions[n], TDS_DEAD);
607 4623 : tds_mutex_unlock(&conn->list_mtx);
608 : #else
609 2527 : tds_set_state((TDSSOCKET* ) conn, TDS_DEAD);
610 : #endif
611 7150 : }
612 :
613 : /**
614 : * Select on a socket until it's available or the timeout expires.
615 : * Meanwhile, call the interrupt function.
616 : * \return >0 ready descriptors
617 : * 0 timeout
618 : * <0 error (cf. errno). Caller should close socket and return failure.
619 : * This function does not call tdserror or close the socket because it can't know the context in which it's being called.
620 : */
621 : int
622 432937 : tds_select(TDSSOCKET * tds, unsigned tds_sel, int timeout_seconds)
623 : {
624 : int rc, seconds;
625 : unsigned int poll_seconds;
626 :
627 432937 : assert(tds != NULL);
628 432937 : assert(timeout_seconds >= 0);
629 :
630 : /*
631 : * The select loop.
632 : * If an interrupt handler is installed, we iterate once per second,
633 : * else we try once, timing out after timeout_seconds (0 == never).
634 : * If select(2) is interrupted by a signal (e.g. press ^C in sqsh), we timeout.
635 : * (The application can retry if desired by installing a signal handler.)
636 : *
637 : * We do not measure current time against end time, to avoid being tricked by ntpd(8) or similar.
638 : * Instead, we just count down.
639 : *
640 : * We exit on the first of these events:
641 : * 1. a descriptor is ready. (return to caller)
642 : * 2. select(2) returns an important error. (return to caller)
643 : * A timeout of zero says "wait forever". We do that by passing a NULL timeval pointer to select(2).
644 : */
645 432937 : poll_seconds = (tds_get_ctx(tds) && tds_get_ctx(tds)->int_handler)? 1 : timeout_seconds;
646 433493 : for (seconds = timeout_seconds; timeout_seconds == 0 || seconds > 0; seconds -= poll_seconds) {
647 : struct pollfd fds[2];
648 433187 : int timeout = poll_seconds ? poll_seconds * 1000 : -1;
649 :
650 433187 : if (TDS_IS_SOCKET_INVALID(tds_get_s(tds)))
651 432631 : return -1;
652 :
653 594471 : if ((tds_sel & TDSSELREAD) != 0 && tds->conn->tls_session && tds_ssl_pending(tds->conn))
654 : return POLLIN;
655 :
656 403847 : fds[0].fd = tds_get_s(tds);
657 403847 : fds[0].events = tds_sel;
658 403847 : fds[0].revents = 0;
659 403847 : fds[1].fd = tds_wakeup_get_fd(&tds->conn->wakeup);
660 403847 : fds[1].events = POLLIN;
661 403847 : fds[1].revents = 0;
662 403847 : rc = poll(fds, 2, timeout);
663 :
664 403847 : if (rc > 0 ) {
665 403291 : if (fds[0].revents & POLLERR) {
666 4 : set_sock_errno(TDSSOCK_ECONNRESET);
667 4 : return -1;
668 : }
669 403287 : rc = fds[0].revents;
670 403287 : if (fds[1].revents) {
671 : #if ENABLE_ODBC_MARS
672 121 : tds_check_cancel(tds->conn);
673 : #endif
674 317 : rc |= TDSPOLLURG;
675 : }
676 : return rc;
677 : }
678 :
679 556 : if (rc < 0) {
680 : char *errstr;
681 :
682 20 : switch (sock_errno) {
683 20 : case TDSSOCK_EINTR:
684 : case EAGAIN:
685 : case TDSSOCK_EINPROGRESS:
686 : /* FIXME this should be global maximun, not loop one */
687 20 : seconds += poll_seconds;
688 20 : break; /* let interrupt handler be called */
689 0 : default: /* documented: EFAULT, EBADF, EINVAL */
690 0 : errstr = sock_strerror(sock_errno);
691 0 : tdsdump_log(TDS_DBG_ERROR, "error: poll(2) returned %d, \"%s\"\n",
692 : sock_errno, errstr);
693 : sock_strerror_free(errstr);
694 : return rc;
695 : }
696 536 : }
697 :
698 556 : assert(rc == 0 || (rc < 0 && (sock_errno == TDSSOCK_EINTR ||
699 : sock_errno == EAGAIN ||
700 : sock_errno == TDSSOCK_EINPROGRESS
701 : )));
702 :
703 556 : if (tds_get_ctx(tds) && tds_get_ctx(tds)->int_handler) { /* interrupt handler installed */
704 : /*
705 : * "If hndlintr() returns INT_CANCEL, DB-Library sends an attention token [TDS_BUFSTAT_ATTN]
706 : * to the server. This causes the server to discontinue command processing.
707 : * The server may send additional results that have already been computed.
708 : * When control returns to the mainline code, the mainline code should do
709 : * one of the following:
710 : * - Flush the results using dbcancel
711 : * - Process the results normally"
712 : */
713 330 : int timeout_action = (*tds_get_ctx(tds)->int_handler) (tds_get_parent(tds));
714 330 : switch (timeout_action) {
715 330 : case TDS_INT_CONTINUE: /* keep waiting */
716 330 : continue;
717 : case TDS_INT_CANCEL: /* abort the current command batch */
718 : /* FIXME tell tds_goodread() not to call tdserror() */
719 : return 0;
720 0 : default:
721 0 : tdsdump_log(TDS_DBG_NETWORK,
722 : "tds_select: invalid interrupt handler return code: %d\n", timeout_action);
723 : return -1;
724 : }
725 : }
726 : /*
727 : * We can reach here if no interrupt handler was installed and we either timed out or got EINTR.
728 : * We cannot be polling, so we are about to drop out of the loop.
729 : */
730 226 : assert(poll_seconds == timeout_seconds);
731 : }
732 :
733 : return 0;
734 : }
735 :
736 : /**
737 : * Read from an OS socket
738 : * @TODO remove tds, save error somewhere, report error in another way
739 : * @returns 0 if blocking, <0 error >0 bytes read
740 : */
741 : static ptrdiff_t
742 242148 : tds_socket_read(TDSCONNECTION * conn, TDSSOCKET *tds, unsigned char *buf, size_t buflen)
743 : {
744 : ptrdiff_t len;
745 : int err;
746 :
747 : #if ENABLE_EXTRA_CHECKS
748 : /* this simulate the fact that recv can return less bytes */
749 242148 : if (buflen >= 5) {
750 : static int cnt = 0;
751 208218 : if (++cnt == 5) {
752 40666 : cnt = 0;
753 40666 : buflen -= 3;
754 : }
755 : }
756 : #endif
757 :
758 : /* read directly from socket*/
759 242148 : len = READSOCKET(conn->s, buf, buflen);
760 242148 : if (len > 0)
761 : return len;
762 :
763 22 : err = sock_errno;
764 22 : if (len < 0 && TDSSOCK_WOULDBLOCK(err))
765 : return 0;
766 :
767 : /* detect connection close */
768 22 : tds_connection_close(conn);
769 22 : tdserror(conn->tds_ctx, tds, len == 0 ? TDSESEOF : TDSEREAD, len == 0 ? 0 : err);
770 22 : return -1;
771 : }
772 :
773 : /**
774 : * Write to an OS socket
775 : * @returns 0 if blocking, <0 error >0 bytes readed
776 : */
777 : static ptrdiff_t
778 121537 : tds_socket_write(TDSCONNECTION *conn, TDSSOCKET *tds, const unsigned char *buf, size_t buflen)
779 : {
780 : int err;
781 : ptrdiff_t len;
782 : char *errstr;
783 :
784 : #if ENABLE_EXTRA_CHECKS
785 : /* this simulate the fact that send can return less bytes */
786 121537 : if (buflen >= 11) {
787 : static int cnt = 0;
788 100181 : if (++cnt == 5) {
789 19121 : cnt = 0;
790 19121 : buflen -= 3;
791 : }
792 : }
793 : #endif
794 :
795 : #ifdef USE_CORK
796 121537 : if (!conn->corked) {
797 96306 : int opt = 1;
798 96306 : setsockopt(conn->s, SOL_TCP, TCP_CORK, (const void *) &opt, sizeof(opt));
799 96306 : conn->corked = true;
800 : }
801 : #endif
802 :
803 : #if defined(SO_NOSIGPIPE)
804 : len = send(conn->s, buf, buflen, 0);
805 : #else
806 121537 : len = WRITESOCKET(conn->s, buf, buflen);
807 : #endif
808 121537 : if (len > 0)
809 : return len;
810 :
811 75 : err = sock_errno;
812 75 : if (0 == len || TDSSOCK_WOULDBLOCK(err) || err == TDSSOCK_EINTR)
813 : return 0;
814 :
815 75 : assert(len < 0);
816 :
817 : /* detect connection close */
818 75 : errstr = sock_strerror(err);
819 75 : tdsdump_log(TDS_DBG_NETWORK, "send(2) failed: %d (%s)\n", err, errstr);
820 : sock_strerror_free(errstr);
821 75 : tds_connection_close(conn);
822 75 : tdserror(conn->tds_ctx, tds, TDSEWRIT, err);
823 75 : return -1;
824 : }
825 :
826 : int
827 4984 : tds_wakeup_init(TDSPOLLWAKEUP *wakeup)
828 : {
829 : TDS_SYS_SOCKET sv[2];
830 : int ret;
831 :
832 4984 : wakeup->s_signal = wakeup->s_signaled = INVALID_SOCKET;
833 : #if defined(__linux__) && HAVE_EVENTFD
834 : # ifdef EFD_CLOEXEC
835 4984 : ret = eventfd(0, EFD_CLOEXEC|EFD_NONBLOCK);
836 : # else
837 : ret = -1;
838 : # endif
839 : /* Linux version up to 2.6.26 do not support flags, try without */
840 4984 : if (ret < 0 && (ret = eventfd(0, 0)) >= 0) {
841 0 : fcntl(ret, F_SETFD, fcntl(ret, F_GETFD, 0) | FD_CLOEXEC);
842 0 : fcntl(ret, F_SETFL, fcntl(ret, F_GETFL, 0) | O_NONBLOCK);
843 : }
844 4984 : if (ret >= 0) {
845 4984 : wakeup->s_signaled = ret;
846 4984 : return 0;
847 : }
848 : #endif
849 0 : ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
850 0 : if (ret)
851 : return ret;
852 0 : wakeup->s_signal = sv[0];
853 0 : wakeup->s_signaled = sv[1];
854 0 : return 0;
855 : }
856 :
857 : void
858 4984 : tds_wakeup_close(TDSPOLLWAKEUP *wakeup)
859 : {
860 4984 : if (!TDS_IS_SOCKET_INVALID(wakeup->s_signal))
861 0 : CLOSESOCKET(wakeup->s_signal);
862 4984 : if (!TDS_IS_SOCKET_INVALID(wakeup->s_signaled))
863 4984 : CLOSESOCKET(wakeup->s_signaled);
864 4984 : }
865 :
866 :
867 : void
868 322 : tds_wakeup_send(TDSPOLLWAKEUP *wakeup, char cancel)
869 : {
870 : #if defined(__linux__) && HAVE_EVENTFD
871 322 : if (wakeup->s_signal == -1) {
872 322 : uint64_t one = 1;
873 322 : (void) write(wakeup->s_signaled, &one, sizeof(one));
874 : return;
875 : }
876 : #endif
877 0 : send(wakeup->s_signal, &cancel, sizeof(cancel), 0);
878 : }
879 :
880 : static int
881 317 : tds_connection_signaled(TDSCONNECTION *conn)
882 : {
883 : ptrdiff_t len;
884 : char to_cancel[16];
885 :
886 : #if defined(__linux__) && HAVE_EVENTFD
887 317 : if (conn->wakeup.s_signal == -1)
888 317 : return read(conn->wakeup.s_signaled, to_cancel, 8) > 0;
889 : #endif
890 :
891 0 : len = READSOCKET(conn->wakeup.s_signaled, to_cancel, sizeof(to_cancel));
892 : do {
893 : /* no cancel found */
894 0 : if (len <= 0)
895 : return 0;
896 0 : } while(!to_cancel[--len]);
897 : return 1;
898 : }
899 :
900 : #if ENABLE_ODBC_MARS
901 : static void
902 121 : tds_check_cancel(TDSCONNECTION *conn)
903 : {
904 : TDSSOCKET *tds;
905 : int rc;
906 :
907 121 : if (!tds_connection_signaled(conn))
908 : return;
909 :
910 : do {
911 121 : unsigned n = 0;
912 :
913 121 : rc = TDS_SUCCESS;
914 121 : tds_mutex_lock(&conn->list_mtx);
915 : /* Here we scan all list searching for sessions that should send cancel packets */
916 7865 : for (; n < conn->num_sessions; ++n)
917 7744 : if (TDSSOCKET_VALID(tds=conn->sessions[n]) && tds->in_cancel == 1) {
918 : /* send cancel */
919 121 : tds->in_cancel = 2;
920 121 : tds_mutex_unlock(&conn->list_mtx);
921 121 : rc = tds_append_cancel(tds);
922 121 : tds_mutex_lock(&conn->list_mtx);
923 121 : if (rc != TDS_SUCCESS)
924 : break;
925 : }
926 121 : tds_mutex_unlock(&conn->list_mtx);
927 : /* for all failed */
928 : /* this must be done outside loop cause it can alter list */
929 : /* this must be done unlocked cause it can lock again */
930 121 : if (rc != TDS_SUCCESS)
931 0 : tds_close_socket(tds);
932 121 : } while(rc != TDS_SUCCESS);
933 : }
934 : #endif
935 :
936 : /**
937 : * Loops until we have received some characters
938 : * return -1 on failure
939 : */
940 : ptrdiff_t
941 163970 : tds_goodread(TDSSOCKET * tds, unsigned char *buf, size_t buflen)
942 : {
943 163970 : if (tds == NULL || buf == NULL || buflen < 1)
944 : return -1;
945 :
946 : for (;;) {
947 : ptrdiff_t len;
948 : int err;
949 :
950 : /* FIXME this block writing from other sessions */
951 164294 : len = tds_select(tds, TDSSELREAD, tds->query_timeout);
952 : #if !ENABLE_ODBC_MARS
953 117888 : if (len > 0 && (len & TDSPOLLURG)) {
954 196 : tds_connection_signaled(tds->conn);
955 : /* send cancel */
956 196 : if (tds->in_cancel == 1)
957 128 : tds_put_cancel(tds);
958 196 : continue;
959 : }
960 : #endif
961 164098 : if (len > 0) {
962 163943 : len = tds_socket_read(tds->conn, tds, buf, buflen);
963 163943 : if (len == 0)
964 0 : continue;
965 : return len;
966 : }
967 :
968 : /* error */
969 155 : if (len < 0) {
970 2 : if (TDSSOCK_WOULDBLOCK(sock_errno)) /* shouldn't happen, but OK */
971 0 : continue;
972 2 : err = sock_errno;
973 2 : tds_connection_close(tds->conn);
974 2 : tdserror(tds_get_ctx(tds), tds, TDSEREAD, err);
975 2 : return -1;
976 : }
977 :
978 : /* timeout */
979 153 : switch (tdserror(tds_get_ctx(tds), tds, TDSETIME, sock_errno)) {
980 : case TDS_INT_CONTINUE:
981 : break;
982 25 : default:
983 : case TDS_INT_CANCEL:
984 25 : tds_close_socket(tds);
985 25 : return -1;
986 : }
987 : }
988 : }
989 :
990 : ptrdiff_t
991 236827 : tds_connection_read(TDSSOCKET * tds, unsigned char *buf, size_t buflen)
992 : {
993 236827 : TDSCONNECTION *conn = tds->conn;
994 :
995 236827 : if (conn->tls_session)
996 174232 : return tds_ssl_read(conn, buf, buflen);
997 :
998 : #if ENABLE_ODBC_MARS
999 78205 : return tds_socket_read(conn, tds, buf, buflen);
1000 : #else
1001 71506 : return tds_goodread(tds, buf, buflen);
1002 : #endif
1003 : }
1004 :
1005 : /**
1006 : * \param tds the famous socket
1007 : * \param buffer data to send
1008 : * \param buflen bytes in buffer
1009 : * \param last 1 if this is the last packet, else 0
1010 : * \return length written (>0), <0 on failure
1011 : */
1012 : ptrdiff_t
1013 70661 : tds_goodwrite(TDSSOCKET * tds, const unsigned char *buffer, size_t buflen)
1014 : {
1015 : ptrdiff_t len;
1016 70661 : size_t sent = 0;
1017 :
1018 70661 : assert(tds && buffer);
1019 :
1020 154743 : while (sent < buflen) {
1021 : /* TODO if send buffer is full we block receive !!! */
1022 84139 : len = tds_select(tds, TDSSELWRITE, tds->query_timeout);
1023 :
1024 84139 : if (len > 0) {
1025 84129 : len = tds_socket_write(tds->conn, tds, buffer + sent, buflen - sent);
1026 84129 : if (len == 0)
1027 0 : continue;
1028 84129 : if (len < 0)
1029 : return len;
1030 :
1031 84082 : sent += len;
1032 84082 : continue;
1033 : }
1034 :
1035 : /* error */
1036 10 : if (len < 0) {
1037 10 : int err = sock_errno;
1038 : char *errstr;
1039 :
1040 10 : if (TDSSOCK_WOULDBLOCK(err)) /* shouldn't happen, but OK, retry */
1041 0 : continue;
1042 10 : errstr = sock_strerror(err);
1043 10 : tdsdump_log(TDS_DBG_NETWORK, "select(2) failed: %d (%s)\n", err, errstr);
1044 : sock_strerror_free(errstr);
1045 10 : tds_connection_close(tds->conn);
1046 10 : tdserror(tds_get_ctx(tds), tds, TDSEWRIT, err);
1047 10 : return -1;
1048 : }
1049 :
1050 : /* timeout */
1051 0 : tdsdump_log(TDS_DBG_NETWORK, "tds_goodwrite(): timed out, asking client\n");
1052 0 : switch (tdserror(tds_get_ctx(tds), tds, TDSETIME, sock_errno)) {
1053 : case TDS_INT_CONTINUE:
1054 : break;
1055 0 : default:
1056 : case TDS_INT_CANCEL:
1057 0 : tds_close_socket(tds);
1058 0 : return -1;
1059 : }
1060 : }
1061 :
1062 70604 : return (int) sent;
1063 : }
1064 :
1065 : void
1066 34784 : tds_connection_coalesce(TDSSOCKET *tds TDS_UNUSED)
1067 : {
1068 : #ifdef USE_CORK
1069 34784 : TDSCONNECTION *conn = tds->conn;
1070 :
1071 34784 : if (!conn->corked) {
1072 33326 : int opt = 1;
1073 33326 : setsockopt(conn->s, SOL_TCP, TCP_CORK, (const void *) &opt, sizeof(opt));
1074 33326 : conn->corked = true;
1075 : }
1076 : #endif
1077 34784 : }
1078 :
1079 : void
1080 129606 : tds_connection_flush(TDSSOCKET *tds TDS_UNUSED)
1081 : {
1082 : #ifdef USE_CORK
1083 129606 : TDSCONNECTION *conn = tds->conn;
1084 :
1085 129606 : if (conn->corked) {
1086 129600 : int opt = 0;
1087 129600 : setsockopt(conn->s, SOL_TCP, TCP_CORK, (const void *) &opt, sizeof(opt));
1088 129600 : conn->corked = false;
1089 : }
1090 : #endif
1091 129606 : }
1092 :
1093 : ptrdiff_t
1094 108069 : tds_connection_write(TDSSOCKET *tds, const unsigned char *buf, size_t buflen, int final)
1095 : {
1096 : ptrdiff_t sent;
1097 108069 : TDSCONNECTION *conn = tds->conn;
1098 :
1099 : #if !defined(_WIN32) && !defined(MSG_NOSIGNAL) && !defined(DOS32X) && !defined(SO_NOSIGPIPE)
1100 : void (*oldsig) (int);
1101 :
1102 : oldsig = signal(SIGPIPE, SIG_IGN);
1103 : if (oldsig == SIG_ERR) {
1104 : tdsdump_log(TDS_DBG_WARN, "TDS: Warning: Couldn't set SIGPIPE signal to be ignored\n");
1105 : }
1106 : #endif
1107 :
1108 108069 : if (conn->tls_session)
1109 78018 : sent = tds_ssl_write(conn, buf, buflen);
1110 : else
1111 : #if ENABLE_ODBC_MARS
1112 37408 : sent = tds_socket_write(conn, tds, buf, buflen);
1113 : #else
1114 31652 : sent = tds_goodwrite(tds, buf, buflen);
1115 : #endif
1116 :
1117 : /* force packet flush */
1118 108069 : if (final && sent >= buflen)
1119 96282 : tds_connection_flush(tds);
1120 :
1121 : #if !defined(_WIN32) && !defined(MSG_NOSIGNAL) && !defined(DOS32X) && !defined(SO_NOSIGPIPE)
1122 : if (signal(SIGPIPE, oldsig) == SIG_ERR) {
1123 : tdsdump_log(TDS_DBG_WARN, "TDS: Warning: Couldn't reset SIGPIPE signal to previous value\n");
1124 : }
1125 : #endif
1126 108069 : return sent;
1127 : }
1128 :
1129 : /**
1130 : * Get port of all instances
1131 : * @return default port number or 0 if error
1132 : * @remark experimental, cf. MC-SQLR.pdf.
1133 : */
1134 : int
1135 0 : tds7_get_instance_ports(FILE *output, struct addrinfo *addr)
1136 : {
1137 : int num_try;
1138 : struct pollfd fd;
1139 : int retval;
1140 : TDS_SYS_SOCKET s;
1141 : char msg[16*1024];
1142 0 : ptrdiff_t msg_len = 0;
1143 0 : int port = 0;
1144 :
1145 0 : tds_addrinfo_set_port(addr, 1434);
1146 :
1147 0 : tdsdump_log(TDS_DBG_ERROR, "tds7_get_instance_ports(%s)\n", addrinfo2str(addr));
1148 :
1149 : /* create an UDP socket */
1150 0 : if (TDS_IS_SOCKET_INVALID(s = socket(addr->ai_family, SOCK_DGRAM, 0))) {
1151 0 : char *errstr = sock_strerror(sock_errno);
1152 0 : tdsdump_log(TDS_DBG_ERROR, "socket creation error: %s\n", errstr);
1153 : sock_strerror_free(errstr);
1154 : return 0;
1155 : }
1156 :
1157 : /*
1158 : * on cluster environment is possible that reply packet came from
1159 : * different IP so do not filter by ip with connect
1160 : */
1161 :
1162 0 : if (tds_socket_set_nonblocking(s) != 0) {
1163 0 : CLOSESOCKET(s);
1164 0 : return 0;
1165 : }
1166 :
1167 : /*
1168 : * Request the instance's port from the server.
1169 : * There is no easy way to detect if port is closed so we always try to
1170 : * get a reply from server 16 times.
1171 : */
1172 0 : for (num_try = 0; num_try < 16 && msg_len == 0; ++num_try) {
1173 : /* send the request */
1174 0 : char msg_type = 3;
1175 :
1176 0 : if (sendto(s, &msg_type, 1, 0, addr->ai_addr, addr->ai_addrlen) < 0)
1177 : break;
1178 :
1179 0 : fd.fd = s;
1180 0 : fd.events = POLLIN;
1181 0 : fd.revents = 0;
1182 :
1183 0 : retval = poll(&fd, 1, 1000);
1184 :
1185 : /* on interrupt ignore */
1186 0 : if (retval < 0 && sock_errno == TDSSOCK_EINTR)
1187 0 : continue;
1188 :
1189 0 : if (retval == 0) { /* timed out */
1190 : #if 1
1191 0 : tdsdump_log(TDS_DBG_ERROR, "tds7_get_instance_port: timed out on try %d of 16\n", num_try);
1192 0 : continue;
1193 : #else
1194 : int rc;
1195 : tdsdump_log(TDS_DBG_INFO1, "timed out\n");
1196 :
1197 : switch(rc = tdserror(NULL, NULL, TDSETIME, 0)) {
1198 : case TDS_INT_CONTINUE:
1199 : continue; /* try again */
1200 :
1201 : default:
1202 : tdsdump_log(TDS_DBG_ERROR, "error: client error handler returned %d\n", rc);
1203 : case TDS_INT_CANCEL:
1204 : CLOSESOCKET(s);
1205 : return 0;
1206 : }
1207 : #endif
1208 : }
1209 0 : if (retval < 0)
1210 : break;
1211 :
1212 : /* got data, read and parse */
1213 0 : if ((msg_len = recv(s, msg, sizeof(msg) - 1, 0)) > 3 && msg[0] == 5) {
1214 0 : char *name, sep[2] = ";", *save;
1215 :
1216 : /* assure null terminated */
1217 0 : msg[msg_len] = 0;
1218 0 : tdsdump_dump_buf(TDS_DBG_INFO1, "instance info", msg, msg_len);
1219 :
1220 : if (0) { /* To debug, print the whole string. */
1221 : char *p;
1222 :
1223 : for (*sep = '\n', p=msg+3; p < msg + msg_len; p++) {
1224 : if( *p == ';' )
1225 : *p = *sep;
1226 : }
1227 : fputs(msg + 3, output);
1228 : }
1229 :
1230 : /*
1231 : * Parse and print message.
1232 : */
1233 0 : name = strtok_r(msg+3, sep, &save);
1234 0 : while (name && output) {
1235 : int i;
1236 : static const char *const names[] = { "ServerName", "InstanceName", "IsClustered", "Version",
1237 : "tcp", "np", "via" };
1238 :
1239 0 : for (i=0; name && i < TDS_VECTOR_SIZE(names); i++) {
1240 0 : const char *value = strtok_r(NULL, sep, &save);
1241 :
1242 0 : if (strcmp(name, names[i]) != 0)
1243 0 : fprintf(output, "error: expecting '%s', found '%s'\n", names[i], name);
1244 0 : if (value)
1245 0 : fprintf(output, "%15s %s\n", name, value);
1246 : else
1247 : break;
1248 :
1249 0 : name = strtok_r(NULL, sep, &save);
1250 :
1251 0 : if (name && strcmp(name, names[0]) == 0)
1252 : break;
1253 : }
1254 0 : if (name)
1255 0 : fprintf(output, "\n");
1256 : }
1257 : }
1258 : }
1259 0 : CLOSESOCKET(s);
1260 0 : tdsdump_log(TDS_DBG_ERROR, "default instance port is %d\n", port);
1261 : return port;
1262 : }
1263 :
1264 : /**
1265 : * Get port of given instance
1266 : * @return port number or 0 if error
1267 : */
1268 : int
1269 2 : tds7_get_instance_port(struct addrinfo *addr, const char *instance)
1270 : {
1271 : int num_try;
1272 : struct pollfd fd;
1273 : int retval;
1274 : TDS_SYS_SOCKET s;
1275 : char msg[1024];
1276 : ptrdiff_t msg_len;
1277 2 : int port = 0;
1278 :
1279 2 : tds_addrinfo_set_port(addr, 1434);
1280 :
1281 2 : tdsdump_log(TDS_DBG_ERROR, "tds7_get_instance_port(%s, %s)\n", addrinfo2str(addr), instance);
1282 :
1283 : /* create an UDP socket */
1284 2 : if (TDS_IS_SOCKET_INVALID(s = socket(addr->ai_family, SOCK_DGRAM, 0))) {
1285 0 : char *errstr = sock_strerror(sock_errno);
1286 0 : tdsdump_log(TDS_DBG_ERROR, "socket creation error: %s\n", errstr);
1287 : sock_strerror_free(errstr);
1288 : return 0;
1289 : }
1290 :
1291 : /*
1292 : * on cluster environment is possible that reply packet came from
1293 : * different IP so do not filter by ip with connect
1294 : */
1295 :
1296 2 : if (tds_socket_set_nonblocking(s) != 0) {
1297 0 : CLOSESOCKET(s);
1298 0 : return 0;
1299 : }
1300 :
1301 : /*
1302 : * Request the instance's port from the server.
1303 : * There is no easy way to detect if port is closed so we always try to
1304 : * get a reply from server 16 times.
1305 : */
1306 0 : for (num_try = 0; num_try < 16; ++num_try) {
1307 : /* send the request */
1308 2 : msg[0] = 4;
1309 2 : strlcpy(msg + 1, instance, sizeof(msg) - 1);
1310 2 : if (sendto(s, msg, (int)strlen(msg) + 1, 0, addr->ai_addr, addr->ai_addrlen) < 0)
1311 : break;
1312 :
1313 2 : fd.fd = s;
1314 2 : fd.events = POLLIN;
1315 2 : fd.revents = 0;
1316 :
1317 2 : retval = poll(&fd, 1, 1000);
1318 :
1319 : /* on interrupt ignore */
1320 2 : if (retval < 0 && sock_errno == TDSSOCK_EINTR)
1321 0 : continue;
1322 :
1323 2 : if (retval == 0) { /* timed out */
1324 : #if 1
1325 0 : tdsdump_log(TDS_DBG_ERROR, "tds7_get_instance_port: timed out on try %d of 16\n", num_try);
1326 0 : continue;
1327 : #else
1328 : int rc;
1329 : tdsdump_log(TDS_DBG_INFO1, "timed out\n");
1330 :
1331 : switch(rc = tdserror(NULL, NULL, TDSETIME, 0)) {
1332 : case TDS_INT_CONTINUE:
1333 : continue; /* try again */
1334 :
1335 : default:
1336 : tdsdump_log(TDS_DBG_ERROR, "error: client error handler returned %d\n", rc);
1337 : case TDS_INT_CANCEL:
1338 : CLOSESOCKET(s);
1339 : return 0;
1340 : }
1341 : #endif
1342 : }
1343 2 : if (retval < 0)
1344 : break;
1345 :
1346 : /* TODO pass also connection and set instance/servername ?? */
1347 :
1348 : /* got data, read and parse */
1349 2 : if ((msg_len = recv(s, msg, sizeof(msg) - 1, 0)) > 3 && msg[0] == 5) {
1350 : char *p;
1351 2 : long l = 0;
1352 2 : int instance_ok = 0, port_ok = 0;
1353 :
1354 : /* assure null terminated */
1355 2 : msg[msg_len] = 0;
1356 2 : tdsdump_dump_buf(TDS_DBG_INFO1, "instance info", msg, msg_len);
1357 :
1358 : /*
1359 : * Parse message and check instance name and port.
1360 : * We don't check servername cause it can be very different from the client's.
1361 : */
1362 2 : for (p = msg + 3;;) {
1363 : char *name, *value;
1364 :
1365 12 : name = p;
1366 12 : p = strchr(p, ';');
1367 12 : if (!p)
1368 : break;
1369 10 : *p++ = 0;
1370 :
1371 10 : value = name;
1372 10 : if (*name) {
1373 10 : value = p;
1374 10 : p = strchr(p, ';');
1375 10 : if (!p)
1376 : break;
1377 10 : *p++ = 0;
1378 : }
1379 :
1380 10 : if (strcasecmp(name, "InstanceName") == 0) {
1381 2 : if (strcasecmp(value, instance) != 0)
1382 : break;
1383 : instance_ok = 1;
1384 8 : } else if (strcasecmp(name, "tcp") == 0) {
1385 2 : l = strtol(value, &p, 10);
1386 2 : if (l > 0 && l <= 0xffff && *p == 0)
1387 2 : port_ok = 1;
1388 : }
1389 : }
1390 2 : if (port_ok && instance_ok) {
1391 2 : port = (int) l;
1392 2 : break;
1393 : }
1394 : }
1395 : }
1396 2 : CLOSESOCKET(s);
1397 2 : tdsdump_log(TDS_DBG_ERROR, "instance port is %d\n", port);
1398 : return port;
1399 : }
1400 :
1401 : #if defined(_WIN32)
1402 : static const char tds_unknown_wsaerror[] = "undocumented WSA error code";
1403 :
1404 : char *
1405 : tds_prwsaerror(int erc)
1406 : {
1407 : char *errstr = NULL;
1408 : FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, NULL, erc,
1409 : MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), (LPTSTR)&errstr, 0, NULL);
1410 : if (errstr) {
1411 : size_t len = strlen(errstr);
1412 : while (len > 0 && (errstr[len-1] == '\r' || errstr[len-1] == '\n'))
1413 : errstr[len-1] = 0;
1414 : return errstr;
1415 : }
1416 : return (char*) tds_unknown_wsaerror;
1417 : }
1418 :
1419 : void
1420 : tds_prwsaerror_free(char *s)
1421 : {
1422 : if (s != tds_unknown_wsaerror)
1423 : LocalFree((HLOCAL) s);
1424 : }
1425 : #endif
1426 :
1427 : /** @} */
1428 :
|