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

Generated by: LCOV version 1.13