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

Generated by: LCOV version 1.13