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