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-02-21 09:36:06 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       96612 : tds_get_packet(TDSCONNECTION *conn, unsigned len)
      65             : {
      66       96612 :         TDSPACKET *packet, *to_free = NULL;
      67             : 
      68       96612 :         tds_mutex_lock(&conn->list_mtx);
      69      196796 :         while ((packet = conn->packet_cache) != NULL) {
      70       94282 :                 --conn->num_cached_packets;
      71       94282 :                 conn->packet_cache = packet->next;
      72             : 
      73             :                 /* return it */
      74       94282 :                 if (packet->capacity >= len) {
      75       90710 :                         TDS_MARK_UNDEFINED(packet->buf, packet->capacity);
      76       90710 :                         packet->next = NULL;
      77       90700 :                         tds_packet_zero_data_start(packet);
      78       90710 :                         packet->data_len = 0;
      79       90710 :                         packet->sid = 0;
      80       90710 :                         break;
      81             :                 }
      82             : 
      83             :                 /* discard packet if too small */
      84        3572 :                 packet->next = to_free;
      85        3572 :                 to_free = packet;
      86             :         }
      87       96612 :         tds_mutex_unlock(&conn->list_mtx);
      88             : 
      89       96612 :         if (to_free)
      90        3357 :                 tds_free_packets(to_free);
      91             : 
      92       96612 :         if (!packet)
      93        5902 :                 packet = tds_alloc_packet(NULL, len);
      94             : 
      95       96612 :         return packet;
      96             : }
      97             : 
      98             : /* append packets in cached list. must have the lock! */
      99             : static void
     100       96695 : tds_packet_cache_add(TDSCONNECTION *conn, TDSPACKET *packet)
     101             : {
     102             :         TDSPACKET *last;
     103       96695 :         unsigned count = 1;
     104             : 
     105       96695 :         assert(conn && packet);
     106       96695 :         tds_mutex_check_owned(&conn->list_mtx);
     107             : 
     108       96695 :         if (conn->num_cached_packets >= 8) {
     109           0 :                 tds_free_packets(packet);
     110           0 :                 return;
     111             :         }
     112             : 
     113          88 :         for (last = packet; last->next; last = last->next)
     114          88 :                 ++count;
     115             : 
     116       96695 :         last->next = conn->packet_cache;
     117       96695 :         conn->packet_cache = packet;
     118       96695 :         conn->num_cached_packets += count;
     119             : 
     120             : #if ENABLE_EXTRA_CHECKS
     121       96695 :         count = 0;
     122      196466 :         for (packet = conn->packet_cache; packet; packet = packet->next)
     123       99771 :                 ++count;
     124       96695 :         assert(count == conn->num_cached_packets);
     125             : #endif
     126             : }
     127             : 
     128             : #if ENABLE_ODBC_MARS
     129             : /* read partial packet */
     130             : static bool
     131      119711 : tds_packet_read(TDSCONNECTION *conn, TDSSOCKET *tds)
     132             : {
     133      119711 :         TDSPACKET *packet = conn->recv_packet;
     134             :         int len;
     135             : 
     136             :         /* allocate some space to read data */
     137      119711 :         if (!packet) {
     138       49009 :                 conn->recv_packet = packet = tds_get_packet(conn, MAX(conn->env.block_size + sizeof(TDS72_SMP_HEADER), 512));
     139       49009 :                 if (!packet) goto Memory_Error;
     140       49009 :                 TDS_MARK_UNDEFINED(packet->buf, packet->capacity);
     141       49009 :                 conn->recv_pos = 0;
     142       49009 :                 packet->data_len = 8;
     143             :         }
     144             : 
     145      119711 :         assert(packet->data_start == 0);
     146             : 
     147      119711 :         assert(conn->recv_pos < packet->data_len && packet->data_len <= packet->capacity);
     148             : 
     149      119711 :         len = tds_connection_read(tds, packet->buf + conn->recv_pos, packet->data_len - conn->recv_pos);
     150      119711 :         if (len < 0)
     151             :                 goto Severe_Error;
     152      119700 :         conn->recv_pos += len;
     153      119700 :         assert(conn->recv_pos <= packet->data_len && packet->data_len <= packet->capacity);
     154             : 
     155             :         /* handle SMP */
     156      119700 :         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       29472 :                 if (conn->recv_pos < sizeof(mars_header)) {
     164        9883 :                         packet->data_len = sizeof(mars_header);
     165       39355 :                         return false;
     166             :                 }
     167             : 
     168       19589 :                 memcpy(&mars_header, packet->buf, sizeof(mars_header));
     169       19589 :                 tdsdump_dump_buf(TDS_DBG_HEADER, "Received MARS header", &mars_header, sizeof(mars_header));
     170       19589 :                 sid = TDS_GET_A2LE(&mars_header.sid);
     171             : 
     172             :                 /* FIXME this is done even by caller !! */
     173       19589 :                 tds = NULL;
     174       19589 :                 tds_mutex_lock(&conn->list_mtx);
     175       19589 :                 if (sid < conn->num_sessions) {
     176       19589 :                         tds = conn->sessions[sid];
     177       19589 :                         packet->sid = sid;
     178             :                 }
     179       19589 :                 tds_mutex_unlock(&conn->list_mtx);
     180             : 
     181       19589 :                 if (tds == BUSY_SOCKET) {
     182           5 :                         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           5 :                         tds_mutex_lock(&conn->list_mtx);
     189           5 :                         conn->sessions[sid] = NULL;
     190           5 :                         tds_mutex_unlock(&conn->list_mtx);
     191             : 
     192             :                         /* reset packet to initial state to reuse it */
     193           5 :                         packet->data_len = 8;
     194           5 :                         conn->recv_pos = 0;
     195           5 :                         return false;
     196             :                 }
     197             : 
     198       19584 :                 if (!tds) {
     199             :                         /* server sent a unknown packet, close connection */
     200             :                         goto Severe_Error;
     201             :                 }
     202             : 
     203       19584 :                 tds->send_wnd = TDS_GET_A4LE(&mars_header.wnd);
     204       19584 :                 size = TDS_GET_A4LE(&mars_header.size);
     205       19584 :                 if (mars_header.type == TDS_SMP_ACK) {
     206         172 :                         if (size != sizeof(mars_header))
     207             :                                 goto Severe_Error;
     208       19412 :                 } else if (mars_header.type == TDS_SMP_DATA) {
     209       19412 :                         if (size < 0x18 || size > 0xffffu + sizeof(mars_header))
     210             :                                 goto Severe_Error;
     211             :                         /* avoid recursive SMP */
     212       19412 :                         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       19412 :                         if (conn->recv_pos >= 20 && TDS_GET_A2BE(&packet->buf[18]) != size - 16)
     216             :                                 goto Severe_Error;
     217       19412 :                         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       19584 :                 if (mars_header.type != TDS_SMP_DATA)
     231         172 :                         return conn->recv_pos >= size;
     232       19412 :                 if (packet->data_len < size) {
     233        9706 :                         packet = tds_realloc_packet(packet, size);
     234        9706 :                         if (!packet)
     235             :                                 goto Memory_Error;
     236        9706 :                         conn->recv_packet = packet;
     237             :                 }
     238       19412 :                 packet->data_len = size;
     239       19412 :                 if (conn->recv_pos >= size) {
     240        9706 :                         packet->data_start = sizeof(TDS72_SMP_HEADER);
     241        9706 :                         packet->data_len -= sizeof(TDS72_SMP_HEADER);
     242        9706 :                         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       90228 :         if (conn->recv_pos >= 8) {
     250       83917 :                 len = TDS_GET_A2BE(&packet->buf[2]);
     251       83917 :                 if (len < 8)
     252             :                         goto Severe_Error;
     253       83917 :                 if (packet->data_len < len) {
     254       39119 :                         packet = tds_realloc_packet(packet, len);
     255       39119 :                         if (!packet) goto Memory_Error;
     256       39119 :                         conn->recv_packet = packet;
     257             :                 }
     258       83917 :                 packet->data_len = len;
     259       83917 :                 return conn->recv_pos >= len;
     260             :         }
     261             :         return false;
     262             : 
     263          11 : Memory_Error:
     264          11 : Severe_Error:
     265          11 :         tds_connection_close(conn);
     266          11 :         tds_free_packets(packet);
     267          11 :         conn->recv_packet = NULL;
     268          11 :         return false;
     269             : }
     270             : 
     271             : static TDSPACKET*
     272         119 : 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         119 :         p = mars;
     279         119 :         if (buf[0] != TDS72_SMP && tds->conn->mars) {
     280          40 :                 p->signature = TDS72_SMP;
     281          40 :                 p->type = TDS_SMP_DATA;
     282          40 :                 TDS_PUT_A2LE(&p->sid, tds->sid);
     283          40 :                 TDS_PUT_A4LE(&p->size, len+16);
     284          40 :                 ++tds->send_seq;
     285          40 :                 TDS_PUT_A4LE(&p->seq, tds->send_seq);
     286             :                 /* this is the acknowledge we give to server to stop sending !!! */
     287          40 :                 tds->recv_wnd = tds->recv_seq + 4;
     288          40 :                 TDS_PUT_A4LE(&p->wnd, tds->recv_wnd);
     289          40 :                 p++;
     290             :         }
     291             : 
     292         119 :         start = (char*) p - (char *) mars;
     293         119 :         packet = tds_get_packet(tds->conn, len + start);
     294         119 :         if (TDS_LIKELY(packet)) {
     295         119 :                 packet->sid = tds->sid;
     296         119 :                 memcpy(packet->buf, mars, start);
     297         119 :                 memcpy(packet->buf + start, buf, len);
     298         119 :                 packet->data_len = len + start;
     299             :         }
     300         119 :         return packet;
     301             : }
     302             : 
     303             : static void
     304             : tds_append_packet(TDSPACKET **p_packet, TDSPACKET *packet)
     305             : {
     306       96855 :         while (*p_packet)
     307         364 :                 p_packet = &((*p_packet)->next);
     308       96491 :         *p_packet = packet;
     309             : }
     310             : 
     311             : int
     312         119 : tds_append_cancel(TDSSOCKET *tds)
     313             : {
     314             :         unsigned char buf[8];
     315             :         TDSPACKET *packet;
     316             : 
     317         119 :         buf[0] = TDS_CANCEL;
     318         119 :         buf[1] = 1;
     319         119 :         TDS_PUT_A2BE(buf+2, 8);
     320         119 :         TDS_PUT_A4(buf+4, 0);
     321         119 :         if (IS_TDS7_PLUS(tds->conn) && !tds->login)
     322          88 :                 buf[6] = 0x01;
     323             : 
     324         119 :         packet = tds_build_packet(tds, buf, 8);
     325         119 :         if (!packet)
     326             :                 return TDS_FAIL;
     327             : 
     328         119 :         tds_mutex_lock(&tds->conn->list_mtx);
     329         238 :         tds_append_packet(&tds->conn->send_packets, packet);
     330         119 :         tds_mutex_unlock(&tds->conn->list_mtx);
     331             : 
     332         119 :         return TDS_SUCCESS;
     333             : }
     334             : 
     335             : 
     336             : static void
     337       96688 : tds_connection_network(TDSCONNECTION *conn, TDSSOCKET *tds, int send)
     338             : {
     339       96688 :         assert(!conn->in_net_tds);
     340       96688 :         conn->in_net_tds = tds;
     341       96688 :         tds_mutex_unlock(&conn->list_mtx);
     342             : 
     343             :         for (;;) {
     344             :                 /* wait packets or update */
     345      172909 :                 int rc = tds_select(tds, conn->send_packets ? TDSSELREAD|TDSSELWRITE : TDSSELREAD, tds->query_timeout);
     346             : 
     347      172909 :                 if (rc < 0) {
     348             :                         /* FIXME better error report */
     349          53 :                         tds_connection_close(conn);
     350          53 :                         break;
     351             :                 }
     352             : 
     353             :                 /* change notify */
     354             :                 /* TODO async */
     355             : 
     356      172856 :                 if (!rc) { /* timeout */
     357         153 :                         tdsdump_log(TDS_DBG_INFO1, "timeout\n");
     358         153 :                         switch (rc = tdserror(tds_get_ctx(tds), tds, TDSETIME, sock_errno)) {
     359         128 :                         case TDS_INT_CONTINUE:
     360         128 :                                 continue;
     361          25 :                         default:
     362             :                         case TDS_INT_CANCEL:
     363          25 :                                 tds_close_socket(tds);
     364             :                         }
     365          25 :                         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      172703 :                 if (conn->send_packets && (rc & POLLOUT) != 0) {
     374             :                         TDSSOCKET *s;
     375             : 
     376       52874 :                         int sid = tds_packet_write(conn);
     377       52874 :                         if (sid < 0)
     378        5252 :                                 continue;
     379             : 
     380       47622 :                         if (sid == tds->sid)
     381             :                                 break;  /* return to caller */
     382             : 
     383          10 :                         tds_mutex_lock(&conn->list_mtx);
     384          10 :                         if (sid < conn->num_sessions) {
     385          10 :                                 s = conn->sessions[sid];
     386          10 :                                 if (TDSSOCKET_VALID(s))
     387           0 :                                         tds_cond_signal(&s->packet_cond);
     388             :                         }
     389          10 :                         tds_mutex_unlock(&conn->list_mtx);
     390             :                         /* avoid using a possible closed connection */
     391          10 :                         continue;
     392             :                 }
     393             : 
     394             :                 /* received */
     395      119829 :                 if (rc & (POLLIN|POLLHUP)) {
     396             :                         TDSPACKET *packet;
     397             :                         TDSSOCKET *s;
     398             : 
     399             :                         /* try to read a packet */
     400      119711 :                         if (!tds_packet_read(conn, tds))
     401       70713 :                                 continue;       /* packet not complete */
     402       48998 :                         packet = conn->recv_packet;
     403       48998 :                         conn->recv_packet = NULL;
     404       48998 :                         conn->recv_pos = 0;
     405             : 
     406       48998 :                         tdsdump_dump_buf(TDS_DBG_NETWORK, "Received packet", packet->buf, packet->data_start + packet->data_len);
     407             : 
     408       48998 :                         tds_mutex_lock(&conn->list_mtx);
     409       48998 :                         if (packet->sid < conn->num_sessions) {
     410       48998 :                                 s = conn->sessions[packet->sid];
     411       48998 :                                 if (TDSSOCKET_VALID(s)) {
     412             :                                         /* append to correct session */
     413       48998 :                                         if (packet->buf[0] == TDS72_SMP && packet->buf[1] != TDS_SMP_DATA)
     414         172 :                                                 tds_packet_cache_add(conn, packet);
     415             :                                         else
     416       48826 :                                                 tds_append_packet(&conn->packets, packet);
     417       48998 :                                         packet = NULL;
     418             :                                         /* notify */
     419       48998 :                                         tds_cond_signal(&s->packet_cond);
     420             :                                 }
     421             :                         }
     422       48998 :                         tds_mutex_unlock(&conn->list_mtx);
     423       48998 :                         tds_free_packets(packet);
     424             :                         /* if we are receiving return the packet */
     425       48998 :                         if (!send) break;
     426             :                 }
     427             :         }
     428             : 
     429       96688 :         tds_mutex_lock(&conn->list_mtx);
     430       96688 :         conn->in_net_tds = NULL;
     431       96688 : }
     432             : 
     433             : static TDSRET
     434       46974 : tds_connection_put_packet(TDSSOCKET *tds, TDSPACKET *packet)
     435             : {
     436       46974 :         TDSCONNECTION *conn = tds->conn;
     437             : 
     438       46974 :         CHECK_TDS_EXTRA(tds);
     439             : 
     440       46974 :         packet->sid = tds->sid;
     441             : 
     442       46974 :         tds_mutex_lock(&conn->list_mtx);
     443       46974 :         tds->sending_packet = packet;
     444       94386 :         while (tds->sending_packet) {
     445             :                 int wait_res;
     446             : 
     447       47412 :                 if (IS_TDSDEAD(tds)) {
     448          44 :                         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       47368 :                 if (packet && (int32_t) (tds->send_seq - tds->send_wnd) < 0) {
     454             :                         /* prepare MARS header if needed */
     455       46970 :                         if (tds->conn->mars) {
     456             :                                 TDS72_SMP_HEADER *hdr;
     457             : 
     458             :                                 /* fill SMP data */
     459        9420 :                                 hdr = (TDS72_SMP_HEADER *) packet->buf;
     460        9420 :                                 hdr->signature = TDS72_SMP;
     461        9420 :                                 hdr->type = TDS_SMP_DATA;
     462        9420 :                                 TDS_PUT_A2LE(&hdr->sid, packet->sid);
     463        9420 :                                 TDS_PUT_A4LE(&hdr->size, packet->data_start + packet->data_len);
     464        9420 :                                 ++tds->send_seq;
     465        9420 :                                 TDS_PUT_A4LE(&hdr->seq, tds->send_seq);
     466             :                                 /* this is the acknowledge we give to server to stop sending */
     467        9420 :                                 tds->recv_wnd = tds->recv_seq + 4;
     468        9420 :                                 TDS_PUT_A4LE(&hdr->wnd, tds->recv_wnd);
     469             :                         }
     470             : 
     471             :                         /* append packet */
     472       93940 :                         tds_append_packet(&conn->send_packets, packet);
     473       46970 :                         packet = NULL;
     474             :                 }
     475             : 
     476             :                 /* network ok ? process network */
     477       47368 :                 if (!conn->in_net_tds) {
     478       47368 :                         tds_connection_network(conn, tds, packet ? 0 : 1);
     479       47368 :                         if (tds->sending_packet)
     480         438 :                                 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       46974 :         tds->sending_packet = NULL;
     504       46974 :         tds_mutex_unlock(&conn->list_mtx);
     505       46974 :         if (TDS_UNLIKELY(packet)) {
     506           4 :                 tds_free_packets(packet);
     507           4 :                 return TDS_FAIL;
     508             :         }
     509       46970 :         if (IS_TDSDEAD(tds))
     510             :                 return TDS_FAIL;
     511       46930 :         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       97522 : tds_read_packet(TDSSOCKET * tds)
     524             : {
     525             : #if ENABLE_ODBC_MARS
     526       48864 :         TDSCONNECTION *conn = tds->conn;
     527             : 
     528       48864 :         tds_mutex_lock(&conn->list_mtx);
     529             : 
     530             :         for (;;) {
     531             :                 int wait_res;
     532             :                 TDSPACKET **p_packet;
     533             : 
     534       98184 :                 if (IS_TDSDEAD(tds)) {
     535          38 :                         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       98298 :                 for (p_packet = &conn->packets; *p_packet; p_packet = &(*p_packet)->next)
     541       48978 :                         if ((*p_packet)->sid == tds->sid)
     542             :                                 break;
     543             : 
     544       98146 :                 if (*p_packet) {
     545             :                         /* remove our packet from list */
     546       48826 :                         TDSPACKET *packet = *p_packet;
     547       48826 :                         *p_packet = packet->next;
     548       48826 :                         tds_packet_cache_add(conn, tds->recv_packet);
     549       48826 :                         tds_mutex_unlock(&conn->list_mtx);
     550             : 
     551       48826 :                         packet->next = NULL;
     552       48826 :                         tds->recv_packet = packet;
     553             : 
     554       48826 :                         tds->in_buf = packet->buf + packet->data_start;
     555       48826 :                         tds->in_len = packet->data_len;
     556       48826 :                         tds->in_pos  = 8;
     557       48826 :                         tds->in_flag = tds->in_buf[0];
     558             : 
     559             :                         /* send acknowledge if needed */
     560       48826 :                         if ((int32_t) (tds->recv_seq + 2 - tds->recv_wnd) >= 0)
     561         347 :                                 tds_update_recv_wnd(tds, tds->recv_seq + 4);
     562             : 
     563       48826 :                         return tds->in_len;
     564             :                 }
     565             : 
     566             :                 /* network ok ? process network */
     567       49320 :                 if (!conn->in_net_tds) {
     568       49320 :                         tds_connection_network(conn, tds, 0);
     569       49320 :                         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          38 :         tds_mutex_unlock(&conn->list_mtx);
     586          38 :         return -1;
     587             : #else /* !ENABLE_ODBC_MARS */
     588       48658 :         unsigned char *pkt = tds->in_buf, *p, *end;
     589             : 
     590       48658 :         if (IS_TDSDEAD(tds)) {
     591           0 :                 tdsdump_log(TDS_DBG_NETWORK, "Read attempt when state is TDS_DEAD");
     592             :                 return -1;
     593             :         }
     594             : 
     595       48658 :         tds->in_len = 0;
     596       48658 :         tds->in_pos = 0;
     597      200224 :         for (p = pkt, end = p+8; p < end;) {
     598      102946 :                 int len = tds_connection_read(tds, p, end - p);
     599      102946 :                 if (len <= 0) {
     600          38 :                         tds_close_socket(tds);
     601          38 :                         return -1;
     602             :                 }
     603             : 
     604      102908 :                 p += len;
     605      102908 :                 if (p - pkt >= 4) {
     606      102908 :                         unsigned pktlen = TDS_GET_A2BE(pkt+2);
     607             :                         /* packet must at least contains header */
     608      102908 :                         if (TDS_UNLIKELY(pktlen < 8)) {
     609           0 :                                 tds_close_socket(tds);
     610           0 :                                 return -1;
     611             :                         }
     612      102908 :                         if (TDS_UNLIKELY(pktlen > tds->recv_packet->capacity)) {
     613        1317 :                                 TDSPACKET *packet = tds_realloc_packet(tds->recv_packet, pktlen);
     614        1317 :                                 if (TDS_UNLIKELY(!packet)) {
     615           0 :                                         tds_close_socket(tds);
     616           0 :                                         return -1;
     617             :                                 }
     618        1317 :                                 tds->recv_packet = packet;
     619        1317 :                                 pkt = packet->buf;
     620        1317 :                                 p = pkt + (p-tds->in_buf);
     621        1317 :                                 tds->in_buf = pkt;
     622             :                         }
     623      102908 :                         end = pkt + pktlen;
     624             :                 }
     625             :         }
     626             : 
     627             :         /* set the received packet type flag */
     628       48620 :         tds->in_flag = pkt[0];
     629             : 
     630             :         /* Set the length and pos (not sure what pos is used for now */
     631       48620 :         tds->in_len = p - pkt;
     632       48620 :         tds->in_pos = 8;
     633       48620 :         tdsdump_dump_buf(TDS_DBG_NETWORK, "Received packet", tds->in_buf, tds->in_len);
     634             : 
     635       48620 :         return tds->in_len;
     636             : #endif /* !ENABLE_ODBC_MARS */
     637             : }
     638             : 
     639             : #if ENABLE_ODBC_MARS
     640             : static TDSRET
     641         347 : tds_update_recv_wnd(TDSSOCKET *tds, TDS_UINT new_recv_wnd)
     642             : {
     643             :         TDS72_SMP_HEADER *mars;
     644             :         TDSPACKET *packet;
     645             : 
     646         347 :         if (!tds->conn->mars)
     647             :                 return TDS_SUCCESS;
     648             : 
     649         347 :         packet = tds_get_packet(tds->conn, sizeof(*mars));
     650         347 :         if (!packet)
     651             :                 return TDS_FAIL;        /* TODO check result */
     652             : 
     653         347 :         packet->data_len = sizeof(*mars);
     654         347 :         packet->sid = tds->sid;
     655             : 
     656         347 :         mars = (TDS72_SMP_HEADER *) packet->buf;
     657         347 :         mars->signature = TDS72_SMP;
     658         347 :         mars->type = TDS_SMP_ACK;
     659         347 :         TDS_PUT_A2LE(&mars->sid, tds->sid);
     660         347 :         mars->size = TDS_HOST4LE(16);
     661         347 :         TDS_PUT_A4LE(&mars->seq, tds->send_seq);
     662         347 :         tds->recv_wnd = new_recv_wnd;
     663         347 :         TDS_PUT_A4LE(&mars->wnd, tds->recv_wnd);
     664             : 
     665         347 :         tds_mutex_lock(&tds->conn->list_mtx);
     666         694 :         tds_append_packet(&tds->conn->send_packets, packet);
     667         347 :         tds_mutex_unlock(&tds->conn->list_mtx);
     668             : 
     669         347 :         return TDS_SUCCESS;
     670             : }
     671             : 
     672             : static TDSRET
     673         229 : tds_append_fin_syn(TDSSOCKET *tds, uint8_t type)
     674             : {
     675             :         TDS72_SMP_HEADER mars;
     676             :         TDSPACKET *packet;
     677             : 
     678         229 :         if (!tds->conn->mars)
     679             :                 return TDS_SUCCESS;
     680             : 
     681         229 :         mars.signature = TDS72_SMP;
     682         229 :         mars.type = type;
     683         229 :         TDS_PUT_A2LE(&mars.sid, tds->sid);
     684         229 :         mars.size = TDS_HOST4LE(16);
     685         229 :         TDS_PUT_A4LE(&mars.seq, tds->send_seq);
     686         229 :         tds->recv_wnd = tds->recv_seq + 4;
     687         229 :         TDS_PUT_A4LE(&mars.wnd, tds->recv_wnd);
     688             : 
     689             :         /* do not use tds_get_packet as it require no lock ! */
     690         229 :         packet = tds_alloc_packet(&mars, sizeof(mars));
     691         229 :         if (!packet)
     692             :                 return TDS_FAIL;        /* TODO check result */
     693         229 :         packet->sid = tds->sid;
     694             : 
     695             :         /* we already hold lock so do not lock */
     696         458 :         tds_append_packet(&tds->conn->send_packets, packet);
     697             : 
     698         229 :         if (type == TDS_SMP_FIN) {
     699             :                 /* now is no more an active session */
     700          10 :                 tds->conn->sessions[tds->sid] = BUSY_SOCKET;
     701          10 :                 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          10 : tds_append_fin(TDSSOCKET *tds)
     713             : {
     714          10 :         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         219 : tds_append_syn(TDSSOCKET *tds)
     723             : {
     724             :         TDSRET ret;
     725         219 :         tds_mutex_lock(&tds->conn->list_mtx);
     726         219 :         ret = tds_append_fin_syn(tds, TDS_SMP_SYN);
     727         219 :         tds_mutex_unlock(&tds->conn->list_mtx);
     728         219 :         return ret;
     729             : }
     730             : #endif /* ENABLE_ODBC_MARS */
     731             : 
     732             : 
     733             : TDS_COMPILE_CHECK(additional, TDS_ADDITIONAL_SPACE != 0);
     734             : 
     735             : TDSRET
     736       93316 : tds_write_packet(TDSSOCKET * tds, unsigned char final)
     737             : {
     738             :         TDSRET res;
     739       93316 :         unsigned int left = 0;
     740       93316 :         TDSPACKET *pkt = tds->send_packet, *pkt_next = NULL;
     741             : 
     742       93316 :         CHECK_TDS_EXTRA(tds);
     743             : 
     744             : #if !ENABLE_ODBC_MARS
     745       46296 :         if (tds->frozen)
     746             : #endif
     747             :         {
     748       47137 :                 pkt->next = pkt_next = tds_get_packet(tds->conn, pkt->capacity);
     749       47137 :                 if (!pkt_next)
     750             :                         return TDS_FAIL;
     751             : 
     752             : #if ENABLE_ODBC_MARS
     753       47020 :                 if (tds->conn->mars)
     754        9444 :                         pkt_next->data_start = sizeof(TDS72_SMP_HEADER);
     755             : #endif
     756             :         }
     757             : 
     758       93316 :         if (tds->out_pos > tds->out_buf_max) {
     759         496 :                 left = tds->out_pos - tds->out_buf_max;
     760         243 :                 if (pkt_next)
     761         262 :                         memcpy(pkt_next->buf + tds_packet_get_data_start(pkt_next) + 8, tds->out_buf + tds->out_buf_max, left);
     762         496 :                 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       93316 :         tds->out_buf[0] = tds->out_flag;
     769       93316 :         tds->out_buf[1] = final;
     770       93316 :         TDS_PUT_A2BE(tds->out_buf+2, tds->out_pos);
     771       93316 :         TDS_PUT_A2BE(tds->out_buf+4, tds->conn->client_spid);
     772       93316 :         TDS_PUT_A2(tds->out_buf+6, 0);
     773       93316 :         if (IS_TDS7_PLUS(tds->conn) && !tds->login)
     774       65118 :                 tds->out_buf[6] = 0x01;
     775             : 
     776       93316 :         if (tds->frozen) {
     777         334 :                 pkt->data_len = tds->out_pos;
     778         334 :                 tds_set_current_send_packet(tds, pkt_next);
     779         334 :                 tds->out_pos = left + 8;
     780         334 :                 CHECK_TDS_EXTRA(tds);
     781         334 :                 return TDS_SUCCESS;
     782             :         }
     783             : 
     784             : #if ENABLE_ODBC_MARS
     785       46803 :         pkt->data_len = tds->out_pos;
     786       46803 :         pkt->next = NULL;
     787       46803 :         tds_set_current_send_packet(tds, pkt_next);
     788       46803 :         res = tds_connection_put_packet(tds, pkt);
     789             : #else /* !ENABLE_ODBC_MARS */
     790       46179 :         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       92358 :         res = tds_connection_write(tds, tds->out_buf, tds->out_pos, final) <= 0 ?
     794       46179 :                 TDS_FAIL : TDS_SUCCESS;
     795             : 
     796       46179 :         memcpy(tds->out_buf + 8, tds->out_buf + tds->out_buf_max, left);
     797             : #endif /* !ENABLE_ODBC_MARS */
     798             : 
     799       92982 :         tds->out_pos = left + 8;
     800             : 
     801       92982 :         if (TDS_UNLIKELY(tds->conn->encrypt_single_packet)) {
     802         730 :                 tds->conn->encrypt_single_packet = 0;
     803         730 :                 tds_ssl_deinit(tds->conn);
     804             :         }
     805             : 
     806             :         return res;
     807             : }
     808             : 
     809             : #if !ENABLE_ODBC_MARS
     810             : int
     811         543 : tds_put_cancel(TDSSOCKET * tds)
     812             : {
     813             :         unsigned char out_buf[8];
     814             :         int sent;
     815             : 
     816         543 :         out_buf[0] = TDS_CANCEL;        /* out_flag */
     817         543 :         out_buf[1] = 1; /* final */
     818         543 :         out_buf[2] = 0;
     819         543 :         out_buf[3] = 8;
     820         543 :         TDS_PUT_A4(out_buf+4, 0);
     821         543 :         if (IS_TDS7_PLUS(tds->conn) && !tds->login)
     822         460 :                 out_buf[6] = 0x01;
     823             : 
     824         543 :         tdsdump_dump_buf(TDS_DBG_NETWORK, "Sending packet", out_buf, 8);
     825             : 
     826         543 :         sent = tds_connection_write(tds, out_buf, 8, 1);
     827             : 
     828         543 :         if (sent > 0)
     829         537 :                 tds->in_cancel = 2;
     830             : 
     831             :         /* GW added in check for write() returning <0 and SIGPIPE checking */
     832         543 :         return sent <= 0 ? TDS_FAIL : TDS_SUCCESS;
     833             : }
     834             : #endif /* !ENABLE_ODBC_MARS */
     835             : 
     836             : 
     837             : #if ENABLE_ODBC_MARS
     838             : static int
     839       52874 : tds_packet_write(TDSCONNECTION *conn)
     840             : {
     841             :         int sent;
     842             :         int final;
     843       52874 :         TDSPACKET *packet = conn->send_packets;
     844             : 
     845       52874 :         assert(packet);
     846             : 
     847       52874 :         if (conn->send_pos == 0)
     848       47662 :                 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       52874 :         if (packet->next != NULL)
     852             :                 final = 0;
     853             :         /* take into account other packets for this session */
     854       52592 :         else if (packet->buf[0] != TDS72_SMP)
     855       42816 :                 final = packet->buf[1] & 1;
     856             :         else
     857             :                 final = 1;
     858             : 
     859       52874 :         sent = tds_connection_write(conn->in_net_tds, packet->buf + conn->send_pos,
     860       52874 :                                     packet->data_start + packet->data_len - conn->send_pos, final);
     861             : 
     862       52874 :         if (TDS_UNLIKELY(sent < 0)) {
     863             :                 /* TODO tdserror called ?? */
     864          40 :                 tds_connection_close(conn);
     865          40 :                 return -1;
     866             :         }
     867             : 
     868             :         /* update sent data */
     869       52834 :         conn->send_pos += sent;
     870             :         /* remove packet if sent all data */
     871       52834 :         if (conn->send_pos >= packet->data_start + packet->data_len) {
     872       47622 :                 uint16_t sid = packet->sid;
     873             :                 TDSSOCKET *tds;
     874       47622 :                 tds_mutex_lock(&conn->list_mtx);
     875       47622 :                 tds = conn->sessions[sid];
     876       47622 :                 if (TDSSOCKET_VALID(tds) && tds->sending_packet == packet)
     877       46930 :                         tds->sending_packet = NULL;
     878       47622 :                 conn->send_packets = packet->next;
     879       47622 :                 packet->next = NULL;
     880       47622 :                 tds_packet_cache_add(conn, packet);
     881       47622 :                 tds_mutex_unlock(&conn->list_mtx);
     882       47622 :                 conn->send_pos = 0;
     883       47622 :                 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       79132 : tds_freeze(TDSSOCKET *tds, TDSFREEZE *freeze, unsigned size_len)
     904             : {
     905       79132 :         CHECK_TDS_EXTRA(tds);
     906       79132 :         tds_extra_assert(size_len <= 4 && size_len != 3);
     907             : 
     908       79132 :         if (tds->out_pos > tds->out_buf_max)
     909          15 :                 tds_write_packet(tds, 0x0);
     910             : 
     911       79132 :         if (!tds->frozen)
     912       54561 :                 tds->frozen_packets = tds->send_packet;
     913             : 
     914       79132 :         ++tds->frozen;
     915       79132 :         freeze->tds = tds;
     916       79132 :         freeze->pkt = tds->send_packet;
     917       79132 :         freeze->pkt_pos = tds->out_pos;
     918       79132 :         freeze->size_len = size_len;
     919       79132 :         if (size_len)
     920       73398 :                 tds_put_n(tds, NULL, size_len);
     921             : 
     922       79132 :         CHECK_FREEZE_EXTRA(freeze);
     923       79132 : }
     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       69460 : tds_freeze_written(TDSFREEZE *freeze)
     932             : {
     933       69460 :         TDSSOCKET *tds = freeze->tds;
     934       69460 :         TDSPACKET *pkt = freeze->pkt;
     935             :         size_t size;
     936             : 
     937       69460 :         CHECK_FREEZE_EXTRA(freeze);
     938             : 
     939             :         /* last packet needs special handling */
     940       69460 :         size = tds->out_pos;
     941             : 
     942             :         /* packets before last */
     943       69842 :         for (; pkt->next != NULL; pkt = pkt->next)
     944         382 :                 size += pkt->data_len - 8;
     945             : 
     946       69460 :         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          30 : tds_freeze_abort(TDSFREEZE *freeze)
     958             : {
     959          30 :         TDSSOCKET *tds = freeze->tds;
     960          30 :         TDSPACKET *pkt = freeze->pkt;
     961             : 
     962          30 :         CHECK_FREEZE_EXTRA(freeze);
     963             : 
     964          30 :         if (pkt->next) {
     965          15 :                 tds_mutex_lock(&tds->conn->list_mtx);
     966          15 :                 tds_packet_cache_add(tds->conn, pkt->next);
     967          15 :                 tds_mutex_unlock(&tds->conn->list_mtx);
     968          15 :                 pkt->next = NULL;
     969             : 
     970             :                 tds_set_current_send_packet(tds, pkt);
     971             :         }
     972          30 :         tds->out_pos = freeze->pkt_pos;
     973          30 :         pkt->data_len = 8;
     974             : 
     975          30 :         --tds->frozen;
     976          30 :         if (!tds->frozen)
     977          30 :                 tds->frozen_packets = NULL;
     978          30 :         freeze->tds = NULL;
     979          30 :         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       23752 : tds_freeze_close(TDSFREEZE *freeze)
     993             : {
     994       23752 :         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       14068 : tds_freeze_close_string(TDSFREEZE *freeze)
    1009             : {
    1010       14068 :         size_t written = tds_freeze_written(freeze) - freeze->size_len;
    1011       14068 :         if (IS_TDS7_PLUS(freeze->tds->conn))
    1012       14068 :                 written /= 2;
    1013       14068 :         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       73368 :         unsigned pos = freeze->pkt_pos;
    1021       73368 :         unsigned size_len = freeze->size_len;
    1022             : 
    1023       73368 :         pkt = freeze->pkt;
    1024             :         do {
    1025      234758 :                 if (pos >= pkt->data_len && pkt->next) {
    1026          15 :                         pkt = pkt->next;
    1027          15 :                         pos = 8;
    1028             :                 }
    1029      234758 :                 pkt->buf[tds_packet_get_data_start(pkt) + pos] = size & 0xffu;
    1030      234758 :                 size >>= 8;
    1031      234758 :                 pos++;
    1032      234758 :         } 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       79102 : tds_freeze_close_len(TDSFREEZE *freeze, int32_t size)
    1047             : {
    1048       79102 :         TDSSOCKET *tds = freeze->tds;
    1049             :         TDSPACKET *pkt;
    1050             : #if !ENABLE_ODBC_MARS
    1051       39437 :         TDSPACKET *last_pkt_sent = NULL;
    1052             : #endif
    1053             : 
    1054       79102 :         CHECK_FREEZE_EXTRA(freeze);
    1055             : 
    1056       79102 :         if (freeze->size_len)
    1057       73368 :                 tds_freeze_update_size(freeze, size);
    1058             : 
    1059             :         /* if not last freeze we need just to update size */
    1060       79102 :         freeze->tds = NULL;
    1061       79102 :         if (--tds->frozen != 0)
    1062             :                 return TDS_SUCCESS;
    1063             : 
    1064       54531 :         tds->frozen_packets = NULL;
    1065       54531 :         pkt = freeze->pkt;
    1066      109297 :         while (pkt->next) {
    1067         262 :                 TDSPACKET *next = pkt->next;
    1068             :                 TDSRET rc;
    1069             : #if ENABLE_ODBC_MARS
    1070         171 :                 pkt->next = NULL;
    1071         171 :                 freeze->pkt = next;
    1072             :                 /* packet will get owned by function, no need to release it */
    1073         171 :                 rc = tds_connection_put_packet(tds, pkt);
    1074             : #else
    1075         182 :                 rc = tds_connection_write(tds, pkt->buf, pkt->data_len, 0) <= 0 ?
    1076          91 :                         TDS_FAIL : TDS_SUCCESS;
    1077          91 :                 last_pkt_sent = pkt;
    1078             : #endif
    1079         262 :                 if (TDS_UNLIKELY(TDS_FAILED(rc))) {
    1080          54 :                         while (next->next) {
    1081             :                                 pkt = next;
    1082             :                                 next = pkt->next;
    1083             :                         }
    1084          27 :                         tds_extra_assert(pkt->next != NULL);
    1085          27 :                         tds_extra_assert(pkt->next == tds->send_packet);
    1086             : 
    1087          27 :                         pkt->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          27 :                         return rc;
    1092             :                 }
    1093             :                 pkt = next;
    1094             :         }
    1095             : 
    1096       54504 :         tds_extra_assert(pkt->next == NULL);
    1097       54504 :         tds_extra_assert(pkt == tds->send_packet);
    1098             : 
    1099             : #if !ENABLE_ODBC_MARS
    1100       27159 :         if (last_pkt_sent) {
    1101          33 :                 tds_extra_assert(last_pkt_sent->next == pkt);
    1102          33 :                 last_pkt_sent->next = NULL;
    1103          33 :                 tds_mutex_lock(&tds->conn->list_mtx);
    1104          33 :                 tds_packet_cache_add(tds->conn, freeze->pkt);
    1105          33 :                 tds_mutex_unlock(&tds->conn->list_mtx);
    1106             :         }
    1107             : #endif
    1108             : 
    1109             :         /* keep final packet so we can continue to add data */
    1110       27345 :         return TDS_SUCCESS;
    1111             : }
    1112             : 
    1113             : /** @} */

Generated by: LCOV version 1.13