sock.c - quark - quark web server | |
git clone git://git.suckless.org/quark | |
Log | |
Files | |
Refs | |
LICENSE | |
--- | |
sock.c (4386B) | |
--- | |
1 /* See LICENSE file for copyright and license details. */ | |
2 #include <arpa/inet.h> | |
3 #include <errno.h> | |
4 #include <fcntl.h> | |
5 #include <netdb.h> | |
6 #include <netinet/in.h> | |
7 #include <stddef.h> | |
8 #include <stdio.h> | |
9 #include <string.h> | |
10 #include <sys/types.h> | |
11 #include <sys/socket.h> | |
12 #include <sys/stat.h> | |
13 #include <sys/time.h> | |
14 #include <sys/un.h> | |
15 #include <unistd.h> | |
16 | |
17 #include "sock.h" | |
18 #include "util.h" | |
19 | |
20 int | |
21 sock_get_ips(const char *host, const char* port) | |
22 { | |
23 struct addrinfo hints = { | |
24 .ai_flags = AI_NUMERICSERV, | |
25 .ai_family = AF_UNSPEC, | |
26 .ai_socktype = SOCK_STREAM, | |
27 }; | |
28 struct addrinfo *ai, *p; | |
29 int ret, insock = 0; | |
30 | |
31 if ((ret = getaddrinfo(host, port, &hints, &ai))) { | |
32 die("getaddrinfo: %s", gai_strerror(ret)); | |
33 } | |
34 | |
35 for (p = ai; p; p = p->ai_next) { | |
36 if ((insock = socket(p->ai_family, p->ai_socktype, | |
37 p->ai_protocol)) < 0) { | |
38 continue; | |
39 } | |
40 if (setsockopt(insock, SOL_SOCKET, SO_REUSEADDR, | |
41 &(int){1}, sizeof(int)) < 0) { | |
42 die("setsockopt:"); | |
43 } | |
44 if (bind(insock, p->ai_addr, p->ai_addrlen) < 0) { | |
45 /* bind failed, close the insock and retry */ | |
46 if (close(insock) < 0) { | |
47 die("close:"); | |
48 } | |
49 continue; | |
50 } | |
51 break; | |
52 } | |
53 freeaddrinfo(ai); | |
54 if (!p) { | |
55 /* we exhaustet the addrinfo-list and found no connectio… | |
56 if (errno == EACCES) { | |
57 die("You need to run as root or have " | |
58 "CAP_NET_BIND_SERVICE set to bind to " | |
59 "privileged ports"); | |
60 } else { | |
61 die("bind:"); | |
62 } | |
63 } | |
64 | |
65 if (listen(insock, SOMAXCONN) < 0) { | |
66 die("listen:"); | |
67 } | |
68 | |
69 return insock; | |
70 } | |
71 | |
72 int | |
73 sock_get_uds(const char *udsname, uid_t uid, gid_t gid) | |
74 { | |
75 struct sockaddr_un addr = { | |
76 .sun_family = AF_UNIX, | |
77 }; | |
78 size_t udsnamelen; | |
79 int insock, sockmode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | | |
80 S_IROTH | S_IWOTH; | |
81 | |
82 if ((insock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { | |
83 die("socket:"); | |
84 } | |
85 | |
86 if ((udsnamelen = strlen(udsname)) > sizeof(addr.sun_path) - 1) { | |
87 die("UNIX-domain socket name truncated"); | |
88 } | |
89 memcpy(addr.sun_path, udsname, udsnamelen + 1); | |
90 | |
91 if (bind(insock, (const struct sockaddr *)&addr, sizeof(addr)) <… | |
92 die("bind '%s':", udsname); | |
93 } | |
94 | |
95 if (listen(insock, SOMAXCONN) < 0) { | |
96 sock_rem_uds(udsname); | |
97 die("listen:"); | |
98 } | |
99 | |
100 if (chmod(udsname, sockmode) < 0) { | |
101 sock_rem_uds(udsname); | |
102 die("chmod '%s':", udsname); | |
103 } | |
104 | |
105 if (chown(udsname, uid, gid) < 0) { | |
106 sock_rem_uds(udsname); | |
107 die("chown '%s':", udsname); | |
108 } | |
109 | |
110 return insock; | |
111 } | |
112 | |
113 void | |
114 sock_rem_uds(const char *udsname) | |
115 { | |
116 if (unlink(udsname) < 0) { | |
117 die("unlink '%s':", udsname); | |
118 } | |
119 } | |
120 | |
121 int | |
122 sock_set_timeout(int fd, int sec) | |
123 { | |
124 struct timeval tv; | |
125 | |
126 tv.tv_sec = sec; | |
127 tv.tv_usec = 0; | |
128 | |
129 if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0… | |
130 setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0… | |
131 warn("setsockopt:"); | |
132 return 1; | |
133 } | |
134 | |
135 return 0; | |
136 } | |
137 | |
138 int | |
139 sock_set_nonblocking(int fd) | |
140 { | |
141 int flags; | |
142 | |
143 if ((flags = fcntl(fd, F_GETFL, 0)) < 0) { | |
144 warn("fcntl:"); | |
145 return 1; | |
146 } | |
147 | |
148 flags |= O_NONBLOCK; | |
149 | |
150 if (fcntl(fd, F_SETFL, flags) < 0) { | |
151 warn("fcntl:"); | |
152 return 1; | |
153 } | |
154 | |
155 return 0; | |
156 } | |
157 | |
158 int | |
159 sock_get_inaddr_str(const struct sockaddr_storage *in_sa, char *str, | |
160 size_t len) | |
161 { | |
162 switch (in_sa->ss_family) { | |
163 case AF_INET: | |
164 if (!inet_ntop(AF_INET, | |
165 &(((struct sockaddr_in *)in_sa)->sin_addr… | |
166 str, len)) { | |
167 warn("inet_ntop:"); | |
168 return 1; | |
169 } | |
170 break; | |
171 case AF_INET6: | |
172 if (!inet_ntop(AF_INET6, | |
173 &(((struct sockaddr_in6 *)in_sa)->sin6_ad… | |
174 str, len)) { | |
175 warn("inet_ntop:"); | |
176 return 1; | |
177 } | |
178 break; | |
179 case AF_UNIX: | |
180 snprintf(str, len, "uds"); | |
181 break; | |
182 default: | |
183 snprintf(str, len, "-"); | |
184 } | |
185 | |
186 return 0; | |
187 } | |
188 | |
189 int | |
190 sock_same_addr(const struct sockaddr_storage *sa1, const struct sockaddr… | |
191 { | |
192 /* return early if address-families don't match */ | |
193 if (sa1->ss_family != sa2->ss_family) { | |
194 return 0; | |
195 } | |
196 | |
197 switch (sa1->ss_family) { | |
198 case AF_INET6: | |
199 return memcmp(((struct sockaddr_in6 *)sa1)->sin6_addr.s6… | |
200 ((struct sockaddr_in6 *)sa2)->sin6_addr.s6… | |
201 sizeof(((struct sockaddr_in6 *)sa1)->sin6_… | |
202 case AF_INET: | |
203 return ((struct sockaddr_in *)sa1)->sin_addr.s_addr == | |
204 ((struct sockaddr_in *)sa2)->sin_addr.s_addr; | |
205 default: /* AF_UNIX */ | |
206 return strcmp(((struct sockaddr_un *)sa1)->sun_path, | |
207 ((struct sockaddr_un *)sa2)->sun_path) == … | |
208 } | |
209 } |