#ifndef LINT static char *rcsid="$Id: serv_unix.c,v 1.13 2001/07/20 07:35:54 crosser Exp $"; #endif /* $Log: serv_unix.c,v $ Revision 1.13 2001/07/20 07:35:54 crosser more tuning of AF_UNIX address size, now works on FreeBSD Revision 1.12 2001/07/20 05:48:59 crosser address bug with AF_UNIX address size fix permissions of unix datagram socket (on Linux, honors umask) Revision 1.11 1999/10/03 21:18:04 crosser First (probably) working version with new run time config parser. Also added listenq parameter (backlog size for listen()) and renamed wtest to whoson (and with man page). Release 2.00beta1. Revision 1.10 1999/08/19 17:22:16 crosser Move to new config scheme (does not work yet) Revision 1.9 1999/06/02 22:10:36 crosser deal with UNIX_PATH_MAX in a better way Revision 1.8 1998/07/28 17:51:53 crosser make 64bit architecure happy Revision 1.7 1998/07/26 14:06:40 crosser create pipe with 666 mode for compatibility Revision 1.6 1998/07/05 00:26:18 crosser Change copyright Revision 1.5 1998/07/03 09:32:48 crosser make persistant connections work Revision 1.4 1998/07/02 18:01:15 crosser change error reporting to syslog Revision 1.3 1998/07/02 15:51:24 crosser change DPRINT Revision 1.2 1998/07/02 15:37:07 crosser make right responce if req invalid Revision 1.1 1998/07/01 21:55:16 crosser Initial revision */ /* WHAT IS IT: Implementation of experimental "whoson" protocol AUTHOR: Eugene G. Crosser COPYRIGHT: Public domain */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "whosond.h" #include "rtconfig.h" #include "serv_common.h" #include "report.h" #include "rtc_begin.h" #include "serv_unix_cfg.h" #include "rtc_middle.h" #include "serv_unix_cfg.h" #include "rtc_end.h" struct _unix_data_rec { time_t ttl; int off; char buf[512]; }; static void search_request(int fd,struct _unix_data_rec *data) { char c,*p,*q; int crcount=0,lfcount=0; char retbuf[512]; for (p=data->buf;*p;p=q) { for (q=p;*q;q++) { switch (*q) { case '\r': crcount++; break; case '\n': lfcount++; break; default: crcount=0; lfcount=0; break; } if ((crcount > 1) || (lfcount > 1)) break; } if ((crcount > 1) || (lfcount > 1)) { while (*q && ((*q == '\r') || (*q == '\n'))) q++; c=*q; *q='\0'; retbuf[0]='\0'; do_request(p,retbuf,sizeof(retbuf)); write(fd,retbuf,strlen(retbuf)); *q=c; } else break; } if (*p) { /* move possible trailer to the start of buffer */ q=data->buf; while (*p) *q++=*p++; data->off=strlen(data->buf); } else data->off=0; } static struct _evdesc unix_read_evproc(int fd,void *priv) { struct _unix_data_rec *data=(struct _unix_data_rec *)priv; struct _evdesc evdesc; int len; DPRINT(("unix_read_evproc(%d,%p)\n",fd,priv)) memset(&evdesc,0,sizeof(struct _evdesc)); evdesc.fd=-1; if (fd < 0) { fd=-fd; close(fd); free(data); } else { if ((len=read(fd,(data->buf)+(data->off), sizeof(data->buf)-(data->off)-1)) > 0) { (data->off) += len; (data->buf)[data->off]='\0'; search_request(fd,data); evdesc.fd=fd; evdesc.evproc=unix_read_evproc; evdesc.ttl=data->ttl; evdesc.priv=data; } else { if (len < 0) ERRLOG((LOG_ERR,"read from socket: %m")) evdesc.fd=fd; close(fd); free(data); } } DPRINT(("unix_read_evproc returns fd=%d evproc=%p\n",evdesc.fd,evdesc.evproc)) return evdesc; } static struct _evdesc unix_ctl_evproc(int fd,void *priv) { wso_serv_unix_cfg *rec=(wso_serv_unix_cfg *)priv; struct _unix_data_rec *data; struct _evdesc evdesc; struct sockaddr_un from; int flen=sizeof(from); int msgsock; DPRINT(("unix_ctl_evproc(%d,%p)\n",fd,priv)) msgsock=accept(fd,(struct sockaddr*)&from,&flen); if (msgsock < 0) { ERRLOG((LOG_ERR,"accept: %m")) } memset(&evdesc,0,sizeof(struct _evdesc)); evdesc.fd=-1; if (msgsock >= 0) { if ((data=(struct _unix_data_rec *)malloc (sizeof(struct _unix_data_rec)))) { memset(data,0,sizeof(struct _unix_data_rec)); data->ttl=rec->keepalive; evdesc.fd=msgsock; /* accept real socket */ evdesc.evproc=unix_read_evproc; evdesc.ttl=rec->keepalive; evdesc.priv=data; } else { ERRLOG((LOG_ERR,"allocating wso_serv_unix_cfg: %m")) close(msgsock); } } DPRINT(("unix_ctl_evproc returns fd=%d evproc=%p\n",evdesc.fd,evdesc.evproc)) return evdesc; } struct _evdesc unix_serv_init(void *priv) { wso_serv_unix_cfg *rec=(wso_serv_unix_cfg *)priv; struct _evdesc evdesc; struct sockaddr_un server; int ctlsock=-1; int tries,on=1; int savemask; DPRINT(("unix_serv_init(%p)\n",priv)) memset((char *)&server,0,sizeof(server)); server.sun_family = AF_UNIX; strncpy(server.sun_path,rec->port,sizeof(server.sun_path)-1); server.sun_path[sizeof(server.sun_path)-1]='\0'; (void)unlink(server.sun_path); if ((ctlsock=socket(AF_UNIX,SOCK_STREAM,0)) < 0) { ERRLOG((LOG_ERR,"socket: %m")) goto exit; } if (setsockopt(ctlsock,SOL_SOCKET,SO_REUSEADDR, (char*)&on,sizeof(on)) < 0) { ERRLOG((LOG_ERR,"setsockopt: %m")) ctlsock=-1; goto exit; } savemask=umask(0); for (tries=0;;tries++) { if (bind(ctlsock,(struct sockaddr*)&server, sizeof(server)-sizeof(server.sun_path)+ strlen(server.sun_path)+1) < 0) { if ((errno == EADDRINUSE) && (tries < 10)) { sleep(tries); continue; } ERRLOG((LOG_ERR,"bind: %m")) ctlsock=-1; goto exit; } else break; } (void)umask(savemask); if (rec->listenq == 0) rec->listenq=5; if (listen(ctlsock,rec->listenq) < 0) { ERRLOG((LOG_ERR,"listen: %m")) } exit: memset(&evdesc,0,sizeof(struct _evdesc)); evdesc.fd=ctlsock; evdesc.evproc=unix_ctl_evproc; evdesc.ttl=0; evdesc.priv=priv; DPRINT(("unix_serv_init returns fd=%d evproc=%p\n",evdesc.fd,evdesc.evproc)) return evdesc; }