Annotation of src/usr.bin/sndiod/listen.c, Revision 1.14
1.14 ! ratchov 1: /* $OpenBSD: listen.c,v 1.13 2019/06/28 13:35:03 deraadt Exp $ */
1.1 ratchov 2: /*
3: * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
8: *
9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16: */
17: #include <sys/types.h>
18: #include <sys/socket.h>
19: #include <sys/stat.h>
20: #include <sys/un.h>
21:
22: #include <netinet/in.h>
23: #include <netinet/tcp.h>
24: #include <netdb.h>
25:
26: #include <errno.h>
27: #include <fcntl.h>
28: #include <poll.h>
29: #include <stdio.h>
30: #include <string.h>
31: #include <unistd.h>
32:
33: #include "listen.h"
34: #include "file.h"
35: #include "sock.h"
36: #include "utils.h"
37:
38: int listen_pollfd(void *, struct pollfd *);
39: int listen_revents(void *, struct pollfd *);
40: void listen_in(void *);
41: void listen_out(void *);
42: void listen_hup(void *);
43:
44: struct fileops listen_fileops = {
45: "listen",
46: listen_pollfd,
47: listen_revents,
48: listen_in,
49: listen_out,
50: listen_hup
51: };
52:
53: struct listen *listen_list = NULL;
54:
55: void
56: listen_close(struct listen *f)
57: {
58: struct listen **pf;
59:
60: for (pf = &listen_list; *pf != f; pf = &(*pf)->next) {
61: #ifdef DEBUG
62: if (*pf == NULL) {
63: log_puts("listen_close: not on list\n");
64: panic();
65: }
66: #endif
67: }
68: *pf = f->next;
69:
1.8 ratchov 70: if (f->path != NULL) {
1.1 ratchov 71: xfree(f->path);
1.8 ratchov 72: }
1.1 ratchov 73: file_del(f->file);
74: close(f->fd);
75: xfree(f);
76: }
77:
1.8 ratchov 78: int
1.1 ratchov 79: listen_new_un(char *path)
80: {
81: int sock, oldumask;
82: struct sockaddr_un sockname;
83: struct listen *f;
84:
85: sock = socket(AF_UNIX, SOCK_STREAM, 0);
1.13 deraadt 86: if (sock == -1) {
1.8 ratchov 87: log_puts(path);
88: log_puts(": failed to create socket\n");
89: return 0;
1.1 ratchov 90: }
1.13 deraadt 91: if (unlink(path) == -1 && errno != ENOENT) {
1.8 ratchov 92: log_puts(path);
93: log_puts(": failed to unlink socket\n");
1.1 ratchov 94: goto bad_close;
95: }
96: sockname.sun_family = AF_UNIX;
97: strlcpy(sockname.sun_path, path, sizeof(sockname.sun_path));
98: oldumask = umask(0111);
99: if (bind(sock, (struct sockaddr *)&sockname,
1.13 deraadt 100: sizeof(struct sockaddr_un)) == -1) {
1.8 ratchov 101: log_puts(path);
102: log_puts(": failed to bind socket\n");
1.1 ratchov 103: goto bad_close;
104: }
1.13 deraadt 105: if (listen(sock, 1) == -1) {
1.8 ratchov 106: log_puts(path);
107: log_puts(": failed to listen\n");
1.1 ratchov 108: goto bad_close;
109: }
110: umask(oldumask);
111: f = xmalloc(sizeof(struct listen));
112: f->file = file_new(&listen_fileops, f, path, 1);
113: if (f->file == NULL)
114: goto bad_close;
115: f->path = xstrdup(path);
116: f->fd = sock;
117: f->next = listen_list;
118: listen_list = f;
1.8 ratchov 119: return 1;
1.1 ratchov 120: bad_close:
121: close(sock);
1.8 ratchov 122: return 0;
1.1 ratchov 123: }
124:
1.8 ratchov 125: int
1.1 ratchov 126: listen_new_tcp(char *addr, unsigned int port)
127: {
128: char *host, serv[sizeof(unsigned int) * 3 + 1];
129: struct addrinfo *ailist, *ai, aihints;
130: struct listen *f;
131: int s, error, opt = 1, n = 0;
1.10 ratchov 132:
133: /*
134: * obtain a list of possible addresses for the host/port
1.1 ratchov 135: */
136: memset(&aihints, 0, sizeof(struct addrinfo));
137: snprintf(serv, sizeof(serv), "%u", port);
138: host = strcmp(addr, "-") == 0 ? NULL : addr;
139: aihints.ai_flags |= AI_PASSIVE;
140: aihints.ai_socktype = SOCK_STREAM;
141: aihints.ai_protocol = IPPROTO_TCP;
142: error = getaddrinfo(host, serv, &aihints, &ailist);
143: if (error) {
1.8 ratchov 144: log_puts(addr);
145: log_puts(": failed to resolve address\n");
146: return 0;
1.1 ratchov 147: }
148:
1.10 ratchov 149: /*
1.1 ratchov 150: * for each address, try create a listening socket bound on
151: * that address
152: */
153: for (ai = ailist; ai != NULL; ai = ai->ai_next) {
154: s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
1.13 deraadt 155: if (s == -1) {
1.8 ratchov 156: log_puts(addr);
157: log_puts(": failed to create socket\n");
1.1 ratchov 158: continue;
159: }
160: opt = 1;
161: if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
1.13 deraadt 162: &opt, sizeof(int)) == -1) {
1.8 ratchov 163: log_puts(addr);
164: log_puts(": failed to set SO_REUSEADDR\n");
1.1 ratchov 165: goto bad_close;
166: }
1.13 deraadt 167: if (bind(s, ai->ai_addr, ai->ai_addrlen) == -1) {
1.8 ratchov 168: log_puts(addr);
169: log_puts(": failed to bind socket\n");
1.1 ratchov 170: goto bad_close;
171: }
1.13 deraadt 172: if (listen(s, 1) == -1) {
1.8 ratchov 173: log_puts(addr);
174: log_puts(": failed to listen\n");
1.1 ratchov 175: goto bad_close;
176: }
177: f = xmalloc(sizeof(struct listen));
178: f->file = file_new(&listen_fileops, f, addr, 1);
179: if (f == NULL) {
180: bad_close:
181: close(s);
182: continue;
183: }
184: f->path = NULL;
185: f->fd = s;
186: f->next = listen_list;
187: listen_list = f;
188: n++;
189: }
190: freeaddrinfo(ailist);
1.8 ratchov 191: return n;
1.1 ratchov 192: }
193:
194: int
195: listen_init(struct listen *f)
196: {
197: return 1;
198: }
199:
200: int
201: listen_pollfd(void *arg, struct pollfd *pfd)
202: {
203: struct listen *f = arg;
204:
1.4 ratchov 205: f->slowaccept = file_slowaccept;
206: if (f->slowaccept)
1.1 ratchov 207: return 0;
208: pfd->fd = f->fd;
209: pfd->events = POLLIN;
210: return 1;
211: }
212:
213: int
214: listen_revents(void *arg, struct pollfd *pfd)
215: {
1.4 ratchov 216: struct listen *f = arg;
217:
218: if (f->slowaccept)
219: return 0;
1.1 ratchov 220: return pfd->revents;
221: }
222:
223: void
224: listen_in(void *arg)
225: {
226: struct listen *f = arg;
227: struct sockaddr caddr;
228: socklen_t caddrlen;
229: int sock, opt;
230:
231: caddrlen = sizeof(caddrlen);
1.13 deraadt 232: while ((sock = accept(f->fd, &caddr, &caddrlen)) == -1) {
1.1 ratchov 233: if (errno == EINTR)
234: continue;
235: if (errno == ENFILE || errno == EMFILE)
236: file_slowaccept = 1;
237: return;
238: }
1.13 deraadt 239: if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) {
1.8 ratchov 240: file_log(f->file);
241: log_puts(": failed to set non-blocking mode\n");
1.12 ratchov 242: goto bad_close;
1.1 ratchov 243: }
244: if (f->path == NULL) {
245: opt = 1;
246: if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
1.13 deraadt 247: &opt, sizeof(int)) == -1) {
1.8 ratchov 248: file_log(f->file);
249: log_puts(": failed to set TCP_NODELAY flag\n");
1.12 ratchov 250: goto bad_close;
1.1 ratchov 251: }
252: }
1.12 ratchov 253: if (sock_new(sock) == NULL)
254: goto bad_close;
255: return;
256: bad_close:
257: close(sock);
1.1 ratchov 258: }
259:
260: void
261: listen_out(void *arg)
262: {
263: }
264:
265: void
266: listen_hup(void *arg)
267: {
268: struct listen *f = arg;
269:
270: listen_close(f);
271: }