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

Generated by: LCOV version 1.13