#ifndef LINT static char *rcsid="$Id: clnt_unixd.c,v 1.7 2001/07/20 07:35:54 crosser Exp $"; #endif /* $Log: clnt_unixd.c,v $ Revision 1.7 2001/07/20 07:35:54 crosser more tuning of AF_UNIX address size, now works on FreeBSD Revision 1.6 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.5 1999/10/03 21:18:03 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.4 1999/08/19 17:22:15 crosser Move to new config scheme (does not work yet) Revision 1.3 1999/07/27 17:30:05 crosser fix names Revision 1.2 1999/01/30 16:44:17 crosser add unlink() 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 #ifdef HAVE_SYS_SELECT_H #include #endif #include #include #include #include #include #include #include #include #include "whoson.h" #include "rtconfig.h" #include "checkperm.h" #include "clnt_common.h" #include "report.h" #include "rtc_begin.h" #include "clnt_unixd_cfg.h" #include "rtc_middle.h" #include "clnt_unixd_cfg.h" #include "rtc_end.h" #define MAXREQL 1024 #define INITTIMEOUT 100000 #define MAXTRIES 5 #define MAXREREADS 20 int wso_unixd_clnt_connect(void *priv,char *buf) { wso_clnt_unixd_cfg *rec=(wso_clnt_unixd_cfg *)(priv); struct sockaddr_un server,me,frominet; int fd; int len,slen; fd_set rfds,wfds,efds; struct timeval seltimer; unsigned long timeout; int tries,rereads,rc=0; char wbuf[MAXREQL]; mode_t savemask; 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'; if ((fd=socket(AF_UNIX,SOCK_DGRAM,0)) < 0) { ERRLOG((LOG_ERR,"[WHOSON] socket: %m")) return -1; } /* This may sound stupid, but when using UNIX DGRAM socket, we must explicitely bind() it. "man 2 socket" says that a unique address will be assigned automatically, but apparently this ony works for INET sockets... */ memset((char *)&me,0,sizeof(me)); me.sun_family = AF_UNIX; if (tmpnam(me.sun_path) == NULL) { ERRLOG((LOG_ERR,"[WHOSON] cannot create temporary socket address: %m")) return -1; } savemask=umask(0); if (bind(fd,(struct sockaddr*)&me,sizeof(me)-sizeof(me.sun_path)+ strlen(me.sun_path)+1) < 0) { (void)umask(savemask); ERRLOG((LOG_ERR,"[WHOSON] bind: %m")) return -1; } (void)umask(savemask); strncpy(wbuf,buf,sizeof(wbuf)-1); wbuf[sizeof(wbuf)-1]='\0'; timeout=rec->inittimeout; for (tries=0;tries<(rec->maxtries);tries++) { len=strlen(wbuf); if (sendto(fd,wbuf,len,0,(struct sockaddr *)&server, sizeof(server)-sizeof(server.sun_path)+ strlen(server.sun_path)+1) != len) { ERRLOG((LOG_ERR,"[WHOSON] sendto: %m")) close(fd); (void)unlink(me.sun_path); return -1; } rereads=0; reread: DPRINT(("unixd waiting try=%d(%d max) timeout=%lu (init %u)\n", tries,rec->maxtries,timeout,rec->inittimeout)) seltimer.tv_sec=timeout/1000000L; seltimer.tv_usec=timeout%1000000L; DPRINT(("seltimer.tv_sec=%lu, seltimer.tv_usec=%lu\n", (long)seltimer.tv_sec, (long)seltimer.tv_usec)) FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); FD_SET(fd,&rfds); rc=select(fd+1,&rfds,&wfds,&efds,&seltimer); if (rc < 0) { ERRLOG((LOG_ERR,"[WHOSON] select: %m")) close(fd); (void)unlink(me.sun_path); return -1; } else if (rc > 0) { slen=sizeof(frominet); if ((len=recvfrom(fd,buf,MAXREQL-1,0, (struct sockaddr *) &frominet, &slen)) < 0) { ERRLOG((LOG_ERR,"[WHOSON] recvfrom: %m")) close(fd); (void)unlink(me.sun_path); return -1; } buf[len]='\0'; DPRINT(("recvfrom returned %d bytes: \"%s\"\n",len,buf)) if (strcmp(frominet.sun_path,server.sun_path) == 0) break; DPRINT(("did not pass address check: from %s, dest was %s\n", frominet.sun_path,server.sun_path)) ERRLOG((LOG_ERR,"[WHOSON] ignore reply from from %s (dest was %s)", frominet.sun_path,server.sun_path)) if (++rereads < MAXREREADS) goto reread; else sprintf(buf,"*Ignoring reply from %s, sent to %s\r\n\r\n", frominet.sun_path,server.sun_path); } timeout *= 2; } if (rc == 0) { ERRLOG((LOG_ERR,"[WHOSON] unixd excessive retries\n")) close(fd); (void)unlink(me.sun_path); return -1; } close(fd); (void)unlink(me.sun_path); return 0; }