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 1298604 : tds_get_byte(TDSSOCKET * tds)
73 : {
74 2661293 : while (tds->in_pos >= tds->in_len) {
75 64131 : if (tds_read_packet(tds) < 0)
76 : return 0;
77 : }
78 1298558 : 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 50236 : tds_unget_byte(TDSSOCKET * tds)
90 : {
91 : /* this is a one trick pony...don't call it twice */
92 50236 : tds->in_pos--;
93 50236 : }
94 :
95 : /**
96 : * Reads a byte from the TDS stream without removing it
97 : * \tds
98 : */
99 : unsigned char
100 36542 : tds_peek(TDSSOCKET * tds)
101 : {
102 36542 : unsigned char result = tds_get_byte(tds);
103 36542 : if (tds->in_pos > 0)
104 36542 : --tds->in_pos;
105 36542 : return result;
106 : }
107 :
108 : /**
109 : * Get an uint16 from the server.
110 : */
111 : TDS_USMALLINT
112 802636 : tds_get_usmallint(TDSSOCKET * tds)
113 : {
114 : TDS_USMALLINT bytes;
115 :
116 802636 : tds_get_n(tds, &bytes, 2);
117 802636 : return (TDS_USMALLINT) TDS_GET_A2LE(&bytes);
118 : }
119 :
120 : /**
121 : * Get an uint32 from the server.
122 : * \tds
123 : */
124 : TDS_UINT
125 201698 : tds_get_uint(TDSSOCKET * tds)
126 : {
127 : TDS_UINT bytes;
128 :
129 201698 : tds_get_n(tds, &bytes, 4);
130 201698 : return TDS_GET_A4LE(&bytes);
131 : }
132 :
133 : /**
134 : * Get an uint64 from the server.
135 : * \tds
136 : */
137 : TDS_UINT8
138 33476 : tds_get_uint8(TDSSOCKET * tds)
139 : {
140 : TDS_UINT h;
141 : TDS_UINT l;
142 : TDS_UINT bytes[2];
143 :
144 33476 : tds_get_n(tds, bytes, 8);
145 33476 : l = TDS_GET_A4LE(bytes);
146 33476 : h = TDS_GET_A4LE(bytes+1);
147 33476 : 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 147598 : tds_get_string(TDSSOCKET * tds, size_t string_len, char *dest, size_t dest_size)
165 : {
166 147598 : size_t wire_bytes = string_len;
167 147598 : unsigned conv = client2server_chardata;
168 :
169 147598 : if (IS_TDS7_PLUS(tds->conn)) {
170 97165 : wire_bytes *= 2u;
171 97165 : conv = client2ucs2;
172 : }
173 :
174 147598 : if (dest == NULL) {
175 22 : tds_get_n(tds, NULL, wire_bytes);
176 22 : return string_len;
177 : }
178 :
179 147576 : 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 381965 : tds_get_char_data(TDSSOCKET * tds, char *row_buffer, size_t wire_size, TDSCOLUMN * curcol)
194 : {
195 : size_t in_left;
196 :
197 381965 : 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 381965 : if (wire_size == 0) {
206 66 : curcol->column_cur_size = 0;
207 66 : return TDS_SUCCESS;
208 : }
209 :
210 381899 : in_left = curcol->column_size;
211 381899 : curcol->column_cur_size = read_and_convert(tds, curcol->char_conv, &wire_size, row_buffer, in_left);
212 381899 : if (TDS_UNLIKELY(wire_size > 0)) {
213 0 : tds_get_n(tds, NULL, wire_size);
214 0 : tdsdump_log(TDS_DBG_NETWORK, "error: tds_get_char_data: discarded %u on wire while reading %d into client. \n",
215 : (unsigned int) wire_size, curcol->column_cur_size);
216 : return TDS_FAIL;
217 : }
218 : return TDS_SUCCESS;
219 : }
220 :
221 : /**
222 : * Get N bytes from the buffer and return them in the already allocated space
223 : * given to us. We ASSUME that the person calling this function has done the
224 : * bounds checking for us since they know how many bytes they want here.
225 : * dest of NULL means we just want to eat the bytes. (tetherow@nol.org)
226 : */
227 : bool
228 2488530 : tds_get_n(TDSSOCKET * tds, void *dest, size_t need)
229 : {
230 : for (;;) {
231 2494644 : unsigned int have = tds->in_len - tds->in_pos;
232 :
233 2494644 : if (need <= have)
234 : break;
235 : /* We need more than is in the buffer, copy what is there */
236 6114 : if (dest != NULL) {
237 6113 : memcpy((char *) dest, tds->in_buf + tds->in_pos, have);
238 6113 : dest = (char *) dest + have;
239 : }
240 6114 : need -= have;
241 6114 : if (TDS_UNLIKELY((tds->in_buf[1] & TDS_STATUS_EOM) != 0
242 : || tds_read_packet(tds) < 0)) {
243 0 : tds_close_socket(tds); /* evidently out of sync */
244 0 : return false;
245 : }
246 : }
247 2488530 : if (need > 0) {
248 : /* get the remainder if there is any */
249 2134302 : if (dest != NULL) {
250 2098300 : memcpy((char *) dest, tds->in_buf + tds->in_pos, need);
251 : }
252 2134302 : tds->in_pos += need;
253 : }
254 : return true;
255 : }
256 :
257 : /**
258 : * For UTF-8 and similar, tds_iconv() may encounter a partial sequence when the chunk boundary
259 : * is not aligned with the character boundary. In that event, it will return an error, and
260 : * some number of bytes (less than a character) will remain in the tail end of temp[]. They are
261 : * moved to the beginning, ptemp is adjusted to point just behind them, and the next chunk is read.
262 : * \tds
263 : * \param char_conv conversion structure
264 : * \param[out] wire_size size readed from wire
265 : * \param outbuf buffer to write to
266 : * \param outbytesleft buffer length
267 : * \return bytes readed
268 : */
269 : static size_t
270 529475 : read_and_convert(TDSSOCKET * tds, TDSICONV * char_conv, size_t * wire_size, char *outbuf,
271 : size_t outbytesleft)
272 : {
273 : int res;
274 : TDSDATAINSTREAM r;
275 : TDSSTATICOUTSTREAM w;
276 :
277 529475 : tds_datain_stream_init(&r, tds, *wire_size);
278 529475 : tds_staticout_stream_init(&w, outbuf, outbytesleft);
279 :
280 529475 : res = tds_convert_stream(tds, char_conv, to_client, &r.stream, &w.stream);
281 529475 : *wire_size = r.wire_size;
282 529475 : return (char *) w.stream.buffer - outbuf;
283 : }
284 :
285 : /**
286 : * Reads a string from wire and put in a DSTR.
287 : * On error we read the bytes from the wire anyway.
288 : * \tds
289 : * \param[out] s output string
290 : * \param[in] len string length (in characters)
291 : * \return string or NULL on error
292 : */
293 : DSTR*
294 84110 : tds_dstr_get(TDSSOCKET * tds, DSTR * s, size_t len)
295 : {
296 : size_t out_len;
297 :
298 84110 : CHECK_TDS_EXTRA(tds);
299 :
300 : /* assure sufficient space for every conversion */
301 84110 : if (TDS_UNLIKELY(!tds_dstr_alloc(s, len * 4))) {
302 0 : tds_get_n(tds, NULL, len);
303 0 : return NULL;
304 : }
305 :
306 168220 : out_len = tds_get_string(tds, len, tds_dstr_buf(s), len * 4);
307 84110 : tds_dstr_setlen(s, out_len);
308 84110 : return s;
309 : }
310 :
311 : /** @} */
|