/* This file is in the public domain. */ #include #include #include #include #include #include #include extern const char *__progname; #include "netfd.h" #include "config.h" #include "structs.h" #include "pollloop.h" typedef struct listen_local_priv LISTEN_LOCAL_PRIV; struct listen_local_priv { char *path; NETFD fd; LISTEN_LOCAL_PRIV *xfer; } ; extern LEP_OPS lep_ops_local; static int lep_local_add(CONFIG *cfg, LISTEN *l, const char *key, int keylen, const char *rest) { LEP *lep; LISTEN_LOCAL_PRIV *llp; if ((keylen != 5) || bcmp(key,"local",5)) return(0); if (! *rest) config_err(cfg,"missing path on `local' listen line"); llp = malloc(sizeof(LISTEN_LOCAL_PRIV)); llp->path = strdup(rest); netfd_init(&llp->fd); lep = malloc(sizeof(LEP)); lep->ops = &lep_ops_local; lep->priv = llp; lep->link = l->endpoints; l->endpoints = lep; return(1); } static void lep_local_free(void *pv) { LISTEN_LOCAL_PRIV *p; p = pv; free(p->path); netfd_shutdown(&p->fd); free(p); } static void lep_local_pre_transfer(void *pv) { ((LISTEN_LOCAL_PRIV *)pv)->xfer = 0; } static void lep_local_setup_transfer(void *fv, void *tv) { LISTEN_LOCAL_PRIV *f; LISTEN_LOCAL_PRIV *t; f = fv; t = tv; if (f->xfer || t->xfer) return; if (! strcmp(f->path,t->path)) { f->xfer = t; t->xfer = f; } } static void lep_local_do_transfer(void *pv) { LISTEN_LOCAL_PRIV *p; p = pv; if (! p->xfer) return; if (p->xfer->xfer != p) abort(); p->fd.fd = p->xfer->fd.fd; p->xfer->fd.fd = -1; p->xfer->xfer = 0; p->xfer = 0; } static void lep_local_no_transfer(void *pv) { ((LISTEN_LOCAL_PRIV *)pv)->xfer = 0; } static int lep_local_openfds(void *pv) { LISTEN_LOCAL_PRIV *p; struct sockaddr_un *s_un; int len; p = pv; if (p->xfer) return(0); if (p->fd.fd >= 0) abort(); s_un = 0; do <"err"> { p->fd.fd = socket(AF_LOCAL,SOCK_STREAM,0); if (p->fd.fd < 0) { fprintf(stderr,"%s: %s: socket: %s\n",__progname,p->path,strerror(errno)); break <"err">; } len = strlen(p->path); s_un = malloc(sizeof(*s_un)-sizeof(s_un->sun_path)+len+1); s_un->sun_family = AF_LOCAL; s_un->sun_len = sizeof(*s_un) - sizeof(s_un->sun_path) + len; bcopy(p->path,&s_un->sun_path[0],len); do <"bound"> { if (bind(p->fd.fd,(void *)s_un,s_un->sun_len) >= 0) break <"bound">; if (errno == EADDRINUSE) { struct stat stb; if ( (stat(p->path,&stb) >= 0) && ((stb.st_mode & S_IFMT) == S_IFSOCK) ) { unlink(p->path); if (bind(p->fd.fd,(void *)s_un,s_un->sun_len) >= 0) break <"bound">; } errno = EEXIST; } fprintf(stderr,"%s: %s: bind: %s\n",__progname,p->path,strerror(errno)); break <"err">; } while (0); if (listen(p->fd.fd,25) < 0) { fprintf(stderr,"%s: %s: listen: %s\n",__progname,p->path,strerror(errno)); break <"err">; } return(0); } while (0); if (p->fd.fd >= 0) { close(p->fd.fd); p->fd.fd = -1; } if (s_un) free(s_un); return(1); } static int rtest_local(void *av) { return(!av); /* XXX XXX XXX */ } static int wtest_local(void *av) { return(!av); /* XXX XXX XXX */ } static void rd_local(void *av) { av=av; /* XXX XXX XXX */ } static void wr_local(void *av) { av=av; /* XXX XXX XXX */ } static void lep_local_setup_poll(void *pv) { LISTEN_LOCAL_PRIV *p; p = pv; p->fd.ioid = add_poll_fd(p->fd.fd,&rtest_local,&wtest_local,&rd_local,&wr_local,p); } LEP_OPS lep_ops_local = LEP_OPS_INIT(local);