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