remove hash.[ch] - i don't think we will need it
[project/libubox.git] / usock.c
1 #include <sys/types.h>
2 #include <sys/socket.h>
3 #include <sys/un.h>
4 #include <netdb.h>
5 #include <stdlib.h>
6 #include <unistd.h>
7 #include <fcntl.h>
8 #include <errno.h>
9 #include <string.h>
10
11 #include "usock.h"
12
13 int usock(int type, const char *host, const char *service) {
14         int sock = -1;
15
16         if (service && !(type & USOCK_UNIX)) {
17                 struct addrinfo *result, *rp;
18
19                 struct addrinfo hints = {
20                         .ai_family = (type & USOCK_IPV6ONLY) ? AF_INET6 :
21                                 (type & USOCK_IPV4ONLY) ? AF_INET : AF_UNSPEC,
22                         .ai_socktype = ((type & 0xff) == USOCK_TCP)
23                                 ? SOCK_STREAM : SOCK_DGRAM,
24                         .ai_flags = AI_ADDRCONFIG
25                                 | ((type & USOCK_SERVER) ? AI_PASSIVE : 0)
26                                 | ((type & USOCK_NUMERIC) ? AI_NUMERICHOST : 0),
27                 };
28
29                 if (getaddrinfo(host, service, &hints, &result)) {
30                         return -1;
31                 }
32
33                 for (rp = result; rp != NULL; rp = rp->ai_next) {
34                         if ((sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol))
35                         == -1) {
36                                 continue;
37                         }
38
39                         if (!(type & USOCK_NOCLOEXEC)) {
40                                 fcntl(sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC);
41                         }
42
43                         if (type & USOCK_NONBLOCK) {
44                                 fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK);
45                         }
46
47                         if (type & USOCK_SERVER) {
48                                 const int one = 1;
49                                 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
50
51                                 if (!bind(sock, rp->ai_addr, rp->ai_addrlen)
52                                 && ((type & 0xff) != USOCK_TCP || !listen(sock, SOMAXCONN))) {
53                                         break;
54                                 }
55                         } else {
56                                 if (!connect(sock, rp->ai_addr, rp->ai_addrlen)
57                                 || errno == EINPROGRESS) {
58                                         break;
59                                 }
60                         }
61
62                         close(sock);
63                         sock = -1;
64                 }
65                 freeaddrinfo(result);
66         } else {
67                 struct sockaddr_un sun = {.sun_family = AF_UNIX};
68                 if (strlen(host) >= sizeof(sun.sun_path)) {
69                         errno = EINVAL;
70                         return -1;
71                 }
72                 strcpy(sun.sun_path, host);
73
74                 if ((sock = socket(AF_UNIX, ((type & 0xff) == USOCK_TCP)
75                                 ? SOCK_STREAM : SOCK_DGRAM, 0)) == -1) {
76                         return -1;
77                 }
78
79                 if (!(type & USOCK_NOCLOEXEC)) {
80                         fcntl(sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC);
81                 }
82
83                 if (type & USOCK_NONBLOCK) {
84                         fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK);
85                 }
86
87                 if (type & USOCK_SERVER) {
88                         if (bind(sock, (struct sockaddr*)&sun, sizeof(sun)) ||
89                         ((type & 0xff) == USOCK_TCP && listen(sock, SOMAXCONN))) {
90                                 close(sock);
91                                 return -1;
92                         }
93                 } else {
94                         if (connect(sock, (struct sockaddr*)&sun, sizeof(sun))
95                         && errno != EINPROGRESS) {
96                                 close(sock);
97                                 return -1;
98                         }
99                 }
100         }
101         return sock;
102 }