00001 #ifndef WIN32
00002 #include <cstdlib>
00003 #include <cstring>
00004 #include <netdb.h>
00005 #include <signal.h>
00006 #include <unistd.h>
00007 #else
00008 #include <winsock2.h>
00009 #include <ws2tcpip.h>
00010 #include <wspiapi.h>
00011 #endif
00012 #include <algorithm>
00013 #include <iostream>
00014
00015 #include "udt.h"
00016
00017 using namespace std;
00018
00019
00020 const int g_IP_Version = AF_INET;
00021 const int g_Socket_Type = SOCK_STREAM;
00022 const char g_Localhost[] = "127.0.0.1";
00023 const int g_Server_Port = 9000;
00024
00025
00026 int createUDTSocket(UDTSOCKET& usock, int port = 0, bool rendezvous = false)
00027 {
00028 addrinfo hints;
00029 addrinfo* res;
00030 memset(&hints, 0, sizeof(struct addrinfo));
00031 hints.ai_flags = AI_PASSIVE;
00032 hints.ai_family = g_IP_Version;
00033 hints.ai_socktype = g_Socket_Type;
00034
00035 char service[16];
00036 sprintf(service, "%d", port);
00037
00038 if (0 != getaddrinfo(NULL, service, &hints, &res))
00039 {
00040 cout << "illegal port number or port is busy.\n" << endl;
00041 return -1;
00042 }
00043
00044 usock = UDT::socket(res->ai_family, res->ai_socktype, res->ai_protocol);
00045
00046
00047 int snd_buf = 16000;
00048 int rcv_buf = 16000;
00049 UDT::setsockopt(usock, 0, UDT_SNDBUF, &snd_buf, sizeof(int));
00050 UDT::setsockopt(usock, 0, UDT_RCVBUF, &rcv_buf, sizeof(int));
00051 snd_buf = 8192;
00052 rcv_buf = 8192;
00053 UDT::setsockopt(usock, 0, UDP_SNDBUF, &snd_buf, sizeof(int));
00054 UDT::setsockopt(usock, 0, UDP_RCVBUF, &rcv_buf, sizeof(int));
00055 int fc = 16;
00056 UDT::setsockopt(usock, 0, UDT_FC, &fc, sizeof(int));
00057 bool reuse = true;
00058 UDT::setsockopt(usock, 0, UDT_REUSEADDR, &reuse, sizeof(bool));
00059 UDT::setsockopt(usock, 0, UDT_RENDEZVOUS, &rendezvous, sizeof(bool));
00060
00061 if (UDT::ERROR == UDT::bind(usock, res->ai_addr, res->ai_addrlen))
00062 {
00063 cout << "bind: " << UDT::getlasterror().getErrorMessage() << endl;
00064 return -1;
00065 }
00066
00067 freeaddrinfo(res);
00068 return 0;
00069 }
00070
00071 int createTCPSocket(SYSSOCKET& ssock, int port = 0, bool rendezvous = false)
00072 {
00073 addrinfo hints;
00074 addrinfo* res;
00075 memset(&hints, 0, sizeof(struct addrinfo));
00076 hints.ai_flags = AI_PASSIVE;
00077 hints.ai_family = g_IP_Version;
00078 hints.ai_socktype = g_Socket_Type;
00079
00080 char service[16];
00081 sprintf(service, "%d", port);
00082
00083 if (0 != getaddrinfo(NULL, service, &hints, &res))
00084 {
00085 cout << "illegal port number or port is busy.\n" << endl;
00086 return -1;
00087 }
00088
00089 ssock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
00090 if (bind(ssock, res->ai_addr, res->ai_addrlen) != 0)
00091 {
00092 return -1;
00093 }
00094
00095 freeaddrinfo(res);
00096 return 0;
00097 }
00098
00099 int connect(UDTSOCKET& usock, int port)
00100 {
00101 addrinfo hints, *peer;
00102 memset(&hints, 0, sizeof(struct addrinfo));
00103 hints.ai_flags = AI_PASSIVE;
00104 hints.ai_family = g_IP_Version;
00105 hints.ai_socktype = g_Socket_Type;
00106
00107 char buffer[16];
00108 sprintf(buffer, "%d", port);
00109
00110 if (0 != getaddrinfo(g_Localhost, buffer, &hints, &peer))
00111 {
00112 return -1;
00113 }
00114
00115 UDT::connect(usock, peer->ai_addr, peer->ai_addrlen);
00116
00117 freeaddrinfo(peer);
00118 return 0;
00119 }
00120
00121 int tcp_connect(SYSSOCKET& ssock, int port)
00122 {
00123 addrinfo hints, *peer;
00124 memset(&hints, 0, sizeof(struct addrinfo));
00125 hints.ai_flags = AI_PASSIVE;
00126 hints.ai_family = g_IP_Version;
00127 hints.ai_socktype = g_Socket_Type;
00128
00129 char buffer[16];
00130 sprintf(buffer, "%d", port);
00131
00132 if (0 != getaddrinfo(g_Localhost, buffer, &hints, &peer))
00133 {
00134 return -1;
00135 }
00136
00137 connect(ssock, peer->ai_addr, peer->ai_addrlen);
00138
00139 freeaddrinfo(peer);
00140 return 0;
00141 }
00142
00143
00144
00145
00146 const int g_TotalNum = 10000;
00147
00148 #ifndef WIN32
00149 void* Test_1_Srv(void* param)
00150 #else
00151 DWORD WINAPI Test_1_Srv(LPVOID param)
00152 #endif
00153 {
00154 cout << "Testing simple data transfer.\n";
00155
00156 UDTSOCKET serv;
00157 if (createUDTSocket(serv, g_Server_Port) < 0)
00158 return NULL;
00159
00160 UDT::listen(serv, 1024);
00161 sockaddr_storage clientaddr;
00162 int addrlen = sizeof(clientaddr);
00163 UDTSOCKET new_sock = UDT::accept(serv, (sockaddr*)&clientaddr, &addrlen);
00164 UDT::close(serv);
00165
00166 if (new_sock == UDT::INVALID_SOCK)
00167 {
00168 return NULL;
00169 }
00170
00171 int32_t buffer[g_TotalNum];
00172 fill_n(buffer, 0, g_TotalNum);
00173
00174 int torecv = g_TotalNum * sizeof(int32_t);
00175 while (torecv > 0)
00176 {
00177 int rcvd = UDT::recv(new_sock, (char*)buffer + g_TotalNum * sizeof(int32_t) - torecv, torecv, 0);
00178 if (rcvd < 0)
00179 {
00180 cout << "recv: " << UDT::getlasterror().getErrorMessage() << endl;
00181 return NULL;
00182 }
00183 torecv -= rcvd;
00184 }
00185
00186
00187 for (int i = 0; i < g_TotalNum; ++ i)
00188 {
00189 if (buffer[i] != i)
00190 {
00191 cout << "DATA ERROR " << i << " " << buffer[i] << endl;
00192 break;
00193 }
00194 }
00195
00196 int eid = UDT::epoll_create();
00197 UDT::epoll_add_usock(eid, new_sock);
00198
00199
00200
00201
00202
00203
00204
00205
00206 UDTSOCKET readfds[1];
00207 int num = 1;
00208 if (UDT::epoll_wait2(eid, readfds, &num, NULL, NULL, -1) > 0)
00209 {
00210 UDT::close(new_sock);
00211 }
00212
00213 return NULL;
00214 }
00215
00216 #ifndef WIN32
00217 void* Test_1_Cli(void* param)
00218 #else
00219 DWORD WINAPI Test_1_Cli(LPVOID param)
00220 #endif
00221 {
00222 UDTSOCKET client;
00223 if (createUDTSocket(client, 0) < 0)
00224 return NULL;
00225
00226 connect(client, g_Server_Port);
00227
00228 int32_t buffer[g_TotalNum];
00229 for (int i = 0; i < g_TotalNum; ++ i)
00230 buffer[i] = i;
00231
00232 int tosend = g_TotalNum * sizeof(int32_t);
00233 while (tosend > 0)
00234 {
00235 int sent = UDT::send(client, (char*)buffer + g_TotalNum * sizeof(int32_t) - tosend, tosend, 0);
00236 if (sent < 0)
00237 {
00238 cout << "send: " << UDT::getlasterror().getErrorMessage() << endl;
00239 return NULL;
00240 }
00241 tosend -= sent;
00242 }
00243
00244 UDT::close(client);
00245 return NULL;
00246 }
00247
00248
00249
00250
00251 const int g_UDTNum = 200;
00252 const int g_IndUDTNum = 100;
00253 const int g_TCPNum = 10;
00254 int g_ActualUDTNum = 0;
00255
00256 #ifndef WIN32
00257 void* Test_2_Srv(void* param)
00258 #else
00259 DWORD WINAPI Test_2_Srv(LPVOID param)
00260 #endif
00261 {
00262 cout << "Test parallel UDT and TCP connections.\n";
00263
00264 #ifndef WIN32
00265
00266 sigset_t ps;
00267 sigemptyset(&ps);
00268 sigaddset(&ps, SIGPIPE);
00269 pthread_sigmask(SIG_BLOCK, &ps, NULL);
00270 #endif
00271
00272
00273 UDTSOCKET serv;
00274 if (createUDTSocket(serv, g_Server_Port) < 0)
00275 return NULL;
00276
00277 UDT::listen(serv, 1024);
00278
00279 vector<UDTSOCKET> new_socks;
00280 new_socks.resize(g_UDTNum);
00281
00282 int eid = UDT::epoll_create();
00283
00284 for (int i = 0; i < g_UDTNum; ++ i)
00285 {
00286 sockaddr_storage clientaddr;
00287 int addrlen = sizeof(clientaddr);
00288 new_socks[i] = UDT::accept(serv, (sockaddr*)&clientaddr, &addrlen);
00289
00290 if (new_socks[i] == UDT::INVALID_SOCK)
00291 {
00292 cout << "accept: " << UDT::getlasterror().getErrorMessage() << endl;
00293 return NULL;
00294 }
00295 UDT::epoll_add_usock(eid, new_socks[i]);
00296 }
00297
00298
00299
00300 SYSSOCKET tcp_serv;
00301 if (createTCPSocket(tcp_serv, g_Server_Port) < 0)
00302 return NULL;
00303
00304 listen(tcp_serv, 1024);
00305
00306 vector<SYSSOCKET> tcp_socks;
00307 tcp_socks.resize(g_TCPNum);
00308
00309 for (int i = 0; i < g_TCPNum; ++ i)
00310 {
00311 sockaddr_storage clientaddr;
00312 socklen_t addrlen = sizeof(clientaddr);
00313 tcp_socks[i] = accept(tcp_serv, (sockaddr*)&clientaddr, &addrlen);
00314 UDT::epoll_add_ssock(eid, tcp_socks[i]);
00315 }
00316
00317
00318
00319 set<UDTSOCKET> readfds;
00320 set<SYSSOCKET> tcpread;
00321 int count = g_UDTNum + g_TCPNum;
00322 while (count > 0)
00323 {
00324 UDT::epoll_wait(eid, &readfds, NULL, -1, &tcpread);
00325 for (set<UDTSOCKET>::iterator i = readfds.begin(); i != readfds.end(); ++ i)
00326 {
00327 int32_t data;
00328 UDT::recv(*i, (char*)&data, 4, 0);
00329 -- count;
00330 }
00331
00332 for (set<SYSSOCKET>::iterator i = tcpread.begin(); i != tcpread.end(); ++ i)
00333 {
00334 int32_t data;
00335 recv(*i, (char*)&data, 4, 0);
00336 -- count;
00337 }
00338 }
00339
00340 for (vector<UDTSOCKET>::iterator i = new_socks.begin(); i != new_socks.end(); ++ i)
00341 {
00342 UDT::close(*i);
00343 }
00344
00345 for (vector<SYSSOCKET>::iterator i = tcp_socks.begin(); i != tcp_socks.end(); ++ i)
00346 {
00347 #ifndef WIN32
00348 close(*i);
00349 #else
00350 closesocket(*i);
00351 #endif
00352 }
00353
00354 UDT::close(serv);
00355 #ifndef WIN32
00356 close(tcp_serv);
00357 #else
00358 closesocket(tcp_serv);
00359 #endif
00360
00361 return NULL;
00362 }
00363
00364 #ifndef WIN32
00365 void* Test_2_Cli(void* param)
00366 #else
00367 DWORD WINAPI Test_2_Cli(LPVOID param)
00368 #endif
00369 {
00370 #ifndef WIN32
00371
00372 sigset_t ps;
00373 sigemptyset(&ps);
00374 sigaddset(&ps, SIGPIPE);
00375 pthread_sigmask(SIG_BLOCK, &ps, NULL);
00376 #endif
00377
00378
00379 vector<UDTSOCKET> cli_socks;
00380 cli_socks.resize(g_UDTNum);
00381
00382
00383 for (int i = 0; i < g_IndUDTNum; ++ i)
00384 {
00385 if (createUDTSocket(cli_socks[i], 0) < 0)
00386 {
00387 cout << "socket: " << UDT::getlasterror().getErrorMessage() << endl;
00388 return NULL;
00389 }
00390 }
00391
00392
00393 if (createUDTSocket(cli_socks[g_IndUDTNum], 0) < 0)
00394 {
00395 cout << "socket: " << UDT::getlasterror().getErrorMessage() << endl;
00396 return NULL;
00397 }
00398
00399 sockaddr* addr = NULL;
00400 int size = 0;
00401 addr = (sockaddr*)new sockaddr_in;
00402 size = sizeof(sockaddr_in);
00403 UDT::getsockname(cli_socks[g_IndUDTNum], addr, &size);
00404 char sharedport[NI_MAXSERV];
00405 getnameinfo(addr, size, NULL, 0, sharedport, sizeof(sharedport), NI_NUMERICSERV);
00406
00407
00408 for (int i = g_IndUDTNum + 1; i < g_UDTNum; ++ i)
00409 {
00410 if (createUDTSocket(cli_socks[i], atoi(sharedport)) < 0)
00411 {
00412 cout << "socket: " << UDT::getlasterror().getErrorMessage() << endl;
00413 return NULL;
00414 }
00415 }
00416 for (vector<UDTSOCKET>::iterator i = cli_socks.begin(); i != cli_socks.end(); ++ i)
00417 {
00418 if (connect(*i, g_Server_Port) < 0)
00419 {
00420 cout << "connect: " << UDT::getlasterror().getErrorMessage() << endl;
00421 return NULL;
00422 }
00423 }
00424
00425
00426 vector<SYSSOCKET> tcp_socks;
00427 tcp_socks.resize(g_TCPNum);
00428 for (int i = 0; i < g_TCPNum; ++ i)
00429 {
00430 if (createTCPSocket(tcp_socks[i], 0) < 0)
00431 {
00432 return NULL;
00433 }
00434
00435 tcp_connect(tcp_socks[i], g_Server_Port);
00436 }
00437
00438
00439 int32_t data = 0;
00440 for (vector<UDTSOCKET>::iterator i = cli_socks.begin(); i != cli_socks.end(); ++ i)
00441 {
00442 UDT::send(*i, (char*)&data, 4, 0);
00443 ++ data;
00444 }
00445 for (vector<SYSSOCKET>::iterator i = tcp_socks.begin(); i != tcp_socks.end(); ++ i)
00446 {
00447 send(*i, (char*)&data, 4, 0);
00448 ++ data;
00449 }
00450
00451
00452 for (vector<UDTSOCKET>::iterator i = cli_socks.begin(); i != cli_socks.end(); ++ i)
00453 {
00454 UDT::close(*i);
00455 }
00456 for (vector<SYSSOCKET>::iterator i = tcp_socks.begin(); i != tcp_socks.end(); ++ i)
00457 {
00458 #ifndef WIN32
00459 close(*i);
00460 #else
00461 closesocket(*i);
00462 #endif
00463 }
00464
00465 return NULL;
00466 }
00467
00468
00469
00470
00471 const int g_UDTNum3 = 50;
00472
00473 #ifndef WIN32
00474 void* Test_3_Srv(void* param)
00475 #else
00476 DWORD WINAPI Test_3_Srv(LPVOID param)
00477 #endif
00478 {
00479 cout << "Test rendezvous connections.\n";
00480
00481 vector<UDTSOCKET> srv_socks;
00482 srv_socks.resize(g_UDTNum3);
00483
00484 int port = 61000;
00485
00486 for (int i = 0; i < g_UDTNum3; ++ i)
00487 {
00488 if (createUDTSocket(srv_socks[i], port ++, true) < 0)
00489 {
00490 cout << "error\n";
00491 }
00492 }
00493
00494 int peer_port = 51000;
00495
00496 for (vector<UDTSOCKET>::iterator i = srv_socks.begin(); i != srv_socks.end(); ++ i)
00497 {
00498 connect(*i, peer_port ++);
00499 }
00500
00501 for (vector<UDTSOCKET>::iterator i = srv_socks.begin(); i != srv_socks.end(); ++ i)
00502 {
00503 int32_t data = 0;
00504 UDT::recv(*i, (char*)&data, 4, 0);
00505 }
00506
00507 for (vector<UDTSOCKET>::iterator i = srv_socks.begin(); i != srv_socks.end(); ++ i)
00508 {
00509 UDT::close(*i);
00510 }
00511
00512 return NULL;
00513 }
00514
00515 #ifndef WIN32
00516 void* Test_3_Cli(void* param)
00517 #else
00518 DWORD WINAPI Test_3_Cli(LPVOID param)
00519 #endif
00520 {
00521 vector<UDTSOCKET> cli_socks;
00522 cli_socks.resize(g_UDTNum3);
00523
00524 int port = 51000;
00525
00526 for (int i = 0; i < g_UDTNum3; ++ i)
00527 {
00528 if (createUDTSocket(cli_socks[i], port ++, true) < 0)
00529 {
00530 cout << "error\n";
00531 }
00532 }
00533
00534 int peer_port = 61000;
00535
00536 for (vector<UDTSOCKET>::iterator i = cli_socks.begin(); i != cli_socks.end(); ++ i)
00537 {
00538 connect(*i, peer_port ++);
00539 }
00540
00541 int32_t data = 0;
00542 for (vector<UDTSOCKET>::iterator i = cli_socks.begin(); i != cli_socks.end(); ++ i)
00543 {
00544 UDT::send(*i, (char*)&data, 4, 0);
00545 ++ data;
00546 }
00547
00548 for (vector<UDTSOCKET>::iterator i = cli_socks.begin(); i != cli_socks.end(); ++ i)
00549 {
00550 UDT::close(*i);
00551 }
00552
00553 return NULL;
00554 }
00555
00556
00557
00558
00559 const int g_UDTNum4 = 1000;
00560 const int g_UDTThreads = 40;
00561 const int g_UDTPerThread = 25;
00562
00563 #ifndef WIN32
00564 void* Test_4_Srv(void* param)
00565 #else
00566 DWORD WINAPI Test_4_Srv(LPVOID param)
00567 #endif
00568 {
00569 cout << "Test UDT in multiple threads.\n";
00570
00571 UDTSOCKET serv;
00572 if (createUDTSocket(serv, g_Server_Port) < 0)
00573 return NULL;
00574
00575 UDT::listen(serv, 1024);
00576
00577 vector<UDTSOCKET> new_socks;
00578 new_socks.resize(g_UDTNum4);
00579
00580 for (int i = 0; i < g_UDTNum4; ++ i)
00581 {
00582 sockaddr_storage clientaddr;
00583 int addrlen = sizeof(clientaddr);
00584 new_socks[i] = UDT::accept(serv, (sockaddr*)&clientaddr, &addrlen);
00585
00586 if (new_socks[i] == UDT::INVALID_SOCK)
00587 {
00588 cout << "accept: " << UDT::getlasterror().getErrorMessage() << endl;
00589 return NULL;
00590 }
00591 }
00592
00593 for (vector<UDTSOCKET>::iterator i = new_socks.begin(); i != new_socks.end(); ++ i)
00594 {
00595 UDT::close(*i);
00596 }
00597
00598 UDT::close(serv);
00599
00600 return NULL;
00601
00602 }
00603
00604 #ifndef WIN32
00605 void* start_and_destroy_clients(void* param)
00606 #else
00607 DWORD WINAPI start_and_destroy_clients(LPVOID param)
00608 #endif
00609 {
00610 vector<UDTSOCKET> cli_socks;
00611 cli_socks.resize(g_UDTPerThread);
00612
00613 if (createUDTSocket(cli_socks[0], 0) < 0)
00614 {
00615 cout << "socket: " << UDT::getlasterror().getErrorMessage() << endl;
00616 return NULL;
00617 }
00618
00619 sockaddr* addr = NULL;
00620 int size = 0;
00621
00622 addr = (sockaddr*)new sockaddr_in;
00623 size = sizeof(sockaddr_in);
00624
00625 UDT::getsockname(cli_socks[0], addr, &size);
00626 char sharedport[NI_MAXSERV];
00627 getnameinfo(addr, size, NULL, 0, sharedport, sizeof(sharedport), NI_NUMERICSERV);
00628
00629 for (int i = 1; i < g_UDTPerThread; ++ i)
00630 {
00631 if (createUDTSocket(cli_socks[i], atoi(sharedport)) < 0)
00632 {
00633 cout << "socket: " << UDT::getlasterror().getErrorMessage() << endl;
00634 return NULL;
00635 }
00636 }
00637
00638 for (vector<UDTSOCKET>::iterator i = cli_socks.begin(); i != cli_socks.end(); ++ i)
00639 {
00640 if (connect(*i, g_Server_Port) < 0)
00641 {
00642 cout << "connect: " << UDT::getlasterror().getErrorMessage() << endl;
00643 return NULL;
00644 }
00645 }
00646
00647 for (vector<UDTSOCKET>::iterator i = cli_socks.begin(); i != cli_socks.end(); ++ i)
00648 {
00649 UDT::close(*i);
00650 }
00651
00652 return NULL;
00653 }
00654
00655 #ifndef WIN32
00656 void* Test_4_Cli(void*)
00657 #else
00658 DWORD WINAPI Test_4_Cli(LPVOID)
00659 #endif
00660 {
00661 #ifndef WIN32
00662 vector<pthread_t> cli_threads;
00663 cli_threads.resize(g_UDTThreads);
00664
00665 for (vector<pthread_t>::iterator i = cli_threads.begin(); i != cli_threads.end(); ++ i)
00666 {
00667 pthread_create(&(*i), NULL, start_and_destroy_clients, NULL);
00668 }
00669
00670 for (vector<pthread_t>::iterator i = cli_threads.begin(); i != cli_threads.end(); ++ i)
00671 {
00672 pthread_join(*i, NULL);
00673 }
00674 #else
00675 vector<HANDLE> cli_threads;
00676 cli_threads.resize(g_UDTThreads);
00677
00678 for (vector<HANDLE>::iterator i = cli_threads.begin(); i != cli_threads.end(); ++ i)
00679 {
00680 *i = CreateThread(NULL, 0, NULL, start_and_destroy_clients, 0, NULL);
00681 }
00682
00683 for (vector<HANDLE>::iterator i = cli_threads.begin(); i != cli_threads.end(); ++ i)
00684 {
00685 WaitForSingleObject(*i, INFINITE);
00686 }
00687 #endif
00688
00689 return NULL;
00690 }
00691
00692
00693 int main()
00694 {
00695 const int test_case = 4;
00696
00697 #ifndef WIN32
00698 void* (*Test_Srv[test_case])(void*);
00699 void* (*Test_Cli[test_case])(void*);
00700 #else
00701 DWORD (WINAPI *Test_Srv[test_case])(LPVOID);
00702 DWORD (WINAPI *Test_Cli[test_case])(LPVOID);
00703 #endif
00704
00705 Test_Srv[0] = Test_1_Srv;
00706 Test_Cli[0] = Test_1_Cli;
00707 Test_Srv[1] = Test_2_Srv;
00708 Test_Cli[1] = Test_2_Cli;
00709 Test_Srv[2] = Test_3_Srv;
00710 Test_Cli[2] = Test_3_Cli;
00711 Test_Srv[3] = Test_4_Srv;
00712 Test_Cli[3] = Test_4_Cli;
00713
00714 for (int i = 0; i < test_case; ++ i)
00715 {
00716 cout << "Start Test # " << i + 1 << endl;
00717 UDT::startup();
00718
00719 #ifndef WIN32
00720 pthread_t srv, cli;
00721 pthread_create(&srv, NULL, Test_Srv[i], NULL);
00722 pthread_create(&cli, NULL, Test_Cli[i], NULL);
00723 pthread_join(srv, NULL);
00724 pthread_join(cli, NULL);
00725 #else
00726 HANDLE srv, cli;
00727 srv = CreateThread(NULL, 0, Test_Srv[i], NULL, 0, NULL);
00728 cli = CreateThread(NULL, 0, Test_Cli[i], NULL, 0, NULL);
00729 WaitForSingleObject(srv, INFINITE);
00730 WaitForSingleObject(cli, INFINITE);
00731 #endif
00732
00733 UDT::cleanup();
00734 cout << "Test # " << i + 1 << " completed." << endl;
00735 }
00736
00737 return 0;
00738 }