Line data Source code
1 : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2 : * Copyright (C) 2020 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 : * Purpose: test freeze functionality
22 : */
23 : #include "common.h"
24 : #include <assert.h>
25 : #include <freetds/bytes.h>
26 :
27 : #if HAVE_UNISTD_H
28 : #undef getpid
29 : #include <unistd.h>
30 : #endif /* HAVE_UNISTD_H */
31 :
32 : #include <freetds/replacements.h>
33 : #include <freetds/utils.h>
34 :
35 : #ifdef _WIN32
36 : #define SHUT_WR SD_SEND
37 : #endif
38 :
39 : typedef struct {
40 : uint8_t *buf;
41 : size_t len;
42 : size_t capacity;
43 : } buffer;
44 :
45 : #define BUF_INITIALIZER { NULL, 0, 0 }
46 :
47 : static void
48 815 : buf_append(buffer *buf, const void *data, size_t data_len)
49 : {
50 815 : size_t min_size = buf->len + data_len;
51 815 : if (min_size > buf->capacity) {
52 658 : buf->capacity *= 2;
53 658 : if (buf->capacity < min_size)
54 382 : buf->capacity = min_size;
55 658 : assert(TDS_RESIZE(buf->buf, buf->capacity) != NULL);
56 : }
57 815 : memcpy(buf->buf + buf->len, data, data_len);
58 815 : buf->len += data_len;
59 815 : }
60 :
61 : static void
62 : buf_free(buffer *buf)
63 : {
64 270 : free(buf->buf);
65 270 : buf->buf = NULL;
66 270 : buf->len = buf->capacity = 0;
67 : }
68 :
69 : static TDSSOCKET *tds = NULL;
70 : static buffer thread_buf = BUF_INITIALIZER;
71 : static TDS_SYS_SOCKET server_socket = INVALID_SOCKET;
72 : static bool was_shutdown = false;
73 :
74 : static void shutdown_server_socket(void);
75 :
76 : #define BLOCK_SIZE (tds->conn->env.block_size)
77 :
78 : /* thread to read data from main thread */
79 135 : static TDS_THREAD_PROC_DECLARE(fake_thread_proc, arg)
80 : {
81 135 : TDS_SYS_SOCKET s = TDS_PTR2INT(arg);
82 : #if ENABLE_ODBC_MARS
83 90 : unsigned seq = 0;
84 90 : unsigned total_len = 0;
85 : TDS72_SMP_HEADER mars;
86 : #endif
87 :
88 215 : for (;;) {
89 : char buf[4096];
90 350 : int len = READSOCKET(s, buf, sizeof(buf));
91 350 : if (len <= 0)
92 : break;
93 215 : buf_append(&thread_buf, buf, len);
94 215 : tdsdump_dump_buf(TDS_DBG_INFO1, "received", buf, len);
95 : #if ENABLE_ODBC_MARS
96 146 : total_len += len;
97 387 : while (tds->conn->mars && total_len >= BLOCK_SIZE + sizeof(mars)) {
98 95 : mars.signature = TDS72_SMP;
99 95 : mars.type = TDS_SMP_ACK;
100 95 : mars.sid = 0;
101 95 : TDS_PUT_A4LE(&mars.size, 16);
102 95 : TDS_PUT_A4LE(&mars.seq, 4);
103 95 : TDS_PUT_A4LE(&mars.wnd, 4 + seq);
104 95 : WRITESOCKET(s, &mars, sizeof(mars));
105 95 : total_len -= BLOCK_SIZE + sizeof(mars);
106 95 : seq++;
107 : }
108 : #endif
109 : }
110 :
111 : /* close socket to cleanup and signal main thread */
112 135 : CLOSESOCKET(s);
113 135 : return TDS_THREAD_RESULT(0);
114 : }
115 :
116 : /* remove all headers (TDS and MARS) and do some checks on them */
117 : static void
118 135 : strip_headers(buffer *buf)
119 : {
120 135 : uint8_t final = 0;
121 135 : uint8_t *p = buf->buf;
122 135 : uint8_t *dst = p;
123 135 : uint8_t *end = buf->buf + buf->len;
124 525 : while (p < end) {
125 : size_t len;
126 :
127 390 : assert(final == 0);
128 390 : if (p[0] == TDS72_SMP) {
129 130 : assert(end - p >= 8); /* to read SMP part */
130 130 : len = TDS_GET_UA4LE(p+4);
131 130 : assert(len >= 16);
132 130 : assert(p + len <= end);
133 130 : p += 16;
134 130 : len -= 16;
135 130 : assert(end - p >= 4); /* to read TDS header part */
136 130 : assert(len == TDS_GET_UA2BE(p+2));
137 : } else {
138 260 : assert(end - p >= 4); /* to read TDS header part */
139 260 : len = TDS_GET_UA2BE(p+2);
140 : }
141 390 : assert(len > 8);
142 390 : assert(p + len <= end);
143 390 : final = p[1];
144 390 : memmove(dst, p + 8, len - 8);
145 390 : dst += len - 8;
146 390 : p += len;
147 : }
148 135 : assert(final == 1 || was_shutdown);
149 135 : buf->len = dst - buf->buf;
150 135 : }
151 :
152 : static buffer buf = BUF_INITIALIZER;
153 :
154 : /* Append some data to buffer and TDS.
155 : * If data is NULL append some random data */
156 : static void
157 375 : append(const void *data, size_t size)
158 : {
159 : uint8_t rand_buf[2048];
160 375 : if (!data) {
161 : size_t n;
162 285 : assert(size <= sizeof(rand_buf));
163 196635 : for (n = 0; n < size; ++n)
164 196635 : rand_buf[n] = rand();
165 : data = rand_buf;
166 : }
167 375 : tds_put_n(tds, data, size);
168 375 : buf_append(&buf, data, size);
169 375 : }
170 :
171 : /* Append a number for buffer only */
172 : static void
173 225 : append_num(uint64_t num, unsigned size)
174 : {
175 : uint8_t num_buf[8];
176 : unsigned n;
177 :
178 225 : assert(size == 1 || size == 2 || size == 4 || size == 8);
179 675 : for (n = 0; n < size; ++n) {
180 675 : num_buf[n] = num & 0xff;
181 675 : num >>= 8;
182 : }
183 225 : assert(num == 0);
184 225 : buf_append(&buf, num_buf, size);
185 225 : }
186 :
187 : /* base tests
188 : * - lengths;
189 : * - nested freeze;
190 : * - some packet wrapping case;
191 : */
192 : static void
193 15 : test1(void)
194 : {
195 : TDSFREEZE outer, inner;
196 : size_t written;
197 : unsigned left;
198 :
199 : /* just to not start at 0 */
200 15 : append("test", 4);
201 :
202 : /* test writing data as UTF16 */
203 15 : tds_freeze(tds, &outer, 2);
204 15 : append_num(3, 2);
205 15 : append("a\0b\0c", 6);
206 15 : assert(tds_freeze_written(&outer) == 8);
207 15 : written = tds_freeze_written(&outer) / 2 - 1;
208 15 : tds_freeze_close_len(&outer, written);
209 :
210 : /* nested freeze */
211 15 : tds_freeze(tds, &outer, 0);
212 15 : assert(tds_freeze_written(&outer) == 0);
213 15 : append("test", 4);
214 15 : tds_freeze(tds, &inner, 0);
215 15 : assert(tds_freeze_written(&outer) == 4);
216 15 : assert(tds_freeze_written(&inner) == 0);
217 15 : tds_put_smallint(tds, 1234);
218 15 : append_num(1234, 2);
219 15 : append("test", 4);
220 15 : assert(tds_freeze_written(&outer) == 10);
221 15 : assert(tds_freeze_written(&inner) == 6);
222 15 : append(NULL, 600 - 5);
223 15 : append("hello", 5);
224 15 : tdsdump_log(TDS_DBG_INFO2, "%u\n", (unsigned) tds_freeze_written(&outer));
225 15 : assert(tds_freeze_written(&outer) == 610);
226 15 : assert(tds_freeze_written(&inner) == 606);
227 :
228 : /* check values do not change before and after close */
229 15 : tds_freeze_close(&inner);
230 15 : assert(tds_freeze_written(&outer) == 610);
231 :
232 : /* test wrapping packets */
233 15 : append(NULL, 600 - 5);
234 15 : append("hello", 5);
235 15 : tdsdump_log(TDS_DBG_INFO2, "%u\n", (unsigned) tds_freeze_written(&outer));
236 15 : assert(tds_freeze_written(&outer) == 610 + 600);
237 :
238 : /* append data in the additional part to check it */
239 15 : left = tds->out_buf_max - tds->out_pos;
240 15 : append(NULL, left - 3);
241 15 : tds_put_int(tds, 0x12345678);
242 15 : assert(tds->out_pos > tds->out_buf_max);
243 15 : append_num(0x12345678, 4);
244 :
245 15 : tds_freeze_close(&outer);
246 15 : }
247 :
248 : static void
249 15 : test_len1(void)
250 : {
251 : TDSFREEZE outer;
252 :
253 : /* simple len, small */
254 15 : tds_freeze(tds, &outer, 4);
255 15 : append_num(10, 4);
256 15 : append(NULL, 10);
257 15 : tds_freeze_close(&outer);
258 :
259 : /* simple len, large */
260 15 : tds_freeze(tds, &outer, 2);
261 15 : append_num(1234, 2);
262 15 : append(NULL, 1234);
263 15 : tds_freeze_close(&outer);
264 :
265 : /* simple len, large */
266 15 : tds_freeze(tds, &outer, 4);
267 15 : append_num(1045, 4);
268 15 : append(NULL, 1045);
269 15 : tds_freeze_close(&outer);
270 15 : }
271 :
272 : /* similar to test_len1 with other APIs */
273 : static void
274 15 : test_len2(void)
275 : {
276 15 : TDS_START_LEN_UINT(tds) {
277 15 : append_num(4 + 10 + 2 + 1234 + 4 + 1045, 4);
278 :
279 : /* simple len, small */
280 15 : TDS_START_LEN_UINT(tds) {
281 15 : append_num(10, 4);
282 15 : append(NULL, 10);
283 15 : } TDS_END_LEN
284 :
285 : /* simple len, large */
286 15 : TDS_START_LEN_USMALLINT(tds) {
287 15 : append_num(1234, 2);
288 15 : append(NULL, 1234);
289 15 : } TDS_END_LEN
290 :
291 : /* simple len, large */
292 15 : TDS_START_LEN_UINT(tds) {
293 15 : append_num(1045, 4);
294 15 : append(NULL, 1045);
295 15 : } TDS_END_LEN
296 15 : } TDS_END_LEN
297 15 : }
298 :
299 : /* check if sending packet is failing */
300 : static void
301 30 : test_failure(size_t len)
302 : {
303 : TDSFREEZE outer;
304 : size_t old_len;
305 :
306 30 : append(NULL, 123);
307 30 : tds_freeze(tds, &outer, 2);
308 30 : old_len = buf.len;
309 30 : if (len)
310 15 : append(NULL, len);
311 30 : tds_freeze_abort(&outer);
312 30 : memset(buf.buf + old_len, 0xab, buf.capacity - old_len);
313 30 : buf.len = old_len;
314 30 : }
315 :
316 : static void
317 15 : test_failure1(void)
318 : {
319 15 : test_failure(0);
320 15 : }
321 :
322 : static void
323 15 : test_failure2(void)
324 : {
325 15 : test_failure(BLOCK_SIZE * 3 + 56);
326 15 : }
327 :
328 : /* test if server close connection */
329 : static void
330 15 : test_shutdown(void)
331 : {
332 : TDSFREEZE outer;
333 :
334 15 : append(NULL, BLOCK_SIZE + 17);
335 15 : tds_freeze(tds, &outer, 4);
336 15 : append(NULL, BLOCK_SIZE * 2 + 67);
337 15 : shutdown_server_socket();
338 15 : was_shutdown = true;
339 15 : tds_freeze_close(&outer);
340 15 : buf.len = BLOCK_SIZE - 8;
341 15 : }
342 :
343 : /* test freeze cross packet boundary */
344 : static void
345 30 : test_cross(unsigned num_bytes)
346 : {
347 : TDSFREEZE outer;
348 : unsigned left;
349 :
350 30 : left = tds->out_buf_max - tds->out_pos;
351 30 : append(NULL, left - num_bytes);
352 30 : append_num(1234, 4);
353 30 : tds_put_int(tds, 1234);
354 30 : tds_freeze(tds, &outer, 2);
355 30 : append_num(1045, 2);
356 30 : append(NULL, 1045);
357 30 : tds_freeze_close(&outer);
358 30 : }
359 :
360 : /* this will make the first packet a bit bigger than final */
361 : static void
362 15 : test_cross1(void)
363 : {
364 15 : test_cross(1);
365 15 : }
366 :
367 : /* this will make the first packet exact as big as final */
368 : static void
369 15 : test_cross2(void)
370 : {
371 15 : test_cross(4);
372 15 : }
373 :
374 : /* test freeze just when another packet is finished,
375 : * we should not generate an empty final one */
376 : static void
377 15 : test_end(void)
378 : {
379 : TDSFREEZE outer, inner;
380 : unsigned left;
381 :
382 15 : left = tds->out_buf_max - tds->out_pos;
383 15 : append(NULL, left - 1);
384 15 : tds_freeze(tds, &outer, 0);
385 15 : append_num(123, 1);
386 15 : tds_put_byte(tds, 123);
387 15 : tds_freeze(tds, &inner, 0);
388 15 : tds_freeze_close(&inner);
389 15 : tds_freeze_close(&outer);
390 15 : }
391 :
392 : /* close the socket, force thread to stop also */
393 : static void
394 150 : shutdown_server_socket(void)
395 : {
396 : char sock_buf[32];
397 :
398 150 : shutdown(server_socket, SHUT_WR);
399 359 : while (READSOCKET(server_socket, sock_buf, sizeof(sock_buf)) > 0)
400 59 : continue;
401 150 : }
402 :
403 : static void
404 180 : test(int mars, void (*real_test)(void))
405 : {
406 : TDSCONTEXT *ctx;
407 : TDS_SYS_SOCKET sockets[2];
408 : tds_thread fake_thread;
409 :
410 : #if !ENABLE_ODBC_MARS
411 90 : if (mars)
412 45 : return;
413 : #endif
414 :
415 135 : ctx = tds_alloc_context(NULL);
416 135 : assert(ctx);
417 135 : tds = tds_alloc_socket(ctx, 512);
418 135 : assert(tds);
419 :
420 : /* provide connection to a fake remove server */
421 135 : assert(socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) >= 0);
422 135 : tds_socket_set_nosigpipe(sockets[0], 1);
423 135 : was_shutdown = false;
424 135 : tds->state = TDS_IDLE;
425 135 : tds_set_s(tds, sockets[0]);
426 :
427 270 : if (tds_thread_create(&fake_thread, fake_thread_proc, TDS_INT2PTR(sockets[1])) != 0) {
428 0 : perror("tds_thread_create");
429 0 : exit(1);
430 : }
431 135 : server_socket = sockets[0];
432 :
433 : #if ENABLE_ODBC_MARS
434 90 : if (mars) {
435 45 : tds->conn->mars = 1;
436 45 : assert(tds_realloc_socket(tds, tds->out_buf_max));
437 45 : tds_init_write_buf(tds);
438 : }
439 : #endif
440 :
441 135 : real_test();
442 :
443 135 : tds_flush_packet(tds);
444 :
445 : /* flush all data and wait for other thread to finish cleanly */
446 135 : shutdown_server_socket();
447 270 : tds_thread_join(fake_thread, NULL);
448 :
449 135 : tdsdump_dump_buf(TDS_DBG_INFO1, "sent buffer", buf.buf, buf.len);
450 :
451 135 : strip_headers(&thread_buf);
452 135 : tdsdump_dump_buf(TDS_DBG_INFO1, "thread buffer", thread_buf.buf, thread_buf.len);
453 135 : assert(buf.len == thread_buf.len);
454 135 : assert(memcmp(buf.buf, thread_buf.buf, buf.len) == 0);
455 :
456 135 : tds_free_socket(tds);
457 135 : tds = NULL;
458 135 : tds_free_context(ctx);
459 :
460 135 : buf_free(&buf);
461 135 : buf_free(&thread_buf);
462 90 : }
463 :
464 : int
465 10 : main(void)
466 : {
467 : int mars;
468 :
469 10 : setbuf(stdout, NULL);
470 10 : setbuf(stderr, NULL);
471 :
472 10 : tdsdump_open(tds_dir_getenv(TDS_DIR("TDSDUMP")));
473 :
474 30 : for (mars = 0; mars < 2; ++mars) {
475 20 : test(mars, test1);
476 20 : test(mars, test_len1);
477 20 : test(mars, test_len2);
478 20 : test(mars, test_failure1);
479 20 : test(mars, test_failure2);
480 20 : test(mars, test_shutdown);
481 20 : test(mars, test_cross1);
482 20 : test(mars, test_cross2);
483 20 : test(mars, test_end);
484 : }
485 :
486 : return 0;
487 : }
|