Whamcloud - gitweb
Land b_release_1_4_3 onto HEAD (20050619_0305)
[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 void create_pidfile(char *name, int port)
49 {
50         char pidfile[1024];
51         FILE *fp;
52
53         snprintf(pidfile, sizeof(pidfile), "%s/%s-%d.pid",
54                  PIDFILE_DIR, name, port);
55
56         if ((fp = fopen(pidfile, "w"))) {
57                 fprintf(fp, "%d\n", getpid());
58                 fclose(fp);
59         } else {
60                 syslog(LOG_ERR, "%s: %s\n", pidfile,
61                        strerror(errno));
62         }
63 }
64
65 int pidfile_exists(char *name, int port)
66 {
67         char pidfile[1024];
68
69         snprintf(pidfile, sizeof(pidfile), "%s/%s-%d.pid",
70                  PIDFILE_DIR, name, port);
71
72         if (!access(pidfile, F_OK)) {
73                 fprintf(stderr, "%s: exists, acceptor already running.\n",
74                         pidfile);
75                 return (1);
76         }
77         return (0);
78 }
79
80 void
81 show_connection (int fd, __u32 net_ip)
82 {
83         static long last_time;
84         static __u32 host_ip;
85         long now = time(0);
86         struct hostent *h;
87         int  len;
88         char host[1024];
89
90         /* Don't show repeats for same host, it adds no value */
91         if (host_ip == ntohl(net_ip) && (now - last_time) < 5)
92                 return;
93
94         h = gethostbyaddr((char *)&net_ip, sizeof(net_ip), AF_INET);
95         last_time = now;
96         host_ip = ntohl(net_ip);
97
98         if (h == NULL)
99                 snprintf(host, sizeof(host), "%d.%d.%d.%d",
100                          (host_ip >> 24) & 0xff, (host_ip >> 16) & 0xff,
101                          (host_ip >> 8)  & 0xff, host_ip & 0xff);
102         else
103                 snprintf(host, sizeof(host), "%s", h->h_name);
104
105         syslog(LOG_INFO, "Accepted host: %s\n", host);
106 }
107
108 int main(int argc, char **argv)
109 {
110         int o, fd, rc, port, pfd;
111         struct sockaddr_in srvaddr;
112         int c;
113         int noclose = 0;
114         int nal = SOCKNAL;
115         int rport;
116         int require_privports = 1;
117
118         while ((c = getopt (argc, argv, "N:lp")) != -1) {
119                 switch (c) {
120                 case 'N':
121                         if (sscanf(optarg, "%d", &nal) != 1 ||
122                             nal < 0 || nal > NAL_MAX_NR)
123                                 usage(argv[0]);
124                         break;
125                 case 'l':
126                         noclose = 1;
127                         break;
128                 case 'p':
129                         require_privports = 0;
130                         break;
131                 default:
132                         usage (argv[0]);
133                         break;
134                 }
135         }
136
137         if (optind >= argc)
138                 usage (argv[0]);
139
140         port = atol(argv[optind++]);
141
142         if (pidfile_exists(PROGNAME, port))
143                 exit(1);
144
145         memset(&srvaddr, 0, sizeof(srvaddr));
146         srvaddr.sin_family = AF_INET;
147         srvaddr.sin_port = htons(port);
148         srvaddr.sin_addr.s_addr = INADDR_ANY;
149
150         fd = socket(PF_INET, SOCK_STREAM, 0);
151         if (fd < 0) {
152                 perror("opening socket");
153                 exit(1);
154         }
155
156         o = 1;
157         if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &o, sizeof(o))) {
158                 perror("Cannot set REUSEADDR socket opt");
159                 exit(1);
160         }
161
162         rc = bind(fd, (struct sockaddr *)&srvaddr, sizeof(srvaddr));
163         if ( rc == -1 ) {
164                 perror("bind: ");
165                 exit(1);
166         }
167
168         if (listen(fd, 127)) {
169                 perror("listen: ");
170                 exit(1);
171         }
172         fprintf(stderr, "listening on port %d\n", port);
173
174         pfd = open("/dev/portals", O_RDWR);
175         if ( pfd < 0 ) {
176                 perror("opening portals device");
177                 exit(1);
178         }
179
180         rc = daemon(0, noclose);
181         if (rc < 0) {
182                 perror("daemon(): ");
183                 exit(1);
184         }
185
186         openlog(PROGNAME, LOG_PID, LOG_DAEMON);
187         syslog(LOG_INFO, "started, listening on port %d\n", port);
188         create_pidfile(PROGNAME, port);
189
190         while (1) {
191                 struct sockaddr_in clntaddr;
192                 int len = sizeof(clntaddr);
193                 int cfd;
194                 struct portal_ioctl_data data;
195                 struct portals_cfg pcfg;
196 #ifdef HAVE_LIBWRAP
197                 struct request_info request;
198 #endif
199                 char addrstr[INET_ADDRSTRLEN];
200
201                 cfd = accept(fd, (struct sockaddr *)&clntaddr, &len);
202                 if ( cfd < 0 ) {
203                         perror("accept");
204                         exit(0);
205                         continue;
206                 }
207
208 #ifdef HAVE_LIBWRAP
209                 /* libwrap access control */
210                 request_init(&request, RQ_DAEMON, "lustre", RQ_FILE, cfd, 0);
211                 sock_host(&request);
212                 if (!hosts_access(&request)) {
213                         inet_ntop(AF_INET, &clntaddr.sin_addr,
214                                   addrstr, INET_ADDRSTRLEN);
215                         syslog(LOG_WARNING, "Unauthorized access from %s:%hd\n",
216                                addrstr, ntohs(clntaddr.sin_port));
217                         close (cfd);
218                         continue;
219                 }
220 #endif
221
222                 if (require_privports && ntohs(clntaddr.sin_port) >= IPPORT_RESERVED) {
223                         inet_ntop(AF_INET, &clntaddr.sin_addr,
224                                   addrstr, INET_ADDRSTRLEN);
225                         syslog(LOG_ERR, "Closing non-privileged connection from %s:%d\n",
226                                addrstr, ntohs(clntaddr.sin_port));
227                         rc = close(cfd);
228                         if (rc)
229                                 perror ("close un-privileged client failed");
230                         continue;
231                 }
232
233                 show_connection (cfd, clntaddr.sin_addr.s_addr);
234
235                 PCFG_INIT(pcfg, NAL_CMD_REGISTER_PEER_FD);
236                 pcfg.pcfg_nal = nal;
237                 pcfg.pcfg_fd = cfd;
238                 pcfg.pcfg_misc = SOCKNAL_CONN_NONE; /* == incoming connection */
239
240                 PORTAL_IOC_INIT(data);
241                 data.ioc_pbuf1 = (char*)&pcfg;
242                 data.ioc_plen1 = sizeof(pcfg);
243
244                 if (ioctl(pfd, IOC_PORTAL_NAL_CMD, &data) < 0) {
245                         perror("ioctl failed");
246                 } else {
247                         printf("client registered\n");
248                 }
249                 rc = close(cfd);
250                 if (rc)
251                         perror ("close failed");
252         }
253
254         closelog();
255         exit(0);
256
257 }