Line data Source code
1 : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2 : * Copyright (C) 2014 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 : /*
21 : * This test test tds_convert_stream which is supposed to be the main
22 : * character conversion routine
23 : *
24 : * Check that error are reported to error handler if found and tds
25 : * is not NULL.
26 : *
27 : * Check that conversions works with NULL tds.
28 : *
29 : * Check all types of errors (EILSEQ, EINVAL, E2BIG).
30 : *
31 : * Check that error are capture in middle and on end of stream.
32 : */
33 :
34 : #include "common.h"
35 : #include <freetds/iconv.h>
36 : #include <freetds/stream.h>
37 :
38 : #if HAVE_UNISTD_H
39 : #undef getpid
40 : #include <unistd.h>
41 : #endif /* HAVE_UNISTD_H */
42 :
43 : #if HAVE_STDLIB_H
44 : #include <stdlib.h>
45 : #endif /* HAVE_STDLIB_H */
46 :
47 : #include <assert.h>
48 :
49 : /* test tds_bcp_fread */
50 :
51 : static char buf[4096+80];
52 : static char buf_out[4096+80];
53 :
54 : static int last_errno = 0;
55 :
56 : static TDSRET
57 70320 : convert(TDSSOCKET *tds, TDSICONV *conv, TDS_ICONV_DIRECTION direction,
58 : const char *from, size_t from_len, char *dest, size_t *dest_len)
59 : {
60 : /* copy to make valgrind test fail on memory problems */
61 70320 : char *in = tds_new(char, from_len);
62 70320 : char *out = tds_new(char, *dest_len);
63 : int res;
64 : TDSSTATICINSTREAM r;
65 : TDSSTATICOUTSTREAM w;
66 :
67 70320 : assert(in && out);
68 :
69 70320 : memcpy(in, from, from_len);
70 70320 : tds_staticin_stream_init(&r, in, from_len);
71 70320 : tds_staticout_stream_init(&w, out, *dest_len);
72 70320 : last_errno = 0;
73 70320 : res = tds_convert_stream(tds, conv, direction, &r.stream, &w.stream);
74 70320 : last_errno = errno;
75 70320 : memcpy(dest, out, *dest_len - w.stream.buf_len);
76 70320 : *dest_len = *dest_len - w.stream.buf_len;
77 :
78 70320 : free(in);
79 70320 : free(out);
80 70320 : return res;
81 : }
82 :
83 : enum Odd {
84 : ODD_NONE = 0,
85 : ODD_NORMAL,
86 : ODD_INVALID,
87 : ODD_INCOMPLETE,
88 : ODD_NUM_VALUES
89 : };
90 :
91 : static const char *odd_names[] = {
92 : "None", "Normal", "Invalid", "Incomplete"
93 : };
94 :
95 : static int
96 11840 : add_odd(char *buf, int *pos, enum Odd type)
97 : {
98 11840 : const unsigned char x = 0xa0;
99 :
100 11840 : switch (type) {
101 : case ODD_NONE:
102 : return 0;
103 :
104 3552 : case ODD_NORMAL:
105 3552 : buf[*pos] = 0xC0 + (x >> 6);
106 3552 : ++*pos;
107 3552 : buf[*pos] = 0x80 + (x & 0x3f);
108 3552 : ++*pos;
109 3552 : return 0;
110 :
111 3552 : case ODD_INVALID:
112 3552 : buf[*pos] = 0xff;
113 3552 : ++*pos;
114 3552 : return EILSEQ;
115 :
116 1184 : case ODD_INCOMPLETE:
117 1184 : buf[*pos] = 0xC2;
118 1184 : ++*pos;
119 1184 : return EINVAL;
120 :
121 : default:
122 0 : assert(0);
123 : }
124 : return 0;
125 : }
126 :
127 : static void
128 11792 : add_odd2(char *buf, int *pos, enum Odd type)
129 : {
130 11792 : const unsigned char x = 0xa0;
131 :
132 11792 : switch (type) {
133 : case ODD_NONE:
134 : return;
135 3520 : case ODD_NORMAL:
136 3520 : buf[*pos] = x;
137 3520 : ++*pos;
138 3520 : break;
139 : case ODD_INVALID:
140 : break;
141 : case ODD_INCOMPLETE:
142 : break;
143 : default:
144 0 : assert(0);
145 : }
146 : }
147 :
148 : static int captured_errno = 0;
149 :
150 : static int
151 31184 : err_handler(const TDSCONTEXT * tds_ctx, TDSSOCKET * tds, TDSMESSAGE * msg)
152 : {
153 31184 : int old_err = captured_errno;
154 31184 : if (msg->msgno == TDSEICONVAVAIL) {
155 592 : captured_errno = EINVAL;
156 30592 : } else if (strstr(msg->message, "could not be converted")) {
157 1768 : captured_errno = EILSEQ;
158 28824 : } else if (msg->msgno == TDSEICONVIU) {
159 28824 : captured_errno = E2BIG;
160 : } else {
161 0 : fprintf(stderr, "Unexpected error: %s\n", msg->message);
162 0 : exit(1);
163 : }
164 31184 : assert(old_err == 0 || old_err == captured_errno);
165 31184 : return TDS_INT_CANCEL;
166 : }
167 :
168 : static TDSICONV * conv = NULL;
169 : static int pos_type = 0;
170 :
171 : static void
172 192 : test(TDSSOCKET *tds, enum Odd odd_type)
173 : {
174 : int i, l;
175 :
176 192 : captured_errno = 0;
177 :
178 : /* do not complete incomplete */
179 192 : if (odd_type == ODD_INCOMPLETE && pos_type > 0)
180 32 : return;
181 :
182 160 : printf("test pos %d type %s\n", pos_type, odd_names[odd_type]);
183 :
184 12000 : for (i = 0; i < 4096+20; ++i) {
185 : size_t out_len;
186 : TDSRET res;
187 : int err;
188 :
189 11840 : if (i == 34)
190 160 : i = 4096-20;
191 :
192 11840 : l = i;
193 11840 : memset(buf, 'a', sizeof(buf));
194 11840 : switch (pos_type) {
195 4736 : case 0: /* end */
196 4736 : err = add_odd(buf, &l, odd_type);
197 4736 : break;
198 3552 : case 1: /* start */
199 3552 : l = 0;
200 3552 : err = add_odd(buf, &l, odd_type);
201 3552 : if (l > i) continue;
202 3504 : l = i;
203 3504 : break;
204 3552 : case 2: /* middle */
205 3552 : err = add_odd(buf, &l, odd_type);
206 3552 : l = 4096+30;
207 3552 : break;
208 0 : default:
209 0 : exit(1);
210 : return;
211 : }
212 :
213 : /* convert it */
214 11792 : out_len = sizeof(buf_out);
215 11792 : res = convert(tds, conv, to_server, buf, l, buf_out, &out_len);
216 11792 : printf("i %d res %d out_len %u errno %d captured_errno %d\n",
217 : i, (int) res, (unsigned int) out_len, last_errno, captured_errno);
218 :
219 : /* test */
220 11792 : l = i;
221 11792 : memset(buf, 'a', sizeof(buf));
222 11792 : switch (pos_type) {
223 4736 : case 0: /* end */
224 4736 : add_odd2(buf, &l, odd_type);
225 4736 : break;
226 3504 : case 1: /* start */
227 3504 : l = 0;
228 3504 : add_odd2(buf, &l, odd_type);
229 3504 : l = i;
230 3504 : if (odd_type == ODD_NORMAL) l = i-1;
231 3504 : if (odd_type == ODD_INVALID) l = 0;
232 : break;
233 3552 : case 2: /* middle */
234 3552 : add_odd2(buf, &l, odd_type);
235 3552 : l = 4096+30;
236 3552 : if (odd_type == ODD_NORMAL) --l;
237 3552 : if (odd_type == ODD_INVALID) l = i;
238 : break;
239 : }
240 :
241 :
242 11792 : if (err) {
243 4720 : assert(last_errno == err);
244 4720 : assert(TDS_FAILED(res));
245 4720 : assert(!tds || captured_errno == last_errno);
246 : } else {
247 7072 : assert(TDS_SUCCEED(res));
248 7072 : assert(captured_errno == 0);
249 : }
250 11792 : if (out_len != l) {
251 0 : fprintf(stderr, "out %u bytes expected %d\n",
252 : (unsigned int) out_len, l);
253 0 : exit(1);
254 : }
255 11792 : assert(memcmp(buf_out, buf, l) == 0);
256 : }
257 : }
258 :
259 : static void
260 16 : big_test(TDSSOCKET *tds)
261 : {
262 : int i, l;
263 16 : const int limit = 1025;
264 :
265 16 : captured_errno = 0;
266 :
267 16 : printf("E2BIG test\n");
268 :
269 58544 : for (i = 0; i < 4096+20; ++i) {
270 : size_t out_len;
271 : TDSRET res;
272 : int err;
273 :
274 58528 : if (i == 32)
275 16 : i = 490;
276 :
277 58528 : l = i;
278 58528 : memset(buf, 0xa0, sizeof(buf));
279 :
280 : /* convert it */
281 58528 : out_len = limit;
282 58528 : res = convert(tds, conv, to_client, buf, l, buf_out, &out_len);
283 58528 : printf("i %d res %d out_len %u errno %d captured_errno %d\n",
284 : i, (int) res, (unsigned int) out_len, last_errno, captured_errno);
285 59408 : err = l * 2 > limit ? E2BIG : 0;
286 :
287 : if (err) {
288 57648 : assert(last_errno == err);
289 57648 : assert(TDS_FAILED(res));
290 57648 : assert(!tds || captured_errno == last_errno);
291 : } else {
292 880 : assert(TDS_SUCCEED(res));
293 880 : assert(captured_errno == 0);
294 : }
295 58528 : if (out_len != i*2 && i*2 <= limit) {
296 0 : fprintf(stderr, "out %u bytes expected %d\n",
297 : (unsigned int) out_len, i*2);
298 0 : exit(1);
299 : }
300 : }
301 16 : }
302 :
303 :
304 : int
305 8 : main(int argc, char **argv)
306 : {
307 : int i;
308 8 : TDSCONTEXT *ctx = tds_alloc_context(NULL);
309 8 : TDSSOCKET *tds = tds_alloc_socket(ctx, 512);
310 : const char *tdsdump;
311 :
312 8 : setbuf(stdout, NULL);
313 8 : setbuf(stderr, NULL);
314 :
315 8 : ctx->err_handler = err_handler;
316 :
317 : /* allow dumps, we don't have a connection here */
318 8 : tdsdump = getenv("TDSDUMP");
319 8 : if (tdsdump)
320 0 : tdsdump_open(tdsdump);
321 :
322 8 : if (!ctx || !tds) {
323 0 : fprintf(stderr, "Error creating socket!\n");
324 0 : return 1;
325 : }
326 :
327 8 : tds_iconv_open(tds->conn, "ISO-8859-1", 0);
328 :
329 8 : conv = tds_iconv_get(tds->conn, "UTF-8", "ISO-8859-1");
330 8 : if (conv == NULL) {
331 0 : fprintf(stderr, "Error creating conversion, giving up!\n");
332 0 : return 1;
333 : }
334 :
335 192 : for (i = 0; i < ODD_NUM_VALUES*3*2; ++i) {
336 192 : int n = i;
337 192 : enum Odd odd_type = (enum Odd) (n % ODD_NUM_VALUES);
338 192 : n /= ODD_NUM_VALUES;
339 192 : pos_type = n % 3; n /= 3;
340 :
341 192 : test(n ? tds : NULL, odd_type);
342 : }
343 :
344 : /* not try E2BIG error */
345 8 : big_test(NULL);
346 8 : big_test(tds);
347 :
348 8 : tds_free_socket(tds);
349 8 : tds_free_context(ctx);
350 8 : return 0;
351 : }
|