static udp_t * udp_new (int port_nbr) { udp_t *self = (udp_t *) zmalloc (sizeof (udp_t)); self->port_nbr = port_nbr; // Create UDP socket self->handle = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (self->handle == -1) s_handle_io_error ("socket"); // Ask operating system to let us do broadcasts from socket int on = 1; if (setsockopt (self->handle, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) == -1) s_handle_io_error ("setsockopt (SO_BROADCAST)"); // Allow multiple processes to bind to socket; incoming // messages will come to each process if (setsockopt (self->handle, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) == -1) s_handle_io_error ("setsockopt (SO_REUSEADDR)"); struct sockaddr_in sockaddr = { 0 }; sockaddr.sin_family = AF_INET; sockaddr.sin_port = htons (self->port_nbr); sockaddr.sin_addr.s_addr = htonl (INADDR_ANY); if (bind (self->handle, &sockaddr, sizeof (sockaddr)) == -1) s_handle_io_error ("bind"); # if defined (__UNIX__) struct ifaddrs *interfaces; if (getifaddrs (&interfaces) == 0) { struct ifaddrs *interface = interfaces; while (interface) { // Hopefully the last interface will be WiFi if (interface->ifa_addr->sa_family == AF_INET) { self->address = *(struct sockaddr_in *) interface->ifa_addr; self->broadcast = *(struct sockaddr_in *) interface->ifa_broadaddr; self->broadcast.sin_port = htons (self->port_nbr); } interface = interface->ifa_next; } } freeifaddrs (interfaces); # else # error "Interface detection TBD on this operating system" # endif return self; }
zre_udp_t * zre_udp_new (int port_nbr) { zre_udp_t *self = (zre_udp_t *) zmalloc (sizeof (zre_udp_t)); self->port_nbr = port_nbr; // Create UDP socket self->handle = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (self->handle == -1) s_handle_io_error ("socket"); // Ask operating system to let us do broadcasts from socket int on = 1; if (setsockopt (self->handle, SOL_SOCKET, SO_BROADCAST, (char *) &on, sizeof (on)) == -1) s_handle_io_error ("setsockopt (SO_BROADCAST)"); // Allow multiple processes to bind to socket; incoming // messages will come to each process if (setsockopt (self->handle, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof (on)) == -1) s_handle_io_error ("setsockopt (SO_REUSEADDR)"); #if defined (SO_REUSEPORT) if (setsockopt (self->handle, SOL_SOCKET, SO_REUSEPORT, (char *) &on, sizeof (on)) == -1) s_handle_io_error ("setsockopt (SO_REUSEPORT)"); #endif // PROBLEM: this design will not survive the network interface being // killed and restarted while the program is running. struct sockaddr_in sockaddr = { 0 }; sockaddr.sin_family = AF_INET; sockaddr.sin_port = htons (self->port_nbr); sockaddr.sin_addr.s_addr = htonl (INADDR_ANY); if (bind (self->handle, (struct sockaddr *) &sockaddr, sizeof (sockaddr)) == -1) s_handle_io_error ("bind"); // Get the network interface (not portable) s_get_interface (self); // Now get printable address as host name if (self->host) free (self->host); self->host = zmalloc (INET_ADDRSTRLEN); getnameinfo ((struct sockaddr *) &self->address, sizeof (self->address), self->host, INET_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST); return self; }
static int s_binding_input (zloop_t *loop, zmq_pollitem_t *item, void *arg) { vocket_t *vocket = (vocket_t *) arg; driver_t *driver = vocket->driver; struct sockaddr_in addr; // Peer address socklen_t addr_len = sizeof (addr); int handle = accept (item->fd, (struct sockaddr *) &addr, &addr_len); if (handle >= 0) { s_set_nonblock (handle); if (vocket->peerings < vocket->max_peerings) { char *address = s_sin_addr_to_str (&addr); peering_t *peering = peering_require (vocket, address, FALSE); peering->handle = handle; peering_raise (peering); peering_poller (peering, ZMQ_POLLIN + ZMQ_POLLOUT); } else { zclock_log ("W: Max peerings reached for socket"); close (handle); } } else s_handle_io_error ("accept"); return 0; }
static void s_send_wire (peering_t *self) { vocket_t *vocket = self->vocket; driver_t *driver = self->driver; while (TRUE) { byte *data; size_t size = vtx_codec_bin_get (self->output, &data); if (size == 0) { peering_poller (self, ZMQ_POLLIN); break; // Buffer is empty, stop polling out } if (driver->verbose) zclock_log ("I: (tcp) send %zd bytes to %s", size, self->address); int bytes_sent = send (self->handle, data, size, 0); if (driver->verbose) zclock_log ("I: (tcp) actually sent %d bytes", bytes_sent); if (bytes_sent > 0) { vtx_codec_bin_tick (self->output, bytes_sent); if (bytes_sent < size) break; // Wait until network can accept more } else if (bytes_sent == 0 || s_handle_io_error ("send") == -1) { self->exception = TRUE; break; // Signal error and give up } } }
static ssize_t s_recv_wire (peering_t *self) { vocket_t *vocket = self->vocket; driver_t *driver = self->driver; // Read into buffer and dump what we got // TODO: only read as much as we have space in input queue // implement exception strategy here // - drop oldest, drop newest, pushback byte buffer [VTX_TCP_BUFSIZE]; ssize_t size = recv (self->handle, buffer, VTX_TCP_BUFSIZE, MSG_DONTWAIT); if (size == 0) // Other side closed TCP socket, so our peering is down self->exception = TRUE; else if (size == -1) { if (s_handle_io_error ("recv") == -1) // Hard error on socket, so peering is down self->exception = TRUE; } else { if (driver->verbose) zclock_log ("I: (tcp) recv %zd bytes from %s", size, self->address); int rc = vtx_codec_bin_put (self->input, buffer, size); assert (rc == 0); // store binary data into codec // if routing = request // retrieve message, if available // this is a reply // check reply is allowed in state // then send message through to msgpipe // else discard message // reset state machine on peering // if routing = reply // this is a request // if state allows incoming request // retrieve message, if available // vocket->reply_to = peering // send message through to msgpipe // if routing = router // retrieve message, if available // send schemed identity to msgpipe // send message through to msgpipe // any other routing, nomnom allowed // retrieve message, if available // send message through to msgpipe #if 0 else zclock_log ("W: unexpected message from %s - dropping", address); char *colon = strchr (address, ':'); assert (colon); *colon = 0; strcpy (vocket->sender, address); #endif }
static void udp_send (udp_t *self, byte *buffer, size_t length) { assert (self); inet_aton ("255.255.255.255", &self->broadcast.sin_addr); if (sendto (self->handle, buffer, length, 0, &self->broadcast, sizeof (struct sockaddr_in)) == -1) s_handle_io_error ("sendto"); }
void zre_udp_send (zre_udp_t *self, byte *buffer, size_t length) { assert (self); self->broadcast.sin_addr.s_addr = INADDR_BROADCAST; ssize_t size = sendto (self->handle, (char *) buffer, length, 0, (struct sockaddr *) &self->broadcast, sizeof (struct sockaddr_in)); if (size == -1) s_handle_io_error ("sendto"); }
static ssize_t udp_recv (udp_t *self, byte *buffer, size_t length) { assert (self); struct sockaddr_in sockaddr; socklen_t si_len = sizeof (struct sockaddr_in); ssize_t size = recvfrom (self->handle, buffer, length, 0, &sockaddr, &si_len); if (size == -1) s_handle_io_error ("recvfrom"); return size; }
void zre_udp_send (zre_udp_t *self, byte *buffer, size_t length) { assert (self); #if (defined (__WINDOWS__)) self->broadcast.sin_addr.s_addr = INADDR_BROADCAST; #else inet_aton ("255.255.255.255", &self->broadcast.sin_addr); #endif if (sendto (self->handle, (char *)buffer, length, 0, (struct sockaddr *) &self->broadcast, sizeof (struct sockaddr_in)) == -1) s_handle_io_error ("sendto"); }
ssize_t zre_udp_recv (zre_udp_t *self, byte *buffer, size_t length) { assert (self); socklen_t si_len = sizeof (struct sockaddr_in); ssize_t size = recvfrom (self->handle, (char *) buffer, length, 0, (struct sockaddr *) &self->sender, &si_len); if (size == -1) s_handle_io_error ("recvfrom"); // Store sender address as printable string if (self->from) free (self->from); self->from = zmalloc (INET_ADDRSTRLEN); #if (defined (__WINDOWS__)) getnameinfo ((struct sockaddr *) &self->sender, si_len, self->from, INET_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST); #else inet_ntop (AF_INET, &self->sender.sin_addr, self->from, si_len); #endif return size; }
static void s_get_interface (zre_udp_t *self) { #if defined (__UNIX__) # if defined (HAVE_GETIFADDRS) && defined (HAVE_FREEIFADDRS) struct ifaddrs *interfaces; if (getifaddrs (&interfaces) == 0) { struct ifaddrs *interface = interfaces; while (interface) { // Hopefully the last interface will be WiFi or Ethernet if (interface->ifa_addr->sa_family == AF_INET) { self->address = *(struct sockaddr_in *) interface->ifa_addr; self->broadcast = *(struct sockaddr_in *) interface->ifa_broadaddr; self->broadcast.sin_port = htons (self->port_nbr); if (s_wireless_nic (interface->ifa_name)) break; } interface = interface->ifa_next; } } freeifaddrs (interfaces); # else struct ifreq ifr; memset (&ifr, 0, sizeof (ifr)); # if !defined (LIBZRE_HAVE_ANDROID) // TODO: Using hardcoded wlan0 is ugly if (!s_wireless_nic ("wlan0")) s_handle_io_error ("wlan0_not_exist"); # endif int sock = 0; if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) s_handle_io_error ("foo_socket_not_opened"); // Get interface address ifr.ifr_addr.sa_family = AF_INET; strncpy (ifr.ifr_name, "wlan0", sizeof (ifr.ifr_name)); int rc = ioctl (sock, SIOCGIFADDR, (caddr_t) &ifr, sizeof (struct ifreq)); if (rc == -1) s_handle_io_error ("siocgifaddr"); // Get interface broadcast address memcpy (&self->address, ((struct sockaddr_in *) &ifr.ifr_addr), sizeof (struct sockaddr_in)); rc = ioctl (sock, SIOCGIFBRDADDR, (caddr_t) &ifr, sizeof (struct ifreq)); if (rc == -1) s_handle_io_error ("siocgifbrdaddr"); memcpy (&self->broadcast, ((struct sockaddr_in *) &ifr.ifr_broadaddr), sizeof (struct sockaddr_in)); self->broadcast.sin_port = htons (self->port_nbr); close (sock); # endif # elif defined (__WINDOWS__) // Currently does not filter for wireless NIC ULONG addr_size = 0; DWORD rc = GetAdaptersAddresses (AF_INET, GAA_FLAG_INCLUDE_PREFIX, NULL, NULL, &addr_size); assert (rc == ERROR_BUFFER_OVERFLOW); PIP_ADAPTER_ADDRESSES pip_addresses = malloc (addr_size); rc = GetAdaptersAddresses (AF_INET, GAA_FLAG_INCLUDE_PREFIX, NULL, pip_addresses, &addr_size); assert (rc == NO_ERROR); PIP_ADAPTER_ADDRESSES cur_address = pip_addresses; while (cur_address) { PIP_ADAPTER_UNICAST_ADDRESS pUnicast = cur_address->FirstUnicastAddress; PIP_ADAPTER_PREFIX pPrefix = cur_address->FirstPrefix; if (pUnicast && pPrefix) { // self->broadcast.sin_addr is replaced with 255.255.255.255 in zre_udp_send() self->address = *(struct sockaddr_in *)(pUnicast->Address.lpSockaddr); self->broadcast = *(struct sockaddr_in *)(pPrefix->Address.lpSockaddr); self->broadcast.sin_addr.s_addr |= htonl ((1 << (32 - pPrefix->PrefixLength)) - 1); } self->broadcast.sin_port = htons (self->port_nbr); cur_address = cur_address->Next; } free (pip_addresses); # else # error "Interface detection TBD on this operating system" # endif }
zre_udp_t * zre_udp_new (int port_nbr) { zre_udp_t *self = (zre_udp_t *) zmalloc (sizeof (zre_udp_t)); self->port_nbr = port_nbr; // Create UDP socket self->handle = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (self->handle == -1) s_handle_io_error ("socket"); // Ask operating system to let us do broadcasts from socket int on = 1; if (setsockopt (self->handle, SOL_SOCKET, SO_BROADCAST, (char *)&on, sizeof (on)) == -1) s_handle_io_error ("setsockopt (SO_BROADCAST)"); // Allow multiple processes to bind to socket; incoming // messages will come to each process if (setsockopt (self->handle, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) == -1) s_handle_io_error ("setsockopt (SO_REUSEADDR)"); #if defined (SO_REUSEPORT) if (setsockopt (self->handle, SOL_SOCKET, SO_REUSEPORT, &on, sizeof (on)) == -1) s_handle_io_error ("setsockopt (SO_REUSEPORT)"); #endif // PROBLEM: this design will not survive the network interface being // killed and restarted while the program is running. struct sockaddr_in sockaddr = { 0 }; sockaddr.sin_family = AF_INET; sockaddr.sin_port = htons (self->port_nbr); sockaddr.sin_addr.s_addr = htonl (INADDR_ANY); if (bind (self->handle, (struct sockaddr *) &sockaddr, sizeof (sockaddr)) == -1) s_handle_io_error ("bind"); # if defined (__UNIX__) # if defined (HAVE_GETIFADDRS) && defined (HAVE_FREEIFADDRS) struct ifaddrs *interfaces; if (getifaddrs (&interfaces) == 0) { struct ifaddrs *interface = interfaces; while (interface) { // Hopefully the last interface will be WiFi if (interface->ifa_addr->sa_family == AF_INET) { self->address = *(struct sockaddr_in *) interface->ifa_addr; self->broadcast = *(struct sockaddr_in *) interface->ifa_broadaddr; self->broadcast.sin_port = htons (self->port_nbr); if (s_wireless_nic (interface->ifa_name)) break; } interface = interface->ifa_next; } } freeifaddrs (interfaces); # else struct ifreq ifr; memset (&ifr, 0, sizeof (ifr)); /* TODO: Using hardcoded wlan0 is ugly */ # if !defined ( LIBZRE_HAVE_ANDROID ) if (!s_wireless_nic ("wlan0")) s_handle_io_error ("wlan0_not_exist"); # endif int sock = 0; if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) s_handle_io_error ("foo_socket_not_opened"); ifr.ifr_addr.sa_family = AF_INET; strncpy (ifr.ifr_name, "wlan0", sizeof (ifr.ifr_name)); int rc = ioctl (sock, SIOCGIFADDR, (caddr_t) &ifr, sizeof (struct ifreq)); if (rc == -1) s_handle_io_error ("siocgifaddr"); memcpy (&self->address, ((struct sockaddr_in*) &ifr.ifr_addr), sizeof (struct sockaddr_in)); rc = ioctl (sock, SIOCGIFBRDADDR, (caddr_t) &ifr, sizeof (struct ifreq)); if (rc == -1) s_handle_io_error ("siocgifbrdaddr"); memcpy (&self->broadcast, ((struct sockaddr_in*) &ifr.ifr_broadaddr), sizeof (struct sockaddr_in)); self->broadcast.sin_port = htons (self->port_nbr); close (sock); # endif if (self->host) free (self->host); self->host = zmalloc (INET_ADDRSTRLEN); inet_ntop (AF_INET, &self->address.sin_addr, self->host, sizeof (sockaddr)); # elif defined (__WINDOWS__) s_win_get_interface(self); if (self->host) free (self->host); self->host = zmalloc (INET_ADDRSTRLEN); getnameinfo ((struct sockaddr *)&self->address, sizeof (self->address), self->host, INET_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST); # else # error "Interface detection TBD on this operating system" # endif return self; }
static ssize_t s_recv_wire (peering_t *self) { vocket_t *vocket = self->vocket; driver_t *driver = self->driver; // Read into buffer and dump what we got // TODO: only read as much as we have space in input queue // implement exception strategy here // - drop oldest, drop newest, pushback byte buffer [VTX_TCP_BUFSIZE]; ssize_t size = recv (self->handle, buffer, VTX_TCP_BUFSIZE, MSG_DONTWAIT); if (size == 0) // Other side closed TCP socket, so our peering is down self->exception = TRUE; else if (size == -1) { if (s_handle_io_error ("recv") == -1) // Hard error on socket, so peering is down self->exception = TRUE; } else { if (driver->verbose) zclock_log ("I: (tcp) recv %zd bytes from %s", size, self->address); int rc = vtx_codec_bin_put (self->input, buffer, size); assert (rc == 0); Bool first_part = !self->more; Bool more; zmq_msg_t msg; zmq_msg_init (&msg); rc = vtx_codec_msg_get (self->input, &msg, &more); while (rc == 0) { if (vocket->routing == VTX_ROUTING_REQUEST) { // TODO state check // TODO Is reply expected to come from thes peering? int flags = ZMQ_DONTWAIT; if (more) flags |= ZMQ_SNDMORE; zmq_sendmsg (vocket->msgpipe, &msg, flags); } else if (vocket->routing == VTX_ROUTING_REPLY) { // TODO state check vocket->current_peering = self; int flags = ZMQ_DONTWAIT; if (more) flags |= ZMQ_SNDMORE; zmq_sendmsg (vocket->msgpipe, &msg, flags); } else if (vocket->routing == VTX_ROUTING_ROUTER) { // Send peering's ID if (first_part) { size_t id_size = strlen(driver->scheme) + strlen("://") + strlen(self->address); zmq_msg_t msg; rc = zmq_msg_init_size (&msg, id_size + 1); assert (rc == 0); strcpy (zmq_msg_data (&msg), driver->scheme); strcat (zmq_msg_data (&msg), "://"); strcat (zmq_msg_data (&msg), self->address); zmq_sendmsg (vocket->msgpipe, &msg, ZMQ_DONTWAIT|ZMQ_SNDMORE); zmq_msg_close (&msg); } int flags = ZMQ_DONTWAIT; if (more) flags |= ZMQ_SNDMORE; zmq_sendmsg (vocket->msgpipe, &msg, flags); } else if (vocket->nomnom) { int flags = ZMQ_DONTWAIT; if (more) flags |= ZMQ_SNDMORE; zmq_sendmsg (vocket->msgpipe, &msg, flags); } zmq_msg_close (&msg); zmq_msg_init (&msg); self->more = more; first_part = !more; rc = vtx_codec_msg_get (self->input, &msg, &more); } #if 0 else zclock_log ("W: unexpected message from %s - dropping", address); char *colon = strchr (address, ':'); assert (colon); *colon = 0; strcpy (vocket->sender, address); #endif }