static int get_utf16le(const unsigned char *p, size_t len, ICONV_CHAR *out) { ICONV_CHAR c, c2; if (len < 2) return -EINVAL; c = TDS_GET_A2LE(p); if ((c & 0xfc00) == 0xd800) { if (len < 4) return -EINVAL; c2 = TDS_GET_A2LE(p+2); if ((c2 & 0xfc00) != 0xdc00) return -EILSEQ; *out = (c << 10) + c2 - ((0xd800 << 10) + 0xdc00 - 0x10000); return 4; } *out = c; return 2; }
/** * Get an int16 from the server. */ TDS_SMALLINT tds_get_smallint(TDSSOCKET * tds) { unsigned char bytes[2]; tds_get_n(tds, bytes, 2); #if WORDS_BIGENDIAN if (tds->emul_little_endian) return (TDS_SMALLINT) TDS_GET_A2LE(bytes); #endif return (TDS_SMALLINT) TDS_GET_A2(bytes); }
/** * Get an int16 from the server. */ TDS_USMALLINT tds_get_usmallint(TDSSOCKET * tds) { TDS_USMALLINT bytes[1]; tds_get_n(tds, &bytes, 2); #if WORDS_BIGENDIAN if (tds->conn->emul_little_endian) return (TDS_USMALLINT) TDS_GET_A2LE(&bytes); #endif return (TDS_USMALLINT) TDS_GET_A2(&bytes); }
/* read partial packet */ static void tds_packet_read(TDSCONNECTION *conn, TDSSOCKET *tds) { TDSPACKET *packet = conn->recv_packet; int len; /* allocate some space to read data */ if (!packet) { conn->recv_packet = packet = tds_get_packet(conn, MAX(conn->env.block_size + sizeof(TDS72_SMP_HEADER), 512)); if (!packet) goto Memory_Error; TDS_MARK_UNDEFINED(packet->buf, packet->capacity); conn->recv_pos = 0; packet->len = 8; } assert(conn->recv_pos < packet->len && packet->len <= packet->capacity); len = tds_connection_read(tds, packet->buf + conn->recv_pos, packet->len - conn->recv_pos); if (len < 0) goto Severe_Error; conn->recv_pos += len; assert(conn->recv_pos <= packet->len && packet->len <= packet->capacity); /* handle SMP */ if (conn->recv_pos > 0 && packet->buf[0] == TDS72_SMP) { TDS72_SMP_HEADER mars_header; short sid; TDSSOCKET *tds; TDS_UINT size; if (conn->recv_pos < 16) { packet->len = 16; return; } memcpy(&mars_header, packet->buf, sizeof(mars_header)); tdsdump_dump_buf(TDS_DBG_HEADER, "Received MARS header", &mars_header, sizeof(mars_header)); sid = TDS_GET_A2LE(&mars_header.sid); /* FIXME this is done even by caller !! */ tds = NULL; tds_mutex_lock(&conn->list_mtx); if (sid >= 0 && sid < conn->num_sessions) tds = conn->sessions[sid]; tds_mutex_unlock(&conn->list_mtx); packet->sid = sid; if (tds == BUSY_SOCKET) { if (mars_header.type != TDS_SMP_FIN) { tdsdump_log(TDS_DBG_ERROR, "Received MARS with no session (%d)\n", sid); goto Severe_Error; } /* check if was just a "zombie" socket */ tds_mutex_lock(&conn->list_mtx); conn->sessions[sid] = NULL; tds_mutex_unlock(&conn->list_mtx); /* reset packet to initial state to reuse it */ packet->len = 8; conn->recv_pos = 0; return; } if (!tds) { /* server sent a unknown packet, close connection */ goto Severe_Error; } tds->send_wnd = TDS_GET_A4LE(&mars_header.wnd); size = TDS_GET_A4LE(&mars_header.size); if (mars_header.type == TDS_SMP_ACK) { if (size != sizeof(mars_header)) goto Severe_Error; } else if (mars_header.type == TDS_SMP_DATA) { if (size < 0x18 || size > 0xffffu + sizeof(mars_header)) goto Severe_Error; /* avoid recursive SMP */ if (conn->recv_pos > 16 && packet->buf[16] == TDS72_SMP) goto Severe_Error; /* TODO is possible to put 2 TDS packet inside a single DATA ?? */ if (conn->recv_pos >= 20 && TDS_GET_A2BE(&packet->buf[18]) != size - 16) goto Severe_Error; tds->recv_seq = TDS_GET_A4LE(&mars_header.seq); /* * does not sent ACK here cause this would lead to memory waste * if session is not able to handle all that packets */ } else if (mars_header.type == TDS_SMP_FIN) { if (size != sizeof(mars_header)) goto Severe_Error; /* this socket shold now not start another session */ // tds_set_state(tds, TDS_DEAD); // tds->sid = -1; } else goto Severe_Error; if (mars_header.type != TDS_SMP_DATA) return; if (packet->len < size) { packet = tds_realloc_packet(packet, size); if (!packet) goto Memory_Error; conn->recv_packet = packet; } packet->len = size; return; } assert(conn->recv_pos <= packet->len && packet->len <= packet->capacity); /* normal packet */ if (conn->recv_pos >= 8) { len = TDS_GET_A2BE(&packet->buf[2]); if (len < 8) goto Severe_Error; if (packet->len < len) { packet = tds_realloc_packet(packet, len); if (!packet) goto Memory_Error; conn->recv_packet = packet; } packet->len = len; } return; Memory_Error: Severe_Error: tds_connection_close(conn); tds_free_packets(packet); conn->recv_packet = NULL; }