LCOV - code coverage report
Current view: top level - src/tds - packet.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 483 514 94.0 %
Date: 2025-01-18 12:13:41 Functions: 20 20 100.0 %

          Line data    Source code
       1             : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
       2             :  * Copyright (C) 2012 Frediano Ziglio
       3             :  *
       4             :  * This library is free software; you can redistribute it and/or
       5             :  * modify it under the terms of the GNU Library General Public
       6             :  * License as published by the Free Software Foundation; either
       7             :  * version 2 of the License, or (at your option) any later version.
       8             :  *
       9             :  * This library is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12             :  * Library General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU Library General Public
      15             :  * License along with this library; if not, write to the
      16             :  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
      17             :  * Boston, MA 02111-1307, USA.
      18             :  */
      19             : 
      20             : #include <config.h>
      21             : 
      22             : #include <stdarg.h>
      23             : #include <stdio.h>
      24             : #include <assert.h>
      25             : 
      26             : #if HAVE_ERRNO_H
      27             : #include <errno.h>
      28             : #endif /* HAVE_ERRNO_H */
      29             : 
      30             : #if HAVE_STDLIB_H
      31             : #include <stdlib.h>
      32             : #endif /* HAVE_STDLIB_H */
      33             : 
      34             : #if HAVE_STRING_H
      35             : #include <string.h>
      36             : #endif /* HAVE_STRING_H */
      37             : 
      38             : #if HAVE_UNISTD_H
      39             : #include <unistd.h>
      40             : #endif /* HAVE_UNISTD_H */
      41             : 
      42             : #if HAVE_POLL_H
      43             : #include <poll.h>
      44             : #endif /* HAVE_POLL_H */
      45             : 
      46             : #include <freetds/tds.h>
      47             : #include <freetds/bytes.h>
      48             : #include <freetds/iconv.h>
      49             : #include <freetds/replacements.h>
      50             : #include <freetds/checks.h>
      51             : #include <freetds/tls.h>
      52             : 
      53             : #undef MAX
      54             : #define MAX(a,b) (((a) > (b)) ? (a) : (b))
      55             : 
      56             : /**
      57             :  * \addtogroup network
      58             :  * @{ 
      59             :  */
      60             : 
      61             : #if ENABLE_ODBC_MARS
      62             : static TDSRET tds_update_recv_wnd(TDSSOCKET *tds, TDS_UINT new_recv_wnd);
      63             : static int tds_packet_write(TDSCONNECTION *conn);
      64             : #endif
      65             : 
      66             : /* get packet from the cache */
      67             : static TDSPACKET *
      68       74779 : tds_get_packet(TDSCONNECTION *conn, unsigned len)
      69             : {
      70       74779 :         TDSPACKET *packet, *to_free = NULL;
      71             : 
      72       74779 :         tds_mutex_lock(&conn->list_mtx);
      73      152384 :         while ((packet = conn->packet_cache) != NULL) {
      74       72819 :                 --conn->num_cached_packets;
      75       72819 :                 conn->packet_cache = packet->next;
      76             : 
      77             :                 /* return it */
      78       72819 :                 if (packet->capacity >= len) {
      79       69993 :                         TDS_MARK_UNDEFINED(packet->buf, packet->capacity);
      80       69993 :                         packet->next = NULL;
      81       69985 :                         tds_packet_zero_data_start(packet);
      82       69993 :                         packet->data_len = 0;
      83       69993 :                         packet->sid = 0;
      84       69993 :                         break;
      85             :                 }
      86             : 
      87             :                 /* discard packet if too small */
      88        2826 :                 packet->next = to_free;
      89        2826 :                 to_free = packet;
      90             :         }
      91       74779 :         tds_mutex_unlock(&conn->list_mtx);
      92             : 
      93       74779 :         if (to_free)
      94        2720 :                 tds_free_packets(to_free);
      95             : 
      96       74779 :         if (!packet)
      97        4786 :                 packet = tds_alloc_packet(NULL, len);
      98             : 
      99       74779 :         return packet;
     100             : }
     101             : 
     102             : /* append packets in cached list. must have the lock! */
     103             : static void
     104       74785 : tds_packet_cache_add(TDSCONNECTION *conn, TDSPACKET *packet)
     105             : {
     106             :         TDSPACKET *last;
     107       74785 :         unsigned count = 1;
     108             : 
     109       74785 :         assert(conn && packet);
     110       74785 :         tds_mutex_check_owned(&conn->list_mtx);
     111             : 
     112       74785 :         if (conn->num_cached_packets >= 8) {
     113           0 :                 tds_free_packets(packet);
     114           0 :                 return;
     115             :         }
     116             : 
     117          71 :         for (last = packet; last->next; last = last->next)
     118          71 :                 ++count;
     119             : 
     120       74785 :         last->next = conn->packet_cache;
     121       74785 :         conn->packet_cache = packet;
     122       74785 :         conn->num_cached_packets += count;
     123             : 
     124             : #if ENABLE_EXTRA_CHECKS
     125       74785 :         count = 0;
     126      150902 :         for (packet = conn->packet_cache; packet; packet = packet->next)
     127       76117 :                 ++count;
     128       74785 :         assert(count == conn->num_cached_packets);
     129             : #endif
     130             : }
     131             : 
     132             : #if ENABLE_ODBC_MARS
     133             : /* read partial packet */
     134             : static bool
     135       91609 : tds_packet_read(TDSCONNECTION *conn, TDSSOCKET *tds)
     136             : {
     137       91609 :         TDSPACKET *packet = conn->recv_packet;
     138             :         int len;
     139             : 
     140             :         /* allocate some space to read data */
     141       91609 :         if (!packet) {
     142       37826 :                 conn->recv_packet = packet = tds_get_packet(conn, MAX(conn->env.block_size + sizeof(TDS72_SMP_HEADER), 512));
     143       37826 :                 if (!packet) goto Memory_Error;
     144       37826 :                 TDS_MARK_UNDEFINED(packet->buf, packet->capacity);
     145       37826 :                 conn->recv_pos = 0;
     146       37826 :                 packet->data_len = 8;
     147             :         }
     148             : 
     149       91609 :         assert(packet->data_start == 0);
     150             : 
     151       91609 :         assert(conn->recv_pos < packet->data_len && packet->data_len <= packet->capacity);
     152             : 
     153       91609 :         len = tds_connection_read(tds, packet->buf + conn->recv_pos, packet->data_len - conn->recv_pos);
     154       91609 :         if (len < 0)
     155             :                 goto Severe_Error;
     156       91608 :         conn->recv_pos += len;
     157       91608 :         assert(conn->recv_pos <= packet->data_len && packet->data_len <= packet->capacity);
     158             : 
     159             :         /* handle SMP */
     160       91608 :         if (conn->recv_pos > 0 && packet->buf[0] == TDS72_SMP) {
     161             :                 TDS72_SMP_HEADER mars_header;
     162             :                 uint16_t sid;
     163             :                 TDSSOCKET *tds;
     164             :                 TDS_UINT size;
     165             : 
     166             :                 /* make sure we read the header */
     167       14339 :                 if (conn->recv_pos < sizeof(mars_header)) {
     168        4811 :                         packet->data_len = sizeof(mars_header);
     169       19150 :                         return false;
     170             :                 }
     171             : 
     172        9528 :                 memcpy(&mars_header, packet->buf, sizeof(mars_header));
     173        9528 :                 tdsdump_dump_buf(TDS_DBG_HEADER, "Received MARS header", &mars_header, sizeof(mars_header));
     174        9528 :                 sid = TDS_GET_A2LE(&mars_header.sid);
     175             : 
     176             :                 /* FIXME this is done even by caller !! */
     177        9528 :                 tds = NULL;
     178        9528 :                 tds_mutex_lock(&conn->list_mtx);
     179        9528 :                 if (sid < conn->num_sessions) {
     180        9528 :                         tds = conn->sessions[sid];
     181        9528 :                         packet->sid = sid;
     182             :                 }
     183        9528 :                 tds_mutex_unlock(&conn->list_mtx);
     184             : 
     185        9528 :                 if (tds == BUSY_SOCKET) {
     186           2 :                         if (mars_header.type != TDS_SMP_FIN) {
     187           0 :                                 tdsdump_log(TDS_DBG_ERROR, "Received MARS with no session (%u)\n", sid);
     188           0 :                                 goto Severe_Error;
     189             :                         }
     190             : 
     191             :                         /* check if was just a "zombie" socket */
     192           2 :                         tds_mutex_lock(&conn->list_mtx);
     193           2 :                         conn->sessions[sid] = NULL;
     194           2 :                         tds_mutex_unlock(&conn->list_mtx);
     195             : 
     196             :                         /* reset packet to initial state to reuse it */
     197           2 :                         packet->data_len = 8;
     198           2 :                         conn->recv_pos = 0;
     199           2 :                         return false;
     200             :                 }
     201             : 
     202        9526 :                 if (!tds) {
     203             :                         /* server sent a unknown packet, close connection */
     204             :                         goto Severe_Error;
     205             :                 }
     206             : 
     207        9526 :                 tds->send_wnd = TDS_GET_A4LE(&mars_header.wnd);
     208        9526 :                 size = TDS_GET_A4LE(&mars_header.size);
     209        9526 :                 if (mars_header.type == TDS_SMP_ACK) {
     210          92 :                         if (size != sizeof(mars_header))
     211             :                                 goto Severe_Error;
     212        9434 :                 } else if (mars_header.type == TDS_SMP_DATA) {
     213        9434 :                         if (size < 0x18 || size > 0xffffu + sizeof(mars_header))
     214             :                                 goto Severe_Error;
     215             :                         /* avoid recursive SMP */
     216        9434 :                         if (conn->recv_pos > 16 && packet->buf[16] == TDS72_SMP)
     217             :                                 goto Severe_Error;
     218             :                         /* TODO is possible to put 2 TDS packet inside a single DATA ?? */
     219        9434 :                         if (conn->recv_pos >= 20 && TDS_GET_A2BE(&packet->buf[18]) != size - 16)
     220             :                                 goto Severe_Error;
     221        9434 :                         tds->recv_seq = TDS_GET_A4LE(&mars_header.seq);
     222             :                         /*
     223             :                          * do not sent ACK here because this would lead to memory waste
     224             :                          * if session is not able to handle all that packets
     225             :                          */
     226           0 :                 } else if (mars_header.type == TDS_SMP_FIN) {
     227           0 :                         if (size != sizeof(mars_header))
     228             :                                 goto Severe_Error;
     229             :                         /* this socket shold now not start another session */
     230             : //                      tds_set_state(tds, TDS_DEAD);
     231             :                 } else
     232             :                         goto Severe_Error;
     233             : 
     234        9526 :                 if (mars_header.type != TDS_SMP_DATA)
     235          92 :                         return conn->recv_pos >= size;
     236        9434 :                 if (packet->data_len < size) {
     237        4717 :                         packet = tds_realloc_packet(packet, size);
     238        4717 :                         if (!packet)
     239             :                                 goto Memory_Error;
     240        4717 :                         conn->recv_packet = packet;
     241             :                 }
     242        9434 :                 packet->data_len = size;
     243        9434 :                 if (conn->recv_pos >= size) {
     244        4717 :                         packet->data_start = sizeof(TDS72_SMP_HEADER);
     245        4717 :                         packet->data_len -= sizeof(TDS72_SMP_HEADER);
     246        4717 :                         return true;
     247             :                 }
     248             :                 return false;
     249             :         }
     250             :         assert(conn->recv_pos <= packet->data_len && packet->data_len <= packet->capacity);
     251             : 
     252             :         /* normal packet */
     253       77269 :         if (conn->recv_pos >= 8) {
     254       71458 :                 len = TDS_GET_A2BE(&packet->buf[2]);
     255       71458 :                 if (len < 8)
     256             :                         goto Severe_Error;
     257       71458 :                 if (packet->data_len < len) {
     258       33015 :                         packet = tds_realloc_packet(packet, len);
     259       33015 :                         if (!packet) goto Memory_Error;
     260       33015 :                         conn->recv_packet = packet;
     261             :                 }
     262       71458 :                 packet->data_len = len;
     263       71458 :                 return conn->recv_pos >= len;
     264             :         }
     265             :         return false;
     266             : 
     267           1 : Memory_Error:
     268           1 : Severe_Error:
     269           1 :         tds_connection_close(conn);
     270           1 :         tds_free_packets(packet);
     271           1 :         conn->recv_packet = NULL;
     272           1 :         return false;
     273             : }
     274             : 
     275             : static TDSPACKET*
     276          97 : tds_build_packet(TDSSOCKET *tds, unsigned char *buf, unsigned len)
     277             : {
     278             :         unsigned start;
     279             :         TDS72_SMP_HEADER mars[1], *p;
     280             :         TDSPACKET *packet;
     281             : 
     282          97 :         p = mars;
     283          97 :         if (buf[0] != TDS72_SMP && tds->conn->mars) {
     284          20 :                 p->signature = TDS72_SMP;
     285          20 :                 p->type = TDS_SMP_DATA;
     286          20 :                 TDS_PUT_A2LE(&p->sid, tds->sid);
     287          20 :                 TDS_PUT_A4LE(&p->size, len+16);
     288          20 :                 ++tds->send_seq;
     289          20 :                 TDS_PUT_A4LE(&p->seq, tds->send_seq);
     290             :                 /* this is the acknowledge we give to server to stop sending !!! */
     291          20 :                 tds->recv_wnd = tds->recv_seq + 4;
     292          20 :                 TDS_PUT_A4LE(&p->wnd, tds->recv_wnd);
     293          20 :                 p++;
     294             :         }
     295             : 
     296          97 :         start = (char*) p - (char *) mars;
     297          97 :         packet = tds_get_packet(tds->conn, len + start);
     298          97 :         if (TDS_LIKELY(packet)) {
     299          97 :                 packet->sid = tds->sid;
     300          97 :                 memcpy(packet->buf, mars, start);
     301          97 :                 memcpy(packet->buf + start, buf, len);
     302          97 :                 packet->data_len = len + start;
     303             :         }
     304          97 :         return packet;
     305             : }
     306             : 
     307             : static void
     308             : tds_append_packet(TDSPACKET **p_packet, TDSPACKET *packet)
     309             : {
     310       74835 :         while (*p_packet)
     311         171 :                 p_packet = &((*p_packet)->next);
     312       74664 :         *p_packet = packet;
     313             : }
     314             : 
     315             : int
     316          97 : tds_append_cancel(TDSSOCKET *tds)
     317             : {
     318             :         unsigned char buf[8];
     319             :         TDSPACKET *packet;
     320             : 
     321          97 :         buf[0] = TDS_CANCEL;
     322          97 :         buf[1] = 1;
     323          97 :         TDS_PUT_A2BE(buf+2, 8);
     324          97 :         TDS_PUT_A4(buf+4, 0);
     325          97 :         if (IS_TDS7_PLUS(tds->conn) && !tds->login)
     326          67 :                 buf[6] = 0x01;
     327             : 
     328          97 :         packet = tds_build_packet(tds, buf, 8);
     329          97 :         if (!packet)
     330             :                 return TDS_FAIL;
     331             : 
     332          97 :         tds_mutex_lock(&tds->conn->list_mtx);
     333         194 :         tds_append_packet(&tds->conn->send_packets, packet);
     334          97 :         tds_mutex_unlock(&tds->conn->list_mtx);
     335             : 
     336          97 :         return TDS_SUCCESS;
     337             : }
     338             : 
     339             : 
     340             : static void
     341       74770 : tds_connection_network(TDSCONNECTION *conn, TDSSOCKET *tds, int send)
     342             : {
     343       74770 :         assert(!conn->in_net_tds);
     344       74770 :         conn->in_net_tds = tds;
     345       74770 :         tds_mutex_unlock(&conn->list_mtx);
     346             : 
     347             :         for (;;) {
     348             :                 /* wait packets or update */
     349      133769 :                 int rc = tds_select(tds, conn->send_packets ? TDSSELREAD|TDSSELWRITE : TDSSELREAD, tds->query_timeout);
     350             : 
     351      133769 :                 if (rc < 0) {
     352             :                         /* FIXME better error report */
     353          35 :                         tds_connection_close(conn);
     354          35 :                         break;
     355             :                 }
     356             : 
     357             :                 /* change notify */
     358             :                 /* TODO async */
     359             : 
     360      133734 :                 if (!rc) { /* timeout */
     361         112 :                         tdsdump_log(TDS_DBG_INFO1, "timeout\n");
     362         112 :                         switch (rc = tdserror(tds_get_ctx(tds), tds, TDSETIME, sock_errno)) {
     363          96 :                         case TDS_INT_CONTINUE:
     364          96 :                                 continue;
     365          16 :                         default:
     366             :                         case TDS_INT_CANCEL:
     367          16 :                                 tds_close_socket(tds);
     368             :                         }
     369          16 :                         break;
     370             :                 }
     371             : 
     372             :                 /*
     373             :                  * we must write first to catch write errors as
     374             :                  * write errors, not as read
     375             :                  */
     376             :                 /* something to send */
     377      133622 :                 if (conn->send_packets && (rc & POLLOUT) != 0) {
     378             :                         TDSSOCKET *s;
     379             : 
     380       41917 :                         int sid = tds_packet_write(conn);
     381       41917 :                         if (sid < 0)
     382        5018 :                                 continue;
     383             : 
     384       36899 :                         if (sid == tds->sid)
     385             :                                 break;  /* return to caller */
     386             : 
     387           5 :                         tds_mutex_lock(&conn->list_mtx);
     388           5 :                         if (sid < conn->num_sessions) {
     389           5 :                                 s = conn->sessions[sid];
     390           5 :                                 if (TDSSOCKET_VALID(s))
     391           0 :                                         tds_cond_signal(&s->packet_cond);
     392             :                         }
     393           5 :                         tds_mutex_unlock(&conn->list_mtx);
     394             :                         /* avoid using a possible closed connection */
     395           5 :                         continue;
     396             :                 }
     397             : 
     398             :                 /* received */
     399       91705 :                 if (rc & POLLIN) {
     400             :                         TDSPACKET *packet;
     401             :                         TDSSOCKET *s;
     402             : 
     403             :                         /* try to read a packet */
     404       91609 :                         if (!tds_packet_read(conn, tds))
     405       53784 :                                 continue;       /* packet not complete */
     406       37825 :                         packet = conn->recv_packet;
     407       37825 :                         conn->recv_packet = NULL;
     408       37825 :                         conn->recv_pos = 0;
     409             : 
     410       37825 :                         tdsdump_dump_buf(TDS_DBG_NETWORK, "Received packet", packet->buf, packet->data_start + packet->data_len);
     411             : 
     412       37825 :                         tds_mutex_lock(&conn->list_mtx);
     413       37825 :                         if (packet->sid < conn->num_sessions) {
     414       37825 :                                 s = conn->sessions[packet->sid];
     415       37825 :                                 if (TDSSOCKET_VALID(s)) {
     416             :                                         /* append to correct session */
     417       37825 :                                         if (packet->buf[0] == TDS72_SMP && packet->buf[1] != TDS_SMP_DATA)
     418          92 :                                                 tds_packet_cache_add(conn, packet);
     419             :                                         else
     420       37733 :                                                 tds_append_packet(&conn->packets, packet);
     421       37825 :                                         packet = NULL;
     422             :                                         /* notify */
     423       37825 :                                         tds_cond_signal(&s->packet_cond);
     424             :                                 }
     425             :                         }
     426       37825 :                         tds_mutex_unlock(&conn->list_mtx);
     427       37825 :                         tds_free_packets(packet);
     428             :                         /* if we are receiving return the packet */
     429       37825 :                         if (!send) break;
     430             :                 }
     431             :         }
     432             : 
     433       74770 :         tds_mutex_lock(&conn->list_mtx);
     434       74770 :         conn->in_net_tds = NULL;
     435       74770 : }
     436             : 
     437             : static TDSRET
     438       36586 : tds_connection_put_packet(TDSSOCKET *tds, TDSPACKET *packet)
     439             : {
     440       36586 :         TDSCONNECTION *conn = tds->conn;
     441             : 
     442       36586 :         CHECK_TDS_EXTRA(tds);
     443             : 
     444       36586 :         packet->sid = tds->sid;
     445             : 
     446       36586 :         tds_mutex_lock(&conn->list_mtx);
     447       36586 :         tds->sending_packet = packet;
     448       73404 :         while (tds->sending_packet) {
     449             :                 int wait_res;
     450             : 
     451       36818 :                 if (IS_TDSDEAD(tds)) {
     452          35 :                         tdsdump_log(TDS_DBG_NETWORK, "Write attempt when state is TDS_DEAD");
     453             :                         break;
     454             :                 }
     455             : 
     456             :                 /* limit packet sending looking at sequence/window */
     457       36783 :                 if (packet && (int32_t) (tds->send_seq - tds->send_wnd) < 0) {
     458             :                         /* prepare MARS header if needed */
     459       36583 :                         if (tds->conn->mars) {
     460             :                                 TDS72_SMP_HEADER *hdr;
     461             : 
     462             :                                 /* fill SMP data */
     463        4681 :                                 hdr = (TDS72_SMP_HEADER *) packet->buf;
     464        4681 :                                 hdr->signature = TDS72_SMP;
     465        4681 :                                 hdr->type = TDS_SMP_DATA;
     466        4681 :                                 TDS_PUT_A2LE(&hdr->sid, packet->sid);
     467        4681 :                                 TDS_PUT_A4LE(&hdr->size, packet->data_start + packet->data_len);
     468        4681 :                                 ++tds->send_seq;
     469        4681 :                                 TDS_PUT_A4LE(&hdr->seq, tds->send_seq);
     470             :                                 /* this is the acknowledge we give to server to stop sending */
     471        4681 :                                 tds->recv_wnd = tds->recv_seq + 4;
     472        4681 :                                 TDS_PUT_A4LE(&hdr->wnd, tds->recv_wnd);
     473             :                         }
     474             : 
     475             :                         /* append packet */
     476       73166 :                         tds_append_packet(&conn->send_packets, packet);
     477       36583 :                         packet = NULL;
     478             :                 }
     479             : 
     480             :                 /* network ok ? process network */
     481       36783 :                 if (!conn->in_net_tds) {
     482       36783 :                         tds_connection_network(conn, tds, packet ? 0 : 1);
     483       36783 :                         if (tds->sending_packet)
     484         232 :                                 continue;
     485             :                         /* here we are sure we sent the packet */
     486             :                         break;
     487             :                 }
     488             : 
     489             :                 /* signal thread processing network to handle our packet */
     490             :                 /* TODO check result */
     491           0 :                 tds_wakeup_send(&conn->wakeup, 0);
     492             : 
     493             :                 /* wait local condition */
     494           0 :                 wait_res = tds_cond_timedwait(&tds->packet_cond, &conn->list_mtx, tds->query_timeout);
     495           0 :                 if (wait_res != ETIMEDOUT)
     496           0 :                         continue;
     497             : 
     498           0 :                 tds_mutex_unlock(&conn->list_mtx);
     499           0 :                 if (tdserror(tds_get_ctx(tds), tds, TDSETIME, ETIMEDOUT) != TDS_INT_CONTINUE) {
     500           0 :                         tds->sending_packet = NULL;
     501           0 :                         tds_close_socket(tds);
     502           0 :                         tds_free_packets(packet);
     503           0 :                         return TDS_FAIL;
     504             :                 }
     505           0 :                 tds_mutex_lock(&conn->list_mtx);
     506             :         }
     507       36586 :         tds->sending_packet = NULL;
     508       36586 :         tds_mutex_unlock(&conn->list_mtx);
     509       36586 :         if (TDS_UNLIKELY(packet)) {
     510           3 :                 tds_free_packets(packet);
     511           3 :                 return TDS_FAIL;
     512             :         }
     513       36583 :         if (IS_TDSDEAD(tds))
     514             :                 return TDS_FAIL;
     515       36551 :         return TDS_SUCCESS;
     516             : }
     517             : #endif /* ENABLE_ODBC_MARS */
     518             : 
     519             : /**
     520             :  * Read in one 'packet' from the server.  This is a wrapped outer packet of
     521             :  * the protocol (they bundle result packets into chunks and wrap them at
     522             :  * what appears to be 512 bytes regardless of how that breaks internal packet
     523             :  * up.   (tetherow\@nol.org)
     524             :  * @return bytes read or -1 on failure
     525             :  */
     526             : int
     527       75415 : tds_read_packet(TDSSOCKET * tds)
     528             : {
     529             : #if ENABLE_ODBC_MARS
     530       37752 :         TDSCONNECTION *conn = tds->conn;
     531             : 
     532       37752 :         tds_mutex_lock(&conn->list_mtx);
     533             : 
     534             :         for (;;) {
     535             :                 int wait_res;
     536             :                 TDSPACKET **p_packet;
     537             : 
     538       75739 :                 if (IS_TDSDEAD(tds)) {
     539          19 :                         tdsdump_log(TDS_DBG_NETWORK, "Read attempt when state is TDS_DEAD\n");
     540             :                         break;
     541             :                 }
     542             : 
     543             :                 /* if there is a packet for me return it */
     544       75783 :                 for (p_packet = &conn->packets; *p_packet; p_packet = &(*p_packet)->next)
     545       37796 :                         if ((*p_packet)->sid == tds->sid)
     546             :                                 break;
     547             : 
     548       75720 :                 if (*p_packet) {
     549             :                         /* remove our packet from list */
     550       37733 :                         TDSPACKET *packet = *p_packet;
     551       37733 :                         *p_packet = packet->next;
     552       37733 :                         tds_packet_cache_add(conn, tds->recv_packet);
     553       37733 :                         tds_mutex_unlock(&conn->list_mtx);
     554             : 
     555       37733 :                         packet->next = NULL;
     556       37733 :                         tds->recv_packet = packet;
     557             : 
     558       37733 :                         tds->in_buf = packet->buf + packet->data_start;
     559       37733 :                         tds->in_len = packet->data_len;
     560       37733 :                         tds->in_pos  = 8;
     561       37733 :                         tds->in_flag = tds->in_buf[0];
     562             : 
     563             :                         /* send acknowledge if needed */
     564       37733 :                         if ((int32_t) (tds->recv_seq + 2 - tds->recv_wnd) >= 0)
     565         138 :                                 tds_update_recv_wnd(tds, tds->recv_seq + 4);
     566             : 
     567       37733 :                         return tds->in_len;
     568             :                 }
     569             : 
     570             :                 /* network ok ? process network */
     571       37987 :                 if (!conn->in_net_tds) {
     572       37987 :                         tds_connection_network(conn, tds, 0);
     573       37987 :                         continue;
     574             :                 }
     575             : 
     576             :                 /* wait local condition */
     577           0 :                 wait_res = tds_cond_timedwait(&tds->packet_cond, &conn->list_mtx, tds->query_timeout);
     578           0 :                 if (wait_res != ETIMEDOUT)
     579           0 :                         continue;
     580             : 
     581           0 :                 tds_mutex_unlock(&conn->list_mtx);
     582           0 :                 if (tdserror(tds_get_ctx(tds), tds, TDSETIME, ETIMEDOUT) != TDS_INT_CONTINUE) {
     583           0 :                         tds_close_socket(tds);
     584           0 :                         return -1;
     585             :                 }
     586           0 :                 tds_mutex_lock(&conn->list_mtx);
     587             :         }
     588             : 
     589          19 :         tds_mutex_unlock(&conn->list_mtx);
     590          19 :         return -1;
     591             : #else /* !ENABLE_ODBC_MARS */
     592       37663 :         unsigned char *pkt = tds->in_buf, *p, *end;
     593             : 
     594       37663 :         if (IS_TDSDEAD(tds)) {
     595           0 :                 tdsdump_log(TDS_DBG_NETWORK, "Read attempt when state is TDS_DEAD");
     596             :                 return -1;
     597             :         }
     598             : 
     599       37663 :         tds->in_len = 0;
     600       37663 :         tds->in_pos = 0;
     601      156030 :         for (p = pkt, end = p+8; p < end;) {
     602       80723 :                 int len = tds_connection_read(tds, p, end - p);
     603       80723 :                 if (len <= 0) {
     604          19 :                         tds_close_socket(tds);
     605          19 :                         return -1;
     606             :                 }
     607             : 
     608       80704 :                 p += len;
     609       80704 :                 if (p - pkt >= 4) {
     610       80704 :                         unsigned pktlen = TDS_GET_A2BE(pkt+2);
     611             :                         /* packet must at least contains header */
     612       80704 :                         if (TDS_UNLIKELY(pktlen < 8)) {
     613           0 :                                 tds_close_socket(tds);
     614           0 :                                 return -1;
     615             :                         }
     616       80704 :                         if (TDS_UNLIKELY(pktlen > tds->recv_packet->capacity)) {
     617         920 :                                 TDSPACKET *packet = tds_realloc_packet(tds->recv_packet, pktlen);
     618         920 :                                 if (TDS_UNLIKELY(!packet)) {
     619           0 :                                         tds_close_socket(tds);
     620           0 :                                         return -1;
     621             :                                 }
     622         920 :                                 tds->recv_packet = packet;
     623         920 :                                 pkt = packet->buf;
     624         920 :                                 p = pkt + (p-tds->in_buf);
     625         920 :                                 tds->in_buf = pkt;
     626             :                         }
     627       80704 :                         end = pkt + pktlen;
     628             :                 }
     629             :         }
     630             : 
     631             :         /* set the received packet type flag */
     632       37644 :         tds->in_flag = pkt[0];
     633             : 
     634             :         /* Set the length and pos (not sure what pos is used for now */
     635       37644 :         tds->in_len = p - pkt;
     636       37644 :         tds->in_pos = 8;
     637       37644 :         tdsdump_dump_buf(TDS_DBG_NETWORK, "Received packet", tds->in_buf, tds->in_len);
     638             : 
     639       37644 :         return tds->in_len;
     640             : #endif /* !ENABLE_ODBC_MARS */
     641             : }
     642             : 
     643             : #if ENABLE_ODBC_MARS
     644             : static TDSRET
     645         138 : tds_update_recv_wnd(TDSSOCKET *tds, TDS_UINT new_recv_wnd)
     646             : {
     647             :         TDS72_SMP_HEADER *mars;
     648             :         TDSPACKET *packet;
     649             : 
     650         138 :         if (!tds->conn->mars)
     651             :                 return TDS_SUCCESS;
     652             : 
     653         138 :         packet = tds_get_packet(tds->conn, sizeof(*mars));
     654         138 :         if (!packet)
     655             :                 return TDS_FAIL;        /* TODO check result */
     656             : 
     657         138 :         packet->data_len = sizeof(*mars);
     658         138 :         packet->sid = tds->sid;
     659             : 
     660         138 :         mars = (TDS72_SMP_HEADER *) packet->buf;
     661         138 :         mars->signature = TDS72_SMP;
     662         138 :         mars->type = TDS_SMP_ACK;
     663         138 :         TDS_PUT_A2LE(&mars->sid, tds->sid);
     664         138 :         mars->size = TDS_HOST4LE(16);
     665         138 :         TDS_PUT_A4LE(&mars->seq, tds->send_seq);
     666         138 :         tds->recv_wnd = new_recv_wnd;
     667         138 :         TDS_PUT_A4LE(&mars->wnd, tds->recv_wnd);
     668             : 
     669         138 :         tds_mutex_lock(&tds->conn->list_mtx);
     670         276 :         tds_append_packet(&tds->conn->send_packets, packet);
     671         138 :         tds_mutex_unlock(&tds->conn->list_mtx);
     672             : 
     673         138 :         return TDS_SUCCESS;
     674             : }
     675             : 
     676             : static TDSRET
     677         113 : tds_append_fin_syn(TDSSOCKET *tds, uint8_t type)
     678             : {
     679             :         TDS72_SMP_HEADER mars;
     680             :         TDSPACKET *packet;
     681             : 
     682         113 :         if (!tds->conn->mars)
     683             :                 return TDS_SUCCESS;
     684             : 
     685         113 :         mars.signature = TDS72_SMP;
     686         113 :         mars.type = type;
     687         113 :         TDS_PUT_A2LE(&mars.sid, tds->sid);
     688         113 :         mars.size = TDS_HOST4LE(16);
     689         113 :         TDS_PUT_A4LE(&mars.seq, tds->send_seq);
     690         113 :         tds->recv_wnd = tds->recv_seq + 4;
     691         113 :         TDS_PUT_A4LE(&mars.wnd, tds->recv_wnd);
     692             : 
     693             :         /* do not use tds_get_packet as it require no lock ! */
     694         113 :         packet = tds_alloc_packet(&mars, sizeof(mars));
     695         113 :         if (!packet)
     696             :                 return TDS_FAIL;        /* TODO check result */
     697         113 :         packet->sid = tds->sid;
     698             : 
     699             :         /* we already hold lock so do not lock */
     700         226 :         tds_append_packet(&tds->conn->send_packets, packet);
     701             : 
     702         113 :         if (type == TDS_SMP_FIN) {
     703             :                 /* now is no more an active session */
     704           5 :                 tds->conn->sessions[tds->sid] = BUSY_SOCKET;
     705           5 :                 tds_set_state(tds, TDS_DEAD);
     706             :         }
     707             : 
     708             :         return TDS_SUCCESS;
     709             : }
     710             : 
     711             : /**
     712             :  * Append a SMP FIN packet.
     713             :  * tds->conn->list_mtx must be locked.
     714             :  */
     715             : TDSRET
     716           5 : tds_append_fin(TDSSOCKET *tds)
     717             : {
     718           5 :         return tds_append_fin_syn(tds, TDS_SMP_FIN);
     719             : }
     720             : 
     721             : /**
     722             :  * Append a SMP SYN packet.
     723             :  * tds->conn->list_mtx must be unlocked.
     724             :  */
     725             : TDSRET
     726         108 : tds_append_syn(TDSSOCKET *tds)
     727             : {
     728             :         TDSRET ret;
     729         108 :         tds_mutex_lock(&tds->conn->list_mtx);
     730         108 :         ret = tds_append_fin_syn(tds, TDS_SMP_SYN);
     731         108 :         tds_mutex_unlock(&tds->conn->list_mtx);
     732         108 :         return ret;
     733             : }
     734             : #endif /* ENABLE_ODBC_MARS */
     735             : 
     736             : 
     737             : TDS_COMPILE_CHECK(additional, TDS_ADDITIONAL_SPACE != 0);
     738             : 
     739             : TDSRET
     740       72724 : tds_write_packet(TDSSOCKET * tds, unsigned char final)
     741             : {
     742             :         TDSRET res;
     743       72724 :         unsigned int left = 0;
     744       72724 :         TDSPACKET *pkt = tds->send_packet, *pkt_next = NULL;
     745             : 
     746       72724 :         CHECK_TDS_EXTRA(tds);
     747             : 
     748             : #if !ENABLE_ODBC_MARS
     749       36101 :         if (tds->frozen)
     750             : #endif
     751             :         {
     752       36718 :                 pkt->next = pkt_next = tds_get_packet(tds->conn, pkt->capacity);
     753       36718 :                 if (!pkt_next)
     754             :                         return TDS_FAIL;
     755             : 
     756             : #if ENABLE_ODBC_MARS
     757       36623 :                 if (tds->conn->mars)
     758        4699 :                         pkt_next->data_start = sizeof(TDS72_SMP_HEADER);
     759             : #endif
     760             :         }
     761             : 
     762       72724 :         if (tds->out_pos > tds->out_buf_max) {
     763         474 :                 left = tds->out_pos - tds->out_buf_max;
     764         233 :                 if (pkt_next)
     765         250 :                         memcpy(pkt_next->buf + tds_packet_get_data_start(pkt_next) + 8, tds->out_buf + tds->out_buf_max, left);
     766         474 :                 tds->out_pos = tds->out_buf_max;
     767             :         }
     768             : 
     769             :         /* we must assure server can accept our packet looking at
     770             :          * send_wnd and waiting for proper send_wnd if send_seq > send_wnd
     771             :          */
     772       72724 :         tds->out_buf[0] = tds->out_flag;
     773       72724 :         tds->out_buf[1] = final;
     774       72724 :         TDS_PUT_A2BE(tds->out_buf+2, tds->out_pos);
     775       72724 :         TDS_PUT_A2BE(tds->out_buf+4, tds->conn->client_spid);
     776       72724 :         TDS_PUT_A2(tds->out_buf+6, 0);
     777       72724 :         if (IS_TDS7_PLUS(tds->conn) && !tds->login)
     778       48555 :                 tds->out_buf[6] = 0x01;
     779             : 
     780       72724 :         if (tds->frozen) {
     781         270 :                 pkt->data_len = tds->out_pos;
     782         270 :                 tds_set_current_send_packet(tds, pkt_next);
     783         270 :                 tds->out_pos = left + 8;
     784         270 :                 CHECK_TDS_EXTRA(tds);
     785         270 :                 return TDS_SUCCESS;
     786             :         }
     787             : 
     788             : #if ENABLE_ODBC_MARS
     789       36448 :         pkt->data_len = tds->out_pos;
     790       36448 :         pkt->next = NULL;
     791       36448 :         tds_set_current_send_packet(tds, pkt_next);
     792       36448 :         res = tds_connection_put_packet(tds, pkt);
     793             : #else /* !ENABLE_ODBC_MARS */
     794       36006 :         tdsdump_dump_buf(TDS_DBG_NETWORK, "Sending packet", tds->out_buf, tds->out_pos);
     795             : 
     796             :         /* GW added in check for write() returning <0 and SIGPIPE checking */
     797       72012 :         res = tds_connection_write(tds, tds->out_buf, tds->out_pos, final) <= 0 ?
     798       36006 :                 TDS_FAIL : TDS_SUCCESS;
     799             : 
     800       36006 :         memcpy(tds->out_buf + 8, tds->out_buf + tds->out_buf_max, left);
     801             : #endif /* !ENABLE_ODBC_MARS */
     802             : 
     803       72454 :         tds->out_pos = left + 8;
     804             : 
     805       72454 :         if (TDS_UNLIKELY(tds->conn->encrypt_single_packet)) {
     806         720 :                 tds->conn->encrypt_single_packet = 0;
     807         720 :                 tds_ssl_deinit(tds->conn);
     808             :         }
     809             : 
     810             :         return res;
     811             : }
     812             : 
     813             : #if !ENABLE_ODBC_MARS
     814             : int
     815         419 : tds_put_cancel(TDSSOCKET * tds)
     816             : {
     817             :         unsigned char out_buf[8];
     818             :         int sent;
     819             : 
     820         419 :         out_buf[0] = TDS_CANCEL;        /* out_flag */
     821         419 :         out_buf[1] = 1; /* final */
     822         419 :         out_buf[2] = 0;
     823         419 :         out_buf[3] = 8;
     824         419 :         TDS_PUT_A4(out_buf+4, 0);
     825         419 :         if (IS_TDS7_PLUS(tds->conn) && !tds->login)
     826         338 :                 out_buf[6] = 0x01;
     827             : 
     828         419 :         tdsdump_dump_buf(TDS_DBG_NETWORK, "Sending packet", out_buf, 8);
     829             : 
     830         419 :         sent = tds_connection_write(tds, out_buf, 8, 1);
     831             : 
     832         419 :         if (sent > 0)
     833         418 :                 tds->in_cancel = 2;
     834             : 
     835             :         /* GW added in check for write() returning <0 and SIGPIPE checking */
     836         419 :         return sent <= 0 ? TDS_FAIL : TDS_SUCCESS;
     837             : }
     838             : #endif /* !ENABLE_ODBC_MARS */
     839             : 
     840             : 
     841             : #if ENABLE_ODBC_MARS
     842             : static int
     843       41917 : tds_packet_write(TDSCONNECTION *conn)
     844             : {
     845             :         int sent;
     846             :         int final;
     847       41917 :         TDSPACKET *packet = conn->send_packets;
     848             : 
     849       41917 :         assert(packet);
     850             : 
     851       41917 :         if (conn->send_pos == 0)
     852       36931 :                 tdsdump_dump_buf(TDS_DBG_NETWORK, "Sending packet", packet->buf, packet->data_start + packet->data_len);
     853             : 
     854             :         /* take into account other session packets */
     855       41917 :         if (packet->next != NULL)
     856             :                 final = 0;
     857             :         /* take into account other packets for this session */
     858       41781 :         else if (packet->buf[0] != TDS72_SMP)
     859       36945 :                 final = packet->buf[1] & 1;
     860             :         else
     861             :                 final = 1;
     862             : 
     863       41917 :         sent = tds_connection_write(conn->in_net_tds, packet->buf + conn->send_pos,
     864       41917 :                                     packet->data_start + packet->data_len - conn->send_pos, final);
     865             : 
     866       41917 :         if (TDS_UNLIKELY(sent < 0)) {
     867             :                 /* TODO tdserror called ?? */
     868          32 :                 tds_connection_close(conn);
     869          32 :                 return -1;
     870             :         }
     871             : 
     872             :         /* update sent data */
     873       41885 :         conn->send_pos += sent;
     874             :         /* remove packet if sent all data */
     875       41885 :         if (conn->send_pos >= packet->data_start + packet->data_len) {
     876       36899 :                 uint16_t sid = packet->sid;
     877             :                 TDSSOCKET *tds;
     878       36899 :                 tds_mutex_lock(&conn->list_mtx);
     879       36899 :                 tds = conn->sessions[sid];
     880       36899 :                 if (TDSSOCKET_VALID(tds) && tds->sending_packet == packet)
     881       36551 :                         tds->sending_packet = NULL;
     882       36899 :                 conn->send_packets = packet->next;
     883       36899 :                 packet->next = NULL;
     884       36899 :                 tds_packet_cache_add(conn, packet);
     885       36899 :                 tds_mutex_unlock(&conn->list_mtx);
     886       36899 :                 conn->send_pos = 0;
     887       36899 :                 return sid;
     888             :         }
     889             : 
     890             :         return -1;
     891             : }
     892             : #endif /* ENABLE_ODBC_MARS */
     893             : 
     894             : /**
     895             :  * Stop writing to server and cache every packet not sending them to server.
     896             :  * This is used to write data without worrying to compute length before.
     897             :  * If size_len is provided the number of bytes written between ::tds_freeze and
     898             :  * ::tds_freeze_close will be written as a number of size size_len.
     899             :  * This call should be followed by a ::tds_freeze_close, ::tds_freeze_close_len or
     900             :  * a ::tds_freeze_abort. Failing to match ::tds_freeze with a close would possibly
     901             :  * result in a disconnection from the server.
     902             :  *
     903             :  * @param[out]  freeze    structure to initialize
     904             :  * @param       size_len  length of the size to automatically write on close (0, 1, 2, or 4)
     905             :  */
     906             : void
     907       42605 : tds_freeze(TDSSOCKET *tds, TDSFREEZE *freeze, unsigned size_len)
     908             : {
     909       42605 :         CHECK_TDS_EXTRA(tds);
     910       42605 :         tds_extra_assert(size_len <= 4 && size_len != 3);
     911             : 
     912       42605 :         if (tds->out_pos > tds->out_buf_max)
     913          12 :                 tds_write_packet(tds, 0x0);
     914             : 
     915       42605 :         if (!tds->frozen)
     916       32107 :                 tds->frozen_packets = tds->send_packet;
     917             : 
     918       42605 :         ++tds->frozen;
     919       42605 :         freeze->tds = tds;
     920       42605 :         freeze->pkt = tds->send_packet;
     921       42605 :         freeze->pkt_pos = tds->out_pos;
     922       42605 :         freeze->size_len = size_len;
     923       42605 :         if (size_len)
     924       38243 :                 tds_put_n(tds, NULL, size_len);
     925             : 
     926       42605 :         CHECK_FREEZE_EXTRA(freeze);
     927       42605 : }
     928             : 
     929             : /**
     930             :  * Compute how many bytes has been written from freeze
     931             :  *
     932             :  * @return bytes written since ::tds_freeze call
     933             :  */
     934             : size_t
     935       35491 : tds_freeze_written(TDSFREEZE *freeze)
     936             : {
     937       35491 :         TDSSOCKET *tds = freeze->tds;
     938       35491 :         TDSPACKET *pkt = freeze->pkt;
     939             :         size_t size;
     940             : 
     941       35491 :         CHECK_FREEZE_EXTRA(freeze);
     942             : 
     943             :         /* last packet needs special handling */
     944       35491 :         size = tds->out_pos;
     945             : 
     946             :         /* packets before last */
     947       35801 :         for (; pkt->next != NULL; pkt = pkt->next)
     948         310 :                 size += pkt->data_len - 8;
     949             : 
     950       35491 :         return size - freeze->pkt_pos;
     951             : }
     952             : 
     953             : /**
     954             :  * Discard all data written after the freeze
     955             :  *
     956             :  * After this call freeze should not be used.
     957             :  *
     958             :  * @param[in]  freeze  structure to work on
     959             :  */
     960             : TDSRET
     961          24 : tds_freeze_abort(TDSFREEZE *freeze)
     962             : {
     963          24 :         TDSSOCKET *tds = freeze->tds;
     964          24 :         TDSPACKET *pkt = freeze->pkt;
     965             : 
     966          24 :         CHECK_FREEZE_EXTRA(freeze);
     967             : 
     968          24 :         if (pkt->next) {
     969          12 :                 tds_mutex_lock(&tds->conn->list_mtx);
     970          12 :                 tds_packet_cache_add(tds->conn, pkt->next);
     971          12 :                 tds_mutex_unlock(&tds->conn->list_mtx);
     972          12 :                 pkt->next = NULL;
     973             : 
     974             :                 tds_set_current_send_packet(tds, pkt);
     975             :         }
     976          24 :         tds->out_pos = freeze->pkt_pos;
     977          24 :         pkt->data_len = 8;
     978             : 
     979          24 :         --tds->frozen;
     980          24 :         if (!tds->frozen)
     981          24 :                 tds->frozen_packets = NULL;
     982          24 :         freeze->tds = NULL;
     983          24 :         return TDS_SUCCESS;
     984             : }
     985             : 
     986             : /**
     987             :  * Stop keeping data for this specific freeze.
     988             :  *
     989             :  * If size_len was used for ::tds_freeze this function write the written bytes
     990             :  * at position when ::tds_freeze was called.
     991             :  * After this call freeze should not be used.
     992             :  *
     993             :  * @param[in]  freeze  structure to work on
     994             :  */
     995             : TDSRET
     996       17430 : tds_freeze_close(TDSFREEZE *freeze)
     997             : {
     998       17430 :         return tds_freeze_close_len(freeze, freeze->size_len ? tds_freeze_written(freeze) - freeze->size_len : 0);
     999             : }
    1000             : 
    1001             : static void
    1002             : tds_freeze_update_size(const TDSFREEZE *freeze, int32_t size)
    1003             : {
    1004             :         TDSPACKET *pkt;
    1005       38219 :         unsigned pos = freeze->pkt_pos;
    1006       38219 :         unsigned size_len = freeze->size_len;
    1007             : 
    1008       38219 :         pkt = freeze->pkt;
    1009             :         do {
    1010      136424 :                 if (pos >= pkt->data_len && pkt->next) {
    1011          12 :                         pkt = pkt->next;
    1012          12 :                         pos = 8;
    1013             :                 }
    1014      136424 :                 pkt->buf[tds_packet_get_data_start(pkt) + pos] = size & 0xffu;
    1015      136424 :                 size >>= 8;
    1016      136424 :                 pos++;
    1017      136424 :         } while (--size_len);
    1018             : }
    1019             : 
    1020             : /**
    1021             :  * Stop keeping data for this specific freeze.
    1022             :  *
    1023             :  * Similar to ::tds_freeze_close but specify the size to be written instead
    1024             :  * of letting ::tds_freeze_close compute it.
    1025             :  * After this call freeze should not be used.
    1026             :  *
    1027             :  * @param[in]  freeze  structure to work on
    1028             :  * @param[in]  size    size to write
    1029             :  */
    1030             : TDSRET
    1031       42581 : tds_freeze_close_len(TDSFREEZE *freeze, int32_t size)
    1032             : {
    1033       42581 :         TDSSOCKET *tds = freeze->tds;
    1034             :         TDSPACKET *pkt;
    1035             : #if !ENABLE_ODBC_MARS
    1036       21222 :         TDSPACKET *last_pkt_sent = NULL;
    1037             : #endif
    1038             : 
    1039       42581 :         CHECK_FREEZE_EXTRA(freeze);
    1040             : 
    1041       42581 :         if (freeze->size_len)
    1042       38219 :                 tds_freeze_update_size(freeze, size);
    1043             : 
    1044             :         /* if not last freeze we need just to update size */
    1045       42581 :         freeze->tds = NULL;
    1046       42581 :         if (--tds->frozen != 0)
    1047             :                 return TDS_SUCCESS;
    1048             : 
    1049       32083 :         tds->frozen_packets = NULL;
    1050       32083 :         pkt = freeze->pkt;
    1051       64356 :         while (pkt->next) {
    1052         212 :                 TDSPACKET *next = pkt->next;
    1053             :                 TDSRET rc;
    1054             : #if ENABLE_ODBC_MARS
    1055         138 :                 pkt->next = NULL;
    1056         138 :                 freeze->pkt = next;
    1057             :                 /* packet will get owned by function, no need to release it */
    1058         138 :                 rc = tds_connection_put_packet(tds, pkt);
    1059             : #else
    1060         148 :                 rc = tds_connection_write(tds, pkt->buf, pkt->data_len, 0) <= 0 ?
    1061          74 :                         TDS_FAIL : TDS_SUCCESS;
    1062          74 :                 last_pkt_sent = pkt;
    1063             : #endif
    1064         212 :                 if (TDS_UNLIKELY(TDS_FAILED(rc))) {
    1065          44 :                         while (next->next) {
    1066             :                                 pkt = next;
    1067             :                                 next = pkt->next;
    1068             :                         }
    1069          22 :                         tds_extra_assert(pkt->next != NULL);
    1070          22 :                         tds_extra_assert(pkt->next == tds->send_packet);
    1071             : 
    1072          22 :                         pkt->next = NULL;
    1073          22 :                         tds_mutex_lock(&tds->conn->list_mtx);
    1074          22 :                         tds_packet_cache_add(tds->conn, freeze->pkt);
    1075          22 :                         tds_mutex_unlock(&tds->conn->list_mtx);
    1076          22 :                         return rc;
    1077             :                 }
    1078             :                 pkt = next;
    1079             :         }
    1080             : 
    1081       32061 :         tds_extra_assert(pkt->next == NULL);
    1082       32061 :         tds_extra_assert(pkt == tds->send_packet);
    1083             : 
    1084             : #if !ENABLE_ODBC_MARS
    1085       15977 :         if (last_pkt_sent) {
    1086          27 :                 tds_extra_assert(last_pkt_sent->next == pkt);
    1087          27 :                 last_pkt_sent->next = NULL;
    1088          27 :                 tds_mutex_lock(&tds->conn->list_mtx);
    1089          27 :                 tds_packet_cache_add(tds->conn, freeze->pkt);
    1090          27 :                 tds_mutex_unlock(&tds->conn->list_mtx);
    1091             :         }
    1092             : #endif
    1093             : 
    1094             :         /* keep final packet so we can continue to add data */
    1095       16084 :         return TDS_SUCCESS;
    1096             : }
    1097             : 
    1098             : /** @} */

Generated by: LCOV version 1.13