Line data Source code
1 : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2 : * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Brian Bruns
3 : * Copyright (C) 2005-2014 Frediano Ziglio
4 : *
5 : * This library is free software; you can redistribute it and/or
6 : * modify it under the terms of the GNU Library General Public
7 : * License as published by the Free Software Foundation; either
8 : * version 2 of the License, or (at your option) any later version.
9 : *
10 : * This library is distributed in the hope that it will be useful,
11 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 : * Library General Public License for more details.
14 : *
15 : * You should have received a copy of the GNU Library General Public
16 : * License along with this library; if not, write to the
17 : * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 : * Boston, MA 02111-1307, USA.
19 : */
20 :
21 : /**
22 : * \file
23 : * \brief Grab data from TDS packets
24 : */
25 :
26 : #include <config.h>
27 :
28 : #if HAVE_ERRNO_H
29 : #include <errno.h>
30 : #endif /* HAVE_ERRNO_H */
31 :
32 : #if HAVE_STDLIB_H
33 : #include <stdlib.h>
34 : #endif /* HAVE_STDLIB_H */
35 :
36 : #if HAVE_STRING_H
37 : #include <string.h>
38 : #endif /* HAVE_STRING_H */
39 :
40 : #if HAVE_UNISTD_H
41 : #include <unistd.h>
42 : #endif /* HAVE_UNISTD_H */
43 :
44 : #include <assert.h>
45 :
46 : #include <freetds/tds.h>
47 : #include <freetds/iconv.h>
48 : #include <freetds/bytes.h>
49 : #include <freetds/stream.h>
50 : #include <freetds/utils/string.h>
51 : #include <freetds/checks.h>
52 :
53 : static size_t read_and_convert(TDSSOCKET * tds, TDSICONV * char_conv,
54 : size_t * wire_size, char *outbuf, size_t outbytesleft);
55 :
56 : /**
57 : * \ingroup libtds
58 : * \defgroup network Network functions
59 : * Functions for reading or writing from network.
60 : */
61 :
62 : /**
63 : * \addtogroup network
64 : * @{
65 : */
66 :
67 : /**
68 : * Return a single byte from the input buffer
69 : * \tds
70 : */
71 : unsigned char
72 1627629 : tds_get_byte(TDSSOCKET * tds)
73 : {
74 3336605 : while (tds->in_pos >= tds->in_len) {
75 81403 : if (tds_read_packet(tds) < 0)
76 : return 0;
77 : }
78 1627573 : return tds->in_buf[tds->in_pos++];
79 : }
80 :
81 : /**
82 : * Unget will always work as long as you don't call it twice in a row. It
83 : * it may work if you call it multiple times as long as you don't backup
84 : * over the beginning of network packet boundary which can occur anywhere in
85 : * the token stream.
86 : * \tds
87 : */
88 : void
89 65693 : tds_unget_byte(TDSSOCKET * tds)
90 : {
91 : /* this is a one trick pony...don't call it twice */
92 65693 : tds->in_pos--;
93 65693 : }
94 :
95 : /**
96 : * Reads a byte from the TDS stream without removing it
97 : * \tds
98 : */
99 : unsigned char
100 46564 : tds_peek(TDSSOCKET * tds)
101 : {
102 46564 : unsigned char result = tds_get_byte(tds);
103 46564 : if (tds->in_pos > 0)
104 46564 : --tds->in_pos;
105 46564 : return result;
106 : }
107 :
108 : /**
109 : * Get an uint16 from the server.
110 : */
111 : TDS_USMALLINT
112 1043474 : tds_get_usmallint(TDSSOCKET * tds)
113 : {
114 : TDS_USMALLINT bytes;
115 :
116 1043474 : tds_get_n(tds, &bytes, 2);
117 1043474 : return (TDS_USMALLINT) TDS_GET_A2LE(&bytes);
118 : }
119 :
120 : /**
121 : * Get an uint32 from the server.
122 : * \tds
123 : */
124 : TDS_UINT
125 229205 : tds_get_uint(TDSSOCKET * tds)
126 : {
127 : TDS_UINT bytes;
128 :
129 229205 : tds_get_n(tds, &bytes, 4);
130 229205 : return TDS_GET_A4LE(&bytes);
131 : }
132 :
133 : /**
134 : * Get an uint64 from the server.
135 : * \tds
136 : */
137 : TDS_UINT8
138 67119 : tds_get_uint8(TDSSOCKET * tds)
139 : {
140 : TDS_UINT h;
141 : TDS_UINT l;
142 : TDS_UINT bytes[2];
143 :
144 67119 : tds_get_n(tds, bytes, 8);
145 67119 : l = TDS_GET_A4LE(bytes);
146 67119 : h = TDS_GET_A4LE(bytes+1);
147 67119 : return (((TDS_UINT8) h) << 32) | l;
148 : }
149 :
150 : /**
151 : * Fetch a string from the wire.
152 : * Output string is NOT null terminated.
153 : * If TDS version is 7 or 8 read unicode string and convert it.
154 : * This function should be use to read server default encoding strings like
155 : * columns name, table names, etc, not for data (use tds_get_char_data instead)
156 : * @return bytes written to \a dest
157 : * @param tds connection information
158 : * @param string_len length of string to read from wire
159 : * (in server characters, bytes for tds4-tds5, ucs2 for tds7+)
160 : * @param dest destination buffer, if NULL string is read and discarded
161 : * @param dest_size destination buffer size, in bytes
162 : */
163 : size_t
164 180162 : tds_get_string(TDSSOCKET * tds, size_t string_len, char *dest, size_t dest_size)
165 : {
166 180162 : size_t wire_bytes = string_len;
167 180162 : unsigned conv = client2server_chardata;
168 :
169 180162 : if (IS_TDS7_PLUS(tds->conn)) {
170 129415 : wire_bytes *= 2u;
171 129415 : conv = client2ucs2;
172 : }
173 :
174 180162 : if (dest == NULL) {
175 44 : tds_get_n(tds, NULL, wire_bytes);
176 44 : return string_len;
177 : }
178 :
179 180118 : return read_and_convert(tds, tds->conn->char_convs[conv], &wire_bytes, dest, dest_size);
180 : }
181 :
182 : /**
183 : * Fetch character data the wire.
184 : * Output is NOT null terminated.
185 : * If \a char_conv is not NULL, convert data accordingly.
186 : * \param tds state information for the socket and the TDS protocol
187 : * \param row_buffer destination buffer in current_row. Can't be NULL
188 : * \param wire_size size to read from wire (in bytes)
189 : * \param curcol column information
190 : * \return TDS_SUCCESS or TDS_FAIL (probably memory error on text data)
191 : */
192 : TDSRET
193 485663 : tds_get_char_data(TDSSOCKET * tds, char *row_buffer, size_t wire_size, TDSCOLUMN * curcol)
194 : {
195 : size_t in_left;
196 :
197 485663 : assert(curcol->char_conv);
198 :
199 : /*
200 : * row_buffer is a column buffer, allocated when the column's metadata are processed
201 : * and reused for each row.
202 : */
203 :
204 : /* silly case, empty string */
205 485663 : if (wire_size == 0) {
206 88 : curcol->column_cur_size = 0;
207 88 : return TDS_SUCCESS;
208 : }
209 :
210 485575 : in_left = curcol->column_size;
211 485575 : curcol->column_cur_size =
212 485575 : (TDS_INT) read_and_convert(tds, curcol->char_conv, &wire_size, row_buffer, in_left);
213 485575 : if (TDS_UNLIKELY(wire_size > 0)) {
214 0 : tds_get_n(tds, NULL, wire_size);
215 0 : tdsdump_log(TDS_DBG_NETWORK, "error: tds_get_char_data: discarded %u on wire while reading %d into client. \n",
216 : (unsigned int) wire_size, curcol->column_cur_size);
217 : return TDS_FAIL;
218 : }
219 : return TDS_SUCCESS;
220 : }
221 :
222 : /**
223 : * Get N bytes from the buffer and return them in the already allocated space
224 : * given to us. We ASSUME that the person calling this function has done the
225 : * bounds checking for us since they know how many bytes they want here.
226 : * dest of NULL means we just want to eat the bytes. (tetherow@nol.org)
227 : */
228 : bool
229 3187178 : tds_get_n(TDSSOCKET * tds, void *dest, size_t need)
230 : {
231 : for (;;) {
232 3194300 : unsigned int have = tds->in_len - tds->in_pos;
233 :
234 3194300 : if (need <= have)
235 : break;
236 : /* We need more than is in the buffer, copy what is there */
237 7122 : if (dest != NULL) {
238 7121 : memcpy((char *) dest, tds->in_buf + tds->in_pos, have);
239 7121 : dest = (char *) dest + have;
240 : }
241 7122 : need -= have;
242 7122 : if (TDS_UNLIKELY((tds->in_buf[1] & TDS_STATUS_EOM) != 0
243 : || tds_read_packet(tds) < 0)) {
244 0 : tds_close_socket(tds); /* evidently out of sync */
245 0 : return false;
246 : }
247 : }
248 3187178 : if (need > 0) {
249 : /* get the remainder if there is any */
250 2744118 : if (dest != NULL) {
251 2701692 : memcpy((char *) dest, tds->in_buf + tds->in_pos, need);
252 : }
253 2744118 : tds->in_pos += (unsigned) need;
254 : }
255 : return true;
256 : }
257 :
258 : /**
259 : * For UTF-8 and similar, tds_iconv() may encounter a partial sequence when the chunk boundary
260 : * is not aligned with the character boundary. In that event, it will return an error, and
261 : * some number of bytes (less than a character) will remain in the tail end of temp[]. They are
262 : * moved to the beginning, ptemp is adjusted to point just behind them, and the next chunk is read.
263 : * \tds
264 : * \param char_conv conversion structure
265 : * \param[out] wire_size size readed from wire
266 : * \param outbuf buffer to write to
267 : * \param outbytesleft buffer length
268 : * \return bytes readed
269 : */
270 : static size_t
271 665693 : read_and_convert(TDSSOCKET * tds, TDSICONV * char_conv, size_t * wire_size, char *outbuf,
272 : size_t outbytesleft)
273 : {
274 : int res;
275 : TDSDATAINSTREAM r;
276 : TDSSTATICOUTSTREAM w;
277 :
278 665693 : tds_datain_stream_init(&r, tds, *wire_size);
279 665693 : tds_staticout_stream_init(&w, outbuf, outbytesleft);
280 :
281 665693 : res = tds_convert_stream(tds, char_conv, to_client, &r.stream, &w.stream);
282 665693 : *wire_size = r.wire_size;
283 665693 : return (char *) w.stream.buffer - outbuf;
284 : }
285 :
286 : /**
287 : * Reads a string from wire and put in a DSTR.
288 : * On error we read the bytes from the wire anyway.
289 : * \tds
290 : * \param[out] s output string
291 : * \param[in] len string length (in characters)
292 : * \return string or NULL on error
293 : */
294 : DSTR*
295 99621 : tds_dstr_get(TDSSOCKET * tds, DSTR * s, size_t len)
296 : {
297 : size_t out_len;
298 :
299 99621 : CHECK_TDS_EXTRA(tds);
300 :
301 : /* assure sufficient space for every conversion */
302 99621 : if (TDS_UNLIKELY(!tds_dstr_alloc(s, len * 4))) {
303 0 : tds_get_n(tds, NULL, len);
304 0 : return NULL;
305 : }
306 :
307 199242 : out_len = tds_get_string(tds, len, tds_dstr_buf(s), len * 4);
308 99621 : tds_dstr_setlen(s, out_len);
309 99621 : return s;
310 : }
311 :
312 : /** @} */
|