evutils.cc 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. extern "C" {
  2. #include <event2/listener.h>
  3. #include <event2/bufferevent.h>
  4. }
  5. #include "evutils.h"
  6. #include <iostream>
  7. #include <string.h>
  8. #include <netdb.h>
  9. #include <unistd.h>
  10. unsigned int hostlookup(const char *hostname)
  11. {
  12. struct hostent *he = gethostbyname(hostname);
  13. if (!he) {
  14. // Could not resolve hostname
  15. return 0;
  16. }
  17. struct in_addr *addr = (struct in_addr*)(he->h_addr_list[0]);
  18. return addr->s_addr;
  19. }
  20. static unsigned int getlocalIP(void)
  21. {
  22. unsigned int const hostname_len = 257+50;
  23. char hostname[hostname_len];
  24. if (gethostname(hostname, 256)) {
  25. // Could not determine hostname
  26. return 0;
  27. }
  28. hostname[256] = '\0';
  29. #if defined(RIPPLE)
  30. // Use the 4*40Gbps bonded interface on RIPPLE
  31. strcat(hostname, "-data0");
  32. #elif defined(GRAHAM)
  33. // Use the Infiniband interface on GRAHAM
  34. char temp_hostname[hostname_len];
  35. strcpy(temp_hostname, hostname);
  36. snprintf(hostname, sizeof(hostname), "%s%s", "ic-", temp_hostname);
  37. #endif
  38. return hostlookup(hostname);
  39. }
  40. // Create a new listener socket. bindport is the port to bind to (in
  41. // host byte order), or 0 if any port will do. ip and boundport are set
  42. // to the IP and port of the socket, in network byte order.
  43. struct evconnlistener *listener_create(struct event_base *evbase,
  44. unsigned short bindport, evconnlistener_cb cb, void *ctx,
  45. unsigned int *ip, unsigned short *boundport, bool multithread)
  46. {
  47. struct sockaddr_in sin;
  48. sin.sin_family = AF_INET;
  49. sin.sin_addr.s_addr = htonl(0);
  50. sin.sin_port = htons(bindport);
  51. if (ip) {
  52. *ip = getlocalIP();
  53. if (*ip == 0) {
  54. perror("Determining local IP");
  55. return NULL;
  56. }
  57. }
  58. struct evconnlistener *listener = evconnlistener_new_bind(evbase,
  59. cb, ctx, LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE|
  60. (multithread ? LEV_OPT_THREADSAFE : 0),
  61. -1, (struct sockaddr*)&sin, sizeof(sin));
  62. if (!listener) {
  63. perror("Unable to create listener");
  64. return NULL;
  65. }
  66. int localfd = evconnlistener_get_fd(listener);
  67. if (boundport) {
  68. socklen_t addrsize = sizeof(sin);
  69. if (getsockname(localfd, (struct sockaddr*)&sin, &addrsize)) {
  70. perror("Unable to learn local port");
  71. return NULL;
  72. }
  73. *boundport = sin.sin_port;
  74. }
  75. return listener;
  76. }
  77. // Create a client connection to the given 6-byte ipport (4 byte IP, 2
  78. // byte port in network byte order).
  79. struct bufferevent *client_create(struct event_base *evbase,
  80. unsigned char ipport[6], bufferevent_event_cb event_handler,
  81. bool multithread)
  82. {
  83. // Create a Controller client socket
  84. struct sockaddr_in client_sin;
  85. client_sin.sin_family = AF_INET;
  86. memmove(&client_sin.sin_addr.s_addr, ipport, 4);
  87. memmove(&client_sin.sin_port, ipport+4, 2);
  88. struct bufferevent *client_bev = bufferevent_socket_new(evbase,
  89. -1, BEV_OPT_CLOSE_ON_FREE |
  90. (multithread ? BEV_OPT_DEFER_CALLBACKS|BEV_OPT_UNLOCK_CALLBACKS|
  91. BEV_OPT_THREADSAFE : 0));
  92. if (bufferevent_socket_connect(client_bev,
  93. (struct sockaddr *)&client_sin, sizeof(client_sin)) < 0) {
  94. bufferevent_free(client_bev);
  95. fprintf(stderr, "Unable to connect to server\n");
  96. return NULL;
  97. }
  98. bufferevent_setcb(client_bev, NULL, NULL, event_handler, NULL);
  99. return client_bev;
  100. }
  101. // Create a client connection to a controller, with event_handler set as
  102. // the event callback. It will be called when the connection succeeds or
  103. // fails. This function calls the libevent main loop, so it will only return
  104. // when the program is finished.
  105. int controller_client(const char *controller_host,
  106. unsigned short controller_port, bufferevent_event_cb event_handler,
  107. bool multithread, void (*ev_loop_empty_cb)())
  108. {
  109. struct event_base *evbase = event_base_new();
  110. // Create a Controller client socket
  111. struct sockaddr_in controller_sin;
  112. controller_sin.sin_family = AF_INET;
  113. controller_sin.sin_addr.s_addr = hostlookup(controller_host);
  114. if (controller_sin.sin_addr.s_addr == 0) {
  115. fprintf(stderr, "Unknown host %s\n", controller_host);
  116. return 1;
  117. }
  118. controller_sin.sin_port = htons(controller_port);
  119. struct bufferevent *controller_bev = bufferevent_socket_new(evbase,
  120. -1, BEV_OPT_CLOSE_ON_FREE|(multithread ? BEV_OPT_THREADSAFE : 0));
  121. if (bufferevent_socket_connect(controller_bev,
  122. (struct sockaddr *)&controller_sin, sizeof(controller_sin)) < 0) {
  123. bufferevent_free(controller_bev);
  124. fprintf(stderr, "Unable to connect to controller\n");
  125. return 1;
  126. }
  127. bufferevent_setcb(controller_bev, NULL, NULL, event_handler, NULL);
  128. if (ev_loop_empty_cb == NULL) {
  129. event_base_dispatch(evbase);
  130. } else {
  131. while (true) {
  132. event_base_loop(evbase, EVLOOP_ONCE);
  133. ev_loop_empty_cb();
  134. if (event_base_got_exit(evbase) || event_base_got_break(evbase)) {
  135. break;
  136. }
  137. }
  138. }
  139. return 0;
  140. }