Whamcloud - gitweb
Branch HEAD
[fs/lustre-release.git] / lnet / utils / acceptor.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  */
4 #include <stdio.h>
5 #include <sys/types.h>
6 #include <sys/socket.h>
7 #include <netinet/tcp.h>
8 #include <netdb.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <fcntl.h>
12 #include <sys/ioctl.h>
13 #include <unistd.h>
14 #include <syslog.h>
15 #include <stdarg.h>
16 #include <signal.h>
17 #include <errno.h>
18 #ifdef HAVE_LIBWRAP
19 #include <arpa/inet.h>
20 #include <netinet/in.h>
21 #include <tcpd.h>
22 #endif
23
24 #include <libcfs/portals_utils.h>
25 #include <portals/api-support.h>
26 #include <portals/lib-types.h>
27 #include <portals/socknal.h>
28
29 /* should get this from autoconf somehow */
30 #ifndef PIDFILE_DIR
31 #define PIDFILE_DIR "/var/run"
32 #endif
33
34 char progname[] = "acceptor";
35 char name_port[40];             /* for signal handler */
36
37 #ifdef HAVE_LIBWRAP
38 /* needed because libwrap declares these as externs */
39 int allow_severity = LOG_INFO;
40 int deny_severity = LOG_WARNING;
41 #endif
42
43 void usage(char *progname)
44 {
45         fprintf(stderr, "usage: %s [-N nal_id] [-p] [-l] port\n\n"
46                 " -l\tKeep stdin/stdout open\n"
47                 " -p\tAllow connections from non-privileged ports\n", progname);
48         exit (1);
49 }
50
51 void errlog(int level, const char *fmt, ...)
52 {
53         va_list arg;
54         FILE *out;
55
56         switch (level) {
57         case LOG_DEBUG:
58         case LOG_INFO:
59         case LOG_NOTICE:
60                 out = stdout;
61                 break;
62         default:
63                 out = stderr;
64                 break;
65         }
66         va_start(arg, fmt);
67         fprintf(out, "%s: ", name_port);
68         vfprintf(out, fmt, arg);
69         va_end(arg);
70         va_start(arg, fmt);
71         vsyslog(level, fmt, arg);
72         va_end(arg);
73 }
74
75 char *pidfile_name(char *name_port)
76 {
77         static char pidfile[1024];
78
79         snprintf(pidfile, sizeof(pidfile), "%s/%s.pid", PIDFILE_DIR, name_port);
80
81         return pidfile;
82 }
83
84 int pidfile_create(char *name_port)
85 {
86         char *pidfile = pidfile_name(name_port);
87         int fd, rc;
88
89         if ((fd = open(pidfile, O_CREAT | O_WRONLY)) >= 0) {
90                 char pid[16];
91                 int size = snprintf(pid, sizeof(pid), "%u\n", getpid());
92                 if (write(fd, pid, size) != size) {
93                         /* hard error or short write */
94                         rc = errno ? : EIO;
95                 } else {
96                         rc = 0;
97                 }
98                 close(fd);
99         } else {
100                 rc = errno;
101         }
102
103         if (rc)
104                 errlog(LOG_ERR, " error creating %s: %s\n",
105                        pidfile, strerror(rc));
106
107         return rc;
108 }
109
110 int pidfile_cleanup(char *name_port)
111 {
112         char *pidfile = pidfile_name(name_port);
113         int rc;
114
115         rc = unlink(pidfile);
116         if (rc && errno != -ENOENT)
117                 fprintf(stderr, "%s: error removing %s: %s\n",
118                         progname, pidfile, strerror(errno));
119         errlog(LOG_NOTICE, "exiting\n");
120
121         return errno;
122 }
123
124 int pidfile_exists(char *name_port)
125 {
126         char *pidfile = pidfile_name(name_port);
127         FILE *fpid;
128         int pid, rc;
129
130         fpid = fopen(pidfile, "r+");
131         if (fpid == NULL) {
132                 if (errno == ENOENT)
133                         return 0;
134
135                 fprintf(stderr, "%s: error opening %s: %s.\n",
136                         progname, pidfile, strerror(errno));
137                 return (1);
138         }
139
140         rc = fscanf(fpid, "%i", &pid);
141         fclose(fpid);
142         if (rc != 1) {
143                 fprintf(stderr,"%s: %s didn't contain a valid pid, removing.\n",
144                         progname, pidfile);
145                 goto stale;
146         }
147
148         if (kill(pid, 0) == 0) {
149                 fprintf(stderr, "%s: %s exists, acceptor pid %d running.\n",
150                         progname, pidfile, pid);
151                 return (1);
152         }
153
154         fprintf(stderr, "%s: stale %s exists, pid %d doesn't, removing.\n",
155                 progname, pidfile, pid);
156 stale:
157         pidfile_cleanup(name_port);
158         return (0);
159 }
160
161 void handler(int sig)
162 {
163         exit(sig);
164 }
165
166 void atexit_handler(void)
167 {
168         pidfile_cleanup(name_port);
169 }
170
171 void show_connection(int fd, __u32 net_ip)
172 {
173         static long last_time;
174         static __u32 host_ip;
175         long now = time(0);
176         struct hostent *h;
177         int  len;
178         char host[1024];
179
180         /* Don't show repeats for same host, it adds no value */
181         if (host_ip == ntohl(net_ip) && (now - last_time) < 5)
182                 return;
183
184         h = gethostbyaddr((char *)&net_ip, sizeof(net_ip), AF_INET);
185         last_time = now;
186         host_ip = ntohl(net_ip);
187
188         if (h == NULL)
189                 snprintf(host, sizeof(host), "%d.%d.%d.%d",
190                          (host_ip >> 24) & 0xff, (host_ip >> 16) & 0xff,
191                          (host_ip >> 8)  & 0xff, host_ip & 0xff);
192         else
193                 snprintf(host, sizeof(host), "%s", h->h_name);
194
195         syslog(LOG_INFO, "accepted host: %s\n", host);
196 }
197
198 int main(int argc, char **argv)
199 {
200         int o, fd, rc, port, pfd;
201         struct sockaddr_in srvaddr;
202         int c;
203         int noclose = 0;
204         int nal = SOCKNAL;
205         int rport;
206         int require_privports = 1;
207
208         while ((c = getopt (argc, argv, "N:lp")) != -1) {
209                 switch (c) {
210                 case 'N':
211                         if (sscanf(optarg, "%d", &nal) != 1 ||
212                             nal < 0 || nal > NAL_MAX_NR)
213                                 usage(argv[0]);
214                         break;
215                 case 'l':
216                         noclose = 1;
217                         break;
218                 case 'p':
219                         require_privports = 0;
220                         break;
221                 default:
222                         usage (argv[0]);
223                         break;
224                 }
225         }
226
227         if (optind >= argc)
228                 usage (argv[0]);
229
230         port = atol(argv[optind++]);
231
232         snprintf(name_port, sizeof(name_port) - 1, "%s-%d", progname, port);
233         if (pidfile_exists(name_port))
234                 return(EEXIST);
235         openlog(name_port, LOG_PID, LOG_DAEMON);
236
237         memset(&srvaddr, 0, sizeof(srvaddr));
238         srvaddr.sin_family = AF_INET;
239         srvaddr.sin_port = htons(port);
240         srvaddr.sin_addr.s_addr = INADDR_ANY;
241
242         fd = socket(PF_INET, SOCK_STREAM, 0);
243         if (fd < 0) {
244                 rc = errno;
245                 errlog(LOG_ERR, "error opening socket: %s\n", strerror(errno));
246                 return(rc);
247         }
248
249         o = 1;
250         if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &o, sizeof(o))) {
251                 rc = errno;
252                 errlog(LOG_ERR, "cannot set REUSEADDR socket opt: %s\n",
253                        strerror(errno));
254                 return(rc);
255         }
256
257         rc = bind(fd, (struct sockaddr *)&srvaddr, sizeof(srvaddr));
258         if (rc == -1) {
259                 rc = errno;
260                 errlog(LOG_ERR, "error binding to socket: %s\n",
261                        strerror(errno));
262                 return(rc);
263         }
264
265         if (listen(fd, 127)) {
266                 rc = errno;
267                 perror("listen: ");
268                 return(rc);
269         }
270         printf("listening on port %d\n", port);
271
272         pfd = open("/dev/portals", O_RDWR);
273         if (pfd < 0) {
274                 rc = errno;
275                 errlog(LOG_ERR, "opening portals device: %s\n",strerror(errno));
276                 return(rc);
277         }
278
279         rc = daemon(0, noclose);
280         if (rc < 0) {
281                 rc = errno;
282                 errlog(LOG_ERR, "error daemonizing: %s\n", strerror(errno));
283                 return(rc);
284         }
285
286         signal(SIGHUP, SIG_IGN);
287         signal(SIGINT, handler);
288         signal(SIGQUIT, handler);
289         signal(SIGTERM, handler);
290
291         errlog(LOG_NOTICE, "started, listening on port %d\n", port);
292         if (pidfile_create(name_port) == 0)
293                 atexit(atexit_handler);
294
295         while (1) {
296                 struct sockaddr_in clntaddr;
297                 int len = sizeof(clntaddr);
298                 int cfd;
299                 struct portal_ioctl_data data;
300                 struct portals_cfg pcfg;
301 #ifdef HAVE_LIBWRAP
302                 struct request_info request;
303 #endif
304                 char addrstr[INET_ADDRSTRLEN];
305
306                 cfd = accept(fd, (struct sockaddr *)&clntaddr, &len);
307                 if (cfd < 0) {
308                         errlog(LOG_ERR, "error accepting connection: %s\n",
309                                strerror(errno));
310                         break;
311                         //continue;
312                 }
313
314                 inet_ntop(AF_INET, &clntaddr.sin_addr, addrstr,INET_ADDRSTRLEN);
315 #ifdef HAVE_LIBWRAP
316                 /* libwrap access control */
317                 request_init(&request, RQ_DAEMON, "lustre", RQ_FILE, cfd, 0);
318                 sock_host(&request);
319                 if (!hosts_access(&request)) {
320                         errlog(LOG_WARNING, "unauthorized access from %s:%hd\n",
321                                addrstr, ntohs(clntaddr.sin_port));
322                         close (cfd);
323                         continue;
324                 }
325 #endif
326
327                 if (require_privports &&
328                     ntohs(clntaddr.sin_port) >= IPPORT_RESERVED) {
329                         errlog(LOG_ERR,
330                                "closing non-privileged connection from %s:%d\n",
331                                addrstr, ntohs(clntaddr.sin_port));
332                         rc = close(cfd);
333                         if (rc)
334                                 perror ("close un-privileged client failed");
335                         continue;
336                 }
337
338                 show_connection (cfd, clntaddr.sin_addr.s_addr);
339
340                 PCFG_INIT(pcfg, NAL_CMD_REGISTER_PEER_FD);
341                 pcfg.pcfg_nal = nal;
342                 pcfg.pcfg_fd = cfd;
343                 pcfg.pcfg_misc = SOCKNAL_CONN_NONE; /* == incoming connection */
344
345                 PORTAL_IOC_INIT(data);
346                 data.ioc_pbuf1 = (char*)&pcfg;
347                 data.ioc_plen1 = sizeof(pcfg);
348
349                 if (ioctl(pfd, IOC_PORTAL_NAL_CMD, &data) < 0) {
350                         errlog(LOG_ERR, "portals ioctl failed for %s: %s\n",
351                                addrstr, strerror(errno));
352                 } else {
353                         errlog(LOG_DEBUG, "client %s registered\n", addrstr);
354                 }
355                 rc = close(cfd);
356                 if (rc)
357                         perror("close failed");
358         }
359
360         closelog();
361
362         return (0);
363 }