Whamcloud - gitweb
Branch b1_4
[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 <errno.h>
16 #ifdef HAVE_LIBWRAP
17 #include <arpa/inet.h>
18 #include <netinet/in.h>
19 #include <tcpd.h>
20 #endif
21
22 #include <libcfs/portals_utils.h>
23 #include <portals/api-support.h>
24 #include <portals/lib-types.h>
25 #include <portals/socknal.h>
26
27 /* should get this from autoconf somehow */
28 #ifndef PIDFILE_DIR
29 #define PIDFILE_DIR "/var/run"
30 #endif
31
32 #define PROGNAME "acceptor"
33
34 #ifdef HAVE_LIBWRAP
35 /* needed because libwrap declares these as externs */
36 int allow_severity = LOG_INFO;
37 int deny_severity = LOG_WARNING;
38 #endif
39
40 void usage(char *myname)
41 {
42         fprintf(stderr, "usage: %s [-N nal_id] [-p] [-l] port\n\n"
43                 " -l\tKeep stdin/stdout open\n"
44                 " -p\tAllow connections from non-privileged ports\n", myname);
45         exit (1);
46 }
47
48 char *pidfile_name(char *name, int port)
49 {
50         static char pidfile[1024];
51
52         snprintf(pidfile, sizeof(pidfile), "%s/%s-%d.pid",
53                  PIDFILE_DIR, name, port);
54
55         return pidfile;
56 }
57
58 void pidfile_create(char *name, int port)
59 {
60         char *pidfile = pidfile_name(name, port);
61         FILE *fp;
62
63         if ((fp = fopen(pidfile, "w"))) {
64                 fprintf(fp, "%d\n", getpid());
65                 fclose(fp);
66         } else {
67                 syslog(LOG_DAEMON|LOG_ERR, "%s: %s\n", pidfile,strerror(errno));
68         }
69 }
70
71 int pidfile_cleanup(char *name, int port)
72 {
73         char *pidfile = pidfile_name(name, port);
74         int rc;
75
76         rc = unlink(pidfile);
77         if (rc && errno != -ENOENT)
78                 fprintf(stderr, "%s: error removing %s: %s\n",
79                         PROGNAME, pidfile, strerror(errno));
80
81         return errno;
82 }
83
84 int pidfile_exists(char *name, int port)
85 {
86         char *pidfile = pidfile_name(name, port);
87         FILE *fpid;
88         int pid, rc;
89
90         snprintf(pidfile, sizeof(pidfile), "%s/%s-%d.pid",
91                  PIDFILE_DIR, name, port);
92
93         fpid = fopen(pidfile, "r+");
94         if (fpid == NULL) {
95                 if (errno == ENOENT)
96                         return 0;
97
98                 fprintf(stderr, "%s: error opening %s: %s.\n",
99                         PROGNAME, pidfile, strerror(errno));
100                 return (1);
101         }
102
103         rc = fscanf(fpid, "%i", &pid);
104         fclose(fpid);
105         if (rc != 1) {
106                 fprintf(stderr,"%s: %s didn't contain a valid pid, removing.\n",
107                         PROGNAME, pidfile);
108                 goto stale;
109         }
110
111         if (kill(pid, 0) == 0) {
112                 fprintf(stderr, "%s: %s exists, acceptor pid %d running.\n",
113                         PROGNAME, pidfile, pid);
114                 return (1);
115         }
116
117         fprintf(stderr, "%s: stale %s exists, pid %d doesn't, removing.\n",
118                 PROGNAME, pidfile, pid);
119 stale:
120         pidfile_cleanup(name, port);
121         return (0);
122 }
123
124 void
125 show_connection (int fd, __u32 net_ip)
126 {
127         static long last_time;
128         static __u32 host_ip;
129         long now = time(0);
130         struct hostent *h;
131         int  len;
132         char host[1024];
133
134         /* Don't show repeats for same host, it adds no value */
135         if (host_ip == ntohl(net_ip) && (now - last_time) < 5)
136                 return;
137
138         h = gethostbyaddr((char *)&net_ip, sizeof(net_ip), AF_INET);
139         last_time = now;
140         host_ip = ntohl(net_ip);
141
142         if (h == NULL)
143                 snprintf(host, sizeof(host), "%d.%d.%d.%d",
144                          (host_ip >> 24) & 0xff, (host_ip >> 16) & 0xff,
145                          (host_ip >> 8)  & 0xff, host_ip & 0xff);
146         else
147                 snprintf(host, sizeof(host), "%s", h->h_name);
148
149         syslog(LOG_DAEMON | LOG_INFO, "Accepted host: %s\n", host);
150 }
151
152 int main(int argc, char **argv)
153 {
154         int o, fd, rc, port, pfd;
155         struct sockaddr_in srvaddr;
156         int c;
157         int noclose = 0;
158         int nal = SOCKNAL;
159         int rport;
160         int require_privports = 1;
161
162         while ((c = getopt (argc, argv, "N:lp")) != -1) {
163                 switch (c) {
164                 case 'N':
165                         if (sscanf(optarg, "%d", &nal) != 1 ||
166                             nal < 0 || nal > NAL_MAX_NR)
167                                 usage(argv[0]);
168                         break;
169                 case 'l':
170                         noclose = 1;
171                         break;
172                 case 'p':
173                         require_privports = 0;
174                         break;
175                 default:
176                         usage (argv[0]);
177                         break;
178                 }
179         }
180
181         if (optind >= argc)
182                 usage (argv[0]);
183
184         port = atol(argv[optind++]);
185
186         if (pidfile_exists(PROGNAME, port))
187                 return(EEXIST);
188
189         memset(&srvaddr, 0, sizeof(srvaddr));
190         srvaddr.sin_family = AF_INET;
191         srvaddr.sin_port = htons(port);
192         srvaddr.sin_addr.s_addr = INADDR_ANY;
193
194         fd = socket(PF_INET, SOCK_STREAM, 0);
195         if (fd < 0) {
196                 rc = errno;
197                 perror("opening socket");
198                 return(rc);
199         }
200
201         o = 1;
202         if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &o, sizeof(o))) {
203                 rc = errno;
204                 perror("Cannot set REUSEADDR socket opt");
205                 return(rc);
206         }
207
208         rc = bind(fd, (struct sockaddr *)&srvaddr, sizeof(srvaddr));
209         if (rc == -1) {
210                 rc = errno;
211                 perror("bind: ");
212                 return(rc);
213         }
214
215         if (listen(fd, 127)) {
216                 rc = errno;
217                 perror("listen: ");
218                 return(rc);
219         }
220         fprintf(stderr, "listening on port %d\n", port);
221
222         pfd = open("/dev/portals", O_RDWR);
223         if (pfd < 0) {
224                 rc = errno;
225                 perror("opening portals device");
226                 return(rc);
227         }
228
229         rc = daemon(0, noclose);
230         if (rc < 0) {
231                 rc = errno;
232                 perror("daemon(): ");
233                 return(rc);
234         }
235
236         openlog(PROGNAME, LOG_PID, LOG_DAEMON);
237         syslog(LOG_DAEMON | LOG_INFO, "started, listening on port %d\n", port);
238         pidfile_create(PROGNAME, port);
239
240         while (1) {
241                 struct sockaddr_in clntaddr;
242                 int len = sizeof(clntaddr);
243                 int cfd;
244                 struct portal_ioctl_data data;
245                 struct portals_cfg pcfg;
246 #ifdef HAVE_LIBWRAP
247                 struct request_info request;
248 #endif
249                 char addrstr[INET_ADDRSTRLEN];
250
251                 cfd = accept(fd, (struct sockaddr *)&clntaddr, &len);
252                 if ( cfd < 0 ) {
253                         perror("accept");
254                         pidfile_cleanup(PROGNAME, port);
255                         return(0);
256                         continue;
257                 }
258
259 #ifdef HAVE_LIBWRAP
260                 /* libwrap access control */
261                 request_init(&request, RQ_DAEMON, "lustre", RQ_FILE, cfd, 0);
262                 sock_host(&request);
263                 if (!hosts_access(&request)) {
264                         inet_ntop(AF_INET, &clntaddr.sin_addr,
265                                   addrstr, INET_ADDRSTRLEN);
266                         syslog(LOG_DAEMON | LOG_WARNING,
267                                "Unauthorized access from %s:%hd\n",
268                                addrstr, ntohs(clntaddr.sin_port));
269                         close (cfd);
270                         continue;
271                 }
272 #endif
273
274                 if (require_privports && ntohs(clntaddr.sin_port) >= IPPORT_RESERVED) {
275                         inet_ntop(AF_INET, &clntaddr.sin_addr,
276                                   addrstr, INET_ADDRSTRLEN);
277                         syslog(LOG_DAEMON | LOG_ERR,
278                                "Closing non-privileged connection from %s:%d\n",
279                                addrstr, ntohs(clntaddr.sin_port));
280                         rc = close(cfd);
281                         if (rc)
282                                 perror ("close un-privileged client failed");
283                         continue;
284                 }
285
286                 show_connection (cfd, clntaddr.sin_addr.s_addr);
287
288                 PCFG_INIT(pcfg, NAL_CMD_REGISTER_PEER_FD);
289                 pcfg.pcfg_nal = nal;
290                 pcfg.pcfg_fd = cfd;
291                 pcfg.pcfg_misc = SOCKNAL_CONN_NONE; /* == incoming connection */
292
293                 PORTAL_IOC_INIT(data);
294                 data.ioc_pbuf1 = (char*)&pcfg;
295                 data.ioc_plen1 = sizeof(pcfg);
296
297                 if (ioctl(pfd, IOC_PORTAL_NAL_CMD, &data) < 0) {
298                         perror("ioctl failed");
299                 } else {
300                         printf("client registered\n");
301                 }
302                 rc = close(cfd);
303                 if (rc)
304                         perror ("close failed");
305         }
306
307         closelog();
308         pidfile_cleanup(PROGNAME, port);
309
310         return (0);
311 }