Whamcloud - gitweb
landing b_cmobd_merge on 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 <errno.h>
16
17 #include <portals/api-support.h>
18 #include <portals/list.h>
19 #include <portals/lib-types.h>
20 #include <portals/socknal.h>
21
22 /* should get this from autoconf somehow */
23 #ifndef PIDFILE_DIR
24 #define PIDFILE_DIR "/var/run"
25 #endif 
26
27 #define PROGNAME "acceptor"
28
29 void create_pidfile(char *name, int port)
30 {
31         char pidfile[1024];
32         FILE *fp;
33
34         snprintf(pidfile, sizeof(pidfile), "%s/%s-%d.pid", 
35                  PIDFILE_DIR, name, port);
36         
37         if ((fp = fopen(pidfile, "w"))) {
38                 fprintf(fp, "%d\n", getpid());
39                 fclose(fp);
40         } else {
41                 syslog(LOG_ERR, "%s: %s\n", pidfile, 
42                        strerror(errno));
43         }
44 }
45
46 int pidfile_exists(char *name, int port)
47 {
48         char pidfile[1024];
49
50         snprintf(pidfile, sizeof(pidfile), "%s/%s-%d.pid", 
51                  PIDFILE_DIR, name, port);
52         
53         if (!access(pidfile, F_OK)) {
54                 fprintf(stderr, "%s: exists, acceptor already running.\n", 
55                         pidfile);
56                 return (1);
57         } 
58         return (0);
59 }
60
61 int
62 parse_size (int *sizep, char *str)
63 {
64         int             size;
65         char            mod[32];
66
67         switch (sscanf (str, "%d%1[gGmMkK]", &size, mod))
68         {
69         default:
70                 return (-1);
71
72         case 1:
73                 *sizep = size;
74                 return (0);
75
76         case 2:
77                 switch (*mod)
78                 {
79                 case 'g':
80                 case 'G':
81                         *sizep = size << 30;
82                         return (0);
83
84                 case 'm':
85                 case 'M':
86                         *sizep = size << 20;
87                         return (0);
88
89                 case 'k':
90                 case 'K':
91                         *sizep = size << 10;
92                         return (0);
93
94                 default:
95                         *sizep = size;
96                         return (0);
97                 }
98         }
99 }
100
101 void
102 show_connection (int fd, __u32 net_ip)
103 {
104         struct hostent *h = gethostbyaddr ((char *)&net_ip, sizeof net_ip, AF_INET);
105         __u32 host_ip = ntohl (net_ip);
106         int  rxmem = 0;
107         int  txmem = 0;
108         int  nonagle = 0;
109         int  len;
110         char host[1024];
111         
112         len = sizeof (txmem);
113         if (getsockopt (fd, SOL_SOCKET, SO_SNDBUF, &txmem, &len) != 0)
114                 perror ("Cannot get write buffer size");
115         
116         len = sizeof (rxmem);
117         if (getsockopt (fd, SOL_SOCKET, SO_RCVBUF, &rxmem, &len) != 0)
118                 perror ("Cannot get read buffer size");
119         
120         len = sizeof (nonagle);
121         if (getsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &nonagle, &len) != 0)
122                 perror ("Cannot get nagle");
123
124         if (h == NULL)
125                 snprintf (host, sizeof(host), "%d.%d.%d.%d", (host_ip >> 24) & 0xff,
126                                     (host_ip >> 16) & 0xff, (host_ip >> 8) & 0xff, host_ip & 0xff);
127         else
128                 snprintf (host, sizeof(host), "%s", h->h_name);
129                 
130         syslog (LOG_INFO, "Accepted host: %s snd: %d rcv %d nagle: %s\n", 
131                 host, txmem, rxmem, nonagle ? "disabled" : "enabled");
132 }
133
134 void
135 usage (char *myname)
136 {
137         fprintf (stderr, "Usage: %s [-r recv_mem] [-s send_mem] [-n] [-N nal_id] port\n", myname);
138         exit (1);
139 }
140
141 int main(int argc, char **argv)
142 {
143         int o, fd, rc, port, pfd;
144         struct sockaddr_in srvaddr;
145         int c;
146         int rxmem = 0;
147         int txmem = 0;
148         int noclose = 0;
149         int nonagle = 1;
150         int nal = SOCKNAL;
151         int bind_irq = 0;
152         
153         while ((c = getopt (argc, argv, "N:r:s:nli")) != -1)
154                 switch (c)
155                 {
156                 case 'r':
157                         if (parse_size (&rxmem, optarg) != 0 || rxmem < 0)
158                                 usage (argv[0]);
159                         break;
160                         
161                 case 's':
162                         if (parse_size (&txmem, optarg) != 0 || txmem < 0)
163                                 usage (argv[0]);
164                         break;
165
166                 case 'n':
167                         nonagle = 0;
168                         break;
169
170                 case 'l':
171                         noclose = 1;
172                         break;
173
174                 case 'i':
175                         bind_irq = 1;
176                         break;
177                         
178                 case 'N':
179                         if (parse_size(&nal, optarg) != 0 || 
180                             nal < 0 || nal > NAL_MAX_NR)
181                                 usage(argv[0]);
182                         break;
183                         
184                 default:
185                         usage (argv[0]);
186                         break;
187                 }
188
189         if (optind >= argc)
190                 usage (argv[0]);
191
192         port = atol(argv[optind++]);
193
194         if (pidfile_exists(PROGNAME, port))
195                 exit(1);
196
197         memset(&srvaddr, 0, sizeof(srvaddr));
198         srvaddr.sin_family = AF_INET;
199         srvaddr.sin_port = htons(port);
200         srvaddr.sin_addr.s_addr = INADDR_ANY;
201
202         fd = socket(PF_INET, SOCK_STREAM, 0);
203         if (fd < 0) {
204                 perror("opening socket");
205                 exit(1);
206         }
207
208         o = 1;
209         if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &o, sizeof(o))) {
210                 perror("Cannot set REUSEADDR socket opt");
211                 exit(1);
212         }
213
214         if (nonagle)
215         {
216                 o = 1;
217                 rc = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &o, sizeof (o));
218                 if (rc != 0) 
219                 { 
220                         perror ("Cannot disable nagle");
221                         exit (1);
222                 }
223         }
224
225         if (txmem != 0)
226         {
227                 rc = setsockopt (fd, SOL_SOCKET, SO_SNDBUF, &txmem, sizeof (txmem));
228                 if (rc != 0)
229                 {
230                         perror ("Cannot set write buffer size");
231                         exit (1);
232                 }
233         }
234         
235         if (rxmem != 0)
236         {
237                 rc = setsockopt (fd, SOL_SOCKET, SO_RCVBUF, &rxmem, sizeof (rxmem));
238                 if (rc != 0)
239                 {
240                         perror ("Cannot set read buffer size");
241                         exit (1);
242                }
243         }
244                 
245         rc = bind(fd, (struct sockaddr *)&srvaddr, sizeof(srvaddr));
246         if ( rc == -1 ) {
247                 perror("bind: ");
248                 exit(1);
249         }
250
251         if (listen(fd, 127)) {
252                 perror("listen: ");
253                 exit(1);
254         }
255         fprintf(stderr, "listening on port %d\n", port);
256
257         pfd = open("/dev/portals", O_RDWR);
258         if ( pfd < 0 ) {
259                 perror("opening portals device");
260                 exit(1);
261         }
262
263         rc = daemon(1, noclose);
264         if (rc < 0) {
265                 perror("daemon(): ");
266                 exit(1);
267         }
268
269         openlog(PROGNAME, LOG_PID, LOG_DAEMON);
270         syslog(LOG_INFO, "started, listening on port %d\n", port);
271         create_pidfile(PROGNAME, port);
272
273         while (1) {
274                 struct sockaddr_in clntaddr;
275                 int len = sizeof(clntaddr);
276                 int cfd;
277                 struct portal_ioctl_data data;
278                 struct portals_cfg pcfg;
279                 
280                 cfd = accept(fd, (struct sockaddr *)&clntaddr, &len);
281                 if ( cfd < 0 ) {
282                         perror("accept");
283                         exit(0);
284                         continue;
285                 }
286
287                 show_connection (cfd, clntaddr.sin_addr.s_addr);
288
289                 PCFG_INIT(pcfg, NAL_CMD_REGISTER_PEER_FD);
290                 pcfg.pcfg_nal = nal;
291                 pcfg.pcfg_fd = cfd;
292                 pcfg.pcfg_flags = bind_irq;
293                 pcfg.pcfg_misc = SOCKNAL_CONN_NONE; /* == incoming connection */
294                 
295                 PORTAL_IOC_INIT(data);
296                 data.ioc_pbuf1 = (char*)&pcfg;
297                 data.ioc_plen1 = sizeof(pcfg);
298                 
299                 if (ioctl(pfd, IOC_PORTAL_NAL_CMD, &data) < 0) {
300                         perror("ioctl failed");
301                 } else {
302                         printf("client registered\n");
303                 }
304                 rc = close(cfd);
305                 if (rc)
306                         perror ("close failed");
307         }
308
309         closelog();
310         exit(0);
311
312 }