NCBI C++ ToolKit
packet.c
Go to the documentation of this file.

Go to the SVN repository for this file.

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