ip.c revision 296465
1#include "tunala.h"
2
3#ifndef NO_IP
4
5# define IP_LISTENER_BACKLOG 511/* So if it gets masked by 256 or some other
6                                 * such value it'll still be respectable */
7
8/* Any IP-related initialisations. For now, this means blocking SIGPIPE */
9int ip_initialise(void)
10{
11    struct sigaction sa;
12
13    sa.sa_handler = SIG_IGN;
14    sa.sa_flags = 0;
15    sigemptyset(&sa.sa_mask);
16    if (sigaction(SIGPIPE, &sa, NULL) != 0)
17        return 0;
18    return 1;
19}
20
21int ip_create_listener_split(const char *ip, unsigned short port)
22{
23    struct sockaddr_in in_addr;
24    int fd = -1;
25    int reuseVal = 1;
26
27    /* Create the socket */
28    if ((fd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
29        goto err;
30    /* Set the SO_REUSEADDR flag - servers act weird without it */
31    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)(&reuseVal),
32                   sizeof(reuseVal)) != 0)
33        goto err;
34    /* Prepare the listen address stuff */
35    in_addr.sin_family = AF_INET;
36    memcpy(&in_addr.sin_addr.s_addr, ip, 4);
37    in_addr.sin_port = htons(port);
38    /* Bind to the required port/address/interface */
39    if (bind(fd, (struct sockaddr *)&in_addr, sizeof(struct sockaddr_in)) !=
40        0)
41        goto err;
42    /* Start "listening" */
43    if (listen(fd, IP_LISTENER_BACKLOG) != 0)
44        goto err;
45    return fd;
46 err:
47    if (fd != -1)
48        close(fd);
49    return -1;
50}
51
52int ip_create_connection_split(const char *ip, unsigned short port)
53{
54    struct sockaddr_in in_addr;
55    int flags, fd = -1;
56
57    /* Create the socket */
58    if ((fd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
59        goto err;
60    /* Make it non-blocking */
61    if (((flags = fcntl(fd, F_GETFL, 0)) < 0) ||
62        (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0))
63        goto err;
64    /* Prepare the connection address stuff */
65    in_addr.sin_family = AF_INET;
66    memcpy(&in_addr.sin_addr.s_addr, ip, 4);
67    in_addr.sin_port = htons(port);
68    /* Start a connect (non-blocking, in all likelihood) */
69    if ((connect(fd, (struct sockaddr *)&in_addr,
70                 sizeof(struct sockaddr_in)) != 0) && (errno != EINPROGRESS))
71        goto err;
72    return fd;
73 err:
74    if (fd != -1)
75        close(fd);
76    return -1;
77}
78
79static char all_local_ip[] = { 0x00, 0x00, 0x00, 0x00 };
80
81int ip_parse_address(const char *address, const char **parsed_ip,
82                     unsigned short *parsed_port, int accept_all_ip)
83{
84    char buf[256];
85    struct hostent *lookup;
86    unsigned long port;
87    const char *ptr = strstr(address, ":");
88    const char *ip = all_local_ip;
89
90    if (!ptr) {
91        /*
92         * We assume we're listening on all local interfaces and have only
93         * specified a port.
94         */
95        if (!accept_all_ip)
96            return 0;
97        ptr = address;
98        goto determine_port;
99    }
100    if ((ptr - address) > 255)
101        return 0;
102    memset(buf, 0, 256);
103    memcpy(buf, address, ptr - address);
104    ptr++;
105    if ((lookup = gethostbyname(buf)) == NULL) {
106        /*
107         * Spit a message to differentiate between lookup failures and bad
108         * strings.
109         */
110        fprintf(stderr, "hostname lookup for '%s' failed\n", buf);
111        return 0;
112    }
113    ip = lookup->h_addr_list[0];
114 determine_port:
115    if (strlen(ptr) < 1)
116        return 0;
117    if (!int_strtoul(ptr, &port) || (port > 65535))
118        return 0;
119    *parsed_ip = ip;
120    *parsed_port = (unsigned short)port;
121    return 1;
122}
123
124int ip_create_listener(const char *address)
125{
126    const char *ip;
127    unsigned short port;
128
129    if (!ip_parse_address(address, &ip, &port, 1))
130        return -1;
131    return ip_create_listener_split(ip, port);
132}
133
134int ip_create_connection(const char *address)
135{
136    const char *ip;
137    unsigned short port;
138
139    if (!ip_parse_address(address, &ip, &port, 0))
140        return -1;
141    return ip_create_connection_split(ip, port);
142}
143
144int ip_accept_connection(int listen_fd)
145{
146    return accept(listen_fd, NULL, NULL);
147}
148
149#endif                          /* !defined(NO_IP) */
150