LCOV - code coverage report
Current view: top level - src/tds - net.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 351 477 73.6 %
Date: 2025-10-11 18:49:17 Functions: 23 24 95.8 %

          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        4020 : tds_socket_set_nonblocking(TDS_SYS_SOCKET sock)
     146             : {
     147             : #if !defined(_WIN32)
     148        4020 :         unsigned int ioctl_nonblocking = 1;
     149             : #else
     150             :         u_long ioctl_nonblocking = 1;
     151             : #endif
     152             : 
     153        4020 :         if (IOCTLSOCKET(sock, FIONBIO, &ioctl_nonblocking) >= 0)
     154             :                 return 0;
     155           0 :         return sock_errno;
     156             : }
     157             : 
     158             : static void
     159        3292 : tds_addrinfo_set_port(struct addrinfo *addr, unsigned int port)
     160             : {
     161        3292 :         assert(addr != NULL);
     162             : 
     163        3292 :         switch(addr->ai_family) {
     164        3292 :         case AF_INET:
     165        3292 :                 ((struct sockaddr_in *) addr->ai_addr)->sin_port = htons(port);
     166        3292 :                 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        3292 : }
     175             : 
     176             : const char*
     177        3292 : tds_addrinfo2str(struct addrinfo *addr, char *name, int namemax)
     178             : {
     179             : #ifndef NI_NUMERICHOST
     180             : #define NI_NUMERICHOST 0
     181             : #endif
     182        3292 :         if (!name || namemax <= 0)
     183             :                 return "";
     184        3292 :         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        2944 : tds_get_socket_error(TDS_SYS_SOCKET sock)
     195             : {
     196             :         int err;
     197        2944 :         SOCKLEN_T optlen = sizeof(err);
     198             :         char *errstr;
     199             : 
     200             :         /* check socket error */
     201        2944 :         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        2944 :         } 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        2944 :         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        3290 : 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        3290 :         *p_oserr = 0;
     246             : 
     247        3290 :         tds_addrinfo_set_port(addr, port);
     248        3290 :         tds_addrinfo2str(addr, ipaddr, sizeof(ipaddr));
     249             : 
     250        3290 :         *p_sock = sock = socket(addr->ai_family, SOCK_STREAM, 0);
     251        3290 :         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        3290 :         len = 1;
     260        3290 :         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        3290 :         len = TDS_SOCKET_KEEPALIVE_IDLE;
     272        3290 :         setsockopt(sock, SOL_TCP, TCP_KEEPIDLE, (const void *) &len, sizeof(len));
     273        3290 :         len = TDS_SOCKET_KEEPALIVE_INTERVAL;
     274        3290 :         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        3290 :         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        3290 :         setsockopt(sock, SOL_TCP, TCP_NODELAY, (const void *) &len, sizeof(len));
     290        3290 :         setsockopt(sock, SOL_TCP, TCP_CORK, (const void *) &len, sizeof(len));
     291             : #else
     292             : #error One should be defined
     293             : #endif
     294             : 
     295        3290 :         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        3290 :         if ((*p_oserr = tds_socket_set_nonblocking(sock)) != 0) {
     306             :                 return TDSEUSCT;        /* close enough: "Unable to set communications timer" */
     307             :         }
     308        3290 :         retval = connect(sock, addr->ai_addr, addr->ai_addrlen);
     309        3290 :         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        3290 :         err = *p_oserr = sock_errno;
     316        3290 :         errstr = sock_strerror(err);
     317        3290 :         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        3290 :         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        3290 : tds_open_socket(TDSSOCKET *tds, struct addrinfo *addr, unsigned int port, int timeout, int *p_oserr)
     349             : {
     350        3290 :         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        3290 :         *p_oserr = 0;
     365             : 
     366        3290 :         if (!addr)
     367             :                 return TDSECONN;
     368             : 
     369        3294 :         tdsdump_log(TDS_DBG_INFO1, "Connecting with protocol version %d.%d\n",
     370           4 :                     TDS_MAJOR(conn), TDS_MINOR(conn));
     371             : 
     372        6580 :         for (len = 0, curr_addr = addr; curr_addr != NULL; curr_addr = curr_addr->ai_next)
     373        3290 :                 ++len;
     374             : 
     375        3290 :         addresses = (retry_addr *) tds_new0(alloc_addr, len);
     376        3290 :         if (!addresses)
     377             :                 return TDSEMEM;
     378        3290 :         fds = (struct pollfd *) &addresses[len];
     379             : 
     380        3290 :         tds_error = TDSECONN;
     381             : 
     382             :         /* fill all structures */
     383        3290 :         curr_time = start_time = tds_gettime_ms();
     384        6580 :         for (len = 0, curr_addr = addr; curr_addr != NULL; curr_addr = curr_addr->ai_next) {
     385        3290 :                 fds[len].fd = INVALID_SOCKET;
     386        3290 :                 addresses[len].addr = curr_addr;
     387        3290 :                 addresses[len].next_retry_time = curr_time;
     388        3290 :                 addresses[len].retry_count = 0;
     389        3290 :                 ++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        3290 :         if (len == 1)
     395        3290 :                 addresses[0].retry_count = MAX_RETRY;
     396             : 
     397        3290 :         timeout *= 1000;
     398        3290 :         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        3636 :         while (len) {
     405        3636 :                 int rc, poll_timeout = timeout;
     406             : 
     407             :                 /* timeout */
     408        3636 :                 if (poll_timeout >= 0) {
     409        3636 :                         if (curr_time - start_time > (unsigned) poll_timeout) {
     410         346 :                                 *p_oserr = TDSSOCK_ETIMEDOUT;
     411             :                                 goto exit;
     412             :                         }
     413        3290 :                         poll_timeout -= curr_time - start_time;
     414             :                 }
     415             : 
     416             :                 /* try again if needed */
     417        3290 :                 for (i = 0; i < len; ++i) {
     418             :                         int time_left;
     419             : 
     420        3290 :                         if (!TDS_IS_SOCKET_INVALID(fds[i].fd))
     421           0 :                                 continue;
     422        3290 :                         time_left = addresses[i].next_retry_time - curr_time;
     423        3290 :                         if (time_left <= 0) {
     424             :                                 TDS_SYS_SOCKET sock;
     425        3290 :                                 tds_error = tds_setup_socket(&sock, addresses[i].addr, port, p_oserr);
     426        3290 :                                 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        3290 :                                 case TDSEINPROGRESS:
     434             :                                         /* save socket in the list */
     435        3290 :                                         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        3290 :                 for (i = 0; i < len; ++i) {
     456        3290 :                         fds[i].revents = 0;
     457        3290 :                         fds[i].events = TDSSELWRITE|TDSSELERR;
     458             :                 }
     459        3290 :                 tds_error = TDSECONN;
     460        3290 :                 rc = poll(fds, len, poll_timeout);
     461        3290 :                 oserr = sock_errno; /* save to avoid overrides */
     462        3290 :                 curr_time = tds_gettime_ms();
     463             : 
     464             :                 /* error */
     465        3290 :                 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         346 :                 for (i = 0; i < len; ++i) {
     474        3290 :                         if (TDS_IS_SOCKET_INVALID(fds[i].fd))
     475           0 :                                 continue;
     476        3290 :                         if (!fds[i].revents)
     477         346 :                                 continue;
     478        2944 :                         *p_oserr = tds_get_socket_error(fds[i].fd);
     479        2944 :                         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        2944 :                         if (fds[i].revents & POLLOUT) {
     494        2944 :                                 conn->s = fds[i].fd;
     495        2944 :                                 fds[i].fd = INVALID_SOCKET;
     496        2944 :                                 tds_error = TDSEOK;
     497             :                                 goto exit;
     498             :                         }
     499             :                 }
     500             :         }
     501             : 
     502           0 : exit:
     503             :         if (tds_error != TDSEOK) {
     504         346 :                 tdsdump_log(TDS_DBG_ERROR, "tds_open_socket() failed\n");
     505             :         } else {
     506        2944 :                 tdsdump_log(TDS_DBG_INFO2, "tds_open_socket() succeeded\n");
     507        2944 :                 tds->state = TDS_IDLE;
     508             :         }
     509             : 
     510        6580 :         while (len > 0) {
     511        3290 :                 --len;
     512        3290 :                 if (!TDS_IS_SOCKET_INVALID(fds[len].fd))
     513         346 :                         CLOSESOCKET(fds[len].fd);
     514             :         }
     515        3290 :         free(addresses);
     516        3290 :         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        4434 : tds_close_socket(TDSSOCKET * tds)
     528             : {
     529        4434 :         if (!IS_TDSDEAD(tds)) {
     530             : #if ENABLE_ODBC_MARS
     531        1434 :                 TDSCONNECTION *conn = tds->conn;
     532        1434 :                 unsigned n = 0, count = 0;
     533        1434 :                 tds_mutex_lock(&conn->list_mtx);
     534       93210 :                 for (; n < conn->num_sessions; ++n)
     535       91776 :                         if (TDSSOCKET_VALID(conn->sessions[n]))
     536        1434 :                                 ++count;
     537        1434 :                 if (count > 1)
     538           0 :                         tds_append_fin(tds);
     539        1434 :                 tds_mutex_unlock(&conn->list_mtx);
     540        1434 :                 if (count <= 1) {
     541        1434 :                         tds_disconnect(tds);
     542        1434 :                         tds_connection_close(conn);
     543             :                 } else {
     544           0 :                         tds_set_state(tds, TDS_DEAD);
     545             :                 }
     546             : #else
     547        1434 :                 tds_disconnect(tds);
     548        1434 :                 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        1434 :                 tds_set_s(tds, INVALID_SOCKET);
     551        1434 :                 tds_set_state(tds, TDS_DEAD);
     552             : #endif
     553             :         }
     554        4434 : }
     555             : 
     556             : void
     557        5748 : tds_connection_close(TDSCONNECTION *conn)
     558             : {
     559             : #if ENABLE_ODBC_MARS
     560        3657 :         unsigned n = 0;
     561             : #endif
     562             : 
     563        5748 :         if (!TDS_IS_SOCKET_INVALID(conn->s)) {
     564             :                 /* TODO check error ?? how to return it ?? */
     565        2364 :                 CLOSESOCKET(conn->s);
     566        2364 :                 conn->s = INVALID_SOCKET;
     567             :         }
     568             : 
     569             : #if ENABLE_ODBC_MARS
     570        3657 :         tds_mutex_lock(&conn->list_mtx);
     571      237705 :         for (; n < conn->num_sessions; ++n)
     572      234048 :                 if (TDSSOCKET_VALID(conn->sessions[n]))
     573        1571 :                         tds_set_state(conn->sessions[n], TDS_DEAD);
     574        3657 :         tds_mutex_unlock(&conn->list_mtx);
     575             : #else
     576        2091 :         tds_set_state((TDSSOCKET* ) conn, TDS_DEAD);
     577             : #endif
     578        5748 : }
     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      302139 : tds_select(TDSSOCKET * tds, unsigned tds_sel, int timeout_seconds)
     590             : {
     591             :         int rc, seconds;
     592             :         unsigned int poll_seconds;
     593             : 
     594      302139 :         assert(tds != NULL);
     595      302139 :         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      302139 :         poll_seconds = (tds_get_ctx(tds) && tds_get_ctx(tds)->int_handler)? 1 : timeout_seconds;
     613      302589 :         for (seconds = timeout_seconds; timeout_seconds == 0 || seconds > 0; seconds -= poll_seconds) {
     614             :                 struct pollfd fds[2];
     615      302339 :                 int timeout = poll_seconds ? poll_seconds * 1000 : -1;
     616             : 
     617      302339 :                 if (TDS_IS_SOCKET_INVALID(tds_get_s(tds)))
     618      301889 :                         return -1;
     619             : 
     620      379118 :                 if ((tds_sel & TDSSELREAD) != 0 && tds->conn->tls_session && tds_ssl_pending(tds->conn))
     621             :                         return POLLIN;
     622             : 
     623      288210 :                 fds[0].fd = tds_get_s(tds);
     624      288210 :                 fds[0].events = tds_sel;
     625      288210 :                 fds[0].revents = 0;
     626      288210 :                 fds[1].fd = tds_wakeup_get_fd(&tds->conn->wakeup);
     627      288210 :                 fds[1].events = POLLIN;
     628      288210 :                 fds[1].revents = 0;
     629      288210 :                 rc = poll(fds, 2, timeout);
     630             : 
     631      288210 :                 if (rc > 0 ) {
     632      287760 :                         if (fds[0].revents & POLLERR) {
     633           4 :                                 set_sock_errno(TDSSOCK_ECONNRESET);
     634           4 :                                 return -1;
     635             :                         }
     636      287756 :                         rc = fds[0].revents;
     637      287756 :                         if (fds[1].revents) {
     638             : #if ENABLE_ODBC_MARS
     639          98 :                                 tds_check_cancel(tds->conn);
     640             : #endif
     641         225 :                                 rc |= TDSPOLLURG;
     642             :                         }
     643             :                         return rc;
     644             :                 }
     645             : 
     646         450 :                 if (rc < 0) {
     647             :                         char *errstr;
     648             : 
     649          16 :                         switch (sock_errno) {
     650          16 :                         case TDSSOCK_EINTR:
     651             :                         case EAGAIN:
     652             :                         case TDSSOCK_EINPROGRESS:
     653             :                                 /* FIXME this should be global maximun, not loop one */
     654          16 :                                 seconds += poll_seconds;
     655          16 :                                 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         434 :                 }
     664             : 
     665         450 :                 assert(rc == 0 || (rc < 0 && (sock_errno == TDSSOCK_EINTR ||
     666             :                                               sock_errno == EAGAIN ||
     667             :                                               sock_errno == TDSSOCK_EINPROGRESS
     668             :                                               )));
     669             : 
     670         450 :                 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         264 :                         int timeout_action = (*tds_get_ctx(tds)->int_handler) (tds_get_parent(tds));
     681         264 :                         switch (timeout_action) {
     682         264 :                         case TDS_INT_CONTINUE:          /* keep waiting */
     683         264 :                                 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         186 :                 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 int
     709      179750 : tds_socket_read(TDSCONNECTION * conn, TDSSOCKET *tds, unsigned char *buf, int buflen)
     710             : {
     711             :         int len, err;
     712             : 
     713             : #if ENABLE_EXTRA_CHECKS
     714             :         /* this simulate the fact that recv can return less bytes */
     715      179750 :         if (buflen >= 5) {
     716             :                 static int cnt = 0;
     717      155355 :                 if (++cnt == 5) {
     718       30416 :                         cnt = 0;
     719       30416 :                         buflen -= 3;
     720             :                 }
     721             :         }
     722             : #endif
     723             : 
     724             :         /* read directly from socket*/
     725      179750 :         len = READSOCKET(conn->s, buf, buflen);
     726      179750 :         if (len > 0)
     727             :                 return len;
     728             : 
     729          22 :         err = sock_errno;
     730          22 :         if (len < 0 && TDSSOCK_WOULDBLOCK(err))
     731             :                 return 0;
     732             : 
     733             :         /* detect connection close */
     734          22 :         tds_connection_close(conn);
     735          22 :         tdserror(conn->tds_ctx, tds, len == 0 ? TDSESEOF : TDSEREAD, len == 0 ? 0 : err);
     736          22 :         return -1;
     737             : }
     738             : 
     739             : /**
     740             :  * Write to an OS socket
     741             :  * @returns 0 if blocking, <0 error >0 bytes readed
     742             :  */
     743             : static int
     744       88986 : tds_socket_write(TDSCONNECTION *conn, TDSSOCKET *tds, const unsigned char *buf, int buflen)
     745             : {
     746             :         int err, len;
     747             :         char *errstr;
     748             : 
     749             : #if ENABLE_EXTRA_CHECKS
     750             :         /* this simulate the fact that send can return less bytes */
     751       88986 :         if (buflen >= 11) {
     752             :                 static int cnt = 0;
     753       73006 :                 if (++cnt == 5) {
     754       13968 :                         cnt = 0;
     755       13968 :                         buflen -= 3;
     756             :                 }
     757             :         }
     758             : #endif
     759             : 
     760             : #ifdef USE_CORK
     761       88986 :         if (!conn->corked) {
     762       71969 :                 int opt = 1;
     763       71969 :                 setsockopt(conn->s, SOL_TCP, TCP_CORK, (const void *) &opt, sizeof(opt));
     764       71969 :                 conn->corked = true;
     765             :         }
     766             : #endif
     767             : 
     768             : #if defined(SO_NOSIGPIPE)
     769             :         len = send(conn->s, buf, buflen, 0);
     770             : #else
     771       88986 :         len = WRITESOCKET(conn->s, buf, buflen);
     772             : #endif
     773       88986 :         if (len > 0)
     774             :                 return len;
     775             : 
     776          63 :         err = sock_errno;
     777          63 :         if (0 == len || TDSSOCK_WOULDBLOCK(err) || err == TDSSOCK_EINTR)
     778             :                 return 0;
     779             : 
     780          63 :         assert(len < 0);
     781             : 
     782             :         /* detect connection close */
     783          63 :         errstr = sock_strerror(err);
     784          63 :         tdsdump_log(TDS_DBG_NETWORK, "send(2) failed: %d (%s)\n", err, errstr);
     785             :         sock_strerror_free(errstr);
     786          63 :         tds_connection_close(conn);
     787          63 :         tdserror(conn->tds_ctx, tds, TDSEWRIT, err);
     788          63 :         return -1;
     789             : }
     790             : 
     791             : int
     792        4233 : tds_wakeup_init(TDSPOLLWAKEUP *wakeup)
     793             : {
     794             :         TDS_SYS_SOCKET sv[2];
     795             :         int ret;
     796             : 
     797        4233 :         wakeup->s_signal = wakeup->s_signaled = INVALID_SOCKET;
     798             : #if defined(__linux__) && HAVE_EVENTFD
     799             : #  ifdef EFD_CLOEXEC
     800        4233 :         ret = eventfd(0, EFD_CLOEXEC|EFD_NONBLOCK);
     801             : #  else
     802             :         ret = -1;
     803             : #  endif
     804             :         /* Linux version up to 2.6.26 do not support flags, try without */
     805        4233 :         if (ret < 0 && (ret = eventfd(0, 0)) >= 0) {
     806           0 :                 fcntl(ret, F_SETFD, fcntl(ret, F_GETFD, 0) | FD_CLOEXEC);
     807           0 :                 fcntl(ret, F_SETFL, fcntl(ret, F_GETFL, 0) | O_NONBLOCK);
     808             :         }
     809        4233 :         if (ret >= 0) {
     810        4233 :                 wakeup->s_signaled = ret;
     811        4233 :                 return 0;
     812             :         }
     813             : #endif
     814           0 :         ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
     815           0 :         if (ret)
     816             :                 return ret;
     817           0 :         wakeup->s_signal   = sv[0];
     818           0 :         wakeup->s_signaled = sv[1];
     819           0 :         return 0;
     820             : }
     821             : 
     822             : void
     823        4127 : tds_wakeup_close(TDSPOLLWAKEUP *wakeup)
     824             : {
     825        4127 :         if (!TDS_IS_SOCKET_INVALID(wakeup->s_signal))
     826           0 :                 CLOSESOCKET(wakeup->s_signal);
     827        4127 :         if (!TDS_IS_SOCKET_INVALID(wakeup->s_signaled))
     828        4127 :                 CLOSESOCKET(wakeup->s_signaled);
     829        4127 : }
     830             : 
     831             : 
     832             : void
     833         227 : tds_wakeup_send(TDSPOLLWAKEUP *wakeup, char cancel)
     834             : {
     835             : #if defined(__linux__) && HAVE_EVENTFD
     836         227 :         if (wakeup->s_signal == -1) {
     837         227 :                 uint64_t one = 1;
     838         227 :                 (void) write(wakeup->s_signaled, &one, sizeof(one));
     839             :                 return;
     840             :         }
     841             : #endif
     842           0 :         send(wakeup->s_signal, &cancel, sizeof(cancel), 0);
     843             : }
     844             : 
     845             : static int
     846         224 : tds_connection_signaled(TDSCONNECTION *conn)
     847             : {
     848             :         int len;
     849             :         char to_cancel[16];
     850             : 
     851             : #if defined(__linux__) && HAVE_EVENTFD
     852         224 :         if (conn->wakeup.s_signal == -1)
     853         224 :                 return read(conn->wakeup.s_signaled, to_cancel, 8) > 0;
     854             : #endif
     855             : 
     856           0 :         len = READSOCKET(conn->wakeup.s_signaled, to_cancel, sizeof(to_cancel));
     857             :         do {
     858             :                 /* no cancel found */
     859           0 :                 if (len <= 0)
     860             :                         return 0;
     861           0 :         } while(!to_cancel[--len]);
     862             :         return 1;
     863             : }
     864             : 
     865             : #if ENABLE_ODBC_MARS
     866             : static void
     867          98 : tds_check_cancel(TDSCONNECTION *conn)
     868             : {
     869             :         TDSSOCKET *tds;
     870             :         int rc;
     871             : 
     872          98 :         if (!tds_connection_signaled(conn))
     873             :                 return;
     874             : 
     875             :         do {
     876          98 :                 unsigned n = 0;
     877             : 
     878          98 :                 rc = TDS_SUCCESS;
     879          98 :                 tds_mutex_lock(&conn->list_mtx);
     880             :                 /* Here we scan all list searching for sessions that should send cancel packets */
     881        6370 :                 for (; n < conn->num_sessions; ++n)
     882        6272 :                         if (TDSSOCKET_VALID(tds=conn->sessions[n]) && tds->in_cancel == 1) {
     883             :                                 /* send cancel */
     884          98 :                                 tds->in_cancel = 2;
     885          98 :                                 tds_mutex_unlock(&conn->list_mtx);
     886          98 :                                 rc = tds_append_cancel(tds);
     887          98 :                                 tds_mutex_lock(&conn->list_mtx);
     888          98 :                                 if (rc != TDS_SUCCESS)
     889             :                                         break;
     890             :                         }
     891          98 :                 tds_mutex_unlock(&conn->list_mtx);
     892             :                 /* for all failed */
     893             :                 /* this must be done outside loop cause it can alter list */
     894             :                 /* this must be done unlocked cause it can lock again */
     895          98 :                 if (rc != TDS_SUCCESS)
     896           0 :                         tds_close_socket(tds);
     897          98 :         } while(rc != TDS_SUCCESS);
     898             : }
     899             : #endif
     900             : 
     901             : /**
     902             :  * Loops until we have received some characters
     903             :  * return -1 on failure
     904             :  */
     905             : int
     906      108768 : tds_goodread(TDSSOCKET * tds, unsigned char *buf, int buflen)
     907             : {
     908      108768 :         if (tds == NULL || buf == NULL || buflen < 1)
     909             :                 return -1;
     910             : 
     911             :         for (;;) {
     912             :                 int len, err;
     913             : 
     914             :                 /* FIXME this block writing from other sessions */
     915      108998 :                 len = tds_select(tds, TDSSELREAD, tds->query_timeout);
     916             : #if !ENABLE_ODBC_MARS
     917       86888 :                 if (len > 0 && (len & TDSPOLLURG)) {
     918         126 :                         tds_connection_signaled(tds->conn);
     919             :                         /* send cancel */
     920         126 :                         if (tds->in_cancel == 1)
     921         105 :                                 tds_put_cancel(tds);
     922         126 :                         continue;
     923             :                 }
     924             : #endif
     925      108872 :                 if (len > 0) {
     926      108745 :                         len = tds_socket_read(tds->conn, tds, buf, buflen);
     927      108745 :                         if (len == 0)
     928           0 :                                 continue;
     929             :                         return len;
     930             :                 }
     931             : 
     932             :                 /* error */
     933         127 :                 if (len < 0) {
     934           2 :                         if (TDSSOCK_WOULDBLOCK(sock_errno)) /* shouldn't happen, but OK */
     935           0 :                                 continue;
     936           2 :                         err = sock_errno;
     937           2 :                         tds_connection_close(tds->conn);
     938           2 :                         tdserror(tds_get_ctx(tds), tds, TDSEREAD, err);
     939           2 :                         return -1;
     940             :                 }
     941             : 
     942             :                 /* timeout */
     943         125 :                 switch (tdserror(tds_get_ctx(tds), tds, TDSETIME, sock_errno)) {
     944             :                 case TDS_INT_CONTINUE:
     945             :                         break;
     946          21 :                 default:
     947             :                 case TDS_INT_CANCEL:
     948          21 :                         tds_close_socket(tds);
     949          21 :                         return -1;
     950             :                 }
     951             :         }
     952             : }
     953             : 
     954             : int
     955      177393 : tds_connection_read(TDSSOCKET * tds, unsigned char *buf, int buflen)
     956             : {
     957      177393 :         TDSCONNECTION *conn = tds->conn;
     958             : 
     959      177393 :         if (conn->tls_session)
     960       41429 :                 return tds_ssl_read(conn, buf, buflen);
     961             : 
     962             : #if ENABLE_ODBC_MARS
     963       71005 :         return tds_socket_read(conn, tds, buf, buflen);
     964             : #else
     965       64959 :         return tds_goodread(tds, buf, buflen);
     966             : #endif
     967             : }
     968             : 
     969             : /**
     970             :  * \param tds the famous socket
     971             :  * \param buffer data to send
     972             :  * \param buflen bytes in buffer
     973             :  * \param last 1 if this is the last packet, else 0
     974             :  * \return length written (>0), <0 on failure
     975             :  */
     976             : int
     977       46847 : tds_goodwrite(TDSSOCKET * tds, const unsigned char *buffer, size_t buflen)
     978             : {
     979             :         int len;
     980       46847 :         size_t sent = 0;
     981             : 
     982       46847 :         assert(tds && buffer);
     983             : 
     984      102486 :         while (sent < buflen) {
     985             :                 /* TODO if send buffer is full we block receive !!! */
     986       55682 :                 len = tds_select(tds, TDSSELWRITE, tds->query_timeout);
     987             : 
     988       55682 :                 if (len > 0) {
     989       55674 :                         len = tds_socket_write(tds->conn, tds, buffer + sent, buflen - sent);
     990       55674 :                         if (len == 0)
     991           0 :                                 continue;
     992       55674 :                         if (len < 0)
     993             :                                 return len;
     994             : 
     995       55639 :                         sent += len;
     996       55639 :                         continue;
     997             :                 }
     998             : 
     999             :                 /* error */
    1000           8 :                 if (len < 0) {
    1001           8 :                         int err = sock_errno;
    1002             :                         char *errstr;
    1003             : 
    1004           8 :                         if (TDSSOCK_WOULDBLOCK(err)) /* shouldn't happen, but OK, retry */
    1005           0 :                                 continue;
    1006           8 :                         errstr = sock_strerror(err);
    1007           8 :                         tdsdump_log(TDS_DBG_NETWORK, "select(2) failed: %d (%s)\n", err, errstr);
    1008             :                         sock_strerror_free(errstr);
    1009           8 :                         tds_connection_close(tds->conn);
    1010           8 :                         tdserror(tds_get_ctx(tds), tds, TDSEWRIT, err);
    1011           8 :                         return -1;
    1012             :                 }
    1013             : 
    1014             :                 /* timeout */
    1015           0 :                 tdsdump_log(TDS_DBG_NETWORK, "tds_goodwrite(): timed out, asking client\n");
    1016           0 :                 switch (tdserror(tds_get_ctx(tds), tds, TDSETIME, sock_errno)) {
    1017             :                 case TDS_INT_CONTINUE:
    1018             :                         break;
    1019           0 :                 default:
    1020             :                 case TDS_INT_CANCEL:
    1021           0 :                         tds_close_socket(tds);
    1022           0 :                         return -1;
    1023             :                 }
    1024             :         }
    1025             : 
    1026       46804 :         return (int) sent;
    1027             : }
    1028             : 
    1029             : void
    1030       33027 : tds_connection_coalesce(TDSSOCKET *tds TDS_UNUSED)
    1031             : {
    1032             : #ifdef USE_CORK
    1033       33027 :         TDSCONNECTION *conn = tds->conn;
    1034             : 
    1035       33027 :         if (!conn->corked) {
    1036       32419 :                 int opt = 1;
    1037       32419 :                 setsockopt(conn->s, SOL_TCP, TCP_CORK, (const void *) &opt, sizeof(opt));
    1038       32419 :                 conn->corked = true;
    1039             :         }
    1040             : #endif
    1041       33027 : }
    1042             : 
    1043             : void
    1044      104322 : tds_connection_flush(TDSSOCKET *tds TDS_UNUSED)
    1045             : {
    1046             : #ifdef USE_CORK
    1047      104322 :         TDSCONNECTION *conn = tds->conn;
    1048             : 
    1049      104322 :         if (conn->corked) {
    1050      104322 :                 int opt = 0;
    1051      104322 :                 setsockopt(conn->s, SOL_TCP, TCP_CORK, (const void *) &opt, sizeof(opt));
    1052      104322 :                 conn->corked = false;
    1053             :         }
    1054             : #endif
    1055      104322 : }
    1056             : 
    1057             : int
    1058       80159 : tds_connection_write(TDSSOCKET *tds, const unsigned char *buf, int buflen, int final)
    1059             : {
    1060             :         int sent;
    1061       80159 :         TDSCONNECTION *conn = tds->conn;
    1062             : 
    1063             : #if !defined(_WIN32) && !defined(MSG_NOSIGNAL) && !defined(DOS32X) && !defined(SO_NOSIGPIPE)
    1064             :         void (*oldsig) (int);
    1065             : 
    1066             :         oldsig = signal(SIGPIPE, SIG_IGN);
    1067             :         if (oldsig == SIG_ERR) {
    1068             :                 tdsdump_log(TDS_DBG_WARN, "TDS: Warning: Couldn't set SIGPIPE signal to be ignored\n");
    1069             :         }
    1070             : #endif
    1071             : 
    1072       80159 :         if (conn->tls_session)
    1073       18778 :                 sent = tds_ssl_write(conn, buf, buflen);
    1074             :         else
    1075             : #if ENABLE_ODBC_MARS
    1076       33312 :                 sent = tds_socket_write(conn, tds, buf, buflen);
    1077             : #else
    1078       28069 :                 sent = tds_goodwrite(tds, buf, buflen);
    1079             : #endif
    1080             : 
    1081             :         /* force packet flush */
    1082       80159 :         if (final && sent >= buflen)
    1083       71904 :                 tds_connection_flush(tds);
    1084             : 
    1085             : #if !defined(_WIN32) && !defined(MSG_NOSIGNAL) && !defined(DOS32X) && !defined(SO_NOSIGPIPE)
    1086             :         if (signal(SIGPIPE, oldsig) == SIG_ERR) {
    1087             :                 tdsdump_log(TDS_DBG_WARN, "TDS: Warning: Couldn't reset SIGPIPE signal to previous value\n");
    1088             :         }
    1089             : #endif
    1090       80159 :         return sent;
    1091             : }
    1092             : 
    1093             : /**
    1094             :  * Get port of all instances
    1095             :  * @return default port number or 0 if error
    1096             :  * @remark experimental, cf. MC-SQLR.pdf.
    1097             :  */
    1098             : int
    1099           0 : tds7_get_instance_ports(FILE *output, struct addrinfo *addr)
    1100             : {
    1101             :         int num_try;
    1102             :         struct pollfd fd;
    1103             :         int retval;
    1104             :         TDS_SYS_SOCKET s;
    1105             :         char msg[16*1024];
    1106           0 :         int msg_len = 0;
    1107           0 :         int port = 0;
    1108             :         char ipaddr[128];
    1109             : 
    1110             : 
    1111           0 :         tds_addrinfo_set_port(addr, 1434);
    1112           0 :         tds_addrinfo2str(addr, ipaddr, sizeof(ipaddr));
    1113             : 
    1114           0 :         tdsdump_log(TDS_DBG_ERROR, "tds7_get_instance_ports(%s)\n", ipaddr);
    1115             : 
    1116             :         /* create an UDP socket */
    1117           0 :         if (TDS_IS_SOCKET_INVALID(s = socket(addr->ai_family, SOCK_DGRAM, 0))) {
    1118           0 :                 char *errstr = sock_strerror(sock_errno);
    1119           0 :                 tdsdump_log(TDS_DBG_ERROR, "socket creation error: %s\n", errstr);
    1120             :                 sock_strerror_free(errstr);
    1121             :                 return 0;
    1122             :         }
    1123             : 
    1124             :         /*
    1125             :          * on cluster environment is possible that reply packet came from
    1126             :          * different IP so do not filter by ip with connect
    1127             :          */
    1128             : 
    1129           0 :         if (tds_socket_set_nonblocking(s) != 0) {
    1130           0 :                 CLOSESOCKET(s);
    1131           0 :                 return 0;
    1132             :         }
    1133             : 
    1134             :         /* 
    1135             :          * Request the instance's port from the server.  
    1136             :          * There is no easy way to detect if port is closed so we always try to
    1137             :          * get a reply from server 16 times. 
    1138             :          */
    1139           0 :         for (num_try = 0; num_try < 16 && msg_len == 0; ++num_try) {
    1140             :                 /* send the request */
    1141           0 :                 msg[0] = 3;
    1142           0 :                 if (sendto(s, msg, 1, 0, addr->ai_addr, addr->ai_addrlen) < 0)
    1143             :                         break;
    1144             : 
    1145           0 :                 fd.fd = s;
    1146           0 :                 fd.events = POLLIN;
    1147           0 :                 fd.revents = 0;
    1148             : 
    1149           0 :                 retval = poll(&fd, 1, 1000);
    1150             :                 
    1151             :                 /* on interrupt ignore */
    1152           0 :                 if (retval < 0 && sock_errno == TDSSOCK_EINTR)
    1153           0 :                         continue;
    1154             :                 
    1155           0 :                 if (retval == 0) { /* timed out */
    1156             : #if 1
    1157           0 :                         tdsdump_log(TDS_DBG_ERROR, "tds7_get_instance_port: timed out on try %d of 16\n", num_try);
    1158           0 :                         continue;
    1159             : #else
    1160             :                         int rc;
    1161             :                         tdsdump_log(TDS_DBG_INFO1, "timed out\n");
    1162             : 
    1163             :                         switch(rc = tdserror(NULL, NULL, TDSETIME, 0)) {
    1164             :                         case TDS_INT_CONTINUE:
    1165             :                                 continue;       /* try again */
    1166             : 
    1167             :                         default:
    1168             :                                 tdsdump_log(TDS_DBG_ERROR, "error: client error handler returned %d\n", rc);
    1169             :                         case TDS_INT_CANCEL: 
    1170             :                                 CLOSESOCKET(s);
    1171             :                                 return 0;
    1172             :                         }
    1173             : #endif
    1174             :                 }
    1175           0 :                 if (retval < 0)
    1176             :                         break;
    1177             : 
    1178             :                 /* got data, read and parse */
    1179           0 :                 if ((msg_len = recv(s, msg, sizeof(msg) - 1, 0)) > 3 && msg[0] == 5) {
    1180           0 :                         char *name, sep[2] = ";", *save;
    1181             : 
    1182             :                         /* assure null terminated */
    1183           0 :                         msg[msg_len] = 0;
    1184           0 :                         tdsdump_dump_buf(TDS_DBG_INFO1, "instance info", msg, msg_len);
    1185             :                         
    1186             :                         if (0) {        /* To debug, print the whole string. */
    1187             :                                 char *p;
    1188             : 
    1189             :                                 for (*sep = '\n', p=msg+3; p < msg + msg_len; p++) {
    1190             :                                         if( *p == ';' )
    1191             :                                                 *p = *sep;
    1192             :                                 }
    1193             :                                 fputs(msg + 3, output);
    1194             :                         }
    1195             : 
    1196             :                         /*
    1197             :                          * Parse and print message.
    1198             :                          */
    1199           0 :                         name = strtok_r(msg+3, sep, &save);
    1200           0 :                         while (name && output) {
    1201             :                                 int i;
    1202             :                                 static const char *const names[] = { "ServerName", "InstanceName", "IsClustered", "Version",
    1203             :                                                                "tcp", "np", "via" };
    1204             : 
    1205           0 :                                 for (i=0; name && i < TDS_VECTOR_SIZE(names); i++) {
    1206           0 :                                         const char *value = strtok_r(NULL, sep, &save);
    1207             :                                         
    1208           0 :                                         if (strcmp(name, names[i]) != 0)
    1209           0 :                                                 fprintf(output, "error: expecting '%s', found '%s'\n", names[i], name);
    1210           0 :                                         if (value) 
    1211           0 :                                                 fprintf(output, "%15s %s\n", name, value);
    1212             :                                         else 
    1213             :                                                 break;
    1214             : 
    1215           0 :                                         name = strtok_r(NULL, sep, &save);
    1216             : 
    1217           0 :                                         if (name && strcmp(name, names[0]) == 0)
    1218             :                                                 break;
    1219             :                                 }
    1220           0 :                                 if (name) 
    1221           0 :                                         fprintf(output, "\n");
    1222             :                         }
    1223             :                 }
    1224             :         }
    1225           0 :         CLOSESOCKET(s);
    1226           0 :         tdsdump_log(TDS_DBG_ERROR, "default instance port is %d\n", port);
    1227             :         return port;
    1228             : }
    1229             : 
    1230             : /**
    1231             :  * Get port of given instance
    1232             :  * @return port number or 0 if error
    1233             :  */
    1234             : int
    1235           2 : tds7_get_instance_port(struct addrinfo *addr, const char *instance)
    1236             : {
    1237             :         int num_try;
    1238             :         struct pollfd fd;
    1239             :         int retval;
    1240             :         TDS_SYS_SOCKET s;
    1241             :         char msg[1024];
    1242             :         int msg_len;
    1243           2 :         int port = 0;
    1244             :         char ipaddr[128];
    1245             : 
    1246           2 :         tds_addrinfo_set_port(addr, 1434);
    1247           2 :         tds_addrinfo2str(addr, ipaddr, sizeof(ipaddr));
    1248             : 
    1249           2 :         tdsdump_log(TDS_DBG_ERROR, "tds7_get_instance_port(%s, %s)\n", ipaddr, instance);
    1250             : 
    1251             :         /* create an UDP socket */
    1252           2 :         if (TDS_IS_SOCKET_INVALID(s = socket(addr->ai_family, SOCK_DGRAM, 0))) {
    1253           0 :                 char *errstr = sock_strerror(sock_errno);
    1254           0 :                 tdsdump_log(TDS_DBG_ERROR, "socket creation error: %s\n", errstr);
    1255             :                 sock_strerror_free(errstr);
    1256             :                 return 0;
    1257             :         }
    1258             : 
    1259             :         /*
    1260             :          * on cluster environment is possible that reply packet came from
    1261             :          * different IP so do not filter by ip with connect
    1262             :          */
    1263             : 
    1264           2 :         if (tds_socket_set_nonblocking(s) != 0) {
    1265           0 :                 CLOSESOCKET(s);
    1266           0 :                 return 0;
    1267             :         }
    1268             : 
    1269             :         /* 
    1270             :          * Request the instance's port from the server.  
    1271             :          * There is no easy way to detect if port is closed so we always try to
    1272             :          * get a reply from server 16 times. 
    1273             :          */
    1274           0 :         for (num_try = 0; num_try < 16; ++num_try) {
    1275             :                 /* send the request */
    1276           2 :                 msg[0] = 4;
    1277           2 :                 strlcpy(msg + 1, instance, sizeof(msg) - 1);
    1278           2 :                 if (sendto(s, msg, (int)strlen(msg) + 1, 0, addr->ai_addr, addr->ai_addrlen) < 0)
    1279             :                         break;
    1280             : 
    1281           2 :                 fd.fd = s;
    1282           2 :                 fd.events = POLLIN;
    1283           2 :                 fd.revents = 0;
    1284             : 
    1285           2 :                 retval = poll(&fd, 1, 1000);
    1286             :                 
    1287             :                 /* on interrupt ignore */
    1288           2 :                 if (retval < 0 && sock_errno == TDSSOCK_EINTR)
    1289           0 :                         continue;
    1290             :                 
    1291           2 :                 if (retval == 0) { /* timed out */
    1292             : #if 1
    1293           0 :                         tdsdump_log(TDS_DBG_ERROR, "tds7_get_instance_port: timed out on try %d of 16\n", num_try);
    1294           0 :                         continue;
    1295             : #else
    1296             :                         int rc;
    1297             :                         tdsdump_log(TDS_DBG_INFO1, "timed out\n");
    1298             : 
    1299             :                         switch(rc = tdserror(NULL, NULL, TDSETIME, 0)) {
    1300             :                         case TDS_INT_CONTINUE:
    1301             :                                 continue;       /* try again */
    1302             : 
    1303             :                         default:
    1304             :                                 tdsdump_log(TDS_DBG_ERROR, "error: client error handler returned %d\n", rc);
    1305             :                         case TDS_INT_CANCEL: 
    1306             :                                 CLOSESOCKET(s);
    1307             :                                 return 0;
    1308             :                         }
    1309             : #endif
    1310             :                 }
    1311           2 :                 if (retval < 0)
    1312             :                         break;
    1313             : 
    1314             :                 /* TODO pass also connection and set instance/servername ?? */
    1315             : 
    1316             :                 /* got data, read and parse */
    1317           2 :                 if ((msg_len = recv(s, msg, sizeof(msg) - 1, 0)) > 3 && msg[0] == 5) {
    1318             :                         char *p;
    1319           2 :                         long l = 0;
    1320           2 :                         int instance_ok = 0, port_ok = 0;
    1321             : 
    1322             :                         /* assure null terminated */
    1323           2 :                         msg[msg_len] = 0;
    1324           2 :                         tdsdump_dump_buf(TDS_DBG_INFO1, "instance info", msg, msg_len);
    1325             : 
    1326             :                         /*
    1327             :                          * Parse message and check instance name and port.
    1328             :                          * We don't check servername cause it can be very different from the client's. 
    1329             :                          */
    1330           2 :                         for (p = msg + 3;;) {
    1331             :                                 char *name, *value;
    1332             : 
    1333          12 :                                 name = p;
    1334          12 :                                 p = strchr(p, ';');
    1335          12 :                                 if (!p)
    1336             :                                         break;
    1337          10 :                                 *p++ = 0;
    1338             : 
    1339          10 :                                 value = name;
    1340          10 :                                 if (*name) {
    1341          10 :                                         value = p;
    1342          10 :                                         p = strchr(p, ';');
    1343          10 :                                         if (!p)
    1344             :                                                 break;
    1345          10 :                                         *p++ = 0;
    1346             :                                 }
    1347             : 
    1348          10 :                                 if (strcasecmp(name, "InstanceName") == 0) {
    1349           2 :                                         if (strcasecmp(value, instance) != 0)
    1350             :                                                 break;
    1351             :                                         instance_ok = 1;
    1352           8 :                                 } else if (strcasecmp(name, "tcp") == 0) {
    1353           2 :                                         l = strtol(value, &p, 10);
    1354           2 :                                         if (l > 0 && l <= 0xffff && *p == 0)
    1355           2 :                                                 port_ok = 1;
    1356             :                                 }
    1357             :                         }
    1358           2 :                         if (port_ok && instance_ok) {
    1359           2 :                                 port = l;
    1360           2 :                                 break;
    1361             :                         }
    1362             :                 }
    1363             :         }
    1364           2 :         CLOSESOCKET(s);
    1365           2 :         tdsdump_log(TDS_DBG_ERROR, "instance port is %d\n", port);
    1366             :         return port;
    1367             : }
    1368             : 
    1369             : #if defined(_WIN32)
    1370             : static const char tds_unknown_wsaerror[] = "undocumented WSA error code";
    1371             : 
    1372             : char *
    1373             : tds_prwsaerror(int erc)
    1374             : {
    1375             :         char *errstr = NULL;
    1376             :         FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, NULL, erc,
    1377             :                       MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), (LPTSTR)&errstr, 0, NULL);
    1378             :         if (errstr) {
    1379             :                 size_t len = strlen(errstr);
    1380             :                 while (len > 0 && (errstr[len-1] == '\r' || errstr[len-1] == '\n'))
    1381             :                         errstr[len-1] = 0;
    1382             :                 return errstr;
    1383             :         }
    1384             :         return (char*) tds_unknown_wsaerror;
    1385             : }
    1386             : 
    1387             : void
    1388             : tds_prwsaerror_free(char *s)
    1389             : {
    1390             :         if (s != tds_unknown_wsaerror)
    1391             :                 LocalFree((HLOCAL) s);
    1392             : }
    1393             : #endif
    1394             : 
    1395             : /** @} */
    1396             : 

Generated by: LCOV version 1.13