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