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