/sourcecommon/udp.cpp

https://github.com/MaxBelkov/visualsyslog · C++ · 633 lines · 541 code · 38 blank · 54 comment · 98 complexity · bc6c041133913c4fa94ca8dc2b994973 MD5 · raw file

  1. #include <vcl.h>
  2. #pragma hdrstop
  3. #include "udp.h"
  4. //---------------------------------------------------------------------------
  5. TUDP::TUDP(bool enableExceptions, bool _bBlockProtected)
  6. : handle( NULL ),
  7. Connected( false ),
  8. Error( 0 ),
  9. WSAError( 0 ),
  10. Exceptions( enableExceptions ),
  11. bBlockProtected( _bBlockProtected )
  12. {
  13. InBytes = OutBytes = bytes = FlushSize = 0;
  14. memset(&destAddr, 0, sizeof(destAddr));
  15. destAddr.sin_family = AF_INET;
  16. memset(&localAddr, 0, sizeof(localAddr));
  17. localAddr.sin_family = AF_INET;
  18. WSADATA WsaData;
  19. WORD wVersionRequested = MAKEWORD(2, 0);
  20. WSAError = WSAStartup(wVersionRequested, &WsaData);
  21. if( WSAError )
  22. {
  23. Error = 1;
  24. if( Exceptions ) throw 0;
  25. }
  26. }
  27. //---------------------------------------------------------------------------
  28. TUDP::TUDP(char * dest, WORD port, bool enableExceptions, bool _bBlockProtected)
  29. : handle( NULL ),
  30. Connected( false ),
  31. Error( 0 ),
  32. WSAError( 0 ),
  33. Exceptions( enableExceptions ),
  34. bBlockProtected( _bBlockProtected )
  35. {
  36. InBytes = OutBytes = bytes = FlushSize = 0;
  37. memset(&destAddr, 0, sizeof(destAddr));
  38. destAddr.sin_family = AF_INET;
  39. memset(&localAddr, 0, sizeof(localAddr));
  40. localAddr.sin_family = AF_INET;
  41. WSADATA WsaData;
  42. WSAError = WSAStartup(0x0101, &WsaData); // MAKEWORD(2,0)
  43. if( WSAError )
  44. {
  45. Error = 1;
  46. if( Exceptions ) throw 0;
  47. }
  48. Open("", 0, dest, port);
  49. }
  50. //---------------------------------------------------------------------------
  51. TUDP::~TUDP()
  52. {
  53. Close();
  54. WSACleanup();
  55. }
  56. //---------------------------------------------------------------------------
  57. bool TUDP::Open(char * local, WORD lport, char * dest, WORD dport)
  58. {
  59. Error = 0;
  60. WSAError = 0;
  61. if( handle || !local || !dest )
  62. {
  63. WSAError = MYERROR_UNKNOWNPARAMS;
  64. Error = 1;
  65. if( Exceptions ) throw 0;
  66. return !Error;
  67. }
  68. in_addr l;
  69. l.S_un.S_addr = inet_addr(local);
  70. if( l.S_un.S_addr==4294967295 ) // host name OR error in IP address
  71. {
  72. // try to resolve host name and copy to l
  73. HOSTENT * hostent = gethostbyname(local);
  74. if( hostent )
  75. {
  76. // hostent->h_name ---> Full local name
  77. l.S_un = ((in_addr *)hostent->h_addr_list[0])->S_un;
  78. }
  79. else
  80. {
  81. //l.S_un.S_addr = INADDR_ANY; // Ëîêàëüíûé àäðåñ ìîæåò áûòü íóëåâûì
  82. WSAError = WSAGetLastError();
  83. Error = 2;
  84. if( Exceptions ) throw 0;
  85. return !Error;
  86. }
  87. }
  88. in_addr d;
  89. d.S_un.S_addr = inet_addr(dest);
  90. if( d.S_un.S_addr==4294967295 ) // host name OR error in IP address
  91. {
  92. // try to resolve host name and copy to d
  93. HOSTENT * hostent = gethostbyname(dest);
  94. if( hostent )
  95. {
  96. // hostent->h_name ---> Full dest name
  97. d.S_un = ((in_addr *)hostent->h_addr_list[0])->S_un;
  98. }
  99. else
  100. {
  101. //d.S_un.S_addr = INADDR_ANY; // Óäàëåííûé àäðåñ ìîæåò áûòü íóëåâûì
  102. WSAError = WSAGetLastError();
  103. Error = 3;
  104. if( Exceptions ) throw 0;
  105. return !Error;
  106. }
  107. }
  108. SOCKET h;
  109. // open a TCP socket
  110. h = socket(AF_INET, SOCK_DGRAM, 0);
  111. if( h==INVALID_SOCKET )
  112. {
  113. WSAError = WSAGetLastError();
  114. Error = 4;
  115. if( Exceptions ) throw 0;
  116. return !Error;
  117. }
  118. // Bind our server to the agreed upon port number. See commdef.h for the actual port number
  119. memset(&localAddr, 0, sizeof(localAddr));
  120. localAddr.sin_family = AF_INET;
  121. localAddr.sin_port = htons(lport);
  122. localAddr.sin_addr = l;
  123. if( bind(h, (struct sockaddr *)&localAddr, sizeof(localAddr)) )
  124. {
  125. WSAError = WSAGetLastError();
  126. Error = 6;
  127. closesocket(h);
  128. if( Exceptions ) throw 0;
  129. return !Error;
  130. }
  131. memset(&destAddr, 0, sizeof(destAddr));
  132. destAddr.sin_family = AF_INET;
  133. destAddr.sin_port = htons(dport);
  134. destAddr.sin_addr = d;
  135. if( dport > 0 )
  136. {
  137. if( connect(h, (sockaddr *)&destAddr, sizeof(destAddr)) )
  138. {
  139. WSAError = WSAGetLastError();
  140. Error = 7;
  141. closesocket(h);
  142. if( Exceptions ) throw 0;
  143. return !Error;
  144. }
  145. }
  146. // Ïîëó÷èì ëîêàëüíûé àäðåñ è ïîðò, ê êîòîðîìó ìû ïðèáèíäèëèñü
  147. int addr_len = sizeof(localAddr);
  148. if( getsockname(h, (struct sockaddr *)&localAddr, &addr_len) )
  149. {
  150. WSAError = WSAGetLastError();
  151. Error = 8;
  152. closesocket(h);
  153. if( Exceptions ) throw 0;
  154. return !Error;
  155. }
  156. handle = h;
  157. Connected = true;
  158. return ! Error;
  159. }
  160. //---------------------------------------------------------------------------
  161. bool TUDP::SimpleOpen(char * local, WORD lport, char * dest, WORD dport)
  162. {
  163. Error = 0;
  164. WSAError = 0;
  165. if( handle || !local || !dest )
  166. {
  167. WSAError = MYERROR_UNKNOWNPARAMS;
  168. Error = 1;
  169. if( Exceptions ) throw 0;
  170. return !Error;
  171. }
  172. in_addr l;
  173. l.S_un.S_addr = inet_addr(local);
  174. if( l.S_un.S_addr==4294967295 ) // host name OR error in IP address
  175. {
  176. // try to resolve host name and copy to l
  177. HOSTENT * hostent = gethostbyname(local);
  178. if( hostent )
  179. {
  180. // hostent->h_name ---> Full local name
  181. l.S_un = ((in_addr *)hostent->h_addr_list[0])->S_un;
  182. }
  183. else
  184. {
  185. //l.S_un.S_addr = INADDR_ANY; // Ëîêàëüíûé àäðåñ ìîæåò áûòü íóëåâûì
  186. WSAError = WSAGetLastError();
  187. Error = 2;
  188. if( Exceptions ) throw 0;
  189. return !Error;
  190. }
  191. }
  192. in_addr d;
  193. d.S_un.S_addr = inet_addr(dest);
  194. if( d.S_un.S_addr==4294967295 ) // host name OR error in IP address
  195. {
  196. // try to resolve host name and copy to d
  197. HOSTENT * hostent = gethostbyname(dest);
  198. if( hostent )
  199. {
  200. // hostent->h_name ---> Full dest name
  201. d.S_un = ((in_addr *)hostent->h_addr_list[0])->S_un;
  202. }
  203. else
  204. {
  205. //d.S_un.S_addr = INADDR_ANY; // Óäàëåííûé àäðåñ ìîæåò áûòü íóëåâûì
  206. WSAError = WSAGetLastError();
  207. Error = 3;
  208. if( Exceptions ) throw 0;
  209. return !Error;
  210. }
  211. }
  212. SOCKET h;
  213. // open a TCP socket
  214. h = socket(AF_INET, SOCK_DGRAM, 0);
  215. if( h==INVALID_SOCKET )
  216. {
  217. WSAError = WSAGetLastError();
  218. Error = 4;
  219. if( Exceptions ) throw 0;
  220. return !Error;
  221. }
  222. // Bind our server to the agreed upon port number. See commdef.h for the actual port number
  223. memset(&localAddr, 0, sizeof(localAddr));
  224. localAddr.sin_family = AF_INET;
  225. localAddr.sin_port = htons(lport);
  226. localAddr.sin_addr = l;
  227. memset(&destAddr, 0, sizeof(destAddr));
  228. destAddr.sin_family = AF_INET;
  229. destAddr.sin_port = htons(dport);
  230. destAddr.sin_addr = d;
  231. handle = h;
  232. Connected = true;
  233. return ! Error;
  234. }
  235. //---------------------------------------------------------------------------
  236. bool TUDP::Close(void)
  237. {
  238. WSAError = 0;
  239. Error = 0;
  240. if( !handle || !Connected ) return true;
  241. if( closesocket(handle) )
  242. {
  243. WSAError = WSAGetLastError();
  244. Error = 1;
  245. }
  246. handle = NULL;
  247. Connected = false;
  248. return ! Error;
  249. }
  250. //---------------------------------------------------------------------------
  251. // Ðàçðåøèòü øèðîêîâåùàòåëüíûå ïàêåòû
  252. bool __fastcall TUDP::EnableBroadcast(BOOL enable)
  253. {
  254. WSAError = 0;
  255. Error = 0;
  256. if( !handle )
  257. {
  258. WSAError = MYERROR_UNKNOWNPARAMS;
  259. Error = 1;
  260. if( Exceptions ) throw 0;
  261. return false;
  262. }
  263. if( setsockopt(handle, SOL_SOCKET, SO_BROADCAST, (char *)&enable, sizeof(BOOL))==SOCKET_ERROR )
  264. {
  265. WSAError = WSAGetLastError();
  266. Error = 2;
  267. if( Exceptions ) throw 0;
  268. return false;
  269. }
  270. return true;
  271. }
  272. //---------------------------------------------------------------------------
  273. bool TUDP::Write(void * data, int size)
  274. {
  275. WSAError = 0;
  276. Error = 0;
  277. if( !handle )
  278. {
  279. WSAError = MYERROR_UNKNOWNPARAMS;
  280. Error = 1;
  281. if( Exceptions ) throw 0;
  282. return !Error;
  283. }
  284. int rv = send(handle, (char *)data, size, 0);
  285. if( rv == SOCKET_ERROR )
  286. {
  287. WSAError = WSAGetLastError();
  288. Error = 2;
  289. if( Exceptions ) throw 0;
  290. return !Error;
  291. }
  292. if( rv != size )
  293. {
  294. WSAError = WSAGetLastError();
  295. Error = 3;
  296. if( Exceptions ) throw 0;
  297. return !Error;
  298. }
  299. OutBytes += size;
  300. return ! Error;
  301. }
  302. //---------------------------------------------------------------------------
  303. bool TUDP::Read(void * data, int size, bool bPeek)
  304. {
  305. WSAError = 0;
  306. Error = 0;
  307. bytes = 0;
  308. if( !handle || size<=0 )
  309. {
  310. WSAError = MYERROR_UNKNOWNPARAMS;
  311. Error = 1;
  312. if( Exceptions ) throw 0;
  313. return !Error;
  314. }
  315. // Ñäåëàåì ïðîâåðêó âõîäíîãî áóôåðà
  316. if( bBlockProtected )
  317. {
  318. DWORD bufsize;
  319. if( ioctlsocket(handle, FIONREAD, &bufsize) == SOCKET_ERROR )
  320. {
  321. WSAError = WSAGetLastError();
  322. Error = 2;
  323. if( Exceptions ) throw 0;
  324. return !Error;
  325. }
  326. if( bufsize < (DWORD)size )
  327. {
  328. Error = 3;
  329. if( Exceptions ) throw 0;
  330. return !Error;
  331. }
  332. }
  333. bytes = recv(handle, (char *)data, size, bPeek ? MSG_PEEK : 0);
  334. if( bytes == SOCKET_ERROR )
  335. {
  336. WSAError = WSAGetLastError();
  337. Error = 4;
  338. bytes = 0;
  339. if( Exceptions ) throw 0;
  340. return !Error;
  341. }
  342. if( bytes != size )
  343. {
  344. WSAError = WSAGetLastError();
  345. Error = 5;
  346. if( Exceptions ) throw 0;
  347. return !Error;
  348. }
  349. InBytes += bytes;
  350. return ! Error;
  351. }
  352. //---------------------------------------------------------------------------
  353. bool TUDP::WriteTo(void * data, int size, struct sockaddr * p)
  354. {
  355. WSAError = 0;
  356. Error = 0;
  357. if( !handle )
  358. {
  359. WSAError = MYERROR_UNKNOWNPARAMS;
  360. Error = 1;
  361. if( Exceptions ) throw 0;
  362. return !Error;
  363. }
  364. int rv = sendto(handle, (char *)data, size, 0, p, sizeof(struct sockaddr));
  365. if( rv == SOCKET_ERROR )
  366. {
  367. WSAError = WSAGetLastError();
  368. Error = 2;
  369. if( Exceptions ) throw 0;
  370. return !Error;
  371. }
  372. if( rv != size )
  373. {
  374. WSAError = WSAGetLastError();
  375. Error = 3;
  376. if( Exceptions ) throw 0;
  377. return !Error;
  378. }
  379. OutBytes += size;
  380. return ! Error;
  381. }
  382. //---------------------------------------------------------------------------
  383. bool TUDP::ReadFrom(void * data, int size, struct sockaddr * p, bool bPeek)
  384. {
  385. WSAError = 0;
  386. Error = 0;
  387. bytes = 0;
  388. if( !handle || size<=0 )
  389. {
  390. WSAError = MYERROR_UNKNOWNPARAMS;
  391. Error = 1;
  392. if( Exceptions ) throw 0;
  393. return !Error;
  394. }
  395. // Ñäåëàåì ïðîâåðêó âõîäíîãî áóôåðà
  396. if( bBlockProtected )
  397. {
  398. DWORD bufsize;
  399. if( ioctlsocket(handle, FIONREAD, &bufsize) == SOCKET_ERROR )
  400. {
  401. WSAError = WSAGetLastError();
  402. Error = 2;
  403. if( Exceptions ) throw 0;
  404. return !Error;
  405. }
  406. if( bufsize < (DWORD)size )
  407. {
  408. WSAError = MYERROR_NOREQSIZE;
  409. Error = 3;
  410. if( Exceptions ) throw 0;
  411. return !Error;
  412. }
  413. }
  414. int fromlen = sizeof(struct sockaddr);
  415. bytes = recvfrom(handle, (char *)data, size, bPeek ? MSG_PEEK : 0, p, &fromlen);
  416. if( bytes==SOCKET_ERROR )
  417. {
  418. WSAError = WSAGetLastError();
  419. Error = 4;
  420. bytes = 0;
  421. if( Exceptions ) throw 0;
  422. return !Error;
  423. }
  424. if( bytes != size )
  425. {
  426. // Îáû÷íî ïðîèñõîäèò, êîãäà â ïðèåìíîì áóôåðå íåñêîëüêî UPD ïàêåòîâ
  427. // Ïîëó÷àòü UDP ïàêåòû ìîæíî òîëüêî ïî îäíîìó
  428. // Ïîýòîìó ïîñëå ïîëó÷åíèÿ îäíîãî ïàêåòà bytes < size
  429. // ReadLength() äàåò ñóììàðíûé ðàçìåð ÂÑÅÕ ïàêåòîâ â ïðèåìíîì áóôåðå
  430. WSAError = MYERROR_READCOUNT;
  431. Error = 5;
  432. if( Exceptions ) throw 0;
  433. return !Error;
  434. }
  435. InBytes += bytes;
  436. return ! Error;
  437. }
  438. //---------------------------------------------------------------------------
  439. // Cóììàðíûé ðàçìåð ÂÑÅÕ ïàêåòîâ â ïðèåìíîì áóôåðå
  440. DWORD TUDP::ReadLength(void)
  441. {
  442. WSAError = 0;
  443. Error = 0;
  444. if( !handle )
  445. {
  446. WSAError = MYERROR_UNKNOWNPARAMS;
  447. Error = 1;
  448. if( Exceptions ) throw 0;
  449. return !Error;
  450. }
  451. DWORD bufsize;
  452. if( ioctlsocket(handle, FIONREAD, &bufsize) == SOCKET_ERROR )
  453. {
  454. WSAError = WSAGetLastError();
  455. Error = 1;
  456. bufsize = 0;
  457. if( Exceptions ) throw 0;
  458. return !Error;
  459. }
  460. return bufsize;
  461. }
  462. //---------------------------------------------------------------------------
  463. bool TUDP::Poll(bool bread, bool bwrite, bool berror, long msec)
  464. {
  465. WSAError = 0;
  466. fd_set f;
  467. FD_ZERO(&f);
  468. FD_SET(handle, &f);
  469. timeval t;
  470. t.tv_sec = 0;
  471. t.tv_usec = msec * 1000; // "POLL" SOCKET STATE msec period and return immediately...
  472. int rv = select(FD_SETSIZE, bread ? &f : NULL, bwrite ? &f : NULL, berror ? &f : NULL, &t);
  473. if( rv == SOCKET_ERROR )
  474. {
  475. WSAError = WSAGetLastError();
  476. Error = 1;
  477. bytes = 0;
  478. if( Exceptions ) throw 0;
  479. return !Error;
  480. }
  481. return rv > 0;
  482. }
  483. //---------------------------------------------------------------------------
  484. // Î÷èñòèòü ïðèåìíûé áóôåð
  485. // Âîçâðàùàåò - ñêîëüêî ïàêåòîâ óêó÷åíî
  486. int TUDP::Flush(void)
  487. {
  488. DWORD l;
  489. int count = 0;
  490. FlushSize = 0;
  491. while( (l = ReadLength()) > 0 )
  492. {
  493. BYTE * p = new BYTE[l];
  494. Read(p, l);
  495. delete [] p;
  496. count++;
  497. FlushSize += l;
  498. }
  499. return count;
  500. }
  501. //---------------------------------------------------------------------------
  502. AnsiString TUDP::GetLocalAddr(void)
  503. {
  504. return inet_ntoa(localAddr.sin_addr);
  505. }
  506. //---------------------------------------------------------------------------
  507. WORD TUDP::GetLocalPort(void)
  508. {
  509. return htons(localAddr.sin_port);
  510. }
  511. //---------------------------------------------------------------------------
  512. AnsiString TUDP::GetLocalAddrPort(void)
  513. {
  514. AnsiString rv(inet_ntoa(localAddr.sin_addr));
  515. rv += ":" + IntToStr(htons(localAddr.sin_port));
  516. return rv;
  517. }
  518. //---------------------------------------------------------------------------
  519. AnsiString TUDP::GetRemoteAddr(void)
  520. {
  521. return inet_ntoa(destAddr.sin_addr);
  522. }
  523. //---------------------------------------------------------------------------
  524. WORD TUDP::GetRemotePort(void)
  525. {
  526. return htons(destAddr.sin_port);
  527. }
  528. //---------------------------------------------------------------------------
  529. AnsiString TUDP::GetRemoteAddrPort(void)
  530. {
  531. AnsiString rv(inet_ntoa(destAddr.sin_addr));
  532. rv += ":" + IntToStr(htons(destAddr.sin_port));
  533. return rv;
  534. }
  535. //---------------------------------------------------------------------------
  536. AnsiString TUDP::GetErrorMessage(void)
  537. {
  538. switch( WSAError )
  539. {
  540. case 0: return "";
  541. case WSAEADDRINUSE: return "Àäðåñ èëè ïîðò óæå èñïîëüçóåòñÿ â ñèñòåìå";
  542. case WSAENETDOWN: return "Ñåòü óìåðëà";
  543. case WSAENETUNREACH: return "Ñåòü íåäîñòóïíà";
  544. case WSAECONNABORTED: return "Ñîåäèíåíèå çàêðûòî èç-çà îøèáêè";
  545. case WSAECONNRESET: return "Ñîåäèíåíèå çàêðûòî óäàëåííîé ñòîðîíîé";
  546. case WSAENOBUFS: return "Ñåòåâîé áóôåð ïåðåïîëíåí";
  547. case WSAESHUTDOWN: return "Îáìåí íåâîçìîæåí - ñîåäèíåíèå çàêðûâàåòñÿ";
  548. case WSAETIMEDOUT: return "Òàéìàóò ïîäêëþ÷åíèÿ ïî TCP/IP";
  549. case WSAECONNREFUSED: return "Óäàëåííûé óçåë îòêëîíèë ñîåäèíåíèå";
  550. case WSAEHOSTDOWN: return "Óäàëåííûé óçåë íå ñóùåñòâóåò";
  551. case WSAHOST_NOT_FOUND: return "Èìÿ óçëà íå íàéäåíî";
  552. case WSAENOTSOCK: return "Íåâåðíûé èäåíòèôèêàòîð ñîêåòà";
  553. case WSAEWOULDBLOCK: return "Íåáëîêèðóþùàÿ îïåðàöèÿ âûïîëíÿåòñÿ";
  554. case WSANO_DATA: return "Íå óäàåòñÿ ïîëó÷èòü IP àäðåñ ïî èìåíè óçëà";
  555. // WSAEHOSTUNREACH âîçíèêàåò êîãäà Ethernet êàáåëü âûêëþ÷åí è WiFi íåò
  556. case WSAEHOSTUNREACH: return "Ñåòü íåäîñòóïíà"; // "Óçåë ñåòè íåäîñòóïåí";
  557. case WSAEMSGSIZE: return "Ñîîáùåíèå ñëèøêîì áîëüøîå";
  558. // local error codes
  559. case MYERROR_UNKNOWNPARAMS: return "Íåâåðíûå ïàðàìåòðû";
  560. case MYERROR_READCOUNT: return "Â ïðèåìíîì áóôåðå åùå îñòàëèñü UDP ïàêåòû";
  561. case MYERROR_NOREQSIZE: return " ïðèåìíîì áóôåðå äàííûõ ìåíüøå ÷åì çàïðîøåíî";
  562. }
  563. return AnsiString("Êîä îøèáêè: ") + IntToStr(WSAError);
  564. }
  565. //---------------------------------------------------------------------------
  566. AnsiString TUDP::GetErrorMessageEng(void)
  567. {
  568. switch( WSAError )
  569. {
  570. case 0: return "";
  571. case WSAEADDRINUSE: return "Address or port is already in use";
  572. case WSAENETDOWN: return "Network died";
  573. case WSAENETUNREACH: return "Network is not available";
  574. case WSAECONNABORTED: return "Connection closed because of an error";
  575. case WSAECONNRESET: return "Connection closed by remote side";
  576. case WSAENOBUFS: return "Network buffer overflow";
  577. case WSAESHUTDOWN: return "The exchange is not possible - the connection is closed";
  578. case WSAETIMEDOUT: return "Timeout connecting over TCP/IP";
  579. case WSAECONNREFUSED: return "The remote host refused the connection";
  580. case WSAEHOSTDOWN: return "The remote host does not exist";
  581. case WSAHOST_NOT_FOUND: return "Host Name not found";
  582. case WSAENOTSOCK: return "Invalid socket identification";
  583. case WSAEWOULDBLOCK: return "Non-blocking operation is in progress";
  584. case WSANO_DATA: return "Can not get IP address for the host name";
  585. // WSAEHOSTUNREACH occurs when the Ethernet cable is off and there is no WiFi
  586. case WSAEHOSTUNREACH: return "Network not available"; // "Host not available";
  587. case WSAEMSGSIZE: return "Message too large";
  588. // Local error codes
  589. case MYERROR_UNKNOWNPARAMS: return "Invalid parameters";
  590. case MYERROR_READCOUNT: return "to the receive buffer still have UDP packets";
  591. case MYERROR_NOREQSIZE: return "to the receive buffer data is less than requested";
  592. }
  593. return AnsiString ("Error code: ") + IntToStr(WSAError);
  594. }
  595. //---------------------------------------------------------------------------