/* $OpenBSD: listen.c,v 1.8 2009/02/04 20:35:14 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "conf.h" #include "sock.h" #include "listen.h" struct fileops listen_ops = { "listen", sizeof(struct listen), listen_close, NULL, /* read */ NULL, /* write */ NULL, /* start */ NULL, /* stop */ listen_nfds, listen_pollfd, listen_revents }; struct listen * listen_new(struct fileops *ops, char *path, struct aparams *wpar, struct aparams *rpar, int maxweight) { int sock, oldumask; struct sockaddr_un sockname; struct listen *f; sock = socket(AF_UNIX, SOCK_STREAM, 0); if (sock < 0) { perror("socket"); return NULL; } if (unlink(path) < 0 && errno != ENOENT) { perror("unlink"); goto bad_close; } sockname.sun_family = AF_UNIX; strlcpy(sockname.sun_path, path, sizeof(sockname.sun_path)); oldumask = umask(0111); if (bind(sock, (struct sockaddr *)&sockname, sizeof(struct sockaddr_un)) < 0) { perror("bind"); goto bad_close; } umask(oldumask); if (listen(sock, 1) < 0) { perror("listen"); goto bad_close; } f = (struct listen *)file_new(ops, path, 1); if (f == NULL) goto bad_close; f->path = strdup(path); if (f->path == NULL) { perror("strdup"); exit(1); } f->fd = sock; f->wpar = *wpar; f->rpar = *rpar; f->maxweight = maxweight; #ifdef DEBUG if (debug_level > 0) { fprintf(stderr, "listen_new: %s: wpar=", f->path); aparams_print(&f->wpar); fprintf(stderr, ", rpar="); aparams_print(&f->rpar); fprintf(stderr, ", vol=%u\n", f->maxweight); } #endif return f; bad_close: close(sock); return NULL; } int listen_nfds(struct file *f) { return 1; } int listen_pollfd(struct file *file, struct pollfd *pfd, int events) { struct listen *f = (struct listen *)file; pfd->fd = f->fd; pfd->events = POLLIN; return 1; } int listen_revents(struct file *file, struct pollfd *pfd) { struct listen *f = (struct listen *)file; struct sockaddr caddr; socklen_t caddrlen; int sock; if (pfd->revents & POLLIN) { DPRINTF("listen_revents: %s: accepting connection\n", f->path); caddrlen = sizeof(caddrlen); sock = accept(f->fd, &caddr, &caddrlen); if (sock < 0) { perror("accept"); return 0; } if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) { perror("fcntl(sock, O_NONBLOCK)"); close(sock); return 0; } if (sock_new(&sock_ops, sock, "socket", &f->wpar, &f->rpar, f->maxweight) == NULL) { close(sock); return 0; } } return 0; } void listen_close(struct file *file) { struct listen *f = (struct listen *)file; (void)unlink(f->path); free(f->path); (void)close(f->fd); }