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

Generated by: LCOV version 1.13