4172785f0ef414f50ed31c83ac48c02be5df026f
[vpp.git] / extras / libmemif / examples / icmp_responder-epoll / main.c
1 /*
2  *------------------------------------------------------------------
3  * Copyright (c) 2017 Cisco and/or its affiliates.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *------------------------------------------------------------------
16  */
17
18 #include <stdlib.h>
19 #include <stdint.h>
20 #include <net/if.h>
21 #include <sys/types.h>
22 #include <fcntl.h>
23 #include <sys/ioctl.h>
24 #include <sys/socket.h>
25 #include <sys/un.h>
26 #include <sys/uio.h>
27 #include <sys/mman.h>
28 #include <sys/prctl.h>
29 #include <inttypes.h>
30 #include <string.h>
31 #include <stdio.h>
32 #include <netdb.h>
33 #include <linux/ip.h>
34 #include <linux/icmp.h>
35 #include <arpa/inet.h>
36 #include <stdlib.h>
37 #include <netinet/if_ether.h>
38 #include <net/if_arp.h>
39 #include <asm/byteorder.h>
40 #include <byteswap.h>
41 #include <string.h>
42 #include <sys/epoll.h>
43 #include <errno.h>
44 #include <unistd.h>
45 #include <signal.h>
46
47 #include <libmemif.h>
48 #include <icmp_proto.h>
49
50 #define APP_NAME "ICMP_Responder"
51 #define IF_NAME  "memif_connection"
52
53
54 #ifdef ICMP_DBG
55 #define DBG(...) do {                                               \
56                     printf (APP_NAME":%s:%d: ", __func__, __LINE__);         \
57                     printf (__VA_ARGS__);                           \
58                     printf ("\n");                                  \
59                 } while (0)
60 #else
61 #define DBG(...)
62 #endif
63
64 #define INFO(...) do {                                              \
65                     printf ("INFO: "__VA_ARGS__);                   \
66                     printf ("\n");                                  \
67                 } while (0)
68
69 /* maximum tx/rx memif buffers */
70 #define MAX_MEMIF_BUFS  256
71 #define MAX_CONNS       50
72
73 int epfd;
74
75 typedef struct
76 {
77   uint16_t index;
78   /* memif conenction handle */
79   memif_conn_handle_t conn;
80   /* tx buffers */
81   memif_buffer_t *tx_bufs;
82   /* allocated tx buffers counter */
83   /* number of tx buffers pointing to shared memory */
84   uint16_t tx_buf_num;
85   /* rx buffers */
86   memif_buffer_t *rx_bufs;
87   /* allcoated rx buffers counter */
88   /* number of rx buffers pointing to shared memory */
89   uint16_t rx_buf_num;
90   /* interface ip address */
91   uint8_t ip_addr[4];
92 } memif_connection_t;
93
94 memif_connection_t memif_connection[MAX_CONNS];
95 long ctx[MAX_CONNS];
96
97 /* print details for all memif connections */
98 static void
99 print_memif_details ()
100 {
101   memif_details_t md;
102   ssize_t buflen;
103   char *buf;
104   int err, i, e;
105   buflen = 2048;
106   buf = malloc (buflen);
107   printf ("MEMIF DETAILS\n");
108   printf ("==============================\n");
109   for (i = 0; i < MAX_CONNS; i++)
110     {
111       memif_connection_t *c = &memif_connection[i];
112
113       memset (&md, 0, sizeof (md));
114       memset (buf, 0, buflen);
115
116       err = memif_get_details (c->conn, &md, buf, buflen);
117       if (err != MEMIF_ERR_SUCCESS)
118         {
119           if (err != MEMIF_ERR_NOCONN)
120             INFO ("%s", memif_strerror (err));
121           continue;
122         }
123
124       printf ("interface index: %d\n", i);
125
126       printf ("\tinterface ip: %u.%u.%u.%u\n",
127               c->ip_addr[0], c->ip_addr[1], c->ip_addr[2], c->ip_addr[3]);
128       printf ("\tinterface name: %s\n", (char *) md.if_name);
129       printf ("\tapp name: %s\n", (char *) md.inst_name);
130       printf ("\tremote interface name: %s\n", (char *) md.remote_if_name);
131       printf ("\tremote app name: %s\n", (char *) md.remote_inst_name);
132       printf ("\tid: %u\n", md.id);
133       printf ("\tsecret: %s\n", (char *) md.secret);
134       printf ("\trole: ");
135       if (md.role)
136         printf ("slave\n");
137       else
138         printf ("master\n");
139       printf ("\tmode: ");
140       switch (md.mode)
141         {
142         case 0:
143           printf ("ethernet\n");
144           break;
145         case 1:
146           printf ("ip\n");
147           break;
148         case 2:
149           printf ("punt/inject\n");
150           break;
151         default:
152           printf ("unknown\n");
153           break;
154         }
155       printf ("\tsocket filename: %s\n", (char *) md.socket_filename);
156       printf ("\trx queues:\n");
157       for (e = 0; e < md.rx_queues_num; e++)
158         {
159           printf ("\t\tqueue id: %u\n", md.rx_queues[e].qid);
160           printf ("\t\tring size: %u\n", md.rx_queues[e].ring_size);
161           printf ("\t\tbuffer size: %u\n", md.rx_queues[e].buffer_size);
162         }
163       printf ("\ttx queues:\n");
164       for (e = 0; e < md.tx_queues_num; e++)
165         {
166           printf ("\t\tqueue id: %u\n", md.tx_queues[e].qid);
167           printf ("\t\tring size: %u\n", md.tx_queues[e].ring_size);
168           printf ("\t\tbuffer size: %u\n", md.tx_queues[e].buffer_size);
169         }
170       printf ("\tlink: ");
171       if (md.link_up_down)
172         printf ("up\n");
173       else
174         printf ("down\n");
175     }
176   free (buf);
177 }
178
179 int
180 add_epoll_fd (int fd, uint32_t events)
181 {
182   if (fd < 0)
183     {
184       DBG ("invalid fd %d", fd);
185       return -1;
186     }
187   struct epoll_event evt;
188   memset (&evt, 0, sizeof (evt));
189   evt.events = events;
190   evt.data.fd = fd;
191   if (epoll_ctl (epfd, EPOLL_CTL_ADD, fd, &evt) < 0)
192     {
193       DBG ("epoll_ctl: %s fd %d", strerror (errno), fd);
194       return -1;
195     }
196   DBG ("fd %d added to epoll", fd);
197   return 0;
198 }
199
200 int
201 mod_epoll_fd (int fd, uint32_t events)
202 {
203   if (fd < 0)
204     {
205       DBG ("invalid fd %d", fd);
206       return -1;
207     }
208   struct epoll_event evt;
209   memset (&evt, 0, sizeof (evt));
210   evt.events = events;
211   evt.data.fd = fd;
212   if (epoll_ctl (epfd, EPOLL_CTL_MOD, fd, &evt) < 0)
213     {
214       DBG ("epoll_ctl: %s fd %d", strerror (errno), fd);
215       return -1;
216     }
217   DBG ("fd %d moddified on epoll", fd);
218   return 0;
219 }
220
221 int
222 del_epoll_fd (int fd)
223 {
224   if (fd < 0)
225     {
226       DBG ("invalid fd %d", fd);
227       return -1;
228     }
229   struct epoll_event evt;
230   memset (&evt, 0, sizeof (evt));
231   if (epoll_ctl (epfd, EPOLL_CTL_DEL, fd, &evt) < 0)
232     {
233       DBG ("epoll_ctl: %s fd %d", strerror (errno), fd);
234       return -1;
235     }
236   DBG ("fd %d removed from epoll", fd);
237   return 0;
238 }
239
240 /* informs user about connected status. private_ctx is used by user to identify connection
241     (multiple connections WIP) */
242 int
243 on_connect (memif_conn_handle_t conn, void *private_ctx)
244 {
245   INFO ("memif connected!");
246   return 0;
247 }
248
249 /* informs user about disconnected status. private_ctx is used by user to identify connection
250     (multiple connections WIP) */
251 int
252 on_disconnect (memif_conn_handle_t conn, void *private_ctx)
253 {
254   INFO ("memif disconnected!");
255   return 0;
256 }
257
258 /* user needs to watch new fd or stop watching fd that is about to be closed.
259     control fd will be modified during connection establishment to minimize CPU usage */
260 int
261 control_fd_update (int fd, uint8_t events)
262 {
263   /* convert memif event definitions to epoll events */
264   if (events & MEMIF_FD_EVENT_DEL)
265     return del_epoll_fd (fd);
266
267   uint32_t evt = 0;
268   if (events & MEMIF_FD_EVENT_READ)
269     evt |= EPOLLIN;
270   if (events & MEMIF_FD_EVENT_WRITE)
271     evt |= EPOLLOUT;
272
273   if (events & MEMIF_FD_EVENT_MOD)
274     return mod_epoll_fd (fd, evt);
275
276   return add_epoll_fd (fd, evt);
277 }
278
279 int
280 icmpr_buffer_alloc (long index, long n, uint16_t qid)
281 {
282   memif_connection_t *c = &memif_connection[index];
283   int err;
284   uint16_t r;
285   /* set data pointer to shared memory and set buffer_len to shared mmeory buffer len */
286   err = memif_buffer_alloc (c->conn, qid, c->tx_bufs, n, &r);
287   if (err != MEMIF_ERR_SUCCESS)
288     {
289       INFO ("memif_buffer_alloc: %s", memif_strerror (err));
290       c->tx_buf_num += r;
291       return -1;
292     }
293   c->tx_buf_num += r;
294   DBG ("allocated %d/%ld buffers, %u free buffers", r, n,
295        MAX_MEMIF_BUFS - c->tx_buf_num);
296   return 0;
297 }
298
299 int
300 icmpr_tx_burst (long index, uint16_t qid)
301 {
302   memif_connection_t *c = &memif_connection[index];
303   int err;
304   uint16_t r;
305   /* inform peer memif interface about data in shared memory buffers */
306   /* mark memif buffers as free */
307   err = memif_tx_burst (c->conn, qid, c->tx_bufs, c->tx_buf_num, &r);
308   if (err != MEMIF_ERR_SUCCESS)
309     INFO ("memif_tx_burst: %s", memif_strerror (err));
310   DBG ("tx: %d/%u", r, c->tx_buf_num);
311   c->tx_buf_num -= r;
312   return 0;
313 }
314
315 /* called when event is polled on interrupt file descriptor.
316     there are packets in shared memory ready to be received */
317 int
318 on_interrupt (memif_conn_handle_t conn, void *private_ctx, uint16_t qid)
319 {
320   long index = *((long *) private_ctx);
321   memif_connection_t *c = &memif_connection[index];
322   if (c->index != index)
323     {
324       INFO ("invalid context: %ld/%u", index, c->index);
325       return 0;
326     }
327   int err;
328   uint16_t rx;
329   uint16_t fb;
330   /* receive data from shared memory buffers */
331   err = memif_rx_burst (c->conn, qid, c->rx_bufs, MAX_MEMIF_BUFS, &rx);
332   if (err != MEMIF_ERR_SUCCESS)
333     {
334       INFO ("memif_rx_burst: %s", memif_strerror (err));
335       c->rx_buf_num += rx;
336       goto error;
337     }
338   c->rx_buf_num += rx;
339
340   DBG ("received %d buffers. %u/%u alloc/free buffers",
341        rx, c->rx_buf_num, MAX_MEMIF_BUFS - c->rx_buf_num);
342
343   if (icmpr_buffer_alloc (index, rx, qid) < 0)
344     {
345       INFO ("buffer_alloc error");
346       goto error;
347     }
348   int i;
349   for (i = 0; i < rx; i++)
350     {
351       resolve_packet ((void *) (c->rx_bufs + i)->data,
352                       (c->rx_bufs + i)->data_len,
353                       (void *) (c->tx_bufs + i)->data,
354                       &(c->tx_bufs + i)->data_len, c->ip_addr);
355     }
356
357   /* mark memif buffers and shared memory buffers as free */
358   err = memif_buffer_free (c->conn, qid, c->rx_bufs, rx, &fb);
359   if (err != MEMIF_ERR_SUCCESS)
360     INFO ("memif_buffer_free: %s", memif_strerror (err));
361   c->rx_buf_num -= fb;
362
363   DBG ("freed %d buffers. %u/%u alloc/free buffers",
364        fb, c->rx_buf_num, MAX_MEMIF_BUFS - c->rx_buf_num);
365
366   icmpr_tx_burst (index, qid);
367
368   return 0;
369
370 error:
371   err = memif_buffer_free (c->conn, qid, c->rx_bufs, rx, &fb);
372   if (err != MEMIF_ERR_SUCCESS)
373     INFO ("memif_buffer_free: %s", memif_strerror (err));
374   c->rx_buf_num -= fb;
375   DBG ("freed %d buffers. %u/%u alloc/free buffers",
376        fb, c->rx_buf_num, MAX_MEMIF_BUFS - c->rx_buf_num);
377   return 0;
378 }
379
380 int
381 icmpr_memif_create (long index, long mode)
382 {
383   if (index >= MAX_CONNS)
384     {
385       INFO ("connection array overflow");
386       return 0;
387     }
388   if (index < 0)
389     {
390       INFO ("don't even try...");
391       return 0;
392     }
393   memif_connection_t *c = &memif_connection[index];
394
395   /* setting memif connection arguments */
396   memif_conn_args_t args;
397   int fd = -1;
398   memset (&args, 0, sizeof (args));
399   args.is_master = mode;
400   args.log2_ring_size = 10;
401   args.buffer_size = 2048;
402   args.num_s2m_rings = 2;
403   args.num_m2s_rings = 2;
404   strncpy ((char *) args.interface_name, IF_NAME, strlen (IF_NAME));
405   strncpy ((char *) args.instance_name, APP_NAME, strlen (APP_NAME));
406   args.mode = 0;
407   /* socket filename is not specified, because this app is supposed to
408      connect to VPP over memif. so default socket filename will be used */
409   /* default socketfile = /run/vpp/memif.sock */
410
411   args.interface_id = index;
412   /* last argument for memif_create (void * private_ctx) is used by user
413      to identify connection. this context is returned with callbacks */
414   int err = memif_create (&c->conn,
415                           &args, on_connect, on_disconnect, on_interrupt,
416                           &ctx[index]);
417   if (err != MEMIF_ERR_SUCCESS)
418     {
419       INFO ("memif_create: %s", memif_strerror (err));
420       return 0;
421     }
422
423   c->index = index;
424   /* alloc memif buffers */
425   c->rx_buf_num = 0;
426   c->rx_bufs =
427     (memif_buffer_t *) malloc (sizeof (memif_buffer_t) * MAX_MEMIF_BUFS);
428   c->tx_buf_num = 0;
429   c->tx_bufs =
430     (memif_buffer_t *) malloc (sizeof (memif_buffer_t) * MAX_MEMIF_BUFS);
431
432   c->ip_addr[0] = 192;
433   c->ip_addr[1] = 168;
434   c->ip_addr[2] = c->index + 1;
435   c->ip_addr[3] = 2;
436   return 0;
437 }
438
439 int
440 icmpr_memif_delete (long index)
441 {
442   if (index >= MAX_CONNS)
443     {
444       INFO ("connection array overflow");
445       return 0;
446     }
447   if (index < 0)
448     {
449       INFO ("don't even try...");
450       return 0;
451     }
452   memif_connection_t *c = &memif_connection[index];
453
454   if (c->rx_bufs)
455     free (c->rx_bufs);
456   c->rx_bufs = NULL;
457   c->rx_buf_num = 0;
458   if (c->tx_bufs)
459     free (c->tx_bufs);
460   c->tx_bufs = NULL;
461   c->tx_buf_num = 0;
462
463   int err;
464   /* disconenct then delete memif connection */
465   err = memif_delete (&c->conn);
466   if (err != MEMIF_ERR_SUCCESS)
467     INFO ("memif_delete: %s", memif_strerror (err));
468   if (c->conn != NULL)
469     INFO ("memif delete fail");
470   return 0;
471 }
472
473 void
474 print_help ()
475 {
476   printf ("LIBMEMIF EXAMPLE APP: %s", APP_NAME);
477 #ifdef ICMP_DBG
478   printf (" (debug)");
479 #endif
480   printf ("\n");
481   printf ("==============================\n");
482   printf ("libmemif version: %s", LIBMEMIF_VERSION);
483 #ifdef MEMIF_DBG
484   printf (" (debug)");
485 #endif
486   printf ("\n");
487   printf ("memif version: %d\n", MEMIF_VERSION);
488   printf ("commands:\n");
489   printf ("\thelp - prints this help\n");
490   printf ("\texit - exit app\n");
491   printf
492     ("\tconn <index> <mode> - create memif. index is also used as interface id, mode 0 = slave 1 = master\n");
493   printf ("\tdel  <index> - delete memif\n");
494   printf ("\tshow - show connection details\n");
495   printf ("\tip-set <index> <ip-addr> - set interface ip address\n");
496   printf
497     ("\trx-mode <index> <qid> <polling|interrupt> - set queue rx mode\n");
498 }
499
500 int
501 icmpr_free ()
502 {
503   /* application cleanup */
504   int err;
505   long i;
506   for (i = 0; i < MAX_CONNS; i++)
507     {
508       memif_connection_t *c = &memif_connection[i];
509       if (c->conn)
510         icmpr_memif_delete (i);
511     }
512
513   err = memif_cleanup ();
514   if (err != MEMIF_ERR_SUCCESS)
515     INFO ("memif_delete: %s", memif_strerror (err));
516
517   return 0;
518 }
519
520 int
521 icmpr_set_ip (long index, char *ip)
522 {
523   if (index >= MAX_CONNS)
524     {
525       INFO ("connection array overflow");
526       return 0;
527     }
528   if (index < 0)
529     {
530       INFO ("don't even try...");
531       return 0;
532     }
533   memif_connection_t *c = &memif_connection[index];
534   if (c->conn == NULL)
535     {
536       INFO ("no connection at index %ld", index);
537       return 0;
538     }
539
540   char *end;
541   char *ui;
542   uint8_t tmp[4];
543   ui = strtok (ip, ".");
544   if (ui == NULL)
545     goto error;
546   tmp[0] = strtol (ui, &end, 10);
547
548   ui = strtok (NULL, ".");
549   if (ui == NULL)
550     goto error;
551   tmp[1] = strtol (ui, &end, 10);
552
553   ui = strtok (NULL, ".");
554   if (ui == NULL)
555     goto error;
556   tmp[2] = strtol (ui, &end, 10);
557
558   ui = strtok (NULL, ".");
559   if (ui == NULL)
560     goto error;
561   tmp[3] = strtol (ui, &end, 10);
562
563   c->ip_addr[0] = tmp[0];
564   c->ip_addr[1] = tmp[1];
565   c->ip_addr[2] = tmp[2];
566   c->ip_addr[3] = tmp[3];
567
568   INFO ("memif %ld ip address set to %u.%u.%u.%u",
569         index, c->ip_addr[0], c->ip_addr[1], c->ip_addr[2], c->ip_addr[3]);
570
571   return 0;
572
573 error:
574   INFO ("invalid ip address");
575   return 0;
576 }
577
578 int
579 icmpr_set_rx_mode (long index, long qid, char *mode)
580 {
581   if (index >= MAX_CONNS)
582     {
583       INFO ("connection array overflow");
584       return 0;
585     }
586   if (index < 0)
587     {
588       INFO ("don't even try...");
589       return 0;
590     }
591   memif_connection_t *c = &memif_connection[index];
592
593   if (c->conn == NULL)
594     {
595       INFO ("no connection at index %ld", index);
596       return 0;
597     }
598
599   if (strncmp (mode, "interrupt", 9) == 0)
600     {
601       memif_set_rx_mode (c->conn, MEMIF_RX_MODE_INTERRUPT, qid);
602     }
603
604   else if (strncmp (mode, "polling", 7) == 0)
605     {
606       memif_set_rx_mode (c->conn, MEMIF_RX_MODE_POLLING, qid);
607     }
608   else
609     INFO ("expected rx mode <interrupt|polling>");
610   return 0;
611 }
612
613 int
614 user_input_handler ()
615 {
616   int i;
617   char *in = (char *) malloc (256);
618   char *ui = fgets (in, 256, stdin);
619   char *end;
620   long a;
621   if (in[0] == '\n')
622     goto done;
623   ui = strtok (in, " ");
624   if (strncmp (ui, "exit", 4) == 0)
625     {
626       free (in);
627       icmpr_free ();
628       exit (EXIT_SUCCESS);
629     }
630   else if (strncmp (ui, "help", 4) == 0)
631     {
632       print_help ();
633       goto done;
634     }
635   else if (strncmp (ui, "conn", 4) == 0)
636     {
637       ui = strtok (NULL, " ");
638       if (ui != NULL)
639         a = strtol (ui, &end, 10);
640       else
641         {
642           INFO ("expected id");
643           goto done;
644         }
645       ui = strtok (NULL, " ");
646       if (ui != NULL)
647         icmpr_memif_create (a, strtol (ui, &end, 10));
648       else
649         INFO ("expected mode <0|1>");
650       goto done;
651     }
652   else if (strncmp (ui, "del", 3) == 0)
653     {
654       ui = strtok (NULL, " ");
655       if (ui != NULL)
656         icmpr_memif_delete (strtol (ui, &end, 10));
657       else
658         INFO ("expected id");
659       goto done;
660     }
661   else if (strncmp (ui, "show", 4) == 0)
662     {
663       print_memif_details ();
664       goto done;
665     }
666   else if (strncmp (ui, "ip-set", 6) == 0)
667     {
668       ui = strtok (NULL, " ");
669       if (ui != NULL)
670         icmpr_set_ip (strtol (ui, &end, 10), strtok (NULL, " "));
671       else
672         INFO ("expected id");
673       goto done;
674     }
675   else if (strncmp (ui, "rx-mode", 7) == 0)
676     {
677       ui = strtok (NULL, " ");
678       if (ui != NULL)
679         a = strtol (ui, &end, 10);
680       else
681         {
682           INFO ("expected id");
683           goto done;
684         }
685       ui = strtok (NULL, " ");
686       if (ui != NULL)
687         icmpr_set_rx_mode (a, strtol (ui, &end, 10), strtok (NULL, " "));
688       else
689         INFO ("expected qid");
690       goto done;
691     }
692   else
693     {
694       DBG ("unknown command: %s", ui);
695       goto done;
696     }
697
698   return 0;
699 done:
700   free (in);
701   return 0;
702 }
703
704 int
705 poll_event (int timeout)
706 {
707   struct epoll_event evt, *e;
708   int app_err = 0, memif_err = 0, en = 0;
709   int tmp, nfd;
710   uint32_t events = 0;
711   memset (&evt, 0, sizeof (evt));
712   evt.events = EPOLLIN | EPOLLOUT;
713   sigset_t sigset;
714   sigemptyset (&sigset);
715   en = epoll_pwait (epfd, &evt, 1, timeout, &sigset);
716   if (en < 0)
717     {
718       DBG ("epoll_pwait: %s", strerror (errno));
719       return -1;
720     }
721   if (en > 0)
722     {
723       /* this app does not use any other file descriptors than stds and memif control fds */
724       if (evt.data.fd > 2)
725         {
726           /* event of memif control fd */
727           /* convert epolle events to memif events */
728           if (evt.events & EPOLLIN)
729             events |= MEMIF_FD_EVENT_READ;
730           if (evt.events & EPOLLOUT)
731             events |= MEMIF_FD_EVENT_WRITE;
732           if (evt.events & EPOLLERR)
733             events |= MEMIF_FD_EVENT_ERROR;
734           memif_err = memif_control_fd_handler (evt.data.fd, events);
735           if (memif_err != MEMIF_ERR_SUCCESS)
736             INFO ("memif_control_fd_handler: %s", memif_strerror (memif_err));
737         }
738       else if (evt.data.fd == 0)
739         {
740           app_err = user_input_handler ();
741         }
742       else
743         {
744           DBG ("unexpected event at memif_epfd. fd %d", evt.data.fd);
745         }
746     }
747
748   if ((app_err < 0) || (memif_err < 0))
749     {
750       if (app_err < 0)
751         DBG ("user input handler error");
752       if (memif_err < 0)
753         DBG ("memif control fd handler error");
754       return -1;
755     }
756
757   return 0;
758 }
759
760 int
761 main ()
762 {
763   epfd = epoll_create (1);
764   add_epoll_fd (0, EPOLLIN);
765
766   /* initialize memory interface */
767   int err, i;
768   /* if valid callback is passed as argument, fd event polling will be done by user
769      all file descriptors and events will be passed to user in this callback */
770   /* if callback is set to NULL libmemif will handle fd event polling */
771   err = memif_init (control_fd_update, APP_NAME);
772   if (err != MEMIF_ERR_SUCCESS)
773     INFO ("memif_init: %s", memif_strerror (err));
774
775   for (i = 0; i < MAX_CONNS; i++)
776     {
777       memif_connection[i].conn = NULL;
778       ctx[i] = i;
779     }
780
781   print_help ();
782
783   /* main loop */
784   while (1)
785     {
786       if (poll_event (-1) < 0)
787         {
788           DBG ("poll_event error!");
789         }
790     }
791 }