networkhandler.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  1. /*******************************************************************************
  2. * Copyright (c) 2009, Rockwell Automation, Inc.
  3. * All rights reserved.
  4. *
  5. ******************************************************************************/
  6. #include <stdio.h>
  7. #include <string.h>
  8. #include <stdlib.h>
  9. #include <errno.h>
  10. #include <unistd.h>
  11. #include <sys/time.h>
  12. #include <opener_api.h>
  13. #include "networkhandler.h"
  14. #include <encap.h>
  15. #include <cipconnectionmanager.h>
  16. #include <endianconv.h>
  17. #include <trace.h>
  18. #include <ciptcpipinterface.h>
  19. /* values needed from the connection manager */
  20. extern ConnectionObject *g_active_connection_list;
  21. /* communication buffer */EipUint8 g_acPCEthernetCommBuffer[PC_OPENER_ETHERNET_BUFFER_SIZE];
  22. #define MAX_NO_OF_TCP_SOCKETS 10
  23. typedef unsigned long MILLISECONDS;
  24. typedef unsigned long long MICROSECONDS;
  25. fd_set master;
  26. fd_set read_fds;
  27. /* temporary file descriptor for select() */
  28. int fdmax;
  29. /*!< This var holds the TCP socket the received to last explicit message.
  30. * It is needed for opening point to point connection to determine the peer's
  31. * address.
  32. */
  33. int g_nCurrentActiveTCPSocket;
  34. static struct timeval tv;
  35. static MILLISECONDS actualtime, lasttime;
  36. /*!\brief handle any connection request coming in the TCP server socket.
  37. *
  38. */
  39. void
  40. checkAndHandleTCPListenerSocket();
  41. /*! \brief check if data has been received on the udp broadcast socket and if yes handle it correctly
  42. *
  43. */
  44. void
  45. checkAndHandleUDPBroadCastSocket();
  46. /*! \brief check if on one of the udp consuming sockets data has been received and if yes handle it correctly
  47. *
  48. */
  49. void
  50. checkAndHandleConsumingUDPSockets();
  51. /*! \brief check if the given socket is set in the read set
  52. *
  53. */EipBool8
  54. checkSocketSet(int pa_nSocket);
  55. /*!
  56. *
  57. */
  58. EipStatus
  59. handleDataOnTCPSocket(int pa_nSocket);
  60. static MICROSECONDS getMicroseconds() {
  61. #ifdef WIN32
  62. LARGE_INTEGER lPerformanceCouner;
  63. LARGE_INTEGER lPerformanceFrequency;
  64. QueryPerformanceCounter(&lPerformanceCouner);
  65. QueryPerformanceFrequency(&lPerformanceFrequency);
  66. return (MICROSECONDS) (lPerformanceCouner.QuadPart * 1000000LL / lPerformanceFrequency.QuadPart);
  67. #else
  68. struct timeval tv;
  69. gettimeofday(&tv, 0);
  70. return (MICROSECONDS) tv.tv_sec * 1000000ULL + (MICROSECONDS) tv.tv_usec;
  71. #endif
  72. }
  73. static MILLISECONDS getmilliseconds(void) {
  74. return (MILLISECONDS) (getMicroseconds() / 1000ULL);
  75. }
  76. /* INT8 Start_NetworkHandler()
  77. * start a TCP listening socket, accept connections, receive data in select loop, call manageConnections periodically.
  78. * return status
  79. * -1 .. error
  80. */
  81. struct NetworkStatus {
  82. int nTCPListener;
  83. int nUDPListener;
  84. MILLISECONDS elapsedtime;
  85. } PACKED;
  86. struct NetworkStatus g_network_status;
  87. EipStatus NetworkHandler_Init(void) {
  88. struct sockaddr_in my_addr;
  89. int y;
  90. int nOptVal;
  91. #ifdef WIN32
  92. WORD wVersionRequested;
  93. WSADATA wsaData;
  94. wVersionRequested = MAKEWORD(2, 2);
  95. WSAStartup(wVersionRequested, &wsaData);
  96. #endif
  97. /* clear the master an temp sets */
  98. FD_ZERO(&master);
  99. FD_ZERO(&read_fds);
  100. /* create a new TCP socket */
  101. if ((g_network_status.nTCPListener = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
  102. OPENER_TRACE_ERR("error allocating socket stream listener, %d\n", errno);
  103. return kEipStatusError;
  104. }
  105. nOptVal = 1;
  106. if (setsockopt(g_network_status.nTCPListener, SOL_SOCKET, SO_REUSEADDR,
  107. (char *) &nOptVal, sizeof(nOptVal)) == -1) {
  108. OPENER_TRACE_ERR(
  109. "error setting socket option SO_REUSEADDR on nTCPListener\n");
  110. return kEipStatusError;
  111. }
  112. /* create a new UDP socket */
  113. if ((g_network_status.nUDPListener = socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
  114. OPENER_TRACE_ERR("error allocating udp listener socket, %d\n", errno);
  115. return kEipStatusError;
  116. }
  117. if (setsockopt(g_network_status.nUDPListener, SOL_SOCKET, SO_REUSEADDR,
  118. (char *) &nOptVal, sizeof(nOptVal)) == -1) {
  119. OPENER_TRACE_ERR(
  120. "error setting socket option SO_REUSEADDR on nUDPListener\n");
  121. return kEipStatusError;
  122. }
  123. my_addr.sin_family = AF_INET;
  124. my_addr.sin_port = htons(OPENER_ETHERNET_PORT);
  125. my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  126. memset(&my_addr.sin_zero, 0, sizeof(my_addr.sin_zero));
  127. /* bind the new socket to port 0xAF12 (CIP) */
  128. if ((bind(g_network_status.nTCPListener, (struct sockaddr *) &my_addr,
  129. sizeof(struct sockaddr))) == -1) {
  130. OPENER_TRACE_ERR("error with bind: %s\n", strerror(errno));
  131. return kEipStatusError;
  132. }
  133. /* enable the udp socket to receive broadcast messages*/
  134. y = 1;
  135. if (0
  136. > setsockopt(g_network_status.nUDPListener, SOL_SOCKET, SO_BROADCAST,
  137. (char *) &y, sizeof(int))) {
  138. OPENER_TRACE_ERR(
  139. "error with setting broadcast receive for udp socket: %s\n",
  140. strerror(errno));
  141. return kEipStatusError;
  142. }
  143. if ((bind(g_network_status.nUDPListener, (struct sockaddr *) &my_addr,
  144. sizeof(struct sockaddr))) == -1) {
  145. OPENER_TRACE_ERR("error with udp bind: %s\n", strerror(errno));
  146. return kEipStatusError;
  147. }
  148. /* switch socket in listen mode */
  149. if ((listen(g_network_status.nTCPListener, MAX_NO_OF_TCP_SOCKETS)) == -1) {
  150. OPENER_TRACE_ERR("networkhandler: error with listen: %s\n",
  151. strerror(errno));
  152. return kEipStatusError;
  153. }
  154. /* add the listener socket to the master set */FD_SET(
  155. g_network_status.nTCPListener, &master);
  156. FD_SET(g_network_status.nUDPListener, &master);
  157. /* keep track of the biggest file descriptor */
  158. fdmax =
  159. (g_network_status.nTCPListener > g_network_status.nUDPListener) ?
  160. g_network_status.nTCPListener : g_network_status.nUDPListener;
  161. lasttime = getmilliseconds(); /* initialize time keeping */
  162. g_network_status.elapsedtime = 0;
  163. return kEipStatusOk;
  164. }
  165. EipStatus NetworkHandler_ProcessOnce(void) {
  166. int fd;
  167. int res;
  168. read_fds = master;
  169. tv.tv_sec = 0;
  170. tv.tv_usec = (
  171. g_network_status.elapsedtime < kOpenerTimerTickInMilliSeconds ?
  172. kOpenerTimerTickInMilliSeconds - g_network_status.elapsedtime : 0)
  173. * 1000; /* 10 ms */
  174. res = select(fdmax + 1, &read_fds, 0, 0, &tv);
  175. if (res == -1) {
  176. if (EINTR == errno) /* we have somehow been interrupted. The default behavior is to go back into the select loop. */
  177. {
  178. return kEipStatusOk;
  179. } else {
  180. OPENER_TRACE_ERR("networkhandler: error with select: %s\n",
  181. strerror(errno));
  182. return kEipStatusError;
  183. }
  184. }
  185. if (res > 0) {
  186. checkAndHandleTCPListenerSocket();
  187. checkAndHandleUDPBroadCastSocket();
  188. checkAndHandleConsumingUDPSockets();
  189. for (fd = 0; fd <= fdmax; fd++) {
  190. if (true == checkSocketSet(fd)) {
  191. /* if it is still checked it is a TCP receive */
  192. if (kEipStatusError == handleDataOnTCPSocket(fd)) /* if error */
  193. {
  194. CloseSocket(fd);
  195. CloseSession(fd); /* clean up session and close the socket */
  196. }
  197. }
  198. }
  199. }
  200. actualtime = getmilliseconds();
  201. g_network_status.elapsedtime += actualtime - lasttime;
  202. lasttime = actualtime;
  203. /* check if we had been not able to update the connection manager for several OPENER_TIMER_TICK.
  204. * This should compensate the jitter of the windows timer
  205. */
  206. while (g_network_status.elapsedtime >= kOpenerTimerTickInMilliSeconds) {
  207. /* call manage_connections() in connection manager every OPENER_TIMER_TICK ms */
  208. ManageConnections();
  209. g_network_status.elapsedtime -= kOpenerTimerTickInMilliSeconds;
  210. }
  211. return kEipStatusOk;
  212. }
  213. EipStatus NetworkHandler_Finish(void) {
  214. CloseSocket(g_network_status.nTCPListener);
  215. CloseSocket(g_network_status.nUDPListener);
  216. return kEipStatusOk;
  217. }
  218. EipBool8 checkSocketSet(int pa_nSocket) {
  219. EipBool8 nRetVal = false;
  220. if (FD_ISSET(pa_nSocket, &read_fds)) {
  221. if (FD_ISSET(pa_nSocket, &master)) {
  222. nRetVal = true;
  223. } else {
  224. OPENER_TRACE_INFO("socket: %d closed with pending message\n", pa_nSocket);
  225. }
  226. FD_CLR(pa_nSocket, &read_fds);
  227. /* remove it from the read set so that later checks will not find it */
  228. }
  229. return nRetVal;
  230. }
  231. EipStatus SendUdpData(struct sockaddr_in *pa_pstAddr, int pa_nSockFd,
  232. EipUint8 *pa_acData, EipUint16 pa_nDataLength) {
  233. int sentlength;
  234. sentlength = sendto(pa_nSockFd, (char *) pa_acData, pa_nDataLength, 0,
  235. (struct sockaddr *) pa_pstAddr, sizeof(*pa_pstAddr));
  236. if (sentlength < 0) {
  237. OPENER_TRACE_ERR("networkhandler: error with sendto in sendUDPData: %s\n",
  238. strerror(errno));
  239. return kEipStatusError;
  240. } else if (sentlength != pa_nDataLength) {
  241. OPENER_TRACE_WARN("not all data was sent in sendUDPData, sent %d of %d\n",
  242. sentlength, pa_nDataLength);
  243. return kEipStatusError;
  244. } else
  245. return kEipStatusOk;
  246. }
  247. EipStatus handleDataOnTCPSocket(int pa_nSocket) {
  248. EipUint8 *rxp;
  249. long nCheckVal;
  250. size_t unDataSize;
  251. long nDataSent;
  252. int nRemainingBytes = 0;
  253. /* We will handle just one EIP packet here the rest is done by the select
  254. * method which will inform us if more data is available in the socket
  255. because of the current implementation of the main loop this may not be
  256. the fastest way and a loop here with a non blocking socket would better
  257. fit*/
  258. /*Check how many data is here -- read the first four bytes from the connection */
  259. nCheckVal = recv(pa_nSocket, g_acPCEthernetCommBuffer, 4, 0); /*TODO we may have to set the socket to a non blocking socket */
  260. if (nCheckVal == 0) {
  261. OPENER_TRACE_ERR("networkhandler: connection closed by client: %s\n",
  262. strerror(errno));
  263. return kEipStatusError;
  264. }
  265. if (nCheckVal < 0) {
  266. OPENER_TRACE_ERR("networkhandler: error on recv: %s\n", strerror(errno));
  267. return kEipStatusError;
  268. }
  269. rxp = &g_acPCEthernetCommBuffer[2]; /* at this place EIP stores the data length */
  270. unDataSize = GetIntFromMessage(&rxp) + ENCAPSULATION_HEADER_LENGTH - 4; /* -4 is for the 4 bytes we have already read*/
  271. /* (NOTE this advances the buffer pointer) */
  272. if (PC_OPENER_ETHERNET_BUFFER_SIZE - 4 < unDataSize) { /*TODO can this be handled in a better way?*/
  273. OPENER_TRACE_ERR(
  274. "too large packet received will be ignored, will drop the data\n");
  275. /* Currently we will drop the whole packet */
  276. nDataSent = PC_OPENER_ETHERNET_BUFFER_SIZE;
  277. do {
  278. nCheckVal = recv(pa_nSocket, g_acPCEthernetCommBuffer, nDataSent, 0);
  279. if (nCheckVal == 0) /* got error or connection closed by client */
  280. {
  281. OPENER_TRACE_ERR("networkhandler: connection closed by client: %s\n",
  282. strerror(errno));
  283. return kEipStatusError;
  284. }
  285. if (nCheckVal < 0) {
  286. OPENER_TRACE_ERR("networkhandler: error on recv: %s\n",
  287. strerror(errno));
  288. return kEipStatusError;
  289. }
  290. unDataSize -= nCheckVal;
  291. if ((unDataSize < PC_OPENER_ETHERNET_BUFFER_SIZE) && (unDataSize != 0)) {
  292. nDataSent = unDataSize;
  293. }
  294. } while (0 != unDataSize); /*TODO fragile end statement */
  295. return kEipStatusOk;
  296. }
  297. nCheckVal = recv(pa_nSocket, &g_acPCEthernetCommBuffer[4], unDataSize, 0);
  298. if (nCheckVal == 0) /* got error or connection closed by client */
  299. {
  300. OPENER_TRACE_ERR("networkhandler: connection closed by client: %s\n",
  301. strerror(errno));
  302. return kEipStatusError;
  303. }
  304. if (nCheckVal < 0) {
  305. OPENER_TRACE_ERR("networkhandler: error on recv: %s\n", strerror(errno));
  306. return kEipStatusError;
  307. }
  308. if ((unsigned) nCheckVal == unDataSize) {
  309. /*we got the right amount of data */
  310. unDataSize += 4;
  311. /*TODO handle partial packets*/
  312. OPENER_TRACE_INFO("Data received on tcp:\n");
  313. g_nCurrentActiveTCPSocket = pa_nSocket;
  314. nCheckVal = HandleReceivedExplictTcpData(pa_nSocket,
  315. g_acPCEthernetCommBuffer,
  316. unDataSize, &nRemainingBytes);
  317. g_nCurrentActiveTCPSocket = -1;
  318. if (nRemainingBytes != 0) {
  319. OPENER_TRACE_WARN(
  320. "Warning: received packet was to long: %d Bytes left!\n",
  321. nRemainingBytes);
  322. }
  323. if (nCheckVal > 0) {
  324. OPENER_TRACE_INFO("reply sent:\n");
  325. nDataSent = send(pa_nSocket, (char *) g_acPCEthernetCommBuffer, nCheckVal,
  326. 0);
  327. if (nDataSent != nCheckVal) {
  328. OPENER_TRACE_WARN("TCP response was not fully sent\n");
  329. }
  330. }
  331. return kEipStatusOk;
  332. } else {
  333. /* we got a fragmented packet currently we cannot handle this will
  334. * for this we would need a network buffer per TCP socket
  335. *
  336. * However with typical packet sizes of EIP this should't be a big issue.
  337. */
  338. /*TODO handle fragmented packets */
  339. }
  340. return kEipStatusError;
  341. }
  342. /* create a new UDP socket for the connection manager
  343. returns the fd if successful, else -1 */
  344. int CreateUdpSocket(UdpCommuncationDirection communication_direction,
  345. struct sockaddr_in *socket_data) {
  346. struct sockaddr_in stPeerAdr;
  347. int newfd;
  348. #ifdef WIN32
  349. unsigned long nPeerAddrLen;
  350. #else
  351. socklen_t nPeerAddrLen;
  352. #endif
  353. nPeerAddrLen = sizeof(struct sockaddr_in);
  354. /* create a new UDP socket */
  355. if ((newfd = socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
  356. OPENER_TRACE_ERR("networkhandler: cannot create UDP socket: %s\n",
  357. strerror(errno));
  358. return kEipInvalidSocket;
  359. }
  360. OPENER_TRACE_INFO("networkhandler: UDP socket %d\n", newfd);
  361. /* check if it is sending or receiving */
  362. if (communication_direction == kUdpCommuncationDirectionConsuming) {
  363. int nOptVal = 1;
  364. if (setsockopt(newfd, SOL_SOCKET, SO_REUSEADDR, (char *) &nOptVal,
  365. sizeof(nOptVal)) == -1) {
  366. OPENER_TRACE_ERR(
  367. "error setting socket option SO_REUSEADDR on consuming udp socket\n");
  368. return kEipStatusError;
  369. }
  370. /* bind is only for consuming necessary */
  371. if ((bind(newfd, (struct sockaddr *) socket_data, sizeof(struct sockaddr)))
  372. == -1) {
  373. OPENER_TRACE_ERR("error on bind udp: %s\n", strerror(errno));
  374. return kEipInvalidSocket;
  375. }
  376. OPENER_TRACE_INFO("networkhandler: bind UDP socket %d\n", newfd);
  377. } else { /* we have a producing udp socket */
  378. if (socket_data->sin_addr.s_addr
  379. == g_multicast_configuration.starting_multicast_address) {
  380. if (1 != g_time_to_live_value) { /* we need to set a TTL value for the socket */
  381. if (setsockopt(newfd, IPPROTO_IP, IP_MULTICAST_TTL,
  382. &g_time_to_live_value,
  383. sizeof(g_time_to_live_value) < 0)) {
  384. OPENER_TRACE_ERR(
  385. "networkhandler: could not set the TTL to: %d, error: %s\n",
  386. g_time_to_live_value, strerror(errno));
  387. return kEipInvalidSocket;
  388. }
  389. }
  390. }
  391. }
  392. if ((communication_direction == kUdpCommuncationDirectionConsuming)
  393. || (0 == socket_data->sin_addr.s_addr)) {
  394. /* we have a peer to peer producer or a consuming connection*/
  395. if (getpeername(g_nCurrentActiveTCPSocket, (struct sockaddr *) &stPeerAdr,
  396. &nPeerAddrLen) < 0) {
  397. OPENER_TRACE_ERR("networkhandler: could not get peername: %s\n",
  398. strerror(errno));
  399. return kEipInvalidSocket;
  400. }
  401. /* store the originators address */
  402. socket_data->sin_addr.s_addr = stPeerAdr.sin_addr.s_addr;
  403. }
  404. /* add new fd to the master list */
  405. FD_SET(newfd, &master);
  406. if (newfd > fdmax) {
  407. fdmax = newfd;
  408. }
  409. return newfd;
  410. }
  411. void IApp_CloseSocket_udp(int pa_nSockFd) {
  412. CloseSocket(pa_nSockFd);
  413. }
  414. void IApp_CloseSocket_tcp(int pa_nSockFd) {
  415. CloseSocket(pa_nSockFd);
  416. }
  417. void CloseSocket(int pa_nSockFd) {
  418. OPENER_TRACE_INFO("networkhandler: closing socket %d\n", pa_nSockFd);
  419. if (kEipInvalidSocket != pa_nSockFd) {
  420. FD_CLR(pa_nSockFd, &master);
  421. #ifdef WIN32
  422. closesocket(pa_nSockFd);
  423. #else
  424. shutdown(pa_nSockFd, SHUT_RDWR);
  425. close(pa_nSockFd);
  426. #endif
  427. }
  428. }
  429. void checkAndHandleTCPListenerSocket() {
  430. int newfd;
  431. /* see if this is a connection request to the TCP listener*/
  432. if (true == checkSocketSet(g_network_status.nTCPListener)) {
  433. OPENER_TRACE_INFO("networkhandler: new TCP connection\n");
  434. newfd = accept(g_network_status.nTCPListener, NULL, NULL);
  435. if (newfd == -1) {
  436. OPENER_TRACE_ERR("networkhandler: error on accept: %s\n",
  437. strerror(errno));
  438. return;
  439. }
  440. FD_SET(newfd, &master);
  441. /* add newfd to master set */
  442. if (newfd > fdmax) {
  443. fdmax = newfd;
  444. }
  445. OPENER_TRACE_STATE("networkhandler: opened new TCP connection on fd %d\n",
  446. newfd);
  447. }
  448. }
  449. void checkAndHandleUDPBroadCastSocket() {
  450. int nReceived_size;
  451. int nRemainingBytes;
  452. int nReplyLen;
  453. EipUint8 *rxp;
  454. struct sockaddr_in stFrom;
  455. #ifndef WIN32
  456. socklen_t nFromLen;
  457. #else
  458. unsigned long nFromLen;
  459. #endif
  460. /* see if this is an unsolicited inbound UDP message */
  461. if (true == checkSocketSet(g_network_status.nUDPListener)) {
  462. nFromLen = sizeof(stFrom);
  463. OPENER_TRACE_STATE(
  464. "networkhandler: unsolicited UDP message on EIP broadcast socket\n");
  465. /*Handle udp broadcast messages */
  466. nReceived_size = recvfrom(g_network_status.nUDPListener,
  467. g_acPCEthernetCommBuffer,
  468. PC_OPENER_ETHERNET_BUFFER_SIZE, 0,
  469. (struct sockaddr *) &stFrom, &nFromLen);
  470. if (nReceived_size <= 0) { /* got error */
  471. OPENER_TRACE_ERR(
  472. "networkhandler: error on recvfrom udp broadcast port: %s\n",
  473. strerror(errno));
  474. return;
  475. }
  476. OPENER_TRACE_INFO("Data received on udp:\n");
  477. rxp = &g_acPCEthernetCommBuffer[0];
  478. do {
  479. nReplyLen = HandleReceivedExplictUdpData(g_network_status.nUDPListener,
  480. &stFrom, rxp, nReceived_size,
  481. &nRemainingBytes);
  482. rxp += nReceived_size - nRemainingBytes;
  483. nReceived_size = nRemainingBytes;
  484. if (nReplyLen > 0) {
  485. OPENER_TRACE_INFO("reply sent:\n");
  486. /* if the active fd matches a registered UDP callback, handle a UDP packet */
  487. if (sendto(g_network_status.nUDPListener,
  488. (char *) g_acPCEthernetCommBuffer, nReplyLen, 0,
  489. (struct sockaddr *) &stFrom, sizeof(stFrom)) != nReplyLen) {
  490. OPENER_TRACE_INFO(
  491. "networkhandler: UDP response was not fully sent\n");
  492. }
  493. }
  494. } while (nRemainingBytes > 0);
  495. }
  496. }
  497. void checkAndHandleConsumingUDPSockets() {
  498. int nReceived_size;
  499. struct sockaddr_in stFrom;
  500. #ifndef WIN32
  501. socklen_t nFromLen;
  502. #else
  503. unsigned long nFromLen;
  504. #endif
  505. ConnectionObject *pstRunner = g_active_connection_list;
  506. ConnectionObject *pstCurrent;
  507. /* see a message on one of the registered UDP sockets has been received */
  508. while (NULL != pstRunner) {
  509. pstCurrent = pstRunner;
  510. pstRunner = pstRunner->next_connection_object; /* do this at the beginning as the close function may can make the entry invalid */
  511. if ((-1 != pstCurrent->socket[kUdpCommuncationDirectionConsuming])
  512. && (true
  513. == checkSocketSet(
  514. pstCurrent->socket[kUdpCommuncationDirectionConsuming]))) {
  515. nFromLen = sizeof(stFrom);
  516. nReceived_size = recvfrom(
  517. pstCurrent->socket[kUdpCommuncationDirectionConsuming],
  518. g_acPCEthernetCommBuffer, PC_OPENER_ETHERNET_BUFFER_SIZE, 0,
  519. (struct sockaddr *) &stFrom, &nFromLen);
  520. if (0 == nReceived_size) {
  521. OPENER_TRACE_STATE("connection closed by client\n");
  522. pstCurrent->connection_close_function(pstCurrent);
  523. continue;
  524. }
  525. if (0 > nReceived_size) {
  526. OPENER_TRACE_ERR("networkhandler: error on recv: %s\n",
  527. strerror(errno));
  528. pstCurrent->connection_close_function(pstCurrent);
  529. continue;
  530. }
  531. HandleReceivedConnectedData(g_acPCEthernetCommBuffer, nReceived_size,
  532. &stFrom);
  533. }
  534. }
  535. }