int TCPSocket::CreateTCPServer() { sprintf(Message, "Server: Initiating TCP Server...\n"); easyLog("bold"); addrinfo *ai; if (AppStat) FlushAll(); if ((ai = GetAddrInfo()) == NULL) return 1; //Error On Getting Address Information if ((mySocketFD = GetBind(ai)) == -1) return 2; //Error On Binding Socket if (SocketBlockingMode()) return 3; if (ListenOn() == -1) return 4; //Error On Listener sprintf(Message, "Server Ready: TCP Connection Management started...\n"); easyLog("bold"); AppStat = true; ManageConnections(); return 0; }
EipStatus NetworkHandlerInitialize(void) { #ifdef WIN32 WORD wVersionRequested; WSADATA wsaData; wVersionRequested = MAKEWORD(2, 2); WSAStartup(wVersionRequested, &wsaData); #endif /* clear the master an temp sets */ FD_ZERO(&master); FD_ZERO(&read_fds); /* create a new TCP socket */ if ((g_network_status.tcp_listener = socket(PF_INET, SOCK_STREAM, 0)) == -1) { OPENER_TRACE_ERR("error allocating socket stream listener, %d\n", errno); return kEipStatusError; } int nOptVal = 1; if (setsockopt(g_network_status.tcp_listener, SOL_SOCKET, SO_REUSEADDR, (char *)&nOptVal, sizeof(nOptVal)) == -1) { OPENER_TRACE_ERR("error setting socket option SO_REUSEADDR on nTCPListener\n"); return kEipStatusError; } /* create a new UDP unicast socket */ if ((g_network_status.udp_unicast_listener = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { OPENER_TRACE_ERR("error allocating udp listener socket, %d\n", errno); return kEipStatusError; } if (setsockopt(g_network_status.udp_unicast_listener, SOL_SOCKET, SO_REUSEADDR, (char *)&nOptVal, sizeof(nOptVal)) == -1) { OPENER_TRACE_ERR("error setting socket option SO_REUSEADDR on nUDPListener\n"); return kEipStatusError; } /* create a new UDP broadcast socket */ if ((g_network_status.udp_broadcast_listener = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { OPENER_TRACE_ERR("error allocating udp listener socket, %d\n", errno); return kEipStatusError; } if (setsockopt(g_network_status.udp_broadcast_listener, SOL_SOCKET, SO_REUSEADDR, (char *)&nOptVal, sizeof(nOptVal)) == -1) { OPENER_TRACE_ERR("error setting socket option SO_REUSEADDR on nUDPListener\n"); return kEipStatusError; } /* set up unicast udp socket */ struct sockaddr_in unicast_address = { .sin_family = AF_INET, .sin_port = htons(kOpenerEthernetPort), .sin_addr.s_addr = interface_configuration_.ip_address }; if ((bind(g_network_status.udp_unicast_listener, (struct sockaddr *) &unicast_address, sizeof(struct sockaddr))) == -1) { int error_code = WSAGetLastError(); OPENER_TRACE_ERR("error with udp bind: %d, %s\n", error_code, strerror(error_code)); return kEipStatusError; } struct sockaddr_in my_address = { .sin_family = AF_INET, .sin_port = htons(kOpenerEthernetPort), .sin_addr.s_addr = htonl(INADDR_ANY) }; /* bind the new socket to port 0xAF12 (CIP) */ if ((bind(g_network_status.tcp_listener, (struct sockaddr *) &my_address, sizeof(struct sockaddr))) == -1) { OPENER_TRACE_ERR("error with bind: %s\n", strerror(errno)); return kEipStatusError; } /* enable the udp socket to receive broadcast messages*/ int y = 1; if (0 > setsockopt(g_network_status.udp_broadcast_listener, SOL_SOCKET, SO_BROADCAST, (char *)&y, sizeof(int))) { OPENER_TRACE_ERR("error with setting broadcast receive for udp socket: %s\n", strerror(errno)); return kEipStatusError; } if ((bind(g_network_status.udp_broadcast_listener, (struct sockaddr *) &my_address, sizeof(struct sockaddr))) == -1) { OPENER_TRACE_ERR("error with udp bind: %s\n", strerror(errno)); return kEipStatusError; } /* switch socket in listen mode */ if ((listen(g_network_status.tcp_listener, MAX_NO_OF_TCP_SOCKETS)) == -1) { OPENER_TRACE_ERR("networkhandler: error with listen: %s\n", strerror(errno)); return kEipStatusError; } /* add the listener socket to the master set */ FD_SET(g_network_status.tcp_listener, &master); FD_SET(g_network_status.udp_broadcast_listener, &master); FD_SET(g_network_status.udp_unicast_listener, &master); /* keep track of the biggest file descriptor */ fdmax = GetMaxSocket(g_network_status.tcp_listener, g_network_status.udp_unicast_listener, g_network_status.udp_broadcast_listener, -1); last_time = GetMilliSeconds(); /* initialize time keeping */ g_network_status.elapsed_time = 0; return kEipStatusOk; } EipStatus NetworkHandlerProcessOnce(void) { int fd; int res; read_fds = master; time_value.tv_sec = 0; time_value.tv_usec = ( g_network_status.elapsed_time < kOpenerTimerTickInMilliSeconds ? kOpenerTimerTickInMilliSeconds - g_network_status.elapsed_time : 0) * 1000; /* 10 ms */ res = select(fdmax + 1, &read_fds, 0, 0, &time_value); if (res == -1) { if (EINTR == errno) /* we have somehow been interrupted. The default behavior is to go back into the select loop. */ { return kEipStatusOk; } else { OPENER_TRACE_ERR("networkhandler: error with select: %s\n", strerror(errno)); return kEipStatusError; } } if (res > 0) { CheckAndHandleTcpListenerSocket(); CheckAndHandleUdpBroadCastSocket(); CheckAndHandleUdpUnicastSocket(); CheckAndHandleConsumingUdpSockets(); for (fd = 0; fd <= fdmax; fd++) { if (true == checkSocketSet(fd)) { /* if it is still checked it is a TCP receive */ if (kEipStatusError == handleDataOnTCPSocket(fd)) /* if error */ { CloseSocket(fd); CloseSession(fd); /* clean up session and close the socket */ } } } } actual_time = GetMilliSeconds(); g_network_status.elapsed_time += actual_time - last_time; last_time = actual_time; /* check if we had been not able to update the connection manager for several OPENER_TIMER_TICK. * This should compensate the jitter of the windows timer */ while (g_network_status.elapsed_time >= kOpenerTimerTickInMilliSeconds) { /* call manage_connections() in connection manager every OPENER_TIMER_TICK ms */ ManageConnections(); g_network_status.elapsed_time -= kOpenerTimerTickInMilliSeconds; } return kEipStatusOk; }