#ifndef LINT static char *rcsid="$Id: serv_unixd.c,v 1.5 2001/07/20 07:35:54 crosser Exp $"; #endif /* $Log: serv_unixd.c,v $ Revision 1.5 2001/07/20 07:35:54 crosser more tuning of AF_UNIX address size, now works on FreeBSD Revision 1.4 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.3 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.2 1999/08/19 17:22:16 crosser Move to new config scheme (does not work yet) Revision 1.1 1999/01/30 15:43:40 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 #ifdef HAVE_SYS_SELECT_H #include #endif #include #include #include #include #include #include #include "whosond.h" #include "rtconfig.h" #include "serv_common.h" #include "checkperm.h" #include "report.h" #include "rtc_begin.h" #include "serv_unixd_cfg.h" #include "rtc_middle.h" #include "serv_unixd_cfg.h" #include "rtc_end.h" struct _unixd_data_rec { char buf[512]; }; static struct _evdesc unixd_read_evproc(int fd,void *priv) { struct _unixd_data_rec *data=(struct _unixd_data_rec *)priv; struct _evdesc evdesc; int len,slen; struct sockaddr_un fromunix; char retbuf[512]; DPRINT(("unixd_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 { slen = sizeof(fromunix); if ((len=recvfrom(fd,data->buf,sizeof(data->buf)-1, 0,(struct sockaddr *)&fromunix,&slen)) > 0) { DPRINT(("UNIX DGRAM message (%d bytes) from %s\n",len,fromunix.sun_path)) retbuf[0]='\0'; do_request(data->buf,retbuf,sizeof(retbuf)); len=strlen(retbuf); if (sendto(fd,retbuf,len,0, (struct sockaddr *)&fromunix,slen) != len) { ERRLOG((LOG_ERR,"sendto: %m")) } } else { ERRLOG((LOG_ERR,"recvfrom: %m")) } } DPRINT(("unixd_read_evproc returns fd=%d evproc=%p\n",evdesc.fd,evdesc.evproc)) return evdesc; } struct _evdesc unixd_serv_init(void *priv) { wso_serv_unixd_cfg *rec=(wso_serv_unixd_cfg *)priv; struct _evdesc evdesc; struct _unixd_data_rec *data; struct sockaddr_un server; int msgsock=-1; int tries,on=1; mode_t savemask; DPRINT(("unixd_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 ((msgsock=socket(AF_UNIX,SOCK_DGRAM,0)) < 0) { ERRLOG((LOG_ERR,"socket: %m")) goto exit; } if (setsockopt(msgsock,SOL_SOCKET,SO_REUSEADDR, (char*)&on,sizeof(on)) < 0) { ERRLOG((LOG_ERR,"setsockopt: %m")) msgsock=-1; goto exit; } savemask=umask(0); for (tries=0;;tries++) { if (bind(msgsock,(struct sockaddr*)&server,sizeof(server)- sizeof(server.sun_path)+strlen(server.sun_path)+1) < 0) { if ((errno == EADDRINUSE) && (tries < 10)) { sleep(tries); continue; } (void)umask(savemask); ERRLOG((LOG_ERR,"bind: %m")) msgsock=-1; goto exit; } else break; } (void)umask(savemask); exit: memset(&evdesc,0,sizeof(struct _evdesc)); evdesc.fd=msgsock; evdesc.evproc=unixd_read_evproc; evdesc.ttl=0; evdesc.priv=priv; if ((data=(struct _unixd_data_rec *)malloc (sizeof(struct _unixd_data_rec)))) { memset(data,0,sizeof(struct _unixd_data_rec)); evdesc.priv=data; } else { ERRLOG((LOG_ERR,"allocating struct _unixd_data_rec: %m")) evdesc.fd=-1; evdesc.evproc=NULL; } DPRINT(("unixd_serv_init returns fd=%d evproc=%p\n",evdesc.fd,evdesc.evproc)) return evdesc; }