1 #ifndef LINT
2 static char *rcsid="$Id: clnt_unixd.c,v 1.7 2001/07/20 07:35:54 crosser Exp $";
3 #endif
4
5 /*
6 $Log: clnt_unixd.c,v $
7 Revision 1.7 2001/07/20 07:35:54 crosser
8 more tuning of AF_UNIX address size, now works on FreeBSD
9
10 Revision 1.6 2001/07/20 05:48:59 crosser
11 address bug with AF_UNIX address size
12 fix permissions of unix datagram socket (on Linux, honors umask)
13
14 Revision 1.5 1999/10/03 21:18:03 crosser
15 First (probably) working version with new run time config parser.
16 Also added listenq parameter (backlog size for listen()) and
17 renamed wtest to whoson (and with man page). Release 2.00beta1.
18
19 Revision 1.4 1999/08/19 17:22:15 crosser
20 Move to new config scheme (does not work yet)
21
22 Revision 1.3 1999/07/27 17:30:05 crosser
23 fix names
24
25 Revision 1.2 1999/01/30 16:44:17 crosser
26 add unlink()
27
28 Revision 1.1 1999/01/30 15:43:40 crosser
29 Initial revision
30
31 */
32
33 /*
34 WHAT IS IT:
35 Implementation of experimental "whoson" protocol
36 AUTHOR:
37 Eugene G. Crosser <crosser@average.org>
38 COPYRIGHT:
39 Public domain
40 */
41
42 #include "config.h"
43
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <time.h>
47 #include <sys/time.h>
48 #include <sys/socket.h>
49 #include <netinet/in.h>
50 #include <arpa/inet.h>
51 #include <sys/un.h>
52 #include <netdb.h>
53 #ifdef HAVE_SYS_SELECT_H
54 #include <sys/select.h>
55 #endif
56 #include <unistd.h>
57 #include <errno.h>
58 #include <signal.h>
59 #include <setjmp.h>
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <string.h>
63 #include <ctype.h>
64
65 #include "whoson.h"
66 #include "rtconfig.h"
67 #include "checkperm.h"
68 #include "clnt_common.h"
69 #include "report.h"
70
71 #include "rtc_begin.h"
72 #include "clnt_unixd_cfg.h"
73 #include "rtc_middle.h"
74 #include "clnt_unixd_cfg.h"
75 #include "rtc_end.h"
76
77 #define MAXREQL 1024
78
79 #define INITTIMEOUT 100000
80 #define MAXTRIES 5
81 #define MAXREREADS 20
82
wso_unixd_clnt_connect(void * priv,char * buf)83 int wso_unixd_clnt_connect(void *priv,char *buf)
84 {
85 wso_clnt_unixd_cfg *rec=(wso_clnt_unixd_cfg *)(priv);
86 struct sockaddr_un server,me,frominet;
87 int fd;
88 int len,slen;
89 fd_set rfds,wfds,efds;
90 struct timeval seltimer;
91 unsigned long timeout;
92 int tries,rereads,rc=0;
93 char wbuf[MAXREQL];
94 mode_t savemask;
95
96 memset((char *)&server,0,sizeof(server));
97 server.sun_family = AF_UNIX;
98 strncpy(server.sun_path,rec->port,sizeof(server.sun_path)-1);
99 server.sun_path[sizeof(server.sun_path)-1]='\0';
100 if ((fd=socket(AF_UNIX,SOCK_DGRAM,0)) < 0) {
101 ERRLOG((LOG_ERR,"[WHOSON] socket: %m"))
102 return -1;
103 }
104 /* This may sound stupid, but when using UNIX DGRAM socket, we
105 must explicitely bind() it. "man 2 socket" says that a unique
106 address will be assigned automatically, but apparently this
107 ony works for INET sockets... */
108 memset((char *)&me,0,sizeof(me));
109 me.sun_family = AF_UNIX;
110 if (tmpnam(me.sun_path) == NULL) {
111 ERRLOG((LOG_ERR,"[WHOSON] cannot create temporary socket address: %m"))
112 return -1;
113 }
114 savemask=umask(0);
115 if (bind(fd,(struct sockaddr*)&me,sizeof(me)-sizeof(me.sun_path)+
116 strlen(me.sun_path)+1) < 0) {
117 (void)umask(savemask);
118 ERRLOG((LOG_ERR,"[WHOSON] bind: %m"))
119 return -1;
120 }
121 (void)umask(savemask);
122
123 strncpy(wbuf,buf,sizeof(wbuf)-1);
124 wbuf[sizeof(wbuf)-1]='\0';
125 timeout=rec->inittimeout;
126 for (tries=0;tries<(rec->maxtries);tries++) {
127 len=strlen(wbuf);
128 if (sendto(fd,wbuf,len,0,(struct sockaddr *)&server,
129 sizeof(server)-sizeof(server.sun_path)+
130 strlen(server.sun_path)+1) != len) {
131 ERRLOG((LOG_ERR,"[WHOSON] sendto: %m"))
132 close(fd);
133 (void)unlink(me.sun_path);
134 return -1;
135 }
136
137 rereads=0;
138 reread:
139
140 DPRINT(("unixd waiting try=%d(%d max) timeout=%lu (init %u)\n",
141 tries,rec->maxtries,timeout,rec->inittimeout))
142
143 seltimer.tv_sec=timeout/1000000L;
144 seltimer.tv_usec=timeout%1000000L;
145 DPRINT(("seltimer.tv_sec=%lu, seltimer.tv_usec=%lu\n",
146 (long)seltimer.tv_sec,
147 (long)seltimer.tv_usec))
148 FD_ZERO(&rfds);
149 FD_ZERO(&wfds);
150 FD_ZERO(&efds);
151 FD_SET(fd,&rfds);
152
153 rc=select(fd+1,&rfds,&wfds,&efds,&seltimer);
154 if (rc < 0) {
155 ERRLOG((LOG_ERR,"[WHOSON] select: %m"))
156 close(fd);
157 (void)unlink(me.sun_path);
158 return -1;
159 } else if (rc > 0) {
160 slen=sizeof(frominet);
161 if ((len=recvfrom(fd,buf,MAXREQL-1,0,
162 (struct sockaddr *) &frominet, &slen)) < 0) {
163 ERRLOG((LOG_ERR,"[WHOSON] recvfrom: %m"))
164 close(fd);
165 (void)unlink(me.sun_path);
166 return -1;
167 }
168 buf[len]='\0';
169 DPRINT(("recvfrom returned %d bytes: \"%s\"\n",len,buf))
170 if (strcmp(frominet.sun_path,server.sun_path) == 0)
171 break;
172 DPRINT(("did not pass address check: from %s, dest was %s\n",
173 frominet.sun_path,server.sun_path))
174 ERRLOG((LOG_ERR,"[WHOSON] ignore reply from from %s (dest was %s)",
175 frominet.sun_path,server.sun_path))
176 if (++rereads < MAXREREADS)
177 goto reread;
178 else
179 sprintf(buf,"*Ignoring reply from %s, sent to %s\r\n\r\n",
180 frominet.sun_path,server.sun_path);
181 }
182
183 timeout *= 2;
184 }
185
186 if (rc == 0) {
187 ERRLOG((LOG_ERR,"[WHOSON] unixd excessive retries\n"))
188 close(fd);
189 (void)unlink(me.sun_path);
190 return -1;
191 }
192
193 close(fd);
194 (void)unlink(me.sun_path);
195 return 0;
196 }
197