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