sock.c - quark - quark web server
(HTM) git clone git://git.suckless.org/quark
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) 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 connection */
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)) < 0) {
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_addr),
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_storage *sa2)
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_addr,
200 ((struct sockaddr_in6 *)sa2)->sin6_addr.s6_addr,
201 sizeof(((struct sockaddr_in6 *)sa1)->sin6_addr.s6_addr)) == 0;
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) == 0;
208 }
209 }