generic_networkhandler.c 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952
  1. /*******************************************************************************
  2. * Copyright (c) 2009, Rockwell Automation, Inc.
  3. * All rights reserved.
  4. *
  5. ******************************************************************************/
  6. /** @file generic_networkhandler.c
  7. * @author Martin Melik Merkumians
  8. * @brief This file includes all platform-independent functions of the network handler to reduce code duplication
  9. *
  10. * The generic network handler delegates platform-dependent tasks to the platform network handler
  11. */
  12. #include <assert.h>
  13. #include <inttypes.h>
  14. #include <stdbool.h>
  15. #include <signal.h>
  16. #include "generic_networkhandler.h"
  17. #include "typedefs.h"
  18. #include "trace.h"
  19. #include "opener_error.h"
  20. #include "encap.h"
  21. #include "ciptcpipinterface.h"
  22. #include "opener_user_conf.h"
  23. #include "cipqos.h"
  24. #define MAX_NO_OF_TCP_SOCKETS 10
  25. /** @brief Ethernet/IP standard port */
  26. /* ----- Windows size_t PRI macros ------------- */
  27. #if defined(__MINGW32__) || defined(HPMICRO) /* This is a Mingw compiler or HPMICRO target (GCC) */
  28. #define PRIuSZT PRIuPTR
  29. #define PRIxSZT PRIxPTR
  30. #else
  31. /* Even the Visual Studio compilers / libraries since VS2015 know that now. */
  32. #define PRIuSZT "zu"
  33. #define PRIxSZT "zx"
  34. #endif /* if defined(__MINGW32__) */
  35. #if defined(_WIN32)
  36. /* Most network functions take their I/O buffers as (char *) pointers that
  37. * triggers a warning with our CipOctet (aka unsigned char) buffers. */
  38. #define NWBUF_CAST (void *)
  39. #else
  40. #define NWBUF_CAST
  41. #endif
  42. #ifndef MSG_NOSIGNAL
  43. #define MSG_NOSIGNAL 0
  44. #define MSG_NOSIGNAL_PRAGMA_MESSAGE "MSG_NOSIGNAL not defined. Check if your system stops on SIGPIPE, as this can happen with the send() function"
  45. #if defined(_WIN32)
  46. #pragma message(MSG_NOSIGNAL_PRAGMA_MESSAGE)
  47. #else
  48. #pragma GCC warning MSG_NOSIGNAL_PRAGMA_MESSAGE
  49. #endif /* defined(_WIN32) */
  50. #endif
  51. SocketTimer g_timestamps[OPENER_NUMBER_OF_SUPPORTED_SESSIONS];
  52. //EipUint8 g_ethernet_communication_buffer[PC_OPENER_ETHERNET_BUFFER_SIZE]; /**< communication buffer */
  53. /* global vars */
  54. fd_set master_socket;
  55. fd_set read_socket;
  56. int highest_socket_handle;
  57. int g_current_active_tcp_socket;
  58. struct timeval g_time_value;
  59. MilliSeconds g_actual_time;
  60. MilliSeconds g_last_time;
  61. NetworkStatus g_network_status;
  62. /** @brief Size of the timeout checker function pointer array
  63. */
  64. #define OPENER_TIMEOUT_CHECKER_ARRAY_SIZE 10
  65. /** @brief function pointer array for timer checker functions
  66. */
  67. TimeoutCheckerFunction timeout_checker_array[OPENER_TIMEOUT_CHECKER_ARRAY_SIZE];
  68. /** @brief handle any connection request coming in the TCP server socket.
  69. *
  70. */
  71. void CheckAndHandleTcpListenerSocket(void);
  72. /** @brief Checks and processes request received via the UDP unicast socket, currently the implementation is port-specific
  73. *
  74. */
  75. void CheckAndHandleUdpUnicastSocket(void);
  76. /** @brief Checks and handles incoming messages via UDP broadcast
  77. *
  78. */
  79. void CheckAndHandleUdpGlobalBroadcastSocket(void);
  80. /** @brief check if on the UDP consuming socket data has been received and if yes handle it correctly
  81. *
  82. */
  83. void CheckAndHandleConsumingUdpSocket(void);
  84. /** @brief Handles data on an established TCP connection, processed connection is given by socket
  85. *
  86. * @param socket The socket to be processed
  87. * @return kEipStatusOk on success, or kEipStatusError on failure
  88. */
  89. EipStatus HandleDataOnTcpSocket(int socket);
  90. void CheckEncapsulationInactivity(int socket_handle);
  91. void RemoveSocketTimerFromList(const int socket_handle);
  92. /*************************************************
  93. * Function implementations from now on
  94. *************************************************/
  95. EipStatus NetworkHandlerInitialize(void)
  96. {
  97. if (kEipStatusOk != NetworkHandlerInitializePlatform()) {
  98. return kEipStatusError;
  99. }
  100. SocketTimerArrayInitialize(g_timestamps, OPENER_NUMBER_OF_SUPPORTED_SESSIONS);
  101. /* Activate the current DSCP values to become the used set of values. */
  102. CipQosUpdateUsedSetQosValues();
  103. /* Make sure the multicast configuration matches the current IP address. */
  104. CipTcpIpCalculateMulticastIp(&g_tcpip);
  105. /* Freeze IP and network mask matching to the socket setup. This is needed
  106. * for the off subnet multicast routing check later. */
  107. g_network_status.ip_address = g_tcpip.interface_configuration.ip_address;
  108. g_network_status.network_mask = g_tcpip.interface_configuration.network_mask;
  109. /* Initialize encapsulation layer here because it accesses the IP address. */
  110. EncapsulationInit();
  111. /* clear the master and temp sets */
  112. FD_ZERO(&master_socket);
  113. FD_ZERO(&read_socket);
  114. /* create a new TCP socket */
  115. if ((g_network_status.tcp_listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
  116. int error_code = GetSocketErrorNumber();
  117. char *error_message = GetErrorMessage(error_code);
  118. OPENER_TRACE_ERR("networkhandler tcp_listener: error allocating socket, %d - %s\n", error_code, error_message);
  119. FreeErrorMessage(error_message);
  120. return kEipStatusError;
  121. }
  122. int set_socket_option_value = 1; //Represents true for used set socket options
  123. /* Activates address reuse */
  124. if (setsockopt(g_network_status.tcp_listener, SOL_SOCKET, SO_REUSEADDR, (char *)&set_socket_option_value, sizeof(set_socket_option_value)) == -1) {
  125. OPENER_TRACE_ERR("networkhandler tcp_listener: error setting socket option SO_REUSEADDR\n");
  126. return kEipStatusError;
  127. }
  128. if (SetSocketToNonBlocking(g_network_status.tcp_listener) < 0) {
  129. OPENER_TRACE_ERR("networkhandler tcp_listener: error setting socket to non-blocking on new socket\n");
  130. return kEipStatusError;
  131. }
  132. /* create a new UDP socket */
  133. if ((g_network_status.udp_global_broadcast_listener = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == kEipInvalidSocket) {
  134. int error_code = GetSocketErrorNumber();
  135. char *error_message = GetErrorMessage(error_code);
  136. OPENER_TRACE_ERR("networkhandler udp_global_broadcast_listener: error allocating socket, %d - %s\n", error_code, error_message);
  137. FreeErrorMessage(error_message);
  138. return kEipStatusError;
  139. }
  140. /* create a new UDP socket */
  141. if ((g_network_status.udp_unicast_listener = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == kEipInvalidSocket) {
  142. int error_code = GetSocketErrorNumber();
  143. char *error_message = GetErrorMessage(error_code);
  144. OPENER_TRACE_ERR("networkhandler udp_unicast_listener: error allocating socket, %d - %s\n", error_code, error_message);
  145. FreeErrorMessage(error_message);
  146. return kEipStatusError;
  147. }
  148. /* Activates address reuse */
  149. set_socket_option_value = 1;
  150. if (setsockopt(g_network_status.udp_global_broadcast_listener, SOL_SOCKET, SO_REUSEADDR, (char *)&set_socket_option_value,
  151. sizeof(set_socket_option_value)) == -1) {
  152. OPENER_TRACE_ERR("networkhandler udp_global_broadcast_listener: error setting socket option SO_REUSEADDR\n");
  153. return kEipStatusError;
  154. }
  155. if (SetSocketToNonBlocking(g_network_status.udp_global_broadcast_listener) < 0) {
  156. OPENER_TRACE_ERR("networkhandler udp_global_broadcast_listener: error setting socket to non-blocking on new socket\n");
  157. return kEipStatusError;
  158. }
  159. /* Activates address reuse */
  160. set_socket_option_value = 1;
  161. if (setsockopt(g_network_status.udp_unicast_listener, SOL_SOCKET, SO_REUSEADDR, (char *)&set_socket_option_value, sizeof(set_socket_option_value)) == -1) {
  162. OPENER_TRACE_ERR("networkhandler udp_unicast_listener: error setting socket option SO_REUSEADDR\n");
  163. return kEipStatusError;
  164. }
  165. if (SetSocketToNonBlocking(g_network_status.udp_unicast_listener) < 0) {
  166. OPENER_TRACE_ERR("networkhandler udp_unicast_listener: error setting socket to non-blocking\n");
  167. return kEipStatusError;
  168. }
  169. struct sockaddr_in my_address = { .sin_family = AF_INET, .sin_port = htons(kOpenerEthernetPort), .sin_addr.s_addr = g_network_status.ip_address };
  170. /* bind the new socket to port 0xAF12 (CIP) */
  171. if ((bind(g_network_status.tcp_listener, (struct sockaddr *)&my_address, sizeof(struct sockaddr))) == -1) {
  172. int error_code = GetSocketErrorNumber();
  173. char *error_message = GetErrorMessage(error_code);
  174. OPENER_TRACE_ERR("networkhandler tcp_listener: error with TCP bind: %d - %s\n", error_code, error_message);
  175. FreeErrorMessage(error_message);
  176. return kEipStatusError;
  177. }
  178. if ((bind(g_network_status.udp_unicast_listener, (struct sockaddr *)&my_address, sizeof(struct sockaddr))) == -1) {
  179. int error_code = GetSocketErrorNumber();
  180. char *error_message = GetErrorMessage(error_code);
  181. OPENER_TRACE_ERR("networkhandler udp_unicast_listener: error with UDP bind: %d - %s\n", error_code, error_message);
  182. FreeErrorMessage(error_message);
  183. return kEipStatusError;
  184. }
  185. /* have QoS DSCP explicit appear on UDP responses to unicast messages */
  186. if (SetQosOnSocket(g_network_status.udp_unicast_listener, CipQosGetDscpPriority(kConnectionObjectPriorityExplicit)) != 0) {
  187. int error_code = GetSocketErrorNumber();
  188. char *error_message = GetErrorMessage(error_code);
  189. OPENER_TRACE_ERR("networkhandler udp_unicast_listener: error set QoS %d: %d - %s\n", g_network_status.udp_unicast_listener, error_code, error_message);
  190. FreeErrorMessage(error_message);
  191. /* print message but don't abort by intent */
  192. }
  193. struct sockaddr_in global_broadcast_address = { .sin_family = AF_INET, .sin_port = htons(kOpenerEthernetPort), .sin_addr.s_addr = htonl(INADDR_ANY) };
  194. /* enable the UDP socket to receive broadcast messages */
  195. set_socket_option_value = 1;
  196. if (0 > setsockopt(g_network_status.udp_global_broadcast_listener, SOL_SOCKET, SO_BROADCAST, (char *)&set_socket_option_value, sizeof(int))) {
  197. int error_code = GetSocketErrorNumber();
  198. char *error_message = GetErrorMessage(error_code);
  199. OPENER_TRACE_ERR("networkhandler udp_global_broadcast_listener: error with setting broadcast receive: %d - %s\n", error_code, error_message);
  200. FreeErrorMessage(error_message);
  201. return kEipStatusError;
  202. }
  203. if ((bind(g_network_status.udp_global_broadcast_listener, (struct sockaddr *)&global_broadcast_address, sizeof(struct sockaddr))) == -1) {
  204. int error_code = GetSocketErrorNumber();
  205. char *error_message = GetErrorMessage(error_code);
  206. OPENER_TRACE_ERR("networkhandler udp_global_broadcast_listener: error with UDP bind: %d - %s\n", error_code, error_message);
  207. FreeErrorMessage(error_message);
  208. return kEipStatusError;
  209. }
  210. /* have QoS DSCP explicit appear on UDP responses to broadcast messages */
  211. if (SetQosOnSocket(g_network_status.udp_global_broadcast_listener, CipQosGetDscpPriority(kConnectionObjectPriorityExplicit)) != 0) {
  212. int error_code = GetSocketErrorNumber();
  213. char *error_message = GetErrorMessage(error_code);
  214. OPENER_TRACE_ERR("networkhandler udp_global_broadcast_listener: error set QoS %d: %d - %s\n", g_network_status.udp_global_broadcast_listener,
  215. error_code, error_message);
  216. FreeErrorMessage(error_message);
  217. /* print message but don't abort by intent */
  218. }
  219. /* Make QoS DSCP explicit already appear on SYN connection establishment.
  220. * A newly accept()ed TCP socket inherits the setting from this socket.
  221. */
  222. if (SetQosOnSocket(g_network_status.tcp_listener, CipQosGetDscpPriority(kConnectionObjectPriorityExplicit)) != 0) {
  223. int error_code = GetSocketErrorNumber();
  224. char *error_message = GetErrorMessage(error_code);
  225. OPENER_TRACE_ERR("networkhandler tcp_listener: error set QoS %d: %d - %s\n", g_network_status.tcp_listener, error_code, error_message);
  226. FreeErrorMessage(error_message);
  227. /* print message but don't abort by intent */
  228. }
  229. /* switch socket in listen mode */
  230. if ((listen(g_network_status.tcp_listener, MAX_NO_OF_TCP_SOCKETS)) == -1) {
  231. int error_code = GetSocketErrorNumber();
  232. char *error_message = GetErrorMessage(error_code);
  233. OPENER_TRACE_ERR("networkhandler tcp_listener: error with listen: %d - %s\n", error_code, error_message);
  234. FreeErrorMessage(error_message);
  235. return kEipStatusError;
  236. }
  237. /* add the listener socket to the master set */
  238. FD_SET(g_network_status.tcp_listener, &master_socket);
  239. FD_SET(g_network_status.udp_unicast_listener, &master_socket);
  240. FD_SET(g_network_status.udp_global_broadcast_listener, &master_socket);
  241. /* keep track of the biggest file descriptor */
  242. highest_socket_handle =
  243. GetMaxSocket(g_network_status.tcp_listener, g_network_status.udp_global_broadcast_listener, 0, g_network_status.udp_unicast_listener);
  244. g_last_time = GetMilliSeconds(); /* initialize time keeping */
  245. g_network_status.elapsed_time = 0;
  246. return kEipStatusOk;
  247. }
  248. void CloseUdpSocket(int socket_handle)
  249. {
  250. OPENER_TRACE_STATE("Closing UDP socket %d\n", socket_handle);
  251. CloseSocket(socket_handle);
  252. }
  253. void CloseTcpSocket(int socket_handle)
  254. {
  255. OPENER_TRACE_STATE("Closing TCP socket %d\n", socket_handle);
  256. ShutdownSocketPlatform(socket_handle);
  257. RemoveSocketTimerFromList(socket_handle);
  258. CloseSocket(socket_handle);
  259. }
  260. void RemoveSocketTimerFromList(const int socket_handle)
  261. {
  262. SocketTimer *socket_timer = NULL;
  263. while (NULL != (socket_timer = SocketTimerArrayGetSocketTimer(g_timestamps, OPENER_NUMBER_OF_SUPPORTED_SESSIONS, socket_handle))) {
  264. SocketTimerClear(socket_timer);
  265. }
  266. }
  267. EipBool8 CheckSocketSet(int socket)
  268. {
  269. EipBool8 return_value = false;
  270. if (FD_ISSET(socket, &read_socket)) {
  271. if (FD_ISSET(socket, &master_socket)) {
  272. return_value = true;
  273. } else {
  274. OPENER_TRACE_INFO("socket: %d closed with pending message\n", socket);
  275. }
  276. FD_CLR(socket, &read_socket);
  277. /* remove it from the read set so that later checks will not find it */
  278. }
  279. return return_value;
  280. }
  281. void CheckAndHandleTcpListenerSocket(void)
  282. {
  283. int new_socket = kEipInvalidSocket;
  284. /* see if this is a connection request to the TCP listener*/
  285. if (true == CheckSocketSet(g_network_status.tcp_listener)) {
  286. OPENER_TRACE_INFO("networkhandler: new TCP connection\n");
  287. new_socket = accept(g_network_status.tcp_listener, NULL, NULL);
  288. if (new_socket == kEipInvalidSocket) {
  289. int error_code = GetSocketErrorNumber();
  290. char *error_message = GetErrorMessage(error_code);
  291. OPENER_TRACE_ERR("networkhandler: error on accept: %d - %s\n", error_code, error_message);
  292. FreeErrorMessage(error_message);
  293. return;
  294. }
  295. OPENER_TRACE_INFO(">>> network handler: accepting new TCP socket: %d \n", new_socket);
  296. SocketTimer *socket_timer = SocketTimerArrayGetEmptySocketTimer(g_timestamps, OPENER_NUMBER_OF_SUPPORTED_SESSIONS);
  297. // OPENER_TRACE_INFO("Current time stamp: %ld\n", g_actual_time);
  298. // for(size_t i = 0; i < OPENER_NUMBER_OF_SUPPORTED_SESSIONS; i++) {
  299. // OPENER_TRACE_INFO("Socket: %d - Last Update: %ld\n",
  300. // g_timestamps[i].socket,
  301. // g_timestamps[i].last_update);
  302. // }
  303. OPENER_ASSERT(socket_timer != NULL);
  304. FD_SET(new_socket, &master_socket);
  305. /* add newfd to master set */
  306. if (new_socket > highest_socket_handle) {
  307. OPENER_TRACE_INFO("New highest socket: %d\n", new_socket);
  308. highest_socket_handle = new_socket;
  309. }
  310. OPENER_TRACE_STATE("networkhandler: opened new TCP connection on fd %d\n", new_socket);
  311. }
  312. }
  313. EipStatus NetworkHandlerProcessCyclic(void)
  314. {
  315. read_socket = master_socket;
  316. g_time_value.tv_sec = 0;
  317. g_time_value.tv_usec =
  318. (g_network_status.elapsed_time < kOpenerTimerTickInMilliSeconds ? kOpenerTimerTickInMilliSeconds - g_network_status.elapsed_time : 0) *
  319. 1000; /* 10 ms */
  320. int ready_socket = select(highest_socket_handle + 1, &read_socket, 0, 0, &g_time_value);
  321. if (ready_socket == kEipInvalidSocket) {
  322. if (EINTR == errno) /* we have somehow been interrupted. The default behavior is to go back into the select loop. */
  323. {
  324. return kEipStatusOk;
  325. } else {
  326. int error_code = GetSocketErrorNumber();
  327. char *error_message = GetErrorMessage(error_code);
  328. OPENER_TRACE_ERR("networkhandler: error with select: %d - %s\n", error_code, error_message);
  329. FreeErrorMessage(error_message);
  330. return kEipStatusError;
  331. }
  332. }
  333. if (ready_socket > 0) {
  334. CheckAndHandleTcpListenerSocket();
  335. CheckAndHandleUdpUnicastSocket();
  336. CheckAndHandleUdpGlobalBroadcastSocket();
  337. CheckAndHandleConsumingUdpSocket();
  338. for (int socket = 0; socket <= highest_socket_handle; socket++) {
  339. if (true == CheckSocketSet(socket)) {
  340. /* if it is still checked it is a TCP receive */
  341. if (kEipStatusError == HandleDataOnTcpSocket(socket)) /* if error */
  342. {
  343. CloseTcpSocket(socket);
  344. RemoveSession(socket); /* clean up session and close the socket */
  345. }
  346. }
  347. }
  348. }
  349. for (int socket = 0; socket <= highest_socket_handle; socket++) {
  350. CheckEncapsulationInactivity(socket);
  351. }
  352. /* Check if all connections from one originator times out */
  353. //CheckForTimedOutConnectionsAndCloseTCPConnections();
  354. //OPENER_TRACE_INFO("Socket Loop done\n");
  355. g_actual_time = GetMilliSeconds();
  356. g_network_status.elapsed_time += g_actual_time - g_last_time;
  357. g_last_time = g_actual_time;
  358. //OPENER_TRACE_INFO("Elapsed time: %u\n", g_network_status.elapsed_time);
  359. /* check if we had been not able to update the connection manager for several kOpenerTimerTickInMilliSeconds.
  360. * This should compensate the jitter of the windows timer
  361. */
  362. if (g_network_status.elapsed_time >= kOpenerTimerTickInMilliSeconds) {
  363. /* call manage_connections() in connection manager every kOpenerTimerTickInMilliSeconds ms */
  364. ManageConnections(g_network_status.elapsed_time);
  365. /* Call timeout checker functions registered in timeout_checker_array */
  366. for (size_t i = 0; i < OPENER_TIMEOUT_CHECKER_ARRAY_SIZE; i++) {
  367. if (NULL != timeout_checker_array[i]) {
  368. (timeout_checker_array[i])(g_network_status.elapsed_time);
  369. }
  370. }
  371. g_network_status.elapsed_time = 0;
  372. }
  373. return kEipStatusOk;
  374. }
  375. EipStatus NetworkHandlerFinish(void)
  376. {
  377. CloseTcpSocket(g_network_status.tcp_listener);
  378. CloseUdpSocket(g_network_status.udp_unicast_listener);
  379. CloseUdpSocket(g_network_status.udp_global_broadcast_listener);
  380. return kEipStatusOk;
  381. }
  382. void CheckAndHandleUdpGlobalBroadcastSocket(void)
  383. {
  384. /* see if this is an unsolicited inbound UDP message */
  385. if (true == CheckSocketSet(g_network_status.udp_global_broadcast_listener)) {
  386. struct sockaddr_in from_address = { 0 };
  387. socklen_t from_address_length = sizeof(from_address);
  388. OPENER_TRACE_STATE("networkhandler: unsolicited UDP message on EIP global broadcast socket\n");
  389. /* Handle UDP broadcast messages */
  390. CipOctet incoming_message[PC_OPENER_ETHERNET_BUFFER_SIZE] = { 0 };
  391. int received_size = recvfrom(g_network_status.udp_global_broadcast_listener, NWBUF_CAST incoming_message, sizeof(incoming_message), 0,
  392. (struct sockaddr *)&from_address, &from_address_length);
  393. if (received_size <= 0) { /* got error */
  394. int error_code = GetSocketErrorNumber();
  395. char *error_message = GetErrorMessage(error_code);
  396. OPENER_TRACE_ERR("networkhandler: error on recvfrom UDP global broadcast port: %d - %s\n", error_code, error_message);
  397. FreeErrorMessage(error_message);
  398. return;
  399. }
  400. OPENER_TRACE_INFO("Data received on global broadcast UDP:\n");
  401. const EipUint8 *receive_buffer = &incoming_message[0];
  402. int remaining_bytes = 0;
  403. ENIPMessage outgoing_message;
  404. InitializeENIPMessage(&outgoing_message);
  405. EipStatus need_to_send = HandleReceivedExplictUdpData(g_network_status.udp_unicast_listener,
  406. /* sending from unicast port, due to strange behavior of the broadcast port */
  407. &from_address, receive_buffer, received_size, &remaining_bytes, false, &outgoing_message);
  408. receive_buffer += received_size - remaining_bytes;
  409. received_size = remaining_bytes;
  410. if (need_to_send > 0) {
  411. OPENER_TRACE_INFO("UDP broadcast reply sent:\n");
  412. /* if the active socket matches a registered UDP callback, handle a UDP packet */
  413. if (sendto(g_network_status.udp_unicast_listener, /* sending from unicast port, due to strange behavior of the broadcast port */
  414. (char *)outgoing_message.message_buffer, outgoing_message.used_message_length, 0, (struct sockaddr *)&from_address,
  415. sizeof(from_address)) != outgoing_message.used_message_length) {
  416. OPENER_TRACE_INFO("networkhandler: UDP response was not fully sent\n");
  417. }
  418. }
  419. if (remaining_bytes > 0) {
  420. OPENER_TRACE_ERR("Request on broadcast UDP port had too many data (%d)", remaining_bytes);
  421. }
  422. }
  423. }
  424. void CheckAndHandleUdpUnicastSocket(void)
  425. {
  426. /* see if this is an unsolicited inbound UDP message */
  427. if (true == CheckSocketSet(g_network_status.udp_unicast_listener)) {
  428. struct sockaddr_in from_address = { 0 };
  429. socklen_t from_address_length = sizeof(from_address);
  430. OPENER_TRACE_STATE("networkhandler: unsolicited UDP message on EIP unicast socket\n");
  431. /* Handle UDP broadcast messages */
  432. CipOctet incoming_message[PC_OPENER_ETHERNET_BUFFER_SIZE] = { 0 };
  433. int received_size = recvfrom(g_network_status.udp_unicast_listener, NWBUF_CAST incoming_message, sizeof(incoming_message), 0,
  434. (struct sockaddr *)&from_address, &from_address_length);
  435. if (received_size <= 0) { /* got error */
  436. int error_code = GetSocketErrorNumber();
  437. char *error_message = GetErrorMessage(error_code);
  438. OPENER_TRACE_ERR("networkhandler: error on recvfrom UDP unicast port: %d - %s\n", error_code, error_message);
  439. FreeErrorMessage(error_message);
  440. return;
  441. }
  442. OPENER_TRACE_INFO("Data received on UDP unicast:\n");
  443. EipUint8 *receive_buffer = &incoming_message[0];
  444. int remaining_bytes = 0;
  445. ENIPMessage outgoing_message;
  446. InitializeENIPMessage(&outgoing_message);
  447. EipStatus need_to_send = HandleReceivedExplictUdpData(g_network_status.udp_unicast_listener, &from_address, receive_buffer, received_size,
  448. &remaining_bytes, true, &outgoing_message);
  449. receive_buffer += received_size - remaining_bytes;
  450. received_size = remaining_bytes;
  451. if (need_to_send > 0) {
  452. OPENER_TRACE_INFO("UDP unicast reply sent:\n");
  453. /* if the active socket matches a registered UDP callback, handle a UDP packet */
  454. if (sendto(g_network_status.udp_unicast_listener, (char *)outgoing_message.message_buffer, outgoing_message.used_message_length, 0,
  455. (struct sockaddr *)&from_address, sizeof(from_address)) != outgoing_message.used_message_length) {
  456. OPENER_TRACE_INFO("networkhandler: UDP unicast response was not fully sent\n");
  457. }
  458. }
  459. if (remaining_bytes > 0) {
  460. OPENER_TRACE_ERR("Request on broadcast UDP port had too many data (%d)", remaining_bytes);
  461. }
  462. }
  463. }
  464. EipStatus SendUdpData(const struct sockaddr_in *const address, const ENIPMessage *const outgoing_message)
  465. {
  466. #if defined(OPENER_TRACE_ENABLED)
  467. static char ip_str[INET_ADDRSTRLEN];
  468. OPENER_TRACE_INFO("UDP packet to be sent to: %s:%d\n", inet_ntop(AF_INET, &address->sin_addr, ip_str, sizeof ip_str), ntohs(address->sin_port));
  469. #endif
  470. int sent_length = sendto(g_network_status.udp_io_messaging, (char *)outgoing_message->message_buffer, outgoing_message->used_message_length, 0,
  471. (struct sockaddr *)address, sizeof(*address));
  472. if (sent_length < 0) {
  473. int error_code = GetSocketErrorNumber();
  474. char *error_message = GetErrorMessage(error_code);
  475. OPENER_TRACE_ERR("networkhandler: error with sendto in SendUDPData: %d - %s\n", error_code, error_message);
  476. FreeErrorMessage(error_message);
  477. return kEipStatusError;
  478. }
  479. if (sent_length != outgoing_message->used_message_length) {
  480. OPENER_TRACE_WARN("data length sent_length mismatch; probably not all data was sent in SendUdpData, sent %d of %d\n", sent_length,
  481. outgoing_message->used_message_length);
  482. return kEipStatusError;
  483. }
  484. return kEipStatusOk;
  485. }
  486. EipStatus HandleDataOnTcpSocket(int socket)
  487. {
  488. OPENER_TRACE_INFO("Entering HandleDataOnTcpSocket for socket: %d\n", socket);
  489. int remaining_bytes = 0;
  490. long data_sent = PC_OPENER_ETHERNET_BUFFER_SIZE;
  491. /* We will handle just one EIP packet here the rest is done by the select
  492. * method which will inform us if more data is available in the socket
  493. because of the current implementation of the main loop this may not be
  494. the fastest way and a loop here with a non blocking socket would better
  495. fit*/
  496. /*Check how many data is here -- read the first four bytes from the connection */
  497. CipOctet incoming_message[PC_OPENER_ETHERNET_BUFFER_SIZE] = { 0 };
  498. long number_of_read_bytes = recv(socket, NWBUF_CAST incoming_message, 4, 0); /*TODO we may have to set the socket to a non blocking socket */
  499. SocketTimer *const socket_timer = SocketTimerArrayGetSocketTimer(g_timestamps, OPENER_NUMBER_OF_SUPPORTED_SESSIONS, socket);
  500. if (number_of_read_bytes == 0) {
  501. OPENER_TRACE_ERR("networkhandler: socket: %d - connection closed by client.\n", socket);
  502. RemoveSocketTimerFromList(socket);
  503. RemoveSession(socket);
  504. return kEipStatusError;
  505. }
  506. if (number_of_read_bytes < 0) {
  507. int error_code = GetSocketErrorNumber();
  508. if (OPENER_SOCKET_WOULD_BLOCK == error_code) {
  509. return kEipStatusOk;
  510. }
  511. char *error_message = GetErrorMessage(error_code);
  512. OPENER_TRACE_ERR("networkhandler: error on recv: %d - %s\n", error_code, error_message);
  513. FreeErrorMessage(error_message);
  514. return kEipStatusError;
  515. }
  516. const EipUint8 *read_buffer = &incoming_message[2]; /* at this place EIP stores the data length */
  517. size_t data_size = GetUintFromMessage(&read_buffer) + ENCAPSULATION_HEADER_LENGTH - 4; /* -4 is for the 4 bytes we have already read*/
  518. /* (NOTE this advances the buffer pointer) */
  519. if ((PC_OPENER_ETHERNET_BUFFER_SIZE - 4) < data_size) { /*TODO can this be handled in a better way?*/
  520. OPENER_TRACE_ERR("too large packet received will be ignored, will drop the data\n");
  521. /* Currently we will drop the whole packet */
  522. do {
  523. OPENER_TRACE_INFO("Entering consumption loop, remaining data to receive: %ld\n", data_sent);
  524. number_of_read_bytes = recv(socket, NWBUF_CAST & incoming_message[0], data_sent, 0);
  525. if (number_of_read_bytes == 0) /* got error or connection closed by client */
  526. {
  527. int error_code = GetSocketErrorNumber();
  528. char *error_message = GetErrorMessage(error_code);
  529. OPENER_TRACE_ERR("networkhandler: socket: %d - connection closed by client: %d - %s\n", socket, error_code, error_message);
  530. FreeErrorMessage(error_message);
  531. RemoveSocketTimerFromList(socket);
  532. return kEipStatusError;
  533. }
  534. if (number_of_read_bytes < 0) {
  535. int error_code = GetSocketErrorNumber();
  536. char *error_message = GetErrorMessage(error_code);
  537. if (OPENER_SOCKET_WOULD_BLOCK == error_code) {
  538. return kEipStatusOk;
  539. }
  540. OPENER_TRACE_ERR("networkhandler: error on recv: %d - %s\n", error_code, error_message);
  541. FreeErrorMessage(error_message);
  542. return kEipStatusError;
  543. }
  544. data_size -= number_of_read_bytes;
  545. if ((data_size < PC_OPENER_ETHERNET_BUFFER_SIZE) && (data_size != 0)) {
  546. data_sent = data_size;
  547. }
  548. } while (0 < data_size);
  549. SocketTimerSetLastUpdate(socket_timer, g_actual_time);
  550. return kEipStatusOk;
  551. }
  552. number_of_read_bytes = recv(socket, NWBUF_CAST & incoming_message[4], data_size, 0);
  553. if (0 == number_of_read_bytes) /* got error or connection closed by client */
  554. {
  555. int error_code = GetSocketErrorNumber();
  556. char *error_message = GetErrorMessage(error_code);
  557. OPENER_TRACE_ERR("networkhandler: socket: %d - connection closed by client: %d - %s\n", socket, error_code, error_message);
  558. FreeErrorMessage(error_message);
  559. RemoveSocketTimerFromList(socket);
  560. RemoveSession(socket);
  561. return kEipStatusError;
  562. }
  563. if (number_of_read_bytes < 0) {
  564. int error_code = GetSocketErrorNumber();
  565. char *error_message = GetErrorMessage(error_code);
  566. if (OPENER_SOCKET_WOULD_BLOCK == error_code) {
  567. return kEipStatusOk;
  568. }
  569. OPENER_TRACE_ERR("networkhandler: error on recv: %d - %s\n", error_code, error_message);
  570. FreeErrorMessage(error_message);
  571. return kEipStatusError;
  572. }
  573. if ((unsigned)number_of_read_bytes == data_size) {
  574. /*we got the right amount of data */
  575. data_size += 4;
  576. /*TODO handle partial packets*/
  577. OPENER_TRACE_INFO("Data received on TCP: %" PRIuSZT "\n", data_size);
  578. g_current_active_tcp_socket = socket;
  579. struct sockaddr sender_address;
  580. memset(&sender_address, 0, sizeof(sender_address));
  581. socklen_t fromlen = sizeof(sender_address);
  582. if (getpeername(socket, (struct sockaddr *)&sender_address, &fromlen) < 0) {
  583. int error_code = GetSocketErrorNumber();
  584. char *error_message = GetErrorMessage(error_code);
  585. OPENER_TRACE_ERR("networkhandler: could not get peername: %d - %s\n", error_code, error_message);
  586. FreeErrorMessage(error_message);
  587. }
  588. ENIPMessage outgoing_message;
  589. InitializeENIPMessage(&outgoing_message);
  590. EipStatus need_to_send = HandleReceivedExplictTcpData(socket, incoming_message, data_size, &remaining_bytes, &sender_address, &outgoing_message);
  591. if (NULL != socket_timer) {
  592. SocketTimerSetLastUpdate(socket_timer, g_actual_time);
  593. }
  594. g_current_active_tcp_socket = kEipInvalidSocket;
  595. if (remaining_bytes != 0) {
  596. OPENER_TRACE_WARN("Warning: received packet was to long: %d Bytes left!\n", remaining_bytes);
  597. }
  598. if (need_to_send > 0) {
  599. OPENER_TRACE_INFO("TCP reply: send %" PRIuSZT " bytes on %d\n", outgoing_message.used_message_length, socket);
  600. data_sent = send(socket, (char *)outgoing_message.message_buffer, outgoing_message.used_message_length, MSG_NOSIGNAL);
  601. SocketTimerSetLastUpdate(socket_timer, g_actual_time);
  602. if (data_sent != outgoing_message.used_message_length) {
  603. OPENER_TRACE_WARN("TCP response was not fully sent: exp %" PRIuSZT ", sent %ld\n", outgoing_message.used_message_length, data_sent);
  604. }
  605. }
  606. return kEipStatusOk;
  607. } else {
  608. /* we got a fragmented packet currently we cannot handle this will
  609. * for this we would need a network buffer per TCP socket
  610. *
  611. * However with typical packet sizes of EIP this shouldn't be a big issue.
  612. */
  613. /*TODO handle fragmented packets */
  614. }
  615. return kEipStatusError;
  616. }
  617. /** @brief Create the UDP socket for the implicit IO messaging, one socket handles all connections
  618. *
  619. * @return the socket handle if successful, else kEipInvalidSocket */
  620. int CreateUdpSocket(void)
  621. {
  622. /* create a new UDP socket */
  623. g_network_status.udp_io_messaging = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  624. if (g_network_status.udp_io_messaging == kEipInvalidSocket) {
  625. int error_code = GetSocketErrorNumber();
  626. char *error_message = GetErrorMessage(error_code);
  627. OPENER_TRACE_ERR("networkhandler: cannot create UDP socket: %d- %s\n", error_code, error_message);
  628. FreeErrorMessage(error_message);
  629. return kEipInvalidSocket;
  630. }
  631. if (SetSocketToNonBlocking(g_network_status.udp_io_messaging) < 0) {
  632. OPENER_TRACE_ERR("networkhandler udp_io_messaging: error setting socket to non-blocking on new socket\n");
  633. CloseUdpSocket(g_network_status.udp_io_messaging);
  634. OPENER_ASSERT(false); /* This should never happen! */
  635. return kEipInvalidSocket;
  636. }
  637. OPENER_TRACE_INFO("networkhandler: UDP socket %d\n", g_network_status.udp_io_messaging);
  638. int option_value = 1;
  639. if (setsockopt(g_network_status.udp_io_messaging, SOL_SOCKET, SO_REUSEADDR, (char *)&option_value, sizeof(option_value)) < 0) {
  640. OPENER_TRACE_ERR("error setting socket option SO_REUSEADDR on %s UDP socket\n");
  641. CloseUdpSocket(g_network_status.udp_io_messaging);
  642. return kEipInvalidSocket;
  643. }
  644. /* The bind on UDP sockets is necessary as the ENIP spec wants the source port to be specified to 2222 */
  645. struct sockaddr_in source_addr = { .sin_family = AF_INET, .sin_addr.s_addr = htonl(INADDR_ANY), .sin_port = htons(kOpenerEipIoUdpPort) };
  646. if (bind(g_network_status.udp_io_messaging, (struct sockaddr *)&source_addr, sizeof(source_addr)) < 0) {
  647. int error_code = GetSocketErrorNumber();
  648. char *error_message = GetErrorMessage(error_code);
  649. OPENER_TRACE_ERR("error on bind UDP for producing messages: %d - %s\n", error_code, error_message);
  650. FreeErrorMessage(error_message);
  651. CloseUdpSocket(g_network_status.udp_io_messaging);
  652. return kEipInvalidSocket;
  653. }
  654. /* add new socket to the master list */
  655. FD_SET(g_network_status.udp_io_messaging, &master_socket);
  656. if (g_network_status.udp_io_messaging > highest_socket_handle) {
  657. OPENER_TRACE_INFO("New highest socket: %d\n", g_network_status.udp_io_messaging);
  658. highest_socket_handle = g_network_status.udp_io_messaging;
  659. }
  660. return g_network_status.udp_io_messaging;
  661. }
  662. /** @brief Set the Qos the socket for implicit IO messaging
  663. *
  664. * @return 0 if successful, else the error code */
  665. int SetQos(CipUsint qos_for_socket)
  666. {
  667. if (SetQosOnSocket(g_network_status.udp_io_messaging, CipQosGetDscpPriority(qos_for_socket)) != 0) { /* got error */
  668. int error_code = GetSocketErrorNumber();
  669. char *error_message = GetErrorMessage(error_code);
  670. OPENER_TRACE_ERR("networkhandler: error on set QoS on socket: %d - %s\n", error_code, error_message);
  671. return error_code;
  672. }
  673. return 0;
  674. }
  675. /** @brief Set the socket options for Multicast Producer
  676. *
  677. * @return 0 if successful, else the error code */
  678. int SetSocketOptionsMulticastProduce(void)
  679. {
  680. if (g_tcpip.mcast_ttl_value != 1) {
  681. /* we need to set a TTL value for the socket */
  682. if (setsockopt(g_network_status.udp_io_messaging, IPPROTO_IP, IP_MULTICAST_TTL, NWBUF_CAST & g_tcpip.mcast_ttl_value, sizeof(g_tcpip.mcast_ttl_value)) <
  683. 0) {
  684. int error_code = GetSocketErrorNumber();
  685. char *error_message = GetErrorMessage(error_code);
  686. OPENER_TRACE_ERR("networkhandler: could not set the TTL to: %d, error: %d - %s\n", g_tcpip.mcast_ttl_value, error_code, error_message);
  687. FreeErrorMessage(error_message);
  688. return error_code;
  689. }
  690. }
  691. /* Need to specify the interface for outgoing multicast packets on a
  692. device with multiple interfaces. */
  693. struct in_addr my_addr = { .s_addr = g_network_status.ip_address };
  694. if (setsockopt(g_network_status.udp_io_messaging, IPPROTO_IP, IP_MULTICAST_IF, NWBUF_CAST & my_addr.s_addr, sizeof my_addr.s_addr) < 0) {
  695. int error_code = GetSocketErrorNumber();
  696. char *error_message = GetErrorMessage(error_code);
  697. OPENER_TRACE_ERR("networkhandler: could not set the multicast interface, error: %d "
  698. "- %s\n",
  699. error_code, error_message);
  700. FreeErrorMessage(error_message);
  701. return error_code;
  702. }
  703. return 0;
  704. }
  705. /** @brief Get the peer address
  706. *
  707. * @return peer address if successful, else any address (0) */
  708. EipUint32 GetPeerAddress(void)
  709. {
  710. struct sockaddr_in peer_address;
  711. socklen_t peer_address_length = sizeof(peer_address);
  712. if (getpeername(g_current_active_tcp_socket, (struct sockaddr *)&peer_address, &peer_address_length) < 0) {
  713. int error_code = GetSocketErrorNumber();
  714. char *error_message = GetErrorMessage(error_code);
  715. OPENER_TRACE_ERR("networkhandler: could not get peername: %d - %s\n", error_code, error_message);
  716. FreeErrorMessage(error_message);
  717. return htonl(INADDR_ANY);
  718. }
  719. return peer_address.sin_addr.s_addr;
  720. }
  721. void CheckAndHandleConsumingUdpSocket(void)
  722. {
  723. DoublyLinkedListNode *iterator = connection_list.first;
  724. CipConnectionObject *current_connection_object = NULL;
  725. /* see a message of the registered UDP socket has been received */
  726. while (NULL != iterator) {
  727. current_connection_object = (CipConnectionObject *)iterator->data;
  728. iterator = iterator->next; /* do this at the beginning as the close function may can make the entry invalid */
  729. if ((kEipInvalidSocket != current_connection_object->socket[kUdpCommuncationDirectionConsuming]) &&
  730. (true == CheckSocketSet(current_connection_object->socket[kUdpCommuncationDirectionConsuming]))) {
  731. OPENER_TRACE_INFO("Processing UDP consuming message\n");
  732. struct sockaddr_in from_address = { 0 };
  733. socklen_t from_address_length = sizeof(from_address);
  734. CipOctet incoming_message[PC_OPENER_ETHERNET_BUFFER_SIZE] = { 0 };
  735. int received_size = recvfrom(g_network_status.udp_io_messaging, NWBUF_CAST incoming_message, sizeof(incoming_message), 0,
  736. (struct sockaddr *)&from_address, &from_address_length);
  737. if (0 == received_size) {
  738. int error_code = GetSocketErrorNumber();
  739. char *error_message = GetErrorMessage(error_code);
  740. OPENER_TRACE_ERR("networkhandler: socket: %d - connection closed by client: %d - %s\n",
  741. current_connection_object->socket[kUdpCommuncationDirectionConsuming], error_code, error_message);
  742. FreeErrorMessage(error_message);
  743. current_connection_object->connection_close_function(current_connection_object);
  744. continue;
  745. }
  746. if (0 > received_size) {
  747. int error_code = GetSocketErrorNumber();
  748. char *error_message = GetErrorMessage(error_code);
  749. if (OPENER_SOCKET_WOULD_BLOCK == error_code) {
  750. return; // No fatal error, resume execution
  751. }
  752. OPENER_TRACE_ERR("networkhandler: error on recv: %d - %s\n", error_code, error_message);
  753. FreeErrorMessage(error_message);
  754. current_connection_object->connection_close_function(current_connection_object);
  755. continue;
  756. }
  757. HandleReceivedConnectedData(incoming_message, received_size, &from_address);
  758. }
  759. }
  760. }
  761. void CloseSocket(const int socket_handle)
  762. {
  763. OPENER_TRACE_INFO("networkhandler: closing socket %d\n", socket_handle);
  764. if (kEipInvalidSocket != socket_handle) {
  765. FD_CLR(socket_handle, &master_socket);
  766. CloseSocketPlatform(socket_handle);
  767. }
  768. OPENER_TRACE_INFO("networkhandler: closing socket done %d\n", socket_handle);
  769. }
  770. int GetMaxSocket(int socket1, int socket2, int socket3, int socket4)
  771. {
  772. if ((socket1 > socket2) && (socket1 > socket3) && (socket1 > socket4)) {
  773. return socket1;
  774. }
  775. if ((socket2 > socket1) && (socket2 > socket3) && (socket2 > socket4)) {
  776. return socket2;
  777. }
  778. if ((socket3 > socket1) && (socket3 > socket2) && (socket3 > socket4)) {
  779. return socket3;
  780. }
  781. return socket4;
  782. }
  783. void CheckEncapsulationInactivity(int socket_handle)
  784. {
  785. if (0 < g_tcpip.encapsulation_inactivity_timeout) { //*< Encapsulation inactivity timeout is enabled
  786. SocketTimer *socket_timer = SocketTimerArrayGetSocketTimer(g_timestamps, OPENER_NUMBER_OF_SUPPORTED_SESSIONS, socket_handle);
  787. if (NULL != socket_timer) {
  788. MilliSeconds diff_milliseconds = g_actual_time - SocketTimerGetLastUpdate(socket_timer);
  789. if (diff_milliseconds >= (MilliSeconds)(1000UL * g_tcpip.encapsulation_inactivity_timeout)) {
  790. CipSessionHandle encapsulation_session_handle = GetSessionFromSocket(socket_handle);
  791. CloseClass3ConnectionBasedOnSession(encapsulation_session_handle);
  792. CloseTcpSocket(socket_handle);
  793. RemoveSession(socket_handle);
  794. }
  795. }
  796. }
  797. }
  798. void RegisterTimeoutChecker(TimeoutCheckerFunction timeout_checker_function)
  799. {
  800. for (size_t i = 0; i < OPENER_TIMEOUT_CHECKER_ARRAY_SIZE; i++) {
  801. if (NULL == timeout_checker_array[i]) { // find empty array element
  802. timeout_checker_array[i] = timeout_checker_function; // add function pointer to array
  803. break;
  804. }
  805. }
  806. }