Annotation of src/usr.bin/aucat/listen.c, Revision 1.18
1.18 ! ratchov 1: /* $OpenBSD: listen.c,v 1.17 2011/10/12 07:20:04 ratchov 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>
1.13 deraadt 19: #include <sys/signal.h>
1.2 ratchov 20: #include <sys/stat.h>
1.1 ratchov 21: #include <sys/un.h>
1.14 ratchov 22:
23: #include <netinet/in.h>
1.15 ratchov 24: #include <netinet/tcp.h>
1.14 ratchov 25: #include <netdb.h>
26:
1.1 ratchov 27: #include <err.h>
28: #include <errno.h>
29: #include <fcntl.h>
30: #include <poll.h>
31: #include <stdio.h>
32: #include <stdlib.h>
33: #include <string.h>
34: #include <unistd.h>
35:
36: #include "conf.h"
1.10 ratchov 37: #include "listen.h"
1.1 ratchov 38: #include "sock.h"
1.17 ratchov 39: #include "dbg.h"
1.1 ratchov 40:
41: struct fileops listen_ops = {
42: "listen",
43: sizeof(struct listen),
44: listen_close,
45: NULL, /* read */
46: NULL, /* write */
47: NULL, /* start */
48: NULL, /* stop */
49: listen_nfds,
50: listen_pollfd,
51: listen_revents
52: };
53:
1.17 ratchov 54: struct listen *listen_list = NULL;
55:
1.12 ratchov 56: void
57: listen_new_un(char *path)
1.1 ratchov 58: {
1.7 ratchov 59: int sock, oldumask;
1.1 ratchov 60: struct sockaddr_un sockname;
61: struct listen *f;
62:
63: sock = socket(AF_UNIX, SOCK_STREAM, 0);
64: if (sock < 0) {
65: perror("socket");
1.12 ratchov 66: exit(1);
1.1 ratchov 67: }
68: if (unlink(path) < 0 && errno != ENOENT) {
69: perror("unlink");
1.8 ratchov 70: goto bad_close;
1.1 ratchov 71: }
72: sockname.sun_family = AF_UNIX;
73: strlcpy(sockname.sun_path, path, sizeof(sockname.sun_path));
1.7 ratchov 74: oldumask = umask(0111);
1.6 ratchov 75: if (bind(sock, (struct sockaddr *)&sockname,
76: sizeof(struct sockaddr_un)) < 0) {
1.1 ratchov 77: perror("bind");
1.8 ratchov 78: goto bad_close;
1.2 ratchov 79: }
1.7 ratchov 80: umask(oldumask);
1.12 ratchov 81: f = (struct listen *)file_new(&listen_ops, path, 1);
1.8 ratchov 82: if (f == NULL)
83: goto bad_close;
1.1 ratchov 84: f->path = strdup(path);
85: if (f->path == NULL) {
86: perror("strdup");
87: exit(1);
88: }
89: f->fd = sock;
1.17 ratchov 90: f->next = listen_list;
91: listen_list = f;
1.12 ratchov 92: return;
1.8 ratchov 93: bad_close:
94: close(sock);
1.12 ratchov 95: exit(1);
1.14 ratchov 96: }
97:
98: void
99: listen_new_tcp(char *addr, unsigned port)
100: {
101: char *host, serv[sizeof(unsigned) * 3 + 1];
102: struct addrinfo *ailist, *ai, aihints;
103: struct listen *f;
104: int s, error, opt = 1, n = 0;
105:
106: /*
107: * obtain a list of possible addresses for the host/port
108: */
109: memset(&aihints, 0, sizeof(struct addrinfo));
110: snprintf(serv, sizeof(serv), "%u", port);
1.16 ratchov 111: host = strcmp(addr, "-") == 0 ? NULL : addr;
1.14 ratchov 112: aihints.ai_flags |= AI_PASSIVE;
113: aihints.ai_socktype = SOCK_STREAM;
114: aihints.ai_protocol = IPPROTO_TCP;
115: error = getaddrinfo(host, serv, &aihints, &ailist);
116: if (error) {
117: fprintf(stderr, "%s: %s\n", addr, gai_strerror(error));
118: exit(1);
119: }
120:
121: /*
122: * for each address, try create a listening socket bound on
123: * that address
124: */
125: for (ai = ailist; ai != NULL; ai = ai->ai_next) {
126: s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
127: if (s < 0) {
128: perror("socket");
129: continue;
130: }
131: opt = 1;
132: if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int)) < 0) {
133: perror("setsockopt");
134: goto bad_close;
135: }
136: if (bind(s, ai->ai_addr, ai->ai_addrlen) < 0) {
137: perror("bind");
138: goto bad_close;
139: }
140: f = (struct listen *)file_new(&listen_ops, addr, 1);
141: if (f == NULL) {
142: bad_close:
143: close(s);
144: continue;
145: }
146: f->path = NULL;
147: f->fd = s;
1.17 ratchov 148: f->next = listen_list;
149: listen_list = f;
1.14 ratchov 150: n++;
151: }
152: freeaddrinfo(ailist);
153: if (n == 0)
154: exit(1);
1.1 ratchov 155: }
156:
157: int
1.17 ratchov 158: listen_init(struct listen *f)
159: {
160: if (listen(f->fd, 1) < 0) {
161: perror("listen");
162: return 0;
163: }
164: return 1;
165: }
166:
167: int
1.1 ratchov 168: listen_nfds(struct file *f) {
169: return 1;
170: }
171:
172: int
173: listen_pollfd(struct file *file, struct pollfd *pfd, int events)
174: {
175: struct listen *f = (struct listen *)file;
176:
1.18 ! ratchov 177: if (file_slowaccept)
! 178: return 0;
1.1 ratchov 179: pfd->fd = f->fd;
180: pfd->events = POLLIN;
181: return 1;
182: }
183:
184: int
185: listen_revents(struct file *file, struct pollfd *pfd)
186: {
187: struct listen *f = (struct listen *)file;
188: struct sockaddr caddr;
189: socklen_t caddrlen;
1.15 ratchov 190: int sock, opt;
1.1 ratchov 191:
192: if (pfd->revents & POLLIN) {
193: caddrlen = sizeof(caddrlen);
1.18 ! ratchov 194: while ((sock = accept(f->fd, &caddr, &caddrlen)) < 0) {
! 195: if (errno == EINTR)
! 196: continue;
! 197: if (errno == ENFILE || errno == EMFILE)
! 198: file_slowaccept = 1;
! 199: else
! 200: perror("accept");
1.1 ratchov 201: return 0;
202: }
203: if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
204: perror("fcntl(sock, O_NONBLOCK)");
205: close(sock);
206: return 0;
1.15 ratchov 207: }
208: if (f->path == NULL) {
209: opt = 1;
210: if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
211: &opt, sizeof(int)) < 0) {
212: perror("setsockopt");
213: close(sock);
214: return 0;
215: }
1.1 ratchov 216: }
1.9 ratchov 217: if (sock_new(&sock_ops, sock) == NULL) {
1.8 ratchov 218: close(sock);
219: return 0;
220: }
1.1 ratchov 221: }
222: return 0;
223: }
224:
225: void
226: listen_close(struct file *file)
227: {
1.17 ratchov 228: struct listen *f = (struct listen *)file, **pf;
1.1 ratchov 229:
1.12 ratchov 230: if (f->path != NULL) {
231: unlink(f->path);
232: free(f->path);
233: }
1.10 ratchov 234: close(f->fd);
1.17 ratchov 235: for (pf = &listen_list; *pf != f; pf = &(*pf)->next) {
236: #ifdef DEBUG
237: if (*pf == NULL) {
238: dbg_puts("listen_close: not on list\n");
239: dbg_panic();
240: }
241: #endif
1.12 ratchov 242: }
1.17 ratchov 243: *pf = f->next;
1.1 ratchov 244: }