#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 <crosser@average.org>
COPYRIGHT:
Public domain
*/
#include "config.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/un.h>
#include <netdb.h>
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#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;
}
syntax highlighted by Code2HTML, v. 0.9.1