743 lines
18 KiB
C
743 lines
18 KiB
C
|
/*
|
||
|
* This library is free software; you can redistribute it and/or
|
||
|
* modify it under the terms of the GNU Lesser General Public
|
||
|
* License as published by the Free Software Foundation; either
|
||
|
* version 2.1 of the License, or (at your option) any later version.
|
||
|
*
|
||
|
* This library is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
* Lesser General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU Lesser General Public
|
||
|
* License along with this library; if not, write to the Free Software
|
||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||
|
*
|
||
|
* network.c
|
||
|
* Network code for libartnet
|
||
|
* Copyright (C) 2004-2007 Simon Newton
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#include <errno.h>
|
||
|
|
||
|
#ifndef WIN32
|
||
|
#include <sys/socket.h> // socket before net/if.h for mac
|
||
|
#include <net/if.h>
|
||
|
#include <sys/ioctl.h>
|
||
|
#else
|
||
|
typedef int socklen_t;
|
||
|
#include <winsock2.h>
|
||
|
#include <Lm.h>
|
||
|
#include <iphlpapi.h>
|
||
|
#endif
|
||
|
|
||
|
#include <unistd.h>
|
||
|
|
||
|
#include "private.h"
|
||
|
|
||
|
#ifdef HAVE_GETIFADDRS
|
||
|
#ifdef HAVE_LINUX_IF_PACKET_H
|
||
|
#define USE_GETIFADDRS
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
#ifdef USE_GETIFADDRS
|
||
|
#include <ifaddrs.h>
|
||
|
#include <linux/types.h> // required by if_packet
|
||
|
#include <linux/if_packet.h>
|
||
|
#endif
|
||
|
|
||
|
|
||
|
enum { INITIAL_IFACE_COUNT = 10 };
|
||
|
enum { IFACE_COUNT_INC = 5 };
|
||
|
enum { IFNAME_SIZE = 32 }; // 32 sounds a reasonable size
|
||
|
|
||
|
typedef struct iface_s {
|
||
|
struct sockaddr_in ip_addr;
|
||
|
struct sockaddr_in bcast_addr;
|
||
|
int8_t hw_addr[ARTNET_MAC_SIZE];
|
||
|
char if_name[IFNAME_SIZE];
|
||
|
struct iface_s *next;
|
||
|
} iface_t;
|
||
|
|
||
|
unsigned long LOOPBACK_IP = 0x7F000001;
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Free memory used by the iface's list
|
||
|
* @param head a pointer to the head of the list
|
||
|
*/
|
||
|
static void free_ifaces(iface_t *head) {
|
||
|
iface_t *ift, *ift_next;
|
||
|
|
||
|
for (ift = head; ift != NULL; ift = ift_next) {
|
||
|
ift_next = ift->next;
|
||
|
free(ift);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Add a new interface to an interface list
|
||
|
* @param head pointer to the head of the list
|
||
|
* @param tail pointer to the end of the list
|
||
|
* @return a new iface_t or void
|
||
|
*/
|
||
|
static iface_t *new_iface(iface_t **head, iface_t **tail) {
|
||
|
iface_t *iface = (iface_t*) calloc(1, sizeof(iface_t));
|
||
|
|
||
|
if (!iface) {
|
||
|
artnet_error("%s: calloc error %s" , __FUNCTION__, strerror(errno));
|
||
|
return NULL;
|
||
|
}
|
||
|
memset(iface, 0, sizeof(iface_t));
|
||
|
|
||
|
if (!*head) {
|
||
|
*head = *tail = iface;
|
||
|
} else {
|
||
|
(*tail)->next = iface;
|
||
|
*tail = iface;
|
||
|
}
|
||
|
return iface;
|
||
|
}
|
||
|
|
||
|
|
||
|
#ifdef WIN32
|
||
|
|
||
|
/*
|
||
|
* Set if_head to point to a list of iface_t structures which represent the
|
||
|
* interfaces on this machine
|
||
|
* @param ift_head the address of the pointer to the head of the list
|
||
|
*/
|
||
|
static int get_ifaces(iface_t **if_head) {
|
||
|
iface_t *if_tail, *iface;
|
||
|
PIP_ADAPTER_INFO pAdapter = NULL;
|
||
|
PIP_ADAPTER_INFO pAdapterInfo;
|
||
|
IP_ADDR_STRING *ipAddress;
|
||
|
ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
|
||
|
unsigned long net, mask;
|
||
|
if_tail = NULL;
|
||
|
|
||
|
while (1) {
|
||
|
pAdapterInfo = (IP_ADAPTER_INFO*) malloc(ulOutBufLen);
|
||
|
if (!pAdapterInfo) {
|
||
|
artnet_error("Error allocating memory needed for GetAdaptersinfo");
|
||
|
return ARTNET_EMEM;
|
||
|
}
|
||
|
|
||
|
DWORD status = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen);
|
||
|
if (status == NO_ERROR)
|
||
|
break;
|
||
|
|
||
|
free(pAdapterInfo);
|
||
|
if (status != ERROR_BUFFER_OVERFLOW) {
|
||
|
printf("GetAdaptersInfo failed with error: %d\n", (int) status);
|
||
|
return ARTNET_ENET;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (pAdapter = pAdapterInfo;
|
||
|
pAdapter && pAdapter < pAdapterInfo + ulOutBufLen;
|
||
|
pAdapter = pAdapter->Next) {
|
||
|
|
||
|
if(pAdapter->Type != MIB_IF_TYPE_ETHERNET)
|
||
|
continue;
|
||
|
|
||
|
for (ipAddress = &pAdapter->IpAddressList; ipAddress;
|
||
|
ipAddress = ipAddress->Next) {
|
||
|
|
||
|
net = inet_addr(ipAddress->IpAddress.String);
|
||
|
if (net) {
|
||
|
// Windows doesn't seem to have the notion of an interface being 'up'
|
||
|
// so we check if this interface has an address assigned.
|
||
|
iface = new_iface(if_head, &if_tail);
|
||
|
if (!iface)
|
||
|
continue;
|
||
|
|
||
|
mask = inet_addr(ipAddress->IpMask.String);
|
||
|
strncpy(iface->if_name, pAdapter->AdapterName, IFNAME_SIZE);
|
||
|
memcpy(iface->hw_addr, pAdapter->Address, ARTNET_MAC_SIZE);
|
||
|
iface->ip_addr.sin_addr.s_addr = net;
|
||
|
iface->bcast_addr.sin_addr.s_addr = (
|
||
|
(net & mask) | (0xFFFFFFFF ^ mask));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
free(pAdapterInfo);
|
||
|
return (ARTNET_EOK);
|
||
|
}
|
||
|
|
||
|
# else // not WIN32
|
||
|
|
||
|
#ifdef USE_GETIFADDRS
|
||
|
|
||
|
/*
|
||
|
* Check if we are interested in this interface
|
||
|
* @param ifa a pointer to a ifaddr struct
|
||
|
*/
|
||
|
static void add_iface_if_needed(iface_t **head, iface_t **tail,
|
||
|
struct ifaddrs *ifa) {
|
||
|
|
||
|
// skip down, loopback and non inet interfaces
|
||
|
if (!ifa || !ifa->ifa_addr) return;
|
||
|
if (!(ifa->ifa_flags & IFF_UP)) return;
|
||
|
if (ifa->ifa_flags & IFF_LOOPBACK) return;
|
||
|
if (ifa->ifa_addr->sa_family != AF_INET) return;
|
||
|
|
||
|
iface_t *iface = new_iface(head, tail);
|
||
|
struct sockaddr_in *sin = (struct sockaddr_in*) ifa->ifa_addr;
|
||
|
iface->ip_addr.sin_addr = sin->sin_addr;
|
||
|
strncpy(iface->if_name, ifa->ifa_name, IFNAME_SIZE - 1);
|
||
|
|
||
|
if (ifa->ifa_flags & IFF_BROADCAST) {
|
||
|
sin = (struct sockaddr_in *) ifa->ifa_broadaddr;
|
||
|
iface->bcast_addr.sin_addr = sin->sin_addr;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Set if_head to point to a list of iface_t structures which represent the
|
||
|
* interfaces on this machine
|
||
|
* @param ift_head the address of the pointer to the head of the list
|
||
|
*/
|
||
|
static int get_ifaces(iface_t **if_head) {
|
||
|
struct ifaddrs *ifa_list, *ifa_iter;
|
||
|
iface_t *if_tail, *if_iter;
|
||
|
struct sockaddr_ll *sll;
|
||
|
char *if_name, *cptr;
|
||
|
*if_head = if_tail = NULL;
|
||
|
|
||
|
if (getifaddrs(&ifa_list) != 0) {
|
||
|
artnet_error("Error getting interfaces: %s", strerror(errno));
|
||
|
return ARTNET_ENET;
|
||
|
}
|
||
|
|
||
|
for (ifa_iter = ifa_list; ifa_iter; ifa_iter = ifa_iter->ifa_next)
|
||
|
add_iface_if_needed(if_head, &if_tail, ifa_iter);
|
||
|
|
||
|
// Match up the interfaces with the corrosponding AF_PACKET interface
|
||
|
// to fetch the hw addresses
|
||
|
//
|
||
|
// TODO: Will probably not work on OS X, it should
|
||
|
// return AF_LINK -type sockaddr
|
||
|
for (if_iter = *if_head; if_iter; if_iter = if_iter->next) {
|
||
|
if_name = strdup(if_iter->if_name);
|
||
|
|
||
|
// if this is an alias, get mac of real interface
|
||
|
if ((cptr = strchr(if_name, ':')))
|
||
|
*cptr = 0;
|
||
|
|
||
|
// Find corresponding iface_t structure
|
||
|
for (ifa_iter = ifa_list; ifa_iter; ifa_iter = ifa_iter->ifa_next) {
|
||
|
if ((!ifa_iter->ifa_addr) || ifa_iter->ifa_addr->sa_family != AF_PACKET)
|
||
|
continue;
|
||
|
|
||
|
if (strncmp(if_name, ifa_iter->ifa_name, IFNAME_SIZE) == 0) {
|
||
|
// Found matching hw-address
|
||
|
sll = (struct sockaddr_ll*) ifa_iter->ifa_addr;
|
||
|
memcpy(if_iter->hw_addr, sll->sll_addr, ARTNET_MAC_SIZE);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
free(if_name);
|
||
|
}
|
||
|
freeifaddrs(ifa_list);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
#else // no GETIFADDRS
|
||
|
|
||
|
/*
|
||
|
* Set if_head to point to a list of iface_t structures which represent the
|
||
|
* interfaces on this machine
|
||
|
* @param ift_head the address of the pointer to the head of the list
|
||
|
*/
|
||
|
static int get_ifaces(iface_t **if_head) {
|
||
|
struct ifconf ifc;
|
||
|
struct ifreq *ifr, ifrcopy;
|
||
|
struct sockaddr_in *sin;
|
||
|
int len, lastlen, flags;
|
||
|
char *buf, *ptr;
|
||
|
iface_t *if_tail, *iface;
|
||
|
int ret = ARTNET_EOK;
|
||
|
int sd;
|
||
|
|
||
|
*if_head = if_tail = NULL;
|
||
|
|
||
|
// create socket to get iface config
|
||
|
sd = socket(PF_INET, SOCK_DGRAM, 0);
|
||
|
|
||
|
if (sd < 0) {
|
||
|
artnet_error("%s : Could not create socket %s", __FUNCTION__, strerror(errno));
|
||
|
ret = ARTNET_ENET;
|
||
|
goto e_return;
|
||
|
}
|
||
|
|
||
|
// first use ioctl to get a listing of interfaces
|
||
|
lastlen = 0;
|
||
|
len = INITIAL_IFACE_COUNT * sizeof(struct ifreq);
|
||
|
|
||
|
for (;;) {
|
||
|
buf = malloc(len);
|
||
|
|
||
|
if (buf == NULL) {
|
||
|
artnet_error_malloc();
|
||
|
ret = ARTNET_EMEM;
|
||
|
goto e_free;
|
||
|
}
|
||
|
|
||
|
ifc.ifc_len = len;
|
||
|
ifc.ifc_buf = buf;
|
||
|
if (ioctl(sd, SIOCGIFCONF, &ifc) < 0) {
|
||
|
if (errno != EINVAL || lastlen != 0) {
|
||
|
artnet_error("%s : ioctl error %s", __FUNCTION__, strerror(errno));
|
||
|
ret = ARTNET_ENET;
|
||
|
goto e_free;
|
||
|
}
|
||
|
} else {
|
||
|
if (ifc.ifc_len == lastlen)
|
||
|
break;
|
||
|
lastlen = ifc.ifc_len;
|
||
|
}
|
||
|
len += IFACE_COUNT_INC * sizeof(struct ifreq);
|
||
|
free(buf);
|
||
|
}
|
||
|
|
||
|
// loop through each iface
|
||
|
for (ptr = buf; ptr < buf + ifc.ifc_len;) {
|
||
|
ifr = (struct ifreq*) ptr;
|
||
|
|
||
|
// work out length here
|
||
|
#ifdef HAVE_SOCKADDR_SA_LEN
|
||
|
len = max(sizeof(struct sockaddr), ifr->ifr_addr.sa_len);
|
||
|
#else
|
||
|
switch (ifr->ifr_addr.sa_family) {
|
||
|
#ifdef IPV6
|
||
|
case AF_INET6:
|
||
|
len = sizeof(struct sockaddr_in6);
|
||
|
break;
|
||
|
#endif
|
||
|
case AF_INET:
|
||
|
default:
|
||
|
len = sizeof(SA);
|
||
|
break;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
ptr += sizeof(ifr->ifr_name) + len;
|
||
|
|
||
|
// look for AF_INET interfaces
|
||
|
if (ifr->ifr_addr.sa_family == AF_INET) {
|
||
|
ifrcopy = *ifr;
|
||
|
if (ioctl(sd, SIOCGIFFLAGS, &ifrcopy) < 0) {
|
||
|
artnet_error("%s : ioctl error %s" , __FUNCTION__, strerror(errno));
|
||
|
ret = ARTNET_ENET;
|
||
|
goto e_free_list;
|
||
|
}
|
||
|
|
||
|
flags = ifrcopy.ifr_flags;
|
||
|
if ((flags & IFF_UP) == 0)
|
||
|
continue; //skip down interfaces
|
||
|
|
||
|
if ((flags & IFF_LOOPBACK))
|
||
|
continue; //skip lookback
|
||
|
|
||
|
iface = new_iface(if_head, &if_tail);
|
||
|
if (!iface)
|
||
|
goto e_free_list;
|
||
|
|
||
|
sin = (struct sockaddr_in *) &ifr->ifr_addr;
|
||
|
iface->ip_addr.sin_addr = sin->sin_addr;
|
||
|
|
||
|
// fetch bcast address
|
||
|
#ifdef SIOCGIFBRDADDR
|
||
|
if (flags & IFF_BROADCAST) {
|
||
|
if (ioctl(sd, SIOCGIFBRDADDR, &ifrcopy) < 0) {
|
||
|
artnet_error("%s : ioctl error %s" , __FUNCTION__, strerror(errno));
|
||
|
ret = ARTNET_ENET;
|
||
|
goto e_free_list;
|
||
|
}
|
||
|
|
||
|
sin = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr;
|
||
|
iface->bcast_addr.sin_addr = sin->sin_addr;
|
||
|
}
|
||
|
#endif
|
||
|
// fetch hardware address
|
||
|
#ifdef SIOCGIFHWADDR
|
||
|
if (flags & SIOCGIFHWADDR) {
|
||
|
if (ioctl(sd, SIOCGIFHWADDR, &ifrcopy) < 0) {
|
||
|
artnet_error("%s : ioctl error %s", __FUNCTION__, strerror(errno));
|
||
|
ret = ARTNET_ENET;
|
||
|
goto e_free_list;
|
||
|
}
|
||
|
memcpy(&iface->hw_addr, ifrcopy.ifr_hwaddr.sa_data, ARTNET_MAC_SIZE);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/* ok, if that all failed we should prob try and use sysctl to work out the bcast
|
||
|
* and hware addresses
|
||
|
* i'll leave that for another day
|
||
|
*/
|
||
|
}
|
||
|
}
|
||
|
free(buf);
|
||
|
return ARTNET_EOK;
|
||
|
|
||
|
e_free_list:
|
||
|
free_ifaces(*if_head);
|
||
|
e_free:
|
||
|
free(buf);
|
||
|
close(sd);
|
||
|
e_return:
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
#endif // GETIFADDRS
|
||
|
#endif // not WIN32
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Scan for interfaces, and work out which one the user wanted to use.
|
||
|
*/
|
||
|
int artnet_net_init(node n, const char *preferred_ip) {
|
||
|
iface_t *ift, *ift_head = NULL;
|
||
|
struct in_addr wanted_ip;
|
||
|
|
||
|
int found = FALSE;
|
||
|
int i;
|
||
|
int ret = ARTNET_EOK;
|
||
|
|
||
|
if ((ret = get_ifaces(&ift_head)))
|
||
|
goto e_return;
|
||
|
|
||
|
if (n->state.verbose) {
|
||
|
printf("#### INTERFACES FOUND ####\n");
|
||
|
for (ift = ift_head; ift != NULL; ift = ift->next) {
|
||
|
printf("IP: %s\n", inet_ntoa(ift->ip_addr.sin_addr));
|
||
|
printf(" bcast: %s\n" , inet_ntoa(ift->bcast_addr.sin_addr));
|
||
|
printf(" hwaddr: ");
|
||
|
for (i = 0; i < ARTNET_MAC_SIZE; i++) {
|
||
|
if (i)
|
||
|
printf(":");
|
||
|
printf("%02x", (uint8_t) ift->hw_addr[i]);
|
||
|
}
|
||
|
printf("\n");
|
||
|
}
|
||
|
printf("#########################\n");
|
||
|
}
|
||
|
|
||
|
if (preferred_ip) {
|
||
|
// search through list of interfaces for one with the correct address
|
||
|
ret = artnet_net_inet_aton(preferred_ip, &wanted_ip);
|
||
|
if (ret)
|
||
|
goto e_cleanup;
|
||
|
|
||
|
for (ift = ift_head; ift != NULL; ift = ift->next) {
|
||
|
if (ift->ip_addr.sin_addr.s_addr == wanted_ip.s_addr) {
|
||
|
found = TRUE;
|
||
|
n->state.ip_addr = ift->ip_addr.sin_addr;
|
||
|
n->state.bcast_addr = ift->bcast_addr.sin_addr;
|
||
|
memcpy(&n->state.hw_addr, &ift->hw_addr, ARTNET_MAC_SIZE);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (!found) {
|
||
|
artnet_error("Cannot find ip %s", preferred_ip);
|
||
|
ret = ARTNET_ENET;
|
||
|
goto e_cleanup;
|
||
|
}
|
||
|
} else {
|
||
|
if (ift_head) {
|
||
|
// pick first address
|
||
|
// copy ip address, bcast address and hardware address
|
||
|
n->state.ip_addr = ift_head->ip_addr.sin_addr;
|
||
|
n->state.bcast_addr = ift_head->bcast_addr.sin_addr;
|
||
|
memcpy(&n->state.hw_addr, &ift_head->hw_addr, ARTNET_MAC_SIZE);
|
||
|
} else {
|
||
|
artnet_error("No interfaces found!");
|
||
|
ret = ARTNET_ENET;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
e_cleanup:
|
||
|
free_ifaces(ift_head);
|
||
|
e_return :
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Start listening on the socket
|
||
|
*/
|
||
|
int artnet_net_start(node n) {
|
||
|
int sock;
|
||
|
struct sockaddr_in servAddr;
|
||
|
int true_flag = TRUE;
|
||
|
node tmp;
|
||
|
|
||
|
// only attempt to bind if we are the group master
|
||
|
if (n->peering.master == TRUE) {
|
||
|
|
||
|
#ifdef WIN32
|
||
|
// check winsock version
|
||
|
WSADATA wsaData;
|
||
|
WORD wVersionRequested = MAKEWORD(2, 2);
|
||
|
if (WSAStartup(wVersionRequested, &wsaData) != 0)
|
||
|
return (-1);
|
||
|
if (wsaData.wVersion != wVersionRequested)
|
||
|
return (-2);
|
||
|
#endif
|
||
|
|
||
|
// create socket
|
||
|
sock = socket(PF_INET, SOCK_DGRAM, 0);
|
||
|
|
||
|
if (sock < 0) {
|
||
|
artnet_error("Could not create socket %s", artnet_net_last_error());
|
||
|
return ARTNET_ENET;
|
||
|
}
|
||
|
|
||
|
memset(&servAddr, 0x00, sizeof(servAddr));
|
||
|
servAddr.sin_family = AF_INET;
|
||
|
servAddr.sin_port = htons(ARTNET_PORT);
|
||
|
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||
|
|
||
|
if (n->state.verbose)
|
||
|
printf("Binding to %s \n", inet_ntoa(servAddr.sin_addr));
|
||
|
|
||
|
// bind sockets
|
||
|
if (bind(sock, (SA *) &servAddr, sizeof(servAddr)) == -1) {
|
||
|
artnet_error("Failed to bind to socket %s", artnet_net_last_error());
|
||
|
artnet_net_close(sock);
|
||
|
return ARTNET_ENET;
|
||
|
}
|
||
|
|
||
|
// allow bcasting
|
||
|
if (setsockopt(sock,
|
||
|
SOL_SOCKET,
|
||
|
SO_BROADCAST,
|
||
|
(char*) &true_flag, // char* for win32
|
||
|
sizeof(int)) == -1) {
|
||
|
artnet_error("Failed to bind to socket %s", artnet_net_last_error());
|
||
|
artnet_net_close(sock);
|
||
|
return ARTNET_ENET;
|
||
|
}
|
||
|
|
||
|
#ifdef WIN32
|
||
|
// ### LH - 22.08.2008
|
||
|
// make it possible to reuse port, if SO_REUSEADDR
|
||
|
// exists on operating system
|
||
|
|
||
|
// NEVER USE SO_EXCLUSIVEADDRUSE, as that freezes the application
|
||
|
// on WinXP, if port is in use !
|
||
|
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &true_flag,
|
||
|
sizeof(true_flag)) < 0) {
|
||
|
|
||
|
artnet_error("Set reuse failed", artnet_net_last_error());
|
||
|
artnet_net_close(sock);
|
||
|
return ARTNET_ENET;
|
||
|
}
|
||
|
|
||
|
u_long true = 1;
|
||
|
if (SOCKET_ERROR == ioctlsocket(sock, FIONBIO, &true)) {
|
||
|
|
||
|
artnet_error("ioctlsocket", artnet_net_last_error());
|
||
|
artnet_net_close(sock);
|
||
|
return ARTNET_ENET;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
n->sd = sock;
|
||
|
// Propagate the socket to all our peers
|
||
|
for (tmp = n->peering.peer; tmp && tmp != n; tmp = tmp->peering.peer)
|
||
|
tmp->sd = sock;
|
||
|
}
|
||
|
return ARTNET_EOK;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Receive a packet.
|
||
|
*/
|
||
|
int artnet_net_recv(node n, artnet_packet p, int delay) {
|
||
|
ssize_t len;
|
||
|
struct sockaddr_in cliAddr;
|
||
|
socklen_t cliLen = sizeof(cliAddr);
|
||
|
fd_set rset;
|
||
|
struct timeval tv;
|
||
|
int maxfdp1 = n->sd + 1;
|
||
|
|
||
|
FD_ZERO(&rset);
|
||
|
FD_SET((unsigned int) n->sd, &rset);
|
||
|
|
||
|
tv.tv_usec = 0;
|
||
|
tv.tv_sec = delay;
|
||
|
p->length = 0;
|
||
|
|
||
|
switch (select(maxfdp1, &rset, NULL, NULL, &tv)) {
|
||
|
case 0:
|
||
|
// timeout
|
||
|
return RECV_NO_DATA;
|
||
|
break;
|
||
|
case -1:
|
||
|
if ( errno != EINTR) {
|
||
|
artnet_error("Select error %s", artnet_net_last_error());
|
||
|
return ARTNET_ENET;
|
||
|
}
|
||
|
return ARTNET_EOK;
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// need a check here for the amount of data read
|
||
|
// should prob allow an extra byte after data, and pass the size as sizeof(Data) +1
|
||
|
// then check the size read and if equal to size(data)+1 we have an error
|
||
|
len = recvfrom(n->sd,
|
||
|
(char*) &(p->data), // char* for win32
|
||
|
sizeof(p->data),
|
||
|
0,
|
||
|
(SA*) &cliAddr,
|
||
|
&cliLen);
|
||
|
if (len < 0) {
|
||
|
artnet_error("Recvfrom error %s", artnet_net_last_error());
|
||
|
return ARTNET_ENET;
|
||
|
}
|
||
|
|
||
|
if (cliAddr.sin_addr.s_addr == n->state.ip_addr.s_addr ||
|
||
|
ntohl(cliAddr.sin_addr.s_addr) == LOOPBACK_IP) {
|
||
|
p->length = 0;
|
||
|
return ARTNET_EOK;
|
||
|
}
|
||
|
|
||
|
p->length = len;
|
||
|
memcpy(&(p->from), &cliAddr.sin_addr, sizeof(struct in_addr));
|
||
|
// should set to in here if we need it
|
||
|
return ARTNET_EOK;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Send a packet.
|
||
|
*/
|
||
|
int artnet_net_send(node n, artnet_packet p) {
|
||
|
struct sockaddr_in addr;
|
||
|
int ret;
|
||
|
|
||
|
if (n->state.mode != ARTNET_ON)
|
||
|
return ARTNET_EACTION;
|
||
|
|
||
|
addr.sin_family = AF_INET;
|
||
|
addr.sin_port = htons(ARTNET_PORT);
|
||
|
addr.sin_addr = p->to;
|
||
|
p->from = n->state.ip_addr;
|
||
|
|
||
|
if (n->state.verbose)
|
||
|
printf("sending to %s\n" , inet_ntoa(addr.sin_addr));
|
||
|
|
||
|
ret = sendto(n->sd,
|
||
|
(char*) &p->data, // char* required for win32
|
||
|
p->length,
|
||
|
0,
|
||
|
(SA*) &addr,
|
||
|
sizeof(addr));
|
||
|
if (ret == -1) {
|
||
|
artnet_error("Sendto failed: %s", artnet_net_last_error());
|
||
|
n->state.report_code = ARTNET_RCUDPFAIL;
|
||
|
return ARTNET_ENET;
|
||
|
|
||
|
} else if (p->length != ret) {
|
||
|
artnet_error("failed to send full datagram");
|
||
|
n->state.report_code = ARTNET_RCSOCKETWR1;
|
||
|
return ARTNET_ENET;
|
||
|
}
|
||
|
|
||
|
if (n->callbacks.send.fh) {
|
||
|
get_type(p);
|
||
|
n->callbacks.send.fh(n, p, n->callbacks.send.data);
|
||
|
}
|
||
|
return ARTNET_EOK;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
int artnet_net_reprogram(node n) {
|
||
|
iface_t *ift_head, *ift;
|
||
|
int i;
|
||
|
|
||
|
ift_head = get_ifaces(n->sd[0]);
|
||
|
|
||
|
for (ift = ift_head;ift != NULL; ift = ift->next ) {
|
||
|
printf("IP: %s\n", inet_ntoa(ift->ip_addr.sin_addr) );
|
||
|
printf(" bcast: %s\n" , inet_ntoa(ift->bcast_addr.sin_addr) );
|
||
|
printf(" hwaddr: ");
|
||
|
for(i = 0; i < 6; i++ ) {
|
||
|
printf("%hhx:", ift->hw_addr[i] );
|
||
|
}
|
||
|
printf("\n");
|
||
|
}
|
||
|
|
||
|
free_ifaces(ift_head);
|
||
|
|
||
|
}*/
|
||
|
|
||
|
|
||
|
int artnet_net_set_fdset(node n, fd_set *fdset) {
|
||
|
FD_SET((unsigned int) n->sd, fdset);
|
||
|
return ARTNET_EOK;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Close a socket
|
||
|
*/
|
||
|
int artnet_net_close(int sock) {
|
||
|
#ifdef WIN32
|
||
|
shutdown(sock, SD_BOTH);
|
||
|
closesocket(sock);
|
||
|
//WSACancelBlockingCall();
|
||
|
WSACleanup();
|
||
|
#else
|
||
|
if (close(sock)) {
|
||
|
artnet_error(artnet_net_last_error());
|
||
|
return ARTNET_ENET;
|
||
|
}
|
||
|
#endif
|
||
|
return ARTNET_EOK;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Convert a string to an in_addr
|
||
|
*/
|
||
|
int artnet_net_inet_aton(const char *ip_address, struct in_addr *address) {
|
||
|
#ifdef HAVE_INET_ATON
|
||
|
if (!inet_aton(ip_address, address)) {
|
||
|
#else
|
||
|
in_addr_t *addr = (in_addr_t*) address;
|
||
|
if ((*addr = inet_addr(ip_address)) == INADDR_NONE) {
|
||
|
#endif
|
||
|
artnet_error("IP conversion from %s failed", ip_address);
|
||
|
return ARTNET_EARG;
|
||
|
}
|
||
|
return ARTNET_EOK;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
*
|
||
|
*/
|
||
|
const char *artnet_net_last_error() {
|
||
|
#ifdef WIN32
|
||
|
static char error_str[10];
|
||
|
int error = WSAGetLastError();
|
||
|
snprintf(error_str, sizeof(error_str), "%d", error);
|
||
|
return error_str;
|
||
|
#else
|
||
|
return strerror(errno);
|
||
|
#endif
|
||
|
}
|
||
|
|