| #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) */ |