Whamcloud - gitweb
- merge 0.7rc1 from b_devel to HEAD (20030612 merge point)
[fs/lustre-release.git] / lustre / portals / 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
23 /* should get this from autoconf somehow */
24 #ifndef PIDFILE_DIR
25 #define PIDFILE_DIR "/var/run"
26 #endif 
27
28 #define PROGNAME "acceptor"
29
30 void create_pidfile(char *name, int port)
31 {
32         char pidfile[1024];
33         FILE *fp;
34
35         snprintf(pidfile, sizeof(pidfile), "%s/%s-%d.pid", 
36                  PIDFILE_DIR, name, port);
37         
38         if ((fp = fopen(pidfile, "w"))) {
39                 fprintf(fp, "%d\n", getpid());
40                 fclose(fp);
41         } else {
42                 syslog(LOG_ERR, "%s: %s\n", pidfile, 
43                        strerror(errno));
44         }
45 }
46
47 int pidfile_exists(char *name, int port)
48 {
49         char pidfile[1024];
50
51         snprintf(pidfile, sizeof(pidfile), "%s/%s-%d.pid", 
52                  PIDFILE_DIR, name, port);
53         
54         if (!access(pidfile, F_OK)) {
55                 fprintf(stderr, "%s: exists, acceptor already running.\n", 
56                         pidfile);
57                 return (1);
58         } 
59         return (0);
60 }
61
62 int
63 parse_size (int *sizep, char *str)
64 {
65         int             size;
66         char            mod[32];
67
68         switch (sscanf (str, "%d%1[gGmMkK]", &size, mod))
69         {
70         default:
71                 return (-1);
72
73         case 1:
74                 *sizep = size;
75                 return (0);
76
77         case 2:
78                 switch (*mod)
79                 {
80                 case 'g':
81                 case 'G':
82                         *sizep = size << 30;
83                         return (0);
84
85                 case 'm':
86                 case 'M':
87                         *sizep = size << 20;
88                         return (0);
89
90                 case 'k':
91                 case 'K':
92                         *sizep = size << 10;
93                         return (0);
94
95                 default:
96                         *sizep = size;
97                         return (0);
98                 }
99         }
100 }
101
102 void
103 show_connection (int fd, __u32 net_ip, ptl_nid_t nid)
104 {
105         struct hostent *h = gethostbyaddr ((char *)&net_ip, sizeof net_ip, AF_INET);
106         __u32 host_ip = ntohl (net_ip);
107         int  rxmem = 0;
108         int  txmem = 0;
109         int  nonagle = 0;
110         int  len;
111         char host[1024];
112         
113         len = sizeof (txmem);
114         if (getsockopt (fd, SOL_SOCKET, SO_SNDBUF, &txmem, &len) != 0)
115                 perror ("Cannot get write buffer size");
116         
117         len = sizeof (rxmem);
118         if (getsockopt (fd, SOL_SOCKET, SO_RCVBUF, &rxmem, &len) != 0)
119                 perror ("Cannot get read buffer size");
120         
121         len = sizeof (nonagle);
122         if (getsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &nonagle, &len) != 0)
123                 perror ("Cannot get nagle");
124
125         if (h == NULL)
126                 snprintf (host, sizeof(host), "%d.%d.%d.%d", (host_ip >> 24) & 0xff,
127                                     (host_ip >> 16) & 0xff, (host_ip >> 8) & 0xff, host_ip & 0xff);
128         else
129                 snprintf (host, sizeof(host), "%s", h->h_name);
130                 
131         syslog (LOG_INFO, "Accepted host: %s NID: "LPX64" snd: %d rcv %d nagle: %s\n", 
132                  host, nid, txmem, rxmem, nonagle ? "disabled" : "enabled");
133 }
134
135 int
136 sock_write (int cfd, void *buffer, int nob)
137 {
138         while (nob > 0)
139         {
140                 int rc = write (cfd, buffer, nob);
141
142                 if (rc < 0)
143                 {
144                         if (errno == EINTR)
145                                 continue;
146                         
147                         return (rc);
148                 }
149
150                 if (rc == 0)
151                 {
152                         fprintf (stderr, "Unexpected zero sock_write\n");
153                         abort();
154                 }
155
156                 nob -= rc;
157                 buffer = (char *)buffer + nob;
158         }
159         
160         return (0);
161 }
162
163 int
164 sock_read (int cfd, void *buffer, int nob)
165 {
166         while (nob > 0)
167         {
168                 int rc = read (cfd, buffer, nob);
169                 
170                 if (rc < 0)
171                 {
172                         if (errno == EINTR)
173                                 continue;
174                         
175                         return (rc);
176                 }
177                 
178                 if (rc == 0)                    /* EOF */
179                 {
180                         errno = ECONNABORTED;
181                         return (-1);
182                 }
183                 
184                 nob -= rc;
185                 buffer = (char *)buffer + nob;
186         }
187         
188         return (0);
189 }
190
191 int
192 exchange_nids (int cfd, ptl_nid_t my_nid, ptl_nid_t *peer_nid)
193 {
194         int                      rc;
195         ptl_hdr_t                hdr;
196         ptl_magicversion_t      *hmv = (ptl_magicversion_t *)&hdr.dest_nid;
197
198         LASSERT (sizeof (*hmv) == sizeof (hdr.dest_nid));
199
200         memset (&hdr, 0, sizeof (hdr));
201         
202         hmv->magic          = __cpu_to_le32 (PORTALS_PROTO_MAGIC);
203         hmv->version_major  = __cpu_to_le16 (PORTALS_PROTO_VERSION_MAJOR);
204         hmv->version_minor  = __cpu_to_le16 (PORTALS_PROTO_VERSION_MINOR);
205
206         hdr.src_nid = __cpu_to_le64 (my_nid);
207         hdr.type = __cpu_to_le32 (PTL_MSG_HELLO);
208         
209         /* Assume there's sufficient socket buffering for a portals HELLO header */
210         rc = sock_write (cfd, &hdr, sizeof (hdr));
211         if (rc != 0) {
212                 perror ("Can't send initial HELLO");
213                 return (-1);
214         }
215
216         /* First few bytes down the wire are the portals protocol magic and
217          * version, no matter what protocol version we're running. */
218
219         rc = sock_read (cfd, hmv, sizeof (*hmv));
220         if (rc != 0) {
221                 perror ("Can't read from peer");
222                 return (-1);
223         }
224
225         if (__cpu_to_le32 (hmv->magic) != PORTALS_PROTO_MAGIC) {
226                 fprintf (stderr, "Bad magic %#08x (%#08x expected)\n", 
227                          __cpu_to_le32 (hmv->magic), PORTALS_PROTO_MAGIC);
228                 return (-1);
229         }
230
231         if (__cpu_to_le16 (hmv->version_major) != PORTALS_PROTO_VERSION_MAJOR ||
232             __cpu_to_le16 (hmv->version_minor) != PORTALS_PROTO_VERSION_MINOR) {
233                 fprintf (stderr, "Incompatible protocol version %d.%d (%d.%d expected)\n",
234                          __cpu_to_le16 (hmv->version_major),
235                          __cpu_to_le16 (hmv->version_minor),
236                          PORTALS_PROTO_VERSION_MAJOR,
237                          PORTALS_PROTO_VERSION_MINOR);
238         }
239
240         /* version 0 sends magic/version as the dest_nid of a 'hello' header,
241          * so read the rest of it in now... */
242         LASSERT (PORTALS_PROTO_VERSION_MAJOR == 0);
243         rc = sock_read (cfd, hmv + 1, sizeof (hdr) - sizeof (*hmv));
244         if (rc != 0) {
245                 perror ("Can't read rest of HELLO hdr");
246                 return (-1);
247         }
248
249         /* ...and check we got what we expected */
250         if (__cpu_to_le32 (hdr.type) != PTL_MSG_HELLO ||
251             __cpu_to_le32 (PTL_HDR_LENGTH (&hdr)) != 0) {
252                 fprintf (stderr, "Expecting a HELLO hdr with 0 payload,"
253                          " but got type %d with %d payload\n",
254                          __cpu_to_le32 (hdr.type),
255                          __cpu_to_le32 (PTL_HDR_LENGTH (&hdr)));
256                 return (-1);
257         }
258         
259         *peer_nid = __le64_to_cpu (hdr.src_nid);
260         return (0);
261 }
262
263 void
264 usage (char *myname)
265 {
266         fprintf (stderr, "Usage: %s [-r recv_mem] [-s send_mem] [-n] [-N nal_id] port\n", myname);
267         exit (1);
268 }
269
270 int main(int argc, char **argv)
271 {
272         int o, fd, rc, port, pfd;
273         struct sockaddr_in srvaddr;
274         int c;
275         int rxmem = 0;
276         int txmem = 0;
277         int noclose = 0;
278         int nonagle = 1;
279         int nal = SOCKNAL;
280         int xchg_nids = 0;
281         int bind_irq = 0;
282         
283         while ((c = getopt (argc, argv, "N:r:s:nlxi")) != -1)
284                 switch (c)
285                 {
286                 case 'r':
287                         if (parse_size (&rxmem, optarg) != 0 || rxmem < 0)
288                                 usage (argv[0]);
289                         break;
290                         
291                 case 's':
292                         if (parse_size (&txmem, optarg) != 0 || txmem < 0)
293                                 usage (argv[0]);
294                         break;
295
296                 case 'n':
297                         nonagle = 0;
298                         break;
299
300                 case 'l':
301                         noclose = 1;
302                         break;
303
304                 case 'x':
305                         xchg_nids = 1;
306                         break;
307
308                 case 'i':
309                         bind_irq = 1;
310                         break;
311                         
312                 case 'N':
313                         if (parse_size(&nal, optarg) != 0 || 
314                             nal < 0 || nal > NAL_MAX_NR)
315                                 usage(argv[0]);
316                         break;
317                         
318                 default:
319                         usage (argv[0]);
320                         break;
321                 }
322
323         if (optind >= argc)
324                 usage (argv[0]);
325
326         port = atol(argv[optind++]);
327
328         if (pidfile_exists(PROGNAME, port))
329                 exit(1);
330
331         memset(&srvaddr, 0, sizeof(srvaddr));
332         srvaddr.sin_family = AF_INET;
333         srvaddr.sin_port = htons(port);
334         srvaddr.sin_addr.s_addr = INADDR_ANY;
335
336         fd = socket(PF_INET, SOCK_STREAM, 0);
337         if (fd < 0) {
338                 perror("opening socket");
339                 exit(1);
340         }
341
342         o = 1;
343         if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &o, sizeof(o))) {
344                 perror("Cannot set REUSEADDR socket opt");
345                 exit(1);
346         }
347
348         if (nonagle)
349         {
350                 o = 1;
351                 rc = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &o, sizeof (o));
352                 if (rc != 0) 
353                 { 
354                         perror ("Cannot disable nagle");
355                         exit (1);
356                 }
357         }
358
359         if (txmem != 0)
360         {
361                 rc = setsockopt (fd, SOL_SOCKET, SO_SNDBUF, &txmem, sizeof (txmem));
362                 if (rc != 0)
363                 {
364                         perror ("Cannot set write buffer size");
365                         exit (1);
366                 }
367         }
368         
369         if (rxmem != 0)
370         {
371                 rc = setsockopt (fd, SOL_SOCKET, SO_RCVBUF, &rxmem, sizeof (rxmem));
372                 if (rc != 0)
373                 {
374                         perror ("Cannot set read buffer size");
375                         exit (1);
376                }
377         }
378                 
379         rc = bind(fd, (struct sockaddr *)&srvaddr, sizeof(srvaddr));
380         if ( rc == -1 ) {
381                 perror("bind: ");
382                 exit(1);
383         }
384
385         if (listen(fd, 127)) {
386                 perror("listen: ");
387                 exit(1);
388         }
389         fprintf(stderr, "listening on port %d\n", port);
390
391         pfd = open("/dev/portals", O_RDWR);
392         if ( pfd < 0 ) {
393                 perror("opening portals device");
394                 exit(1);
395         }
396
397         rc = daemon(1, noclose);
398         if (rc < 0) {
399                 perror("daemon(): ");
400                 exit(1);
401         }
402
403         openlog(PROGNAME, LOG_PID, LOG_DAEMON);
404         syslog(LOG_INFO, "started, listening on port %d\n", port);
405         create_pidfile(PROGNAME, port);
406
407         while (1) {
408                 struct sockaddr_in clntaddr;
409                 int len = sizeof(clntaddr);
410                 int cfd;
411                 struct portal_ioctl_data data;
412                 ptl_nid_t peer_nid;
413                 
414                 cfd = accept(fd, (struct sockaddr *)&clntaddr, &len);
415                 if ( cfd < 0 ) {
416                         perror("accept");
417                         exit(0);
418                         continue;
419                 }
420
421                 if (!xchg_nids)
422                         peer_nid = ntohl (clntaddr.sin_addr.s_addr); /* HOST byte order */
423                 else
424                 {
425                         PORTAL_IOC_INIT (data);
426                         data.ioc_nal = nal;
427                         rc = ioctl (pfd, IOC_PORTAL_GET_NID, &data);
428                         if (rc < 0)
429                         {
430                                 perror ("Can't get my NID");
431                                 close (cfd);
432                                 continue;
433                         }
434                         
435                         rc = exchange_nids (cfd, data.ioc_nid, &peer_nid);
436                         if (rc != 0)
437                         {
438                                 close (cfd);
439                                 continue;
440                         }
441                 }
442
443                 show_connection (cfd, clntaddr.sin_addr.s_addr, peer_nid);
444                 
445                 PORTAL_IOC_INIT(data);
446                 data.ioc_fd = cfd;
447                 data.ioc_nal = nal;
448                 data.ioc_nal_cmd = NAL_CMD_REGISTER_PEER_FD;
449                 data.ioc_nid = peer_nid;
450                 data.ioc_flags = bind_irq;
451                 
452                 if (ioctl(pfd, IOC_PORTAL_NAL_CMD, &data) < 0) {
453                         perror("ioctl failed");
454
455                 } else {
456                         printf("client registered\n");
457                 }
458                 rc = close(cfd);
459                 if (rc)
460                         perror ("close failed");
461         }
462
463         closelog();
464         exit(0);
465
466 }