diff options
Diffstat (limited to 'openssl/demos/tunala/ip.c')
-rw-r--r-- | openssl/demos/tunala/ip.c | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/openssl/demos/tunala/ip.c b/openssl/demos/tunala/ip.c new file mode 100644 index 000000000..96ef4e653 --- /dev/null +++ b/openssl/demos/tunala/ip.c @@ -0,0 +1,146 @@ +#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) */ + |