/** * @brief Start all of the UDP stuff * @param netPath network object * @param ptpClock PTP clock object * @retval Boolean success */ Boolean netInit(NetPath *netPath, PtpClock *ptpClock) { struct ip_addr interfaceAddr; struct in_addr netAddr; char addrStr[NET_ADDRESS_LENGTH]; DBG("netInit\n"); /* find a network interface */ interfaceAddr.addr = findIface(ptpClock->rtOpts->ifaceName, ptpClock->portUuidField, netPath); if (!(interfaceAddr.addr)) { goto fail01; } /* Open lwIP raw udp interfaces for the event port. */ netPath->eventPcb = udp_new(); if (NULL == netPath->eventPcb) { ERROR("netInit: Failed to open Event UDP PCB\n"); goto fail02; } /* Open lwIP raw udp interfaces for the general port. */ netPath->generalPcb = udp_new(); if (NULL == netPath->generalPcb) { ERROR("netInit: Failed to open General UDP PCB\n"); goto fail03; } /* Initialize the buffer queues. */ netQInit(&netPath->eventQ); netQInit(&netPath->generalQ); /* Configure network (broadcast/unicast) addresses. */ netPath->unicastAddr = 0; /* disable unicast */ /*Init General multicast IP address*/ memcpy(addrStr, DEFAULT_PTP_DOMAIN_ADDRESS, NET_ADDRESS_LENGTH); if (!inet_aton(addrStr, &netAddr)) { ERROR("netInit: failed to encode multi-cast address: %s\n", addrStr); goto fail04; } netPath->multicastAddr = netAddr.s_addr; /* join multicast group (for receiving) on specified interface */ igmp_joingroup(&interfaceAddr, (struct ip_addr *)&netAddr); /*Init Peer multicast IP address*/ memcpy(addrStr, PEER_PTP_DOMAIN_ADDRESS, NET_ADDRESS_LENGTH); if (!inet_aton(addrStr, &netAddr)) { ERROR("netInit: failed to encode peer multi-cast address: %s\n", addrStr); goto fail04; } netPath->peerMulticastAddr = netAddr.s_addr; /* join peer multicast group (for receiving) on specified interface */ igmp_joingroup(&interfaceAddr, (struct ip_addr *)&netAddr); /* multicast send only on specified interface */ netPath->eventPcb->multicast_ip.addr = netPath->multicastAddr; netPath->generalPcb->multicast_ip.addr = netPath->multicastAddr; /* Establish the appropriate UDP bindings/connections for events. */ udp_recv(netPath->eventPcb, netRecvEventCallback, netPath); udp_bind(netPath->eventPcb, IP_ADDR_ANY, PTP_EVENT_PORT); /* udp_connect(netPath->eventPcb, &netAddr, PTP_EVENT_PORT); */ /* Establish the appropriate UDP bindings/connections for general. */ udp_recv(netPath->generalPcb, netRecvGeneralCallback, netPath); udp_bind(netPath->generalPcb, IP_ADDR_ANY, PTP_GENERAL_PORT); /* udp_connect(netPath->generalPcb, &netAddr, PTP_GENERAL_PORT); */ /* Return a success code. */ return TRUE; /* fail05: udp_disconnect(netPath->eventPcb); udp_disconnect(netPath->generalPcb); */ fail04: udp_remove(netPath->generalPcb); fail03: udp_remove(netPath->eventPcb); fail02: fail01: return FALSE; }
/* on socket options, see the 'socket(7)' and 'ip' man pages */ Boolean netInit(NetPath * netPath, RunTimeOpts * rtOpts, PtpClock * ptpClock) { int temp, i; struct in_addr interfaceAddr, netAddr; struct sockaddr_in addr; struct ip_mreq imr; char addrStr[NET_ADDRESS_LENGTH]; char *s; DBG("netInit\n"); /* open sockets */ if ((netPath->eventSock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0 || (netPath->generalSock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { PERROR("failed to initalize sockets"); return FALSE; } /* find a network interface */ if (!(interfaceAddr.s_addr = findIface(rtOpts->ifaceName, &ptpClock->port_communication_technology, ptpClock->port_uuid_field, netPath))) return FALSE; temp = 1; /* allow address reuse */ if (setsockopt(netPath->eventSock, SOL_SOCKET, SO_REUSEADDR, &temp, sizeof(int)) < 0 || setsockopt(netPath->generalSock, SOL_SOCKET, SO_REUSEADDR, &temp, sizeof(int)) < 0) { DBG("failed to set socket reuse\n"); } /* bind sockets */ /* * need INADDR_ANY to allow receipt of multi-cast and uni-cast * messages */ addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = htons(PTP_EVENT_PORT); if (bind(netPath->eventSock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) { PERROR("failed to bind event socket"); return FALSE; } addr.sin_port = htons(PTP_GENERAL_PORT); if (bind(netPath->generalSock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) { PERROR("failed to bind general socket"); return FALSE; } /* set general and port address */ *(Integer16 *) ptpClock->event_port_address = PTP_EVENT_PORT; *(Integer16 *) ptpClock->general_port_address = PTP_GENERAL_PORT; /* send a uni-cast address if specified (useful for testing) */ if (rtOpts->unicastAddress[0]) { if (!inet_aton(rtOpts->unicastAddress, &netAddr)) { ERROR("failed to encode uni-cast address: %s\n", rtOpts->unicastAddress); return FALSE; } netPath->unicastAddr = netAddr.s_addr; } else netPath->unicastAddr = 0; /* resolve PTP subdomain */ if (!lookupSubdomainAddress(rtOpts->subdomainName, addrStr)) return FALSE; if (!inet_aton(addrStr, &netAddr)) { ERROR("failed to encode multi-cast address: %s\n", addrStr); return FALSE; } netPath->multicastAddr = netAddr.s_addr; s = addrStr; for (i = 0; i < SUBDOMAIN_ADDRESS_LENGTH; ++i) { ptpClock->subdomain_address[i] = strtol(s, &s, 0); if (!s) break; ++s; } /* multicast send only on specified interface */ imr.imr_multiaddr.s_addr = netAddr.s_addr; imr.imr_interface.s_addr = interfaceAddr.s_addr; if (setsockopt(netPath->eventSock, IPPROTO_IP, IP_MULTICAST_IF, &imr.imr_interface.s_addr, sizeof(struct in_addr)) < 0 || setsockopt(netPath->generalSock, IPPROTO_IP, IP_MULTICAST_IF, &imr.imr_interface.s_addr, sizeof(struct in_addr)) < 0) { PERROR("failed to enable multi-cast on the interface"); return FALSE; } /* join multicast group (for receiving) on specified interface */ if (setsockopt(netPath->eventSock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(struct ip_mreq)) < 0 || setsockopt(netPath->generalSock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(struct ip_mreq)) < 0) { PERROR("failed to join the multi-cast group"); return FALSE; } /* set socket time-to-live */ if (setsockopt(netPath->eventSock, IPPROTO_IP, IP_MULTICAST_TTL, &rtOpts->ttl, sizeof(int)) < 0 || setsockopt(netPath->generalSock, IPPROTO_IP, IP_MULTICAST_TTL, &rtOpts->ttl, sizeof(int)) < 0) { PERROR("failed to set the multi-cast time-to-live"); return FALSE; } /* enable loopback */ temp = 1; if (setsockopt(netPath->eventSock, IPPROTO_IP, IP_MULTICAST_LOOP, &temp, sizeof(int)) < 0 || setsockopt(netPath->generalSock, IPPROTO_IP, IP_MULTICAST_LOOP, &temp, sizeof(int)) < 0) { PERROR("failed to enable multi-cast loopback"); return FALSE; } /* make timestamps available through recvmsg() */ temp = 1; #if defined(linux) if (setsockopt(netPath->eventSock, SOL_SOCKET, SO_TIMESTAMP, &temp, sizeof(int)) < 0 || setsockopt(netPath->generalSock, SOL_SOCKET, SO_TIMESTAMP, &temp, sizeof(int)) < 0) { #else /* BSD */ if (setsockopt(netPath->eventSock, SOL_SOCKET, SO_BINTIME, &temp, sizeof(int)) < 0 || setsockopt(netPath->generalSock, SOL_SOCKET, SO_BINTIME, &temp, sizeof(int)) < 0) { #endif /* linux or BSD */ PERROR("failed to enable receive time stamps"); return FALSE; } return TRUE; } /* shut down the UDP stuff */ Boolean netShutdown(NetPath * netPath) { struct ip_mreq imr; imr.imr_multiaddr.s_addr = netPath->multicastAddr; imr.imr_interface.s_addr = htonl(INADDR_ANY); setsockopt(netPath->eventSock, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr, sizeof(struct ip_mreq)); setsockopt(netPath->generalSock, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr, sizeof(struct ip_mreq)); netPath->multicastAddr = 0; netPath->unicastAddr = 0; if (netPath->eventSock > 0) close(netPath->eventSock); netPath->eventSock = -1; if (netPath->generalSock > 0) close(netPath->generalSock); netPath->generalSock = -1; return TRUE; } int netSelect(TimeInternal * timeout, NetPath * netPath) { int ret, nfds; fd_set readfds; struct timeval tv, *tv_ptr; if (timeout < 0) return FALSE; FD_ZERO(&readfds); FD_SET(netPath->eventSock, &readfds); FD_SET(netPath->generalSock, &readfds); if (timeout) { tv.tv_sec = timeout->seconds; tv.tv_usec = timeout->nanoseconds / 1000; tv_ptr = &tv; } else tv_ptr = 0; if (netPath->eventSock > netPath->generalSock) nfds = netPath->eventSock; else nfds = netPath->generalSock; ret = select(nfds + 1, &readfds, 0, 0, tv_ptr) > 0; if (ret < 0) { if (errno == EAGAIN || errno == EINTR) return 0; } return ret; }
/* on socket options, see the 'socket(7)' and 'ip' man pages */ Boolean netInit(NetPath *netPath, RunTimeOpts *rtOpts, PtpClock *ptpClock) { int temp, i; struct in_addr interfaceAddr, netAddr; struct sockaddr_in addr; struct ip_mreq imr; char addrStr[NET_ADDRESS_LENGTH]; char *s; DBG("netInit\n"); /* open sockets */ if( (netPath->eventSock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP) ) < 0 || (netPath->generalSock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP) ) < 0 ) { PERROR("failed to initalize sockets"); return FALSE; } /* find a network interface */ if( !(interfaceAddr.s_addr = findIface(rtOpts->ifaceName, &ptpClock->port_communication_technology, ptpClock->port_uuid_field, netPath)) ) return FALSE; temp = 1; /* allow address reuse */ if( setsockopt(netPath->eventSock, SOL_SOCKET, SO_REUSEADDR, &temp, sizeof(int)) < 0 || setsockopt(netPath->generalSock, SOL_SOCKET, SO_REUSEADDR, &temp, sizeof(int)) < 0 ) { DBG("failed to set socket reuse\n"); } /* bind sockets */ /* need INADDR_ANY to allow receipt of multi-cast and uni-cast messages */ addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = htons(PTP_EVENT_PORT); if(bind(netPath->eventSock, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)) < 0) { PERROR("failed to bind event socket"); return FALSE; } addr.sin_port = htons(PTP_GENERAL_PORT); if(bind(netPath->generalSock, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)) < 0) { PERROR("failed to bind general socket"); return FALSE; } /* set general and port address */ *(Integer16*)ptpClock->event_port_address = PTP_EVENT_PORT; *(Integer16*)ptpClock->general_port_address = PTP_GENERAL_PORT; /* send a uni-cast address if specified (useful for testing) */ if(rtOpts->unicastAddress[0]) { if(!inet_aton(rtOpts->unicastAddress, &netAddr)) { ERROR("failed to encode uni-cast address: %s\n", rtOpts->unicastAddress); return FALSE; } netPath->unicastAddr = netAddr.s_addr; } else netPath->unicastAddr = 0; /* resolve PTP subdomain */ if(!lookupSubdomainAddress(rtOpts->subdomainName, addrStr)) return FALSE; if(!inet_aton(addrStr, &netAddr)) { ERROR("failed to encode multi-cast address: %s\n", addrStr); return FALSE; } netPath->multicastAddr = netAddr.s_addr; s = addrStr; for(i = 0; i < SUBDOMAIN_ADDRESS_LENGTH; ++i) { ptpClock->subdomain_address[i] = strtol(s, &s, 0); if(!s) break; ++s; } /* multicast send only on specified interface */ imr.imr_multiaddr.s_addr = netAddr.s_addr; imr.imr_interface.s_addr = interfaceAddr.s_addr; if( setsockopt(netPath->eventSock, IPPROTO_IP, IP_MULTICAST_IF, &imr.imr_interface.s_addr, sizeof(struct in_addr)) < 0 || setsockopt(netPath->generalSock, IPPROTO_IP, IP_MULTICAST_IF, &imr.imr_interface.s_addr, sizeof(struct in_addr)) < 0 ) { PERROR("failed to enable multi-cast on the interface"); return FALSE; } /* join multicast group (for receiving) on specified interface */ if( setsockopt(netPath->eventSock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(struct ip_mreq)) < 0 || setsockopt(netPath->generalSock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(struct ip_mreq)) < 0 ) { PERROR("failed to join the multi-cast group"); return FALSE; } /* set socket time-to-live to 1 */ temp = 1; if( setsockopt(netPath->eventSock, IPPROTO_IP, IP_MULTICAST_TTL, &temp, sizeof(int)) < 0 || setsockopt(netPath->generalSock, IPPROTO_IP, IP_MULTICAST_TTL, &temp, sizeof(int)) < 0 ) { PERROR("failed to set the multi-cast time-to-live"); return FALSE; } /* enable loopback */ temp = 1; if( setsockopt(netPath->eventSock, IPPROTO_IP, IP_MULTICAST_LOOP, &temp, sizeof(int)) < 0 || setsockopt(netPath->generalSock, IPPROTO_IP, IP_MULTICAST_LOOP, &temp, sizeof(int)) < 0 ) { PERROR("failed to enable multi-cast loopback"); return FALSE; } /* make timestamps available through recvmsg() */ temp = 1; if( setsockopt(netPath->eventSock, SOL_SOCKET, SO_TIMESTAMP, &temp, sizeof(int)) < 0 || setsockopt(netPath->generalSock, SOL_SOCKET, SO_TIMESTAMP, &temp, sizeof(int)) < 0 ) { PERROR("failed to enable receive time stamps"); return FALSE; } return TRUE; }