tfpsock2.pp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. program udptest;
  2. {$mode objfpc}{$H+}
  3. uses
  4. {$IFDEF UNIX}
  5. cthreads,
  6. {$ENDIF}
  7. Classes, SysUtils, fpsockets, ctypes;
  8. const
  9. {$if defined(win32)}
  10. LibName = 'msvcrt';
  11. {$elseif defined(win64)}
  12. LibName = 'msvcrt';
  13. {$elseif defined(wince)}
  14. LibName = 'coredll';
  15. {$elseif defined(netware)}
  16. LibName = 'clib';
  17. {$elseif defined(netwlibc)}
  18. LibName = 'libc';
  19. {$elseif defined(macos)}
  20. LibName = 'StdCLib';
  21. {$elseif defined(beos)}
  22. LibName = 'root';
  23. {$else}
  24. LibName = 'c';
  25. {$endif}
  26. procedure CExit(status: cint); cdecl; external LibName name 'exit';
  27. const
  28. HelloStr = 'Hello Server';
  29. ReplyStr = 'Hello Client!';
  30. var ClientError, ServerError: String;
  31. procedure IPv4TestServer;
  32. var
  33. sock: TFPSocket;
  34. Received:TReceiveFromStringMessage;
  35. begin
  36. ServerError := '';
  37. try
  38. sock := UDPSocket(stIPv4);
  39. try
  40. Bind(sock, '0.0.0.0', 1337);
  41. Received := ReceiveStrFrom(sock);
  42. sleep(500);
  43. SendStrTo(sock, Received.FromAddr, Received.FromPort, ReplyStr);
  44. finally
  45. CloseSocket(sock);
  46. end;
  47. if Received.Data <> HelloStr then
  48. ServerError := 'Unexpected response: ' + Received.Data;
  49. except on E: Exception do
  50. ServerError := 'Exception: ' + E.Message;
  51. end;
  52. end;
  53. procedure IPv4TestClient;
  54. var
  55. sock: TFPSocket;
  56. Received: TReceiveFromStringMessage;
  57. begin
  58. ClientError := '';
  59. try
  60. sock := UDPSocket(stIPv4);
  61. try
  62. Sleep(50);
  63. SendStrTo(sock, '127.0.0.1', 1337, HelloStr);
  64. Sleep(50);
  65. Received := ReceiveStrFrom(sock, 16);
  66. finally
  67. CloseSocket(sock);
  68. end;
  69. if Received.Data <> ReplyStr then
  70. ClientError := 'Unexpected response: ' + Received.Data;
  71. except on E: Exception do
  72. ClientError := 'Exception: ' + E.Message;
  73. end;
  74. end;
  75. procedure IPv6TestServer;
  76. var
  77. sock: TFPSocket;
  78. Received:TReceiveFromStringMessage;
  79. begin
  80. ServerError := '';
  81. try
  82. sock := UDPSocket(stIPv6);
  83. try
  84. Bind(sock, '::0', 1337);
  85. Received := ReceiveStrFrom(sock);
  86. SendStrTo(sock, Received.FromAddr, Received.FromPort, ReplyStr);
  87. finally
  88. CloseSocket(sock);
  89. end;
  90. if Received.Data <> HelloStr then
  91. ServerError := 'Unexpected response: ' + Received.Data;
  92. except on E: Exception do
  93. ServerError := 'Exception: ' + E.Message;
  94. end;
  95. end;
  96. procedure IPv6TestClient;
  97. var
  98. sock: TFPSocket;
  99. Received: String;
  100. begin
  101. ClientError := '';
  102. try
  103. sock := UDPSocket(stIPv6);
  104. try
  105. Sleep(50);
  106. SendStrTo(sock, '::1', 1337, HelloStr);
  107. Sleep(50);
  108. Received := ReceiveStr(sock);
  109. if Received <> ReplyStr then
  110. ClientError := 'Unexpected response: ' + Received;
  111. finally
  112. CloseSocket(sock);
  113. end;
  114. except on E: Exception do
  115. ClientError := 'Exception: ' + E.Message;
  116. end;
  117. end;
  118. procedure DualStackTestServer;
  119. var
  120. sock: TFPSocket;
  121. Received:TReceiveFromStringMessage;
  122. begin
  123. ServerError := '';
  124. try
  125. sock := UDPSocket(stIPDualStack);
  126. try
  127. Bind(sock, '::0', 1337);
  128. Received := ReceiveStrFrom(sock);
  129. SendStrTo(sock, Received.FromAddr, Received.FromPort, ReplyStr);
  130. finally
  131. CloseSocket(sock);
  132. end;
  133. if not IsIPv4Mapped(Received.FromAddr) then
  134. ServerError := 'Expected IPv4 mapped Address, got ' + Received.FromAddr.Address;
  135. if Received.Data <> HelloStr then
  136. ServerError := 'Unexpected response: ' + Received.Data;
  137. except on E: Exception do
  138. ServerError := 'Exception: ' + E.Message;
  139. end;
  140. end;
  141. procedure DataAvailableTestClient;
  142. var
  143. sock: TFPSocket;
  144. begin
  145. ClientError := '';
  146. try
  147. sock := UDPSocket(stIPv4);
  148. try
  149. Sleep(50);
  150. SendStrTo(sock, '127.0.0.1', 1337, HelloStr);
  151. Sleep(600);
  152. if not DataAvailable(sock) then
  153. begin
  154. ClientError := 'Should have data from the server pending';
  155. Exit;
  156. end;
  157. if BytesAvailable(sock) <> Length(ReplyStr) then
  158. ClientError := 'Unexpected data length';
  159. finally
  160. CloseSocket(sock);
  161. end;
  162. except on E: Exception do
  163. ClientError := 'Exception: ' + E.Message;
  164. end;
  165. end;
  166. procedure ReceiveArrayTestServer;
  167. var
  168. sock: TFPSocket;
  169. Received: specialize TReceiveFromMessage<specialize TArray<Integer>>; // Hello Server = 12 chars = divisible by 4
  170. i:Integer;
  171. begin
  172. ServerError := '';
  173. try
  174. sock := UDPSocket(stIPv4);
  175. try
  176. Bind(sock, '0.0.0.0', 1337);
  177. Received := specialize ReceiveArrayFrom<Integer>(sock);
  178. SendStrTo(sock, Received.FromAddr, Received.FromPort, ReplyStr);
  179. finally
  180. CloseSocket(sock);
  181. end;
  182. if Length(Received.Data) * SizeOf(Integer) <> Length(HelloStr) then
  183. begin
  184. ServerError := 'Unexpected response length ' + Length(Received.Data).ToString;
  185. Exit;
  186. end;
  187. for i:=0 to Length(HelloStr) -1 do
  188. if PChar(@Received.Data[0])[i]<>HelloStr[i+1] then
  189. begin
  190. ServerError := 'Unexpected response Char ' + PChar(@Received.Data[0])[i] + '@' + i.ToString;;
  191. Exit;
  192. end;
  193. except on E: Exception do
  194. ServerError := 'Exception: ' + E.Message;
  195. end;
  196. end;
  197. procedure ReceiveArrayTestClient;
  198. var
  199. sock: TFPSocket;
  200. Received: specialize TReceiveFromMessage<specialize TArray<Char>>;
  201. i:Integer;
  202. begin
  203. ClientError := '';
  204. try
  205. sock := UDPSocket(stIPv4);
  206. try
  207. Sleep(50);
  208. SendStrTo(sock, '127.0.0.1', 1337, HelloStr);
  209. Sleep(50);
  210. Received := specialize ReceiveArrayFrom<Char>(sock);
  211. finally
  212. CloseSocket(sock);
  213. end;
  214. if Length(Received.Data) <> Length(ReplyStr) then
  215. begin
  216. ClientError := 'Unexpected response length ' + Length(Received.Data).ToString;
  217. Exit;
  218. end;
  219. for i:=0 to Length(Received.Data) -1 do
  220. if Received.Data[i]<>ReplyStr[i+1] then
  221. begin
  222. ClientError := 'Unexpected response Char ' + Received.Data[i] + '@' + i.ToString;
  223. Exit;
  224. end;
  225. except on E: Exception do
  226. ClientError := 'Exception: ' + E.Message;
  227. end;
  228. end;
  229. procedure ChunkTestServer;
  230. type
  231. TChunkString = String[16];
  232. var
  233. sock: TFPSocket;
  234. Received: specialize TReceiveFromMessage<TChunkString>;
  235. begin
  236. ServerError := '';
  237. try
  238. sock := UDPSocket(stIPv4);
  239. try
  240. Bind(sock, '0.0.0.0', 1337);
  241. Received := specialize ReceiveFrom<TChunkString>(sock);
  242. specialize SendTo<TChunkString>(sock, Received.FromAddr, Received.FromPort, ReplyStr);
  243. finally
  244. CloseSocket(sock);
  245. end;
  246. if Received.Data <> HelloStr then
  247. ServerError := 'Unexpected response: ' + Received.Data;
  248. except on E: Exception do
  249. ServerError := 'Exception: ' + E.Message;
  250. end;
  251. end;
  252. procedure ChunkTestClient;
  253. type
  254. TChunkString = String[16];
  255. var
  256. sock: TFPSocket;
  257. Received: TChunkString;
  258. begin
  259. ClientError := '';
  260. try
  261. sock := UDPSocket(stIPv4);
  262. try
  263. Sleep(50);
  264. specialize SendTo<TChunkString>(sock, '127.0.0.1', 1337, HelloStr);
  265. Sleep(50);
  266. Received := specialize ReceiveFrom<TChunkString>(sock).Data;
  267. finally
  268. CloseSocket(sock);
  269. end;
  270. if Received <> ReplyStr then
  271. ClientError := 'Unexpected response: ' + Received;
  272. except on E: Exception do
  273. ClientError := 'Exception: ' + E.Message;
  274. end;
  275. end;
  276. procedure UDPFragmentationTestServer;
  277. type
  278. TChunkString = String[16];
  279. var
  280. sock: TFPSocket;
  281. begin
  282. ServerError := '';
  283. try
  284. sock := UDPSocket(stIPv4);
  285. try
  286. Bind(sock, '0.0.0.0', 1337);
  287. try
  288. specialize ReceiveFrom<TChunkString>(sock);
  289. ServerError := 'Should have thrown fragmentation error';
  290. except on E: EFragmentedData do
  291. if Length(e.Fragment) <> SizeOf(TChunkString) div 2 then
  292. ServerError := 'Unexpected Fragment Size';
  293. on E: Exception do
  294. raise E;
  295. end;
  296. finally
  297. CloseSocket(sock);
  298. end;
  299. except on E: Exception do
  300. ServerError := 'Exception: ' + E.Message;
  301. end;
  302. end;
  303. procedure UDPFragmentationTestClient;
  304. type
  305. TChunkString = String[16];
  306. var
  307. sock: TFPSocket;
  308. toSend: TChunkString;
  309. begin
  310. ClientError := '';
  311. try
  312. sock := UDPSocket(stIPv4);
  313. try
  314. Sleep(50);
  315. toSend := HelloStr;
  316. // Send fragmented in two chunks -> UDP Fragmentation error
  317. SendTo(sock, '127.0.0.1', 1337, @toSend, SizeOf(toSend) div 2);
  318. Sleep(400);
  319. SendTo(sock, '127.0.0.1', 1337, PByte(@toSend) + SizeOf(toSend) div 2, SizeOf(toSend) - SizeOf(toSend) div 2);
  320. finally
  321. CloseSocket(sock);
  322. end;
  323. except on E: Exception do
  324. ClientError := 'Exception: ' + E.Message;
  325. end;
  326. end;
  327. procedure TestNonBlockingServer;
  328. var
  329. sock: TFPSocket;
  330. Received: TReceiveFromStringMessage;
  331. begin
  332. ServerError := '';
  333. try
  334. sock := UDPSocket(stIPv4);
  335. try
  336. SetNonBlocking(sock, True);
  337. Bind(sock, '0.0.0.0', 1337);
  338. while not ReceiveStrFromNonBlocking(sock).Unpack(Received) do
  339. Sleep(100);
  340. Sleep(500);
  341. SendStrTo(sock, Received.FromAddr, Received.FromPort, ReplyStr);
  342. finally
  343. CloseSocket(sock);
  344. end;
  345. if Received.Data <> HelloStr then
  346. ServerError := 'Unexpected response: ' + Received.Data;
  347. except on E: Exception do
  348. ServerError := 'Exception: ' + E.Message;
  349. end;
  350. end;
  351. procedure TestNonBlockingClient;
  352. var
  353. sock: TFPSocket;
  354. Received: specialize TReceiveFromMessage<specialize TArray<Char>>;
  355. i:Integer;
  356. begin
  357. ClientError := '';
  358. try
  359. sock := UDPSocket(stIPv4);
  360. try
  361. SetNonBlocking(sock, True);
  362. Sleep(200);
  363. SendStrTo(sock, '127.0.0.1', 1337, HelloStr);
  364. while not specialize ReceiveArrayFromNonBlocking<Char>(sock, 16).unpack(Received) do
  365. Sleep(100);
  366. finally
  367. CloseSocket(sock);
  368. end;
  369. for i:=0 to Length(Received.Data) -1 do
  370. if Received.Data[i]<>ReplyStr[i+1] then
  371. begin
  372. ClientError := 'Unexpected response Char ' + Received.Data[i] + '@' + i.ToString;;
  373. Exit;
  374. end;
  375. except on E: Exception do
  376. ClientError := 'Exception: ' + E.Message;
  377. end;
  378. end;
  379. procedure TestFragmentationServer;
  380. var
  381. sock: TFPSocket;
  382. begin
  383. ServerError := '';
  384. try
  385. sock := UDPSocket(stIPv4);
  386. try
  387. Bind(sock, '0.0.0.0', 1337);
  388. SetNonBlocking(sock, True);
  389. try
  390. while not specialize ReceiveFromNonBlocking<LongInt>(sock) do
  391. Sleep(50);
  392. ServerError := 'Should have thrown fragmentation exception';
  393. except on E: EFragmentedData do
  394. if Length(e.Fragment) <> SizeOf(Word) then
  395. ServerError := 'Unexpected Fragment Size';
  396. on E: Exception do
  397. raise E;
  398. end;
  399. finally
  400. CloseSocket(sock);
  401. end;
  402. except on E: Exception do
  403. ServerError := 'Exception: ' + E.Message;
  404. end;
  405. end;
  406. procedure TestFragmentationClient;
  407. var
  408. sock: TFPSocket;
  409. begin
  410. ClientError := '';
  411. try
  412. sock := UDPSocket(stIPv4);
  413. try
  414. Sleep(50);
  415. specialize SendTo<Word>(sock, '127.0.0.1', 1337, 42);
  416. finally
  417. CloseSocket(sock);
  418. end;
  419. except on E: Exception do
  420. ClientError := 'Exception: ' + E.Message;
  421. end;
  422. end;
  423. procedure TestFragmentedArrayServer;
  424. var
  425. sock: TFPSocket;
  426. begin
  427. ServerError := '';
  428. try
  429. sock := UDPSocket(stIPv4);
  430. try
  431. Bind(sock, '0.0.0.0', 1337);
  432. SetNonBlocking(sock, True);
  433. try
  434. while specialize ReceiveArray<LongInt>(sock) = nil do
  435. Sleep(50);
  436. ServerError := 'Should have thrown fragmentation exception';
  437. except on E: EFragmentedData do
  438. if Length(e.Fragment) <> SizeOf(LongInt) + SizeOf(Word) then
  439. ServerError := 'Unexpected Fragment Size';
  440. on E: Exception do
  441. raise E;
  442. end;
  443. finally
  444. CloseSocket(sock);
  445. end;
  446. except on E: Exception do
  447. ServerError := 'Exception: ' + E.Message;
  448. end;
  449. end;
  450. procedure TestFragmentedArrayClient;
  451. var
  452. sock: TFPSocket;
  453. begin
  454. ClientError := '';
  455. try
  456. sock := UDPSocket(stIPv4);
  457. try
  458. Sleep(100);
  459. specialize SendArrayTo<Word>(sock, '127.0.0.1', 1337, [42, 43, 44]);
  460. finally
  461. CloseSocket(sock);
  462. end;
  463. except on E: Exception do
  464. ClientError := 'Exception: ' + E.Message;
  465. end;
  466. end;
  467. type
  468. TTimeoutThread = class(TThread)
  469. protected
  470. procedure Execute;override;
  471. end;
  472. procedure TTimeoutThread.Execute;
  473. var
  474. i: Integer;
  475. begin
  476. for i:=1 to 100 do
  477. begin
  478. if Terminated then
  479. Exit;
  480. Sleep(100);
  481. end;
  482. if Terminated then
  483. Exit;
  484. WriteLn(' Timeout');
  485. // FPC Halt does not work with threads... so we just rawkill using libc
  486. cexit(1);
  487. end;
  488. procedure RunTest(const TestName: String; ASrv, ACli: TProcedure);
  489. var
  490. Timeout, SrvThread, CliThread: TThread;
  491. begin
  492. Write('Testing ', TestName, '...');
  493. SrvThread:=TThread.CreateAnonymousThread(ASrv);
  494. SrvThread.FreeOnTerminate := False;
  495. SrvThread.Start;
  496. CliThread:=TThread.CreateAnonymousThread(ACli);
  497. CliThread.FreeOnTerminate := False;
  498. CliThread.Start;
  499. Timeout:=TTimeoutThread.Create(false);
  500. SrvThread.WaitFor;
  501. if not ServerError.IsEmpty then
  502. begin
  503. WriteLn(LineEnding, ' Server Error: ', ServerError);
  504. Halt(1);
  505. end;
  506. CliThread.WaitFor;
  507. if not ClientError.IsEmpty then
  508. begin
  509. WriteLn(LineEnding, ' Client Error: ', ClientError);
  510. Halt(1);
  511. end;
  512. Timeout.Terminate;
  513. Timeout.Free;
  514. WriteLn(' Success!');
  515. CliThread.Free;
  516. SrvThread.Free;
  517. Sleep(500);
  518. end;
  519. begin
  520. RunTest('IPv4Test', @IPv4TestServer, @IPv4TestClient);
  521. RunTest('IPv6Test', @IPv6TestServer, @IPv6TestClient);
  522. RunTest('DualStackTest', @DualStackTestServer, @IPv4TestClient);
  523. RunTest('DataAvailableTest', @IPv4TestServer, @DataAvailableTestClient);
  524. RunTest('ReceiveArrayTest', @ReceiveArrayTestServer, @ReceiveArrayTestClient);
  525. RunTest('ChunkTest', @ChunkTestServer, @ChunkTestClient);
  526. RunTest('UDPFragmentationTest', @UDPFragmentationTestServer, @UDPFragmentationTestClient);
  527. RunTest('NonBlockingTest', @TestNonBlockingServer, @TestNonBlockingClient);
  528. RunTest('FragmentationTest', @TestFragmentationServer, @TestFragmentationClient);
  529. RunTest('FragmentedArrayTest', @TestFragmentedArrayServer, @TestFragmentedArrayClient);
  530. end.