OpENer - Open Source EtherNet/IP(TM) I/O Target Stack  2.1
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
generic_networkhandler.c
Go to the documentation of this file.
1 /*******************************************************************************
2  * Copyright (c) 2009, Rockwell Automation, Inc.
3  * All rights reserved.
4  *
5  ******************************************************************************/
6 
14 #include <assert.h>
15 #include <stdbool.h>
16 
17 #include "generic_networkhandler.h"
18 
19 #include "typedefs.h"
20 #include "trace.h"
21 #include "opener_error.h"
22 #include "encap.h"
23 #include "ciptcpipinterface.h"
24 #include "opener_user_conf.h"
25 #include "cipqos.h"
26 #include "udp_protocol.h"
27 
28 #define MAX_NO_OF_TCP_SOCKETS 10
29 
31 
36 
41 
46 
51 
58 
59 void CheckEncapsulationInactivity(int socket_handle);
60 
61 void RemoveSocketTimerFromList(const int socket_handle);
62 
63 /*************************************************
64 * Function implementations from now on
65 *************************************************/
66 
68 
70  return kEipStatusError;
71  }
72 
74 
75  /* clear the master an temp sets */
76  FD_ZERO(&master_socket);
77  FD_ZERO(&read_socket);
78 
79  /* create a new TCP socket */
81  socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) )
82  == -1 ) {
83  int error_code = GetSocketErrorNumber();
84  char *error_message = GetErrorMessage(error_code);
85  OPENER_TRACE_ERR("error allocating socket stream listener, %d - %s\n",
86  error_code,
87  error_message);
88  FreeErrorMessage(error_message);
89  return kEipStatusError;
90  }
91 
92  int set_socket_option_value = 1; //Represents true for used set socket options
93  /* Activates address reuse */
94  if (setsockopt( g_network_status.tcp_listener, SOL_SOCKET, SO_REUSEADDR,
95  (char *) &set_socket_option_value,
96  sizeof(set_socket_option_value) ) == -1) {
98  "error setting socket option SO_REUSEADDR on tcp_listener\n");
99  return kEipStatusError;
100  }
101 
104  "error setting socket to non-blocking on new socket\n");
105  return kEipStatusError;
106  }
107 
108  /* create a new UDP socket */
110  SOCK_DGRAM,
111  IPPROTO_UDP) )
112  == kEipInvalidSocket ) {
113  int error_code = GetSocketErrorNumber();
114  char *error_message = GetErrorMessage(error_code);
116  "error allocating UDP global broadcast listener socket, %d - %s\n",
117  error_code,
118  error_message);
119  FreeErrorMessage(error_message);
120  return kEipStatusError;
121  }
122 
123  /* create a new UDP socket */
124  if ( ( g_network_status.udp_unicast_listener = socket(AF_INET, SOCK_DGRAM,
125  IPPROTO_UDP) ) ==
126  kEipInvalidSocket ) {
127  int error_code = GetSocketErrorNumber();
128  char *error_message = GetErrorMessage(error_code);
129  OPENER_TRACE_ERR("error allocating UDP unicast listener socket, %d - %s\n",
130  error_code, error_message);
131  FreeErrorMessage(error_message);
132  return kEipStatusError;
133  }
134 
135  /* Activates address reuse */
136  if (setsockopt( g_network_status.udp_global_broadcast_listener, SOL_SOCKET,
137  SO_REUSEADDR, (char *) &set_socket_option_value,
138  sizeof(set_socket_option_value) ) == -1) {
140  "error setting socket option SO_REUSEADDR on udp_broadcast_listener\n");
141  return kEipStatusError;
142  }
143 
145  0) {
147  "error setting socket to non-blocking on new socket\n");
148  return kEipStatusError;
149  }
150 
151  /* Activates address reuse */
152  if (setsockopt( g_network_status.udp_unicast_listener, SOL_SOCKET,
153  SO_REUSEADDR, (char *) &set_socket_option_value,
154  sizeof(set_socket_option_value) ) == -1) {
156  "error setting socket option SO_REUSEADDR on udp_unicast_listener\n");
157  return kEipStatusError;
158  }
159 
162  "error setting socket to non-blocking on udp_unicast_listener\n");
163  return kEipStatusError;
164  }
165 
166  struct sockaddr_in my_address = { .sin_family = AF_INET, .sin_port = htons(
167  kOpenerEthernetPort),
168  .sin_addr.s_addr = interface_configuration_
169  .
170  ip_address };
171 
172  /* bind the new socket to port 0xAF12 (CIP) */
173  if ( ( bind( g_network_status.tcp_listener, (struct sockaddr *) &my_address,
174  sizeof(struct sockaddr) ) ) == -1 ) {
175  int error_code = GetSocketErrorNumber();
176  char *error_message = GetErrorMessage(error_code);
177  OPENER_TRACE_ERR("error with TCP bind: %d - %s\n", error_code,
178  error_message);
179  FreeErrorMessage(error_message);
180  return kEipStatusError;
181  }
182 
184  (struct sockaddr *) &my_address,
185  sizeof(struct sockaddr) ) ) == -1 ) {
186  int error_code = GetSocketErrorNumber();
187  char *error_message = GetErrorMessage(error_code);
188  OPENER_TRACE_ERR( "error with UDP unicast bind: %d - %s\n", error_code,
190  error_code) );
191  FreeErrorMessage(error_message);
192  return kEipStatusError;
193  }
194 
195  struct sockaddr_in global_broadcast_address = { .sin_family = {AF_INET},
196  .sin_port = htons(
197  kOpenerEthernetPort),
198  .sin_addr.s_addr = htonl(
199  INADDR_ANY) };
200 
201  /* enable the UDP socket to receive broadcast messages */
202  if ( 0
203  > setsockopt( g_network_status.udp_global_broadcast_listener, SOL_SOCKET,
204  SO_BROADCAST,
205  (char *) &set_socket_option_value, sizeof(int) ) ) {
206  int error_code = GetSocketErrorNumber();
207  char *error_message = GetErrorMessage(error_code);
209  "error with setting broadcast receive for UDP socket: %d - %s\n",
210  error_code, error_message);
211  FreeErrorMessage(error_message);
212  return kEipStatusError;
213  }
214 
216  (struct sockaddr *) &global_broadcast_address,
217  sizeof(struct sockaddr) ) ) == -1 ) {
218  int error_code = GetSocketErrorNumber();
219  char *error_message = GetErrorMessage(error_code);
220  OPENER_TRACE_ERR("error with global broadcast UDP bind: %d - %s\n",
221  error_code,
222  error_message);
223  FreeErrorMessage(error_message);
224  return kEipStatusError;
225  }
226 
227  /* switch socket in listen mode */
228  if ( ( listen(g_network_status.tcp_listener,
229  MAX_NO_OF_TCP_SOCKETS) ) == -1 ) {
230  int error_code = GetSocketErrorNumber();
231  char *error_message = GetErrorMessage(error_code);
232  OPENER_TRACE_ERR("networkhandler: error with listen: %d - %s\n",
233  error_code,
234  error_message);
235  FreeErrorMessage(error_message);
236  return kEipStatusError;
237  }
238 
239  /* add the listener socket to the master set */
243 
244  /* keep track of the biggest file descriptor */
248  0,
250 
251  g_last_time = GetMilliSeconds(); /* initialize time keeping */
253 
254  return kEipStatusOk;
255 }
256 
257 void CloseUdpSocket(int socket_handle) {
258  CloseSocket(socket_handle);
259 }
260 
261 void CloseTcpSocket(int socket_handle) {
262  RemoveSocketTimerFromList(socket_handle);
263  CloseSocket(socket_handle);
264 }
265 
266 void RemoveSocketTimerFromList(const int socket_handle) {
267  SocketTimer *socket_timer = NULL;
268  while( NULL !=
269  ( socket_timer =
272  socket_handle) ) )
273  {
274  SocketTimerClear(socket_timer);
275  }
276 }
277 
279  EipBool8 return_value = false;
280  if ( FD_ISSET(socket, &read_socket) ) {
281  if ( FD_ISSET(socket, &master_socket) ) {
282  return_value = true;
283  } else {
284  OPENER_TRACE_INFO("socket: %d closed with pending message\n", socket);
285  }
286  FD_CLR(socket, &read_socket);
287  /* remove it from the read set so that later checks will not find it */
288  }
289  return return_value;
290 }
291 
293  int new_socket = kEipInvalidSocket;
294  /* see if this is a connection request to the TCP listener*/
296  OPENER_TRACE_INFO("networkhandler: new TCP connection\n");
297 
298  new_socket = accept(g_network_status.tcp_listener, NULL, NULL);
299  if (new_socket == kEipInvalidSocket) {
300  int error_code = GetSocketErrorNumber();
301  char *error_message = GetErrorMessage(error_code);
302  OPENER_TRACE_ERR("networkhandler: error on accept: %d - %s\n",
303  error_code, error_message);
304  FreeErrorMessage(error_message);
305  return;
306  }
307 
308  if (SetQosOnSocket( new_socket, GetPriorityForSocket(0xFFFF) ) != 0) { /* got error */
309  int error_code = GetSocketErrorNumber();
310  char *error_message = GetErrorMessage(error_code);
312  "networkhandler: error on set QoS on on new socket %d: %d - %s\n",
313  new_socket,
314  error_code,
315  error_message);
316  FreeErrorMessage(error_message);
317  }
318 
319  OPENER_TRACE_INFO(">>> network handler: accepting new TCP socket: %d \n",
320  new_socket);
321 
323  g_timestamps,
325 
326 // OPENER_TRACE_INFO("Current time stamp: %ld\n", g_actual_time);
327 // for(size_t i = 0; i < OPENER_NUMBER_OF_SUPPORTED_SESSIONS; i++) {
328 // OPENER_TRACE_INFO("Socket: %d - Last Update: %ld\n",
329 // g_timestamps[i].socket,
330 // g_timestamps[i].last_update);
331 // }
332 
333  OPENER_ASSERT(socket_timer != NULL)
334 
335  FD_SET(new_socket, &master_socket);
336  /* add newfd to master set */
337  if (new_socket > highest_socket_handle) {
338  OPENER_TRACE_INFO("New highest socket: %d\n", new_socket);
339  highest_socket_handle = new_socket;
340  }
341 
342  OPENER_TRACE_STATE("networkhandler: opened new TCP connection on fd %d\n",
343  new_socket);
344  }
345 }
346 
348 
350 
351  g_time_value.tv_sec = 0;
352  g_time_value.tv_usec = (
353  g_network_status.elapsed_time < kOpenerTimerTickInMilliSeconds ?
354  kOpenerTimerTickInMilliSeconds - g_network_status.elapsed_time : 0)
355  * 1000; /* 10 ms */
356 
357  int ready_socket = select(highest_socket_handle + 1, &read_socket, 0, 0,
358  &g_time_value);
359 
360  if (ready_socket == kEipInvalidSocket) {
361  if (EINTR == errno) /* we have somehow been interrupted. The default behavior is to go back into the select loop. */
362  {
363  return kEipStatusOk;
364  } else {
365  int error_code = GetSocketErrorNumber();
366  char *error_message = GetErrorMessage(error_code);
367  OPENER_TRACE_ERR("networkhandler: error with select: %d - %s\n",
368  error_code,
369  error_message);
370  FreeErrorMessage(error_message);
371  return kEipStatusError;
372  }
373  }
374 
375  if (ready_socket > 0) {
376 
381 
382  for (size_t socket = 0; socket <= highest_socket_handle; socket++) {
383  if ( true == CheckSocketSet(socket) ) {
384  /* if it is still checked it is a TCP receive */
385  if ( kEipStatusError == HandleDataOnTcpSocket(socket) ) /* if error */
386  {
387  CloseTcpSocket(socket);
388  RemoveSession(socket); /* clean up session and close the socket */
389  }
390  }
391  }
392  }
393 
394  for (size_t socket = 0; socket <= highest_socket_handle; socket++) {
396  }
397 
398  /* Check if all connections from one originator times out */
399  //CheckForTimedOutConnectionsAndCloseTCPConnections();
400 
401  //OPENER_TRACE_INFO("Socket Loop done\n");
402 
405  g_last_time = g_actual_time;
406  //OPENER_TRACE_INFO("Elapsed time: %u\n", g_network_status.elapsed_time);
407 
408  /* check if we had been not able to update the connection manager for several kOpenerTimerTickInMilliSeconds.
409  * This should compensate the jitter of the windows timer
410  */
411  if (g_network_status.elapsed_time >= kOpenerTimerTickInMilliSeconds) {
412  /* call manage_connections() in connection manager every kOpenerTimerTickInMilliSeconds ms */
415  }
416  return kEipStatusOk;
417 }
418 
423  return kEipStatusOk;
424 }
425 
427 
428  /* see if this is an unsolicited inbound UDP message */
429  if ( true ==
431  struct sockaddr_in from_address = {0};
432  socklen_t from_address_length = sizeof(from_address);
433 
435  "networkhandler: unsolicited UDP message on EIP global broadcast socket\n");
436 
437  /* Handle UDP broadcast messages */
438  CipOctet incoming_message[PC_OPENER_ETHERNET_BUFFER_SIZE] = {0};
439  int received_size = recvfrom(g_network_status.udp_global_broadcast_listener,
440  incoming_message,
441  sizeof(incoming_message),
442  0, (struct sockaddr *) &from_address,
443  &from_address_length);
444 
445  if (received_size <= 0) { /* got error */
446  int error_code = GetSocketErrorNumber();
447  char *error_message = GetErrorMessage(error_code);
449  "networkhandler: error on recvfrom UDP global broadcast port: %d - %s\n",
450  error_code,
451  error_message);
452  FreeErrorMessage(error_message);
453  return;
454  }
455 
456  OPENER_TRACE_INFO("Data received on global broadcast UDP:\n");
457 
458  const EipUint8 *receive_buffer = &incoming_message[0];
459  int remaining_bytes = 0;
460  do {
461  ENIPMessage outgoing_message;
462  InitializeENIPMessage(&outgoing_message);
463  int reply_length = HandleReceivedExplictUdpData(
465  &from_address,
466  receive_buffer,
467  received_size,
468  &remaining_bytes,
469  false,
470  &outgoing_message);
471 
472  receive_buffer += received_size - remaining_bytes;
473  received_size = remaining_bytes;
474 
475  if (reply_length > 0) {
476  OPENER_TRACE_INFO("UDP broadcast reply sent:\n");
477 
478  /* if the active socket matches a registered UDP callback, handle a UDP packet */
480  (char *) outgoing_message.message_buffer,
481  outgoing_message.used_message_length, 0,
482  (struct sockaddr *) &from_address, sizeof(from_address) )
483  != reply_length) {
485  "networkhandler: UDP response was not fully sent\n");
486  }
487  }
488  } while (remaining_bytes > 0);
489  }
490 }
491 
493  /* see if this is an unsolicited inbound UDP message */
495 
496  struct sockaddr_in from_address = {0};
497  socklen_t from_address_length = sizeof(from_address);
498 
500  "networkhandler: unsolicited UDP message on EIP unicast socket\n");
501 
502  /* Handle UDP broadcast messages */
503  CipOctet incoming_message[PC_OPENER_ETHERNET_BUFFER_SIZE] = {0};
504  int received_size = recvfrom(g_network_status.udp_unicast_listener,
505  incoming_message,
506  sizeof(incoming_message),
507  0, (struct sockaddr *) &from_address,
508  &from_address_length);
509 
510  if (received_size <= 0) { /* got error */
511  int error_code = GetSocketErrorNumber();
512  char *error_message = GetErrorMessage(error_code);
514  "networkhandler: error on recvfrom UDP unicast port: %d - %s\n",
515  error_code,
516  error_message);
517  FreeErrorMessage(error_message);
518  return;
519  }
520 
521  OPENER_TRACE_INFO("Data received on UDP unicast:\n");
522 
523  EipUint8 *receive_buffer = &incoming_message[0];
524  int remaining_bytes = 0;
525  ENIPMessage outgoing_message;
526  InitializeENIPMessage(&outgoing_message);
527  do {
528  int reply_length = HandleReceivedExplictUdpData(
529  g_network_status.udp_unicast_listener, &from_address, receive_buffer,
530  received_size, &remaining_bytes, true, &outgoing_message);
531 
532  receive_buffer += received_size - remaining_bytes;
533  received_size = remaining_bytes;
534 
535  if (reply_length > 0) {
536  OPENER_TRACE_INFO("UDP unicast reply sent:\n");
537 
538  /* if the active socket matches a registered UDP callback, handle a UDP packet */
540  (char *) outgoing_message.message_buffer,
541  outgoing_message.used_message_length, 0,
542  (struct sockaddr *) &from_address, sizeof(from_address) )
543  != reply_length) {
545  "networkhandler: UDP unicast response was not fully sent\n");
546  }
547  }
548  } while (remaining_bytes > 0);
549  }
550 }
551 
552 EipStatus SendUdpData(struct sockaddr_in *address,
553  int socket_handle,
554  EipUint8 *data,
555  EipUint16 data_length) {
556 
557 
558 
559  OPENER_TRACE_INFO("UDP port to be sent to: %x\n", ntohs(address->sin_port) );
560  UDPHeader header = {
561  .source_port = 2222,
562  .destination_port = ntohs(address->sin_port),
563  .packet_length = kUpdHeaderLength + data_length,
564  .checksum = 0
565  };
566 
567  char complete_message[PC_OPENER_ETHERNET_BUFFER_SIZE];
568  memcpy(complete_message + kUpdHeaderLength, data, data_length);
569  UDPHeaderGenerate(&header, (char *)complete_message);
570  UDPHeaderSetChecksum(&header,
571  htons(UDPHeaderCalculateChecksum(complete_message,
572  8 + data_length,
573  interface_configuration_
574  .ip_address,
575  address->sin_addr.s_addr) ) );
576  UDPHeaderGenerate(&header, (char *)complete_message);
577 
578  int sent_length = sendto( socket_handle,
579  (char *) complete_message,
580  data_length + kUpdHeaderLength,
581  0,
582  (struct sockaddr *) address,
583  sizeof(*address) );
584 
585  if (sent_length < 0) {
586  int error_code = GetSocketErrorNumber();
587  char *error_message = GetErrorMessage(error_code);
589  "networkhandler: error with sendto in sendUDPData: %d - %s\n",
590  error_code,
591  error_message);
592  FreeErrorMessage(error_message);
593  return kEipStatusError;
594  }
595 
596  if (sent_length != data_length + kUpdHeaderLength) {
598  "data length sent_length mismatch; probably not all data was sent in SendUdpData, sent %d of %d\n",
599  sent_length,
600  data_length);
601  return kEipStatusError;
602  }
603 
604  return kEipStatusOk;
605 }
606 
608  OPENER_TRACE_INFO("Entering HandleDataOnTcpSocket for socket: %d\n", socket);
609  int remaining_bytes = 0;
610  long data_sent = PC_OPENER_ETHERNET_BUFFER_SIZE;
611 
612  /* We will handle just one EIP packet here the rest is done by the select
613  * method which will inform us if more data is available in the socket
614  because of the current implementation of the main loop this may not be
615  the fastest way and a loop here with a non blocking socket would better
616  fit*/
617 
618  /*Check how many data is here -- read the first four bytes from the connection */
619  CipOctet incoming_message[PC_OPENER_ETHERNET_BUFFER_SIZE] = {0};
620 
621  long number_of_read_bytes = recv(socket, incoming_message, 4,
622  0); /*TODO we may have to set the socket to a non blocking socket */
623 
625  g_timestamps,
627  socket);
628  if (number_of_read_bytes == 0) {
629  int error_code = GetSocketErrorNumber();
630  char *error_message = GetErrorMessage(error_code);
632  "networkhandler: socket: %d - connection closed by client: %d - %s\n",
633  socket,
634  error_code,
635  error_message);
636  FreeErrorMessage(error_message);
638  RemoveSession(socket);
639  return kEipStatusError;
640  }
641  if (number_of_read_bytes < 0) {
642  int error_code = GetSocketErrorNumber();
643  if (OPENER_SOCKET_WOULD_BLOCK == error_code) {
644  return kEipStatusOk;
645  }
646  char *error_message = GetErrorMessage(error_code);
647  OPENER_TRACE_ERR("networkhandler: error on recv: %d - %s\n",
648  error_code,
649  error_message);
650  FreeErrorMessage(error_message);
651  return kEipStatusError;
652  }
653 
654  const EipUint8 *read_buffer = &incoming_message[2]; /* at this place EIP stores the data length */
655  size_t data_size = GetIntFromMessage(&read_buffer)
656  + ENCAPSULATION_HEADER_LENGTH - 4; /* -4 is for the 4 bytes we have already read*/
657  /* (NOTE this advances the buffer pointer) */
658  if ( (PC_OPENER_ETHERNET_BUFFER_SIZE - 4) < data_size ) { /*TODO can this be handled in a better way?*/
660  "too large packet received will be ignored, will drop the data\n");
661  /* Currently we will drop the whole packet */
662 
663  do {
665  "Entering consumption loop, remaining data to receive: %zu\n",
666  data_sent);
667  number_of_read_bytes = recv(socket, &incoming_message[0],
668  data_sent, 0);
669 
670  if (number_of_read_bytes == 0) /* got error or connection closed by client */
671  {
672  int error_code = GetSocketErrorNumber();
673  char *error_message = GetErrorMessage(error_code);
675  "networkhandler: socket: %d - connection closed by client: %d - %s\n",
676  socket,
677  error_code,
678  error_message);
679  FreeErrorMessage(error_message);
681  return kEipStatusError;
682  }
683  if (number_of_read_bytes < 0) {
684  int error_code = GetSocketErrorNumber();
685  char *error_message = GetErrorMessage(error_code);
686  if (OPENER_SOCKET_WOULD_BLOCK == error_code) {
687  return kEipStatusOk;
688  }
689  OPENER_TRACE_ERR("networkhandler: error on recv: %d - %s\n",
690  error_code,
691  error_message);
692  FreeErrorMessage(error_message);
693  return kEipStatusError;
694  }
695  data_size -= number_of_read_bytes;
696  if ( (data_size < PC_OPENER_ETHERNET_BUFFER_SIZE) && (data_size != 0) ) {
697  data_sent = data_size;
698  }
699  } while (0 < data_size);
701  return kEipStatusOk;
702  }
703 
704  number_of_read_bytes = recv(socket, &incoming_message[4],
705  data_size, 0);
706 
707  if (0 == number_of_read_bytes) /* got error or connection closed by client */
708  {
709  int error_code = GetSocketErrorNumber();
710  char *error_message = GetErrorMessage(error_code);
712  "networkhandler: socket: %d - connection closed by client: %d - %s\n",
713  socket,
714  error_code,
715  error_message);
716  FreeErrorMessage(error_message);
718  RemoveSession(socket);
719  return kEipStatusError;
720  }
721  if (number_of_read_bytes < 0) {
722  int error_code = GetSocketErrorNumber();
723  char *error_message = GetErrorMessage(error_code);
724  if (OPENER_SOCKET_WOULD_BLOCK == error_code) {
725  return kEipStatusOk;
726  }
727  OPENER_TRACE_ERR("networkhandler: error on recv: %d - %s\n",
728  error_code,
729  error_message);
730  FreeErrorMessage(error_message);
731  return kEipStatusError;
732  }
733 
734  if ( (unsigned) number_of_read_bytes == data_size ) {
735  /*we got the right amount of data */
736  data_size += 4;
737  /*TODO handle partial packets*/
738  OPENER_TRACE_INFO("Data received on tcp:\n");
739 
741 
742  struct sockaddr sender_address;
743  memset( &sender_address, 0, sizeof(sender_address) );
744  socklen_t fromlen = sizeof(sender_address);
745  if (getpeername(socket, (struct sockaddr *)&sender_address, &fromlen) < 0) {
746  int error_code = GetSocketErrorNumber();
747  char *error_message = GetErrorMessage(error_code);
748  OPENER_TRACE_ERR("networkhandler: could not get peername: %d - %s\n",
749  error_code,
750  error_message);
751  FreeErrorMessage(error_message);
752  }
753 
754  ENIPMessage outgoing_message = {0};
755  InitializeENIPMessage(&outgoing_message);
756  int number_of_bytes_to_send = HandleReceivedExplictTcpData(
757  socket, incoming_message, data_size, &remaining_bytes,
758  &sender_address, &outgoing_message);
760  g_timestamps,
762  socket);
763  if(NULL != socket_timer) {
765  }
766 
767  g_current_active_tcp_socket = kEipInvalidSocket;
768 
769  if (remaining_bytes != 0) {
771  "Warning: received packet was to long: %d Bytes left!\n",
772  remaining_bytes);
773  }
774 
775  if (number_of_bytes_to_send > 0) {
776  OPENER_TRACE_INFO("TCP reply sent:\n");
777 
778  data_sent = send(socket, (char *) outgoing_message.message_buffer,
779  outgoing_message.used_message_length, 0);
781  g_timestamps,
783  socket);
785  if (data_sent != number_of_bytes_to_send) {
786  OPENER_TRACE_WARN("TCP response was not fully sent\n");
787  }
788  }
789 
790  return kEipStatusOk;
791  } else {
792  /* we got a fragmented packet currently we cannot handle this will
793  * for this we would need a network buffer per TCP socket
794  *
795  * However with typical packet sizes of EIP this should't be a big issue.
796  */
797  /*TODO handle fragmented packets */
798  }
799  return kEipStatusError;
800 }
801 
808 int CreateUdpSocket(UdpCommuncationDirection communication_direction,
809  struct sockaddr_in *socket_data,
810  CipUsint qos_for_socket) {
811  struct sockaddr_in peer_address;
812  int new_socket = kEipInvalidSocket;
813 
814  socklen_t peer_address_length = sizeof(struct sockaddr_in);
815  /* create a new UDP socket */
816  if(kUdpCommuncationDirectionConsuming == communication_direction) {
817  new_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
818  }
819 
820  if(kUdpCommuncationDirectionProducing == communication_direction) {
821  new_socket = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
822  }
823 
824  if (new_socket == kEipInvalidSocket) {
825  int error_code = GetSocketErrorNumber();
826  char *error_message = GetErrorMessage(error_code);
827  OPENER_TRACE_ERR("networkhandler: cannot create UDP socket: %d- %s\n",
828  error_code,
829  error_message);
830  FreeErrorMessage(error_message);
831  return new_socket;
832  }
833 
834  if (SetSocketToNonBlocking(new_socket) < 0) {
836  "error setting socket to non-blocking on new socket\n");
837  CloseSocket(new_socket);
838  OPENER_ASSERT(false) /* This should never happen! */
839  return kEipStatusError;
840  }
841 
842  if (SetQosOnSocket(new_socket, GetPriorityForSocket(qos_for_socket) ) != 0) { /* got error */
843  int error_code = GetSocketErrorNumber();
844  char *error_message = GetErrorMessage(error_code);
846  "networkhandler: error on set QoS on socket on new socket: %d - %s\n",
847  error_code,
848  error_message);
849  FreeErrorMessage(error_message);
850  }
851 
852  OPENER_TRACE_INFO("networkhandler: UDP socket %d\n", new_socket);
853 
854  /* check if it is sending or receiving */
855  if (communication_direction == kUdpCommuncationDirectionConsuming) {
856  int option_value = 1;
857  if (setsockopt( new_socket, SOL_SOCKET, SO_REUSEADDR,
858  (char *) &option_value,
859  sizeof(option_value) ) == -1) {
861  "error setting socket option SO_REUSEADDR on consuming udp socket\n");
862  CloseSocket(new_socket);
863  return kEipStatusError;
864  }
865 
866  /* bind is only for consuming necessary */
867  if ( ( bind( new_socket, (struct sockaddr *) socket_data,
868  sizeof(struct sockaddr) ) ) == -1 ) {
869  int error_code = GetSocketErrorNumber();
870  char *error_message = GetErrorMessage(error_code);
871  OPENER_TRACE_ERR("error on bind udp: %d - %s\n", error_code,
872  error_message);
873  FreeErrorMessage(error_message);
874  CloseSocket(new_socket);
875  return new_socket;
876  }
877 
878  OPENER_TRACE_INFO("networkhandler: bind UDP socket %d\n", new_socket);
879  } else { /* we have a producing udp socket */
880 
881  int option_value = 1;
882  setsockopt( new_socket, SOL_SOCKET, SO_REUSEADDR,
883  (char *) &option_value,
884  sizeof(option_value) );
885 
886  if (socket_data->sin_addr.s_addr
888  if (1 != g_time_to_live_value) { /* we need to set a TTL value for the socket */
889  if ( setsockopt(new_socket, IPPROTO_IP, IP_MULTICAST_TTL,
891  sizeof(g_time_to_live_value) ) < 0 ) {
892  int error_code = GetSocketErrorNumber();
893  char *error_message = GetErrorMessage(error_code);
895  "networkhandler: could not set the TTL to: %d, error: %d - %s\n",
896  g_time_to_live_value, error_code, error_message);
897  FreeErrorMessage(error_message);
898  return new_socket;
899  }
900  }
901  }
902  }
903 
904  if ( (communication_direction == kUdpCommuncationDirectionConsuming)
905  || (0 == socket_data->sin_addr.s_addr) ) {
906  /* we have a peer to peer producer or a consuming connection*/
907  if (getpeername(g_current_active_tcp_socket,
908  (struct sockaddr *) &peer_address, &peer_address_length)
909  < 0) {
910  int error_code = GetSocketErrorNumber();
911  char *error_message = GetErrorMessage(error_code);
912  OPENER_TRACE_ERR("networkhandler: could not get peername: %d - %s\n",
913  error_code,
914  error_message);
915  FreeErrorMessage(error_message);
916  return new_socket;
917  }
918  /* store the originators address */
919  socket_data->sin_addr.s_addr = peer_address.sin_addr.s_addr;
920  }
921 
922  if (kUdpCommuncationDirectionConsuming == communication_direction) {
923  /* add new socket to the master list */
924  FD_SET(new_socket, &master_socket);
925  }
926 
927  if (new_socket > highest_socket_handle) {
928  OPENER_TRACE_INFO("New highest socket: %d\n", new_socket);
929  highest_socket_handle = new_socket;
930  }
931  return new_socket;
932 }
933 
936 
937  CipConnectionObject *current_connection_object = NULL;
938 
939  /* see a message on one of the registered UDP sockets has been received */
940  while (NULL != iterator) {
941  current_connection_object = (CipConnectionObject *)iterator->data;
942  iterator = iterator->next; /* do this at the beginning as the close function may can make the entry invalid */
943 
944  if ( (kEipInvalidSocket
945  != current_connection_object->socket[
947  && ( true
948  == CheckSocketSet(
949  current_connection_object->socket[
951  OPENER_TRACE_INFO("Processing UDP consuming message\n");
952  struct sockaddr_in from_address = {0};
953  socklen_t from_address_length = sizeof(from_address);
954  CipOctet incoming_message[PC_OPENER_ETHERNET_BUFFER_SIZE] = {0};
955 
956  int received_size = recvfrom(
957  current_connection_object->socket[kUdpCommuncationDirectionConsuming],
958  incoming_message, sizeof(incoming_message), 0,
959  (struct sockaddr *) &from_address, &from_address_length);
960  if (0 == received_size) {
961  int error_code = GetSocketErrorNumber();
962  char *error_message = GetErrorMessage(error_code);
964  "networkhandler: socket: %d - connection closed by client: %d - %s\n",
965  current_connection_object->socket[
967  error_code,
968  error_message);
969  FreeErrorMessage(error_message);
970  current_connection_object->connection_close_function(
971  current_connection_object);
972  continue;
973  }
974 
975  if (0 > received_size) {
976  int error_code = GetSocketErrorNumber();
977  char *error_message = GetErrorMessage(error_code);
978  if (OPENER_SOCKET_WOULD_BLOCK == error_code) {
979  return; // No fatal error, resume execution
980  }
981  OPENER_TRACE_ERR("networkhandler: error on recv: %d - %s\n",
982  error_code,
983  error_message);
984  FreeErrorMessage(error_message);
985  current_connection_object->connection_close_function(
986  current_connection_object);
987  continue;
988  }
989 
990  HandleReceivedConnectedData(incoming_message,
991  received_size, &from_address);
992 
993  }
994  }
995 }
996 
997 
998 void CloseSocket(const int socket_handle) {
999  OPENER_TRACE_INFO("networkhandler: closing socket %d\n", socket_handle);
1000 
1001  if (kEipInvalidSocket != socket_handle) {
1002  FD_CLR(socket_handle, &master_socket);
1003  CloseSocketPlatform(socket_handle);
1004  }
1005  OPENER_TRACE_INFO("networkhandler: closing socket done %d\n", socket_handle);
1006 }
1007 
1008 int GetMaxSocket(int socket1,
1009  int socket2,
1010  int socket3,
1011  int socket4) {
1012  if ( (socket1 > socket2) && (socket1 > socket3) && (socket1 > socket4) ) {
1013  return socket1;
1014  }
1015 
1016  if ( (socket2 > socket1) && (socket2 > socket3) && (socket2 > socket4) ) {
1017  return socket2;
1018  }
1019 
1020  if ( (socket3 > socket1) && (socket3 > socket2) && (socket3 > socket4) ) {
1021  return socket3;
1022  }
1023 
1024  return socket4;
1025 }
1026 
1027 void CheckEncapsulationInactivity(int socket_handle) {
1028  if (0 < g_encapsulation_inactivity_timeout) { //*< Encapsulation inactivity timeout is enabled
1030  g_timestamps,
1032  socket_handle);
1033 
1034 // OPENER_TRACE_INFO("Check socket %d - socket timer: %p\n",
1035 // socket_handle,
1036 // socket_timer);
1037  if(NULL != socket_timer) {
1038  MilliSeconds diff_milliseconds = g_actual_time - SocketTimerGetLastUpdate(
1039  socket_timer);
1040 
1041  if ( diff_milliseconds >=
1043 
1044  size_t encapsulation_session_handle =
1045  GetSessionFromSocket(socket_handle);
1046 
1047  CloseClass3ConnectionBasedOnSession(encapsulation_session_handle);
1048 
1049  CloseTcpSocket(socket_handle);
1050  RemoveSession(socket_handle);
1051  }
1052  }
1053  }
1054 }
MilliSeconds GetMilliSeconds(void)
This function shall return the current time in milliseconds relative to epoch, and shall be implement...
void CloseSocketPlatform(int socket_handle)
Platform dependent code to close a socket.
#define OPENER_NUMBER_OF_SUPPORTED_SESSIONS
Number of sessions that can be handled at the same time.
void SocketTimerArrayInitialize(SocketTimer *const array_of_socket_timers, const size_t array_length)
Initializes an array of Socket Timer entries.
Definition: socket_timer.c:34
EipStatus NetworkHandlerProcessOnce(void)
Tracing infrastructure for OpENer.
MilliSeconds g_actual_time
MilliSeconds SocketTimerGetLastUpdate(SocketTimer *const socket_timer)
Gets time stamp of the last update.
Definition: socket_timer.c:25
uint16_t UDPHeaderCalculateChecksum(const void *udp_packet, const size_t udp_packet_length, const in_addr_t source_addr, const in_addr_t destination_addr)
Calculates the checksum based on the set UDP packet data and pseudo IP header.
Definition: udp_protocol.c:61
EipStatus SendUdpData(struct sockaddr_in *address, int socket_handle, EipUint8 *data, EipUint16 data_length)
Create a producing or consuming UDP socket.
Data structure to store last usage times for sockets.
Definition: socket_timer.h:15
uint16_t source_port
Definition: udp_protocol.h:34
char * GetErrorMessage(int error_number)
Returns a human readable message for the given error number.
Definition: opener_error.c:21
EipStatus NetworkHandlerFinish(void)
void UDPHeaderSetChecksum(UDPHeader *const header, const uint16_t checksum)
Sets checksum field.
Definition: udp_protocol.c:40
DoublyLinkedListNode * first
This file includes the prototypes for error resolution functions like strerror_r or WSAGetLastError...
Representing the needed information for the UDP header.
Definition: udp_protocol.h:33
void SocketTimerClear(SocketTimer *const socket_timer)
Clears a Socket Timer entry.
Definition: socket_timer.c:29
CipOctet message_buffer[PC_OPENER_ETHERNET_BUFFER_SIZE]
Definition: enipmessage.h:12
int HandleReceivedExplictUdpData(const int socket, const struct sockaddr_in *from_address, const EipUint8 *buffer, const size_t buffer_length, int *number_of_remaining_bytes, bool unicast, ENIPMessage *const outgoing_message)
Notify the encapsulation layer that an explicit message has been received via UDP.
Definition: encap.c:237
void UDPHeaderGenerate(const UDPHeader *header, char *message)
Generate the UDP header in the message according to the header.
Definition: udp_protocol.c:49
void CheckAndHandleConsumingUdpSockets(void)
check if on one of the UDP consuming sockets data has been received and if yes handle it correctly ...
#define OPENER_ASSERT(assertion)
MilliSeconds g_last_time
#define PC_OPENER_ETHERNET_BUFFER_SIZE
The number of bytes used for the Ethernet message buffer on the pc port. For different platforms it m...
UdpCommuncationDirection
Communication direction of an UDP socket; consuming is receiver, producing is sender.
Definition: typedefs.h:104
#define OPENER_TRACE_ERR(...)
Definition: trace.h:86
SocketTimer g_timestamps[OPENER_NUMBER_OF_SUPPORTED_SESSIONS]
void InitializeENIPMessage(ENIPMessage *const message)
Definition: enipmessage.c:10
MulticastAddressConfiguration g_multicast_configuration
#9 The multicast configuration for this device
Public interface of the QoS Object.
EipStatus HandleDataOnTcpSocket(int socket)
Handles data on an established TCP connection, processed connection is given by socket.
struct timeval g_time_value
ConnectionCloseFunction connection_close_function
void CheckAndHandleUdpUnicastSocket(void)
Checks and processes request received via the UDP unicast socket, currently the implementation is por...
void CheckEncapsulationInactivity(int socket_handle)
int SetSocketToNonBlocking(int socket_handle)
uint8_t CipOctet
Data types as defined in the CIP Specification Vol 1 Appendix C.
Definition: typedefs.h:41
DoublyLinkedListNode * next
void CloseClass3ConnectionBasedOnSession(size_t encapsulation_session_handle)
Definition: encap.c:906
EipStatus
EIP stack status enum.
Definition: typedefs.h:93
uint8_t EipUint8
Definition: typedefs.h:32
EipStatus ManageConnections(MilliSeconds elapsed_time)
Check if any of the connection timers (TransmissionTrigger or WatchdogTimeout) have timed out...
#define OPENER_TRACE_INFO(...)
Definition: trace.h:89
void CloseUdpSocket(int socket_handle)
#define MAX_NO_OF_TCP_SOCKETS
CipUint g_encapsulation_inactivity_timeout
#13 Number of seconds of inactivity before TCP connection is closed
unsigned long socklen_t
SocketTimer * SocketTimerArrayGetSocketTimer(SocketTimer *const array_of_socket_timers, const size_t array_length, const int socket)
Get the Socket Timer entry with the spezified socket value.
Definition: socket_timer.c:41
int highest_socket_handle
#define ENCAPSULATION_HEADER_LENGTH
Definition: encap.h:22
SocketTimer * SocketTimerArrayGetEmptySocketTimer(SocketTimer *const array_of_socket_timers, const size_t array_length)
Get an empty Socket Timer entry.
Definition: socket_timer.c:53
uint8_t CipUsint
Definition: typedefs.h:46
void CheckAndHandleTcpListenerSocket(void)
handle any connection request coming in the TCP server socket.
int SetQosOnSocket(int socket, CipUsint qos_value)
EipStatus NetworkHandlerInitializePlatform(void)
Executes platform dependent network handler initialization code.
#define OPENER_TRACE_STATE(...)
Definition: trace.h:88
void RemoveSocketTimerFromList(const int socket_handle)
void RemoveSession(const int socket)
Definition: encap.c:835
NetworkStatus g_network_status
Includes a basic set of operations for UDP header creation and checksum calculation.
CipUsint GetPriorityForSocket(ConnectionObjectPriority priority)
Initializing the data structures of the TCP/IP interface object.
Definition: cipqos.c:91
void CheckAndHandleUdpGlobalBroadcastSocket(void)
Checks and handles incoming messages via UDP broadcast.
Public interface of the TCP/IP Interface Object.
Struct for saving TCP/IP interface information.
Definition: ciptypes.h:294
DoublyLinkedList connection_list
int g_current_active_tcp_socket
This variable holds the TCP socket the received to last explicit message. It is needed for opening po...
fd_set master_socket
#define OPENER_TRACE_WARN(...)
Definition: trace.h:87
uint8_t EipBool8
Definition: typedefs.h:37
This file contains the public interface of the encapsulation layer.
MilliSeconds elapsed_time
unsigned long MilliSeconds
Definition: typedefs.h:68
int CreateUdpSocket(UdpCommuncationDirection communication_direction, struct sockaddr_in *socket_data, CipUsint qos_for_socket)
create a new UDP socket for the connection manager
size_t GetSessionFromSocket(const int socket_handle)
Definition: encap.c:897
EipStatus HandleReceivedConnectedData(const EipUint8 *const data, int data_length, struct sockaddr_in *from_address)
Notify the connection manager that data for a connection has been received.
EipUint16 GetIntFromMessage(const EipUint8 **const buffer)
Reads EIP_UINT16 from *buffer and converts little endian to host.
Definition: endianconv.c:57
fd_set read_socket
void FreeErrorMessage(char *error_message)
Frees the space of the error message generated by GetErrorMessage(int)
Definition: opener_error.c:34
size_t used_message_length
Definition: enipmessage.h:14
EipStatus NetworkHandlerInitialize(void)
Initializes the network handler, shall be implemented by a port-specific networkhandler.
void CloseSocket(const int socket_handle)
Close the given socket and clean up the stack.
uint16_t EipUint16
Definition: typedefs.h:33
int GetSocketErrorNumber()
Gets the error number or equivalent.
Definition: opener_error.c:17
void SocketTimerSetLastUpdate(SocketTimer *const socket_timer, const MilliSeconds actual_time)
Sets time stamp entry of the Socket Timer.
Definition: socket_timer.c:17
int HandleReceivedExplictTcpData(int socket, EipUint8 *buffer, size_t length, int *remaining_bytes, struct sockaddr *originator_address, ENIPMessage *const outgoing_message)
Notify the encapsulation layer that an explicit message has been received via TCP.
Definition: encap.c:153
CipTcpIpNetworkInterfaceConfiguration interface_configuration_
void CloseTcpSocket(int socket_handle)
EipUint8 g_time_to_live_value
#8 the time to live value to be used for multi-cast connections
#define OPENER_SOCKET_WOULD_BLOCK
int GetMaxSocket(int socket1, int socket2, int socket3, int socket4)
Returns the socket with the highest id.
EipBool8 CheckSocketSet(int socket)
check if the given socket is set in the read set