#include "tunala.h" #ifndef NO_IP #define IP_LISTENER_BACKLOG 511 /* So if it gets masked by 256 or some other such value it'll still be respectable */ /* Any IP-related initialisations. For now, this means blocking SIGPIPE */ int ip_initialise(void) { struct sigaction sa; sa.sa_handler = SIG_IGN; sa.sa_flags = 0; sigemptyset(&sa.sa_mask); if(sigaction(SIGPIPE, &sa, NULL) != 0) return 0; return 1; } int ip_create_listener_split(const char *ip, unsigned short port) { struct sockaddr_in in_addr; int fd = -1; int reuseVal = 1; /* Create the socket */ if((fd = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto err; /* Set the SO_REUSEADDR flag - servers act weird without it */ if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)(&reuseVal), sizeof(reuseVal)) != 0) goto err; /* Prepare the listen address stuff */ in_addr.sin_family = AF_INET; memcpy(&in_addr.sin_addr.s_addr, ip, 4); in_addr.sin_port = htons(port); /* Bind to the required port/address/interface */ if(bind(fd, (struct sockaddr *)&in_addr, sizeof(struct sockaddr_in)) != 0) goto err; /* Start "listening" */ if(listen(fd, IP_LISTENER_BACKLOG) != 0) goto err; return fd; err: if(fd != -1) close(fd); return -1; } int ip_create_connection_split(const char *ip, unsigned short port) { struct sockaddr_in in_addr; int flags, fd = -1; /* Create the socket */ if((fd = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto err; /* Make it non-blocking */ if(((flags = fcntl(fd, F_GETFL, 0)) < 0) || (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)) goto err; /* Prepare the connection address stuff */ in_addr.sin_family = AF_INET; memcpy(&in_addr.sin_addr.s_addr, ip, 4); in_addr.sin_port = htons(port); /* Start a connect (non-blocking, in all likelihood) */ if((connect(fd, (struct sockaddr *)&in_addr, sizeof(struct sockaddr_in)) != 0) && (errno != EINPROGRESS)) goto err; return fd; err: if(fd != -1) close(fd); return -1; } static char all_local_ip[] = {0x00,0x00,0x00,0x00}; int ip_parse_address(const char *address, const char **parsed_ip, unsigned short *parsed_port, int accept_all_ip) { char buf[256]; struct hostent *lookup; unsigned long port; const char *ptr = strstr(address, ":"); const char *ip = all_local_ip; if(!ptr) { /* We assume we're listening on all local interfaces and have * only specified a port. */ if(!accept_all_ip) return 0; ptr = address; goto determine_port; } if((ptr - address) > 255) return 0; memset(buf, 0, 256); memcpy(buf, address, ptr - address); ptr++; if((lookup = gethostbyname(buf)) == NULL) { /* Spit a message to differentiate between lookup failures and * bad strings. */ fprintf(stderr, "hostname lookup for '%s' failed\n", buf); return 0; } ip = lookup->h_addr_list[0]; determine_port: if(strlen(ptr) < 1) return 0; if(!int_strtoul(ptr, &port) || (port > 65535)) return 0; *parsed_ip = ip; *parsed_port = (unsigned short)port; return 1; } int ip_create_listener(const char *address) { const char *ip; unsigned short port; if(!ip_parse_address(address, &ip, &port, 1)) return -1; return ip_create_listener_split(ip, port); } int ip_create_connection(const char *address) { const char *ip; unsigned short port; if(!ip_parse_address(address, &ip, &port, 0)) return -1; return ip_create_connection_split(ip, port); } int ip_accept_connection(int listen_fd) { return accept(listen_fd, NULL, NULL); } #endif /* !defined(NO_IP) */