static int get_ucs4le(const unsigned char *p, size_t len, ICONV_CHAR *out) { if (len < 4) return -EINVAL; *out = TDS_GET_A4LE(p); return 4; }
/** * Get an int32 from the server. */ TDS_INT tds_get_int(TDSSOCKET * tds) { unsigned char bytes[4]; tds_get_n(tds, bytes, 4); #if WORDS_BIGENDIAN if (tds->emul_little_endian) return (TDS_INT) TDS_GET_A4LE(bytes); #endif return (TDS_INT) TDS_GET_A4(bytes); }
/** * Get an int32 from the server. * \tds */ TDS_UINT tds_get_uint(TDSSOCKET * tds) { TDS_UINT bytes; tds_get_n(tds, &bytes, 4); #if WORDS_BIGENDIAN if (tds->conn->emul_little_endian) return TDS_GET_A4LE(&bytes); #endif return TDS_GET_A4(&bytes); }
TDS_INT8 tds_get_int8(TDSSOCKET * tds) { TDS_INT h; TDS_UINT l; unsigned char bytes[8]; tds_get_n(tds, bytes, 8); #if WORDS_BIGENDIAN if (tds->emul_little_endian) { l = TDS_GET_A4LE(bytes); h = (TDS_INT) TDS_GET_A4LE(bytes+4); } else { h = (TDS_INT) TDS_GET_A4(bytes); l = TDS_GET_A4(bytes+4); } #else l = TDS_GET_A4(bytes); h = (TDS_INT) TDS_GET_A4(bytes+4); #endif return (((TDS_INT8) h) << 32) | l; }
/** * Get an uint64 from the server. * \tds */ TDS_UINT8 tds_get_uint8(TDSSOCKET * tds) { TDS_UINT h; TDS_UINT l; TDS_UINT bytes[2]; tds_get_n(tds, bytes, 8); #if WORDS_BIGENDIAN if (tds->conn->emul_little_endian) { l = TDS_GET_A4LE(bytes); h = TDS_GET_A4LE(bytes+1); } else { h = TDS_GET_A4(bytes); l = TDS_GET_A4(bytes+1); } #else l = TDS_GET_A4(bytes); h = TDS_GET_A4(bytes+1); #endif return (((TDS_UINT8) h) << 32) | l; }
/* 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; }