dpnode.cc 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. extern "C" {
  2. #include <event2/listener.h>
  3. #include <event2/bufferevent.h>
  4. #include <event2/buffer.h>
  5. #include <event2/util.h>
  6. }
  7. #include <sys/socket.h>
  8. #include <netinet/in.h>
  9. #include <arpa/inet.h>
  10. #include <set>
  11. #include <map>
  12. #ifdef LOG_MEM
  13. #include <stdio.h>
  14. #endif
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <errno.h>
  18. #include "evutils.h"
  19. #include "subproblem.h"
  20. #include "dpnode.h"
  21. typedef map<std::string, pair<ZZ,ZZ> > DTable;
  22. typedef enum {
  23. DPSTATE_START,
  24. DPSTATE_END
  25. } DPState;
  26. struct DPNodeConnInfo {
  27. DPState state;
  28. DPNodeConnInfo() : state(DPSTATE_START) {}
  29. };
  30. static struct DPControllerState {
  31. struct bufferevent *controller_bev;
  32. Subproblem *current_problem;
  33. struct evconnlistener *listener;
  34. std::set<struct bufferevent *> workers;
  35. DTable table;
  36. unsigned long long numdps;
  37. DPControllerState() : controller_bev(NULL), current_problem(NULL),
  38. listener(NULL) {}
  39. } dpctrlstate;
  40. #ifdef LOG_MEM
  41. /* Log the amount of memory used by the process. It turns out each DP
  42. consumes about 338 bytes of heap. Also, memory is not deallocated when
  43. the table is cleared. */
  44. static void logmemusage(const char *label)
  45. {
  46. FILE *smaps;
  47. FILE *logoutput;
  48. char logfilename[256];
  49. sprintf(logfilename, "mem-%05d", getpid());
  50. smaps = fopen("/proc/self/smaps", "r");
  51. if (!smaps) return;
  52. logoutput = fopen(logfilename, "a");
  53. if (!logoutput) {
  54. fclose(smaps);
  55. return;
  56. }
  57. char *line = NULL;
  58. size_t n = 0;
  59. while(getline(&line, &n, smaps) > -1) {
  60. if (!strstr(line, "[heap]")) {
  61. free(line);
  62. line = NULL;
  63. continue;
  64. }
  65. // Read and parse the next line
  66. if (getline(&line, &n, smaps) > -1 && !strncmp(line, "Size:", 5)) {
  67. unsigned long usage;
  68. if (sscanf(line+5, "%lu", &usage) == 1) {
  69. fprintf(logoutput, "%s %lu %lu %lu\n", label,
  70. dpctrlstate.table.size(), dpctrlstate.table.max_size(),
  71. usage);
  72. break;
  73. }
  74. }
  75. }
  76. fclose(logoutput);
  77. fclose(smaps);
  78. }
  79. #endif
  80. static void dpnode_event_cb(struct bufferevent *bev, short events,
  81. void *ctx)
  82. {
  83. if (events & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) {
  84. cerr << "Closing connection " << bev << " ";
  85. if (events & BEV_EVENT_EOF) {
  86. cerr << "EOF";
  87. }
  88. if (events & BEV_EVENT_ERROR) {
  89. cerr << "ERR (" << evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR()) << ")";
  90. }
  91. cerr << "\n";
  92. DPNodeConnInfo *info = (DPNodeConnInfo*)ctx;
  93. delete info;
  94. dpctrlstate.workers.erase(bev);
  95. bufferevent_free(bev);
  96. }
  97. }
  98. static void stop_problem(void);
  99. static void dpnode_reader(struct bufferevent *bev, void *ctx)
  100. {
  101. struct evbuffer *input = bufferevent_get_input(bev);
  102. unsigned int dp[WORDS+6];
  103. while(1) {
  104. size_t len = evbuffer_get_length(input);
  105. if (len < ((WORDS+6)*sizeof(unsigned int))) break;
  106. bufferevent_read(bev, dp, (WORDS+6)*sizeof(unsigned int));
  107. if (dpctrlstate.current_problem == NULL) continue;
  108. // The (WORDS+6) unsigned ints we read are:
  109. // - WORDS words for the value of the dp
  110. // - 3 words for a
  111. // - 3 words for b
  112. ZZ zz_a, zz_b;
  113. ZZFromBytes(zz_a, (const unsigned char *)(dp+WORDS),
  114. 3*sizeof(unsigned int));
  115. ZZFromBytes(zz_b, (const unsigned char *)(dp+WORDS+3),
  116. 3*sizeof(unsigned int));
  117. string x((const char *)(dp), WORDS*sizeof(unsigned int));
  118. pair<ZZ,ZZ> ab(zz_a,zz_b);
  119. pair<DTable::iterator, bool> res =
  120. dpctrlstate.table.insert(DTable::value_type(x,ab));
  121. #ifdef LOG_MEM
  122. if (dpctrlstate.table.size() % 1000 == 0) {
  123. logmemusage("insert");
  124. }
  125. #endif
  126. if (!res.second) {
  127. const ZZ& order = dpctrlstate.current_problem->order;
  128. // Collision!
  129. ZZ adiff = res.first->second.first - zz_a;
  130. ZZ bdiff = zz_b - res.first->second.second;
  131. while (bdiff < 0) bdiff += order;
  132. while (bdiff >= order) bdiff -= order;
  133. while (adiff < 0) adiff += order;
  134. while (adiff >= order) adiff -= order;
  135. ZZ binv;
  136. if (InvModStatus(binv, bdiff, order) == 0) {
  137. ZZ expon = MulMod(binv, adiff, order);
  138. cerr << "Collision after " << dpctrlstate.numdps << " DPs\n";
  139. unsigned char exponbytes[3+3*sizeof(unsigned int)];
  140. exponbytes[0] = 'E';
  141. memmove(exponbytes+1,
  142. &(dpctrlstate.current_problem->problemid), 2);
  143. BytesFromZZ(exponbytes+3, expon, 3*sizeof(unsigned int));
  144. bufferevent_write(dpctrlstate.controller_bev, exponbytes,
  145. 3+3*sizeof(unsigned int));
  146. stop_problem();
  147. return;
  148. }
  149. }
  150. ++dpctrlstate.numdps;
  151. }
  152. }
  153. static void dpnode_accept_cb(struct evconnlistener *listener,
  154. evutil_socket_t fd, struct sockaddr *address, int socklen,
  155. void *ctx)
  156. {
  157. DPNodeConnInfo *info = new DPNodeConnInfo();
  158. // Create a bufferevent for the new connection
  159. struct event_base *base = evconnlistener_get_base(listener);
  160. struct bufferevent *bev = bufferevent_socket_new(
  161. base, fd, BEV_OPT_CLOSE_ON_FREE);
  162. cerr << "accepted connection " << bev << "\n";
  163. bufferevent_setcb(bev, dpnode_reader, NULL,
  164. dpnode_event_cb, info);
  165. bufferevent_enable(bev, EV_READ);
  166. dpctrlstate.workers.insert(bev);
  167. }
  168. // Create a new DPnode socket. ip and boundport are set to the IP and
  169. // port of the socket, in network byte order.
  170. struct evconnlistener *dpnode_create(struct event_base *evbase,
  171. unsigned int *ip, unsigned short *boundport)
  172. {
  173. struct evconnlistener *ecl = listener_create(evbase, 0,
  174. dpnode_accept_cb, NULL, ip, boundport, false);
  175. cerr << "Listening at " << ecl << "\n";
  176. return ecl;
  177. }
  178. typedef enum {
  179. DPCCSTATE_AWAITCMD,
  180. DPCCSTATE_RDPROBLEM,
  181. DPCCSTATE_END
  182. } DPCCState;
  183. struct DPControllerConnInfo {
  184. DPCCState state;
  185. DPControllerConnInfo() : state(DPCCSTATE_AWAITCMD) {}
  186. };
  187. static void stop_problem(void)
  188. {
  189. cerr << "Stopping problem\n";
  190. if (dpctrlstate.current_problem) {
  191. delete dpctrlstate.current_problem;
  192. dpctrlstate.current_problem = NULL;
  193. }
  194. if (dpctrlstate.listener) {
  195. cerr << "Closing listener " << dpctrlstate.listener << "\n";
  196. evconnlistener_free(dpctrlstate.listener);
  197. dpctrlstate.listener = NULL;
  198. }
  199. std::set<struct bufferevent *>::iterator wit;
  200. for (wit = dpctrlstate.workers.begin(); wit != dpctrlstate.workers.end();
  201. ++wit) {
  202. cerr << "Closing connection " << *wit << "\n";
  203. bufferevent_free(*wit);
  204. }
  205. dpctrlstate.workers.clear();
  206. #ifdef LOG_MEM
  207. logmemusage("preclear");
  208. #endif
  209. dpctrlstate.table.clear();
  210. #ifdef LOG_MEM
  211. logmemusage("postclear");
  212. #endif
  213. dpctrlstate.numdps = 0;
  214. }
  215. static void start_problem(struct bufferevent *bev,
  216. const unsigned char *subproblem)
  217. {
  218. unsigned int myip;
  219. unsigned short myport;
  220. stop_problem();
  221. dpctrlstate.current_problem = new Subproblem(subproblem);
  222. dpctrlstate.current_problem->dump(cerr);
  223. // Create the DPNode server socket
  224. dpctrlstate.listener = dpnode_create(bufferevent_get_base(bev),
  225. &myip, &myport);
  226. struct in_addr myaddr = { myip };
  227. fprintf(stderr, "Bound to %s:%d\n", inet_ntoa(myaddr), ntohs(myport));
  228. unsigned char idstring[7];
  229. idstring[0] = 'L';
  230. memmove(idstring+1, &myip, 4);
  231. memmove(idstring+5, &myport, 2);
  232. bufferevent_write(bev, idstring, 7);
  233. }
  234. static void controllerconn_reader(struct bufferevent *bev, void *ctx)
  235. {
  236. struct evbuffer *input = bufferevent_get_input(bev);
  237. DPControllerConnInfo *info = (DPControllerConnInfo *)ctx;
  238. unsigned char cmd[1];
  239. unsigned char subproblem[SUBPROBLEM_DESC_LEN];
  240. while(1) {
  241. size_t len = evbuffer_get_length(input);
  242. switch(info->state) {
  243. case DPCCSTATE_AWAITCMD:
  244. if (len < 1) return;
  245. bufferevent_read(bev, cmd, 1);
  246. cerr << "Received command " << cmd[0] << "\n";
  247. switch(cmd[0]) {
  248. case 'P':
  249. info->state = DPCCSTATE_RDPROBLEM;
  250. break;
  251. case 'S':
  252. stop_problem();
  253. break;
  254. default:
  255. /* Unknown command received */
  256. fprintf(stderr, "Unknown command in "
  257. "controllerconn_reader: %c\n", cmd[0]);
  258. info->state = DPCCSTATE_END;
  259. break;
  260. }
  261. break;
  262. case DPCCSTATE_RDPROBLEM:
  263. if (len < SUBPROBLEM_DESC_LEN) return;
  264. bufferevent_read(bev, subproblem, SUBPROBLEM_DESC_LEN);
  265. start_problem(bev, subproblem);
  266. info->state = DPCCSTATE_AWAITCMD;
  267. break;
  268. case DPCCSTATE_END:
  269. // Shut down
  270. delete info;
  271. event_base_loopbreak(bufferevent_get_base(bev));
  272. cerr << "END conenction " << bev << "\n";
  273. dpctrlstate.workers.erase(bev);
  274. bufferevent_free(bev);
  275. return;
  276. }
  277. }
  278. }
  279. static void controllerconn_event_cb(struct bufferevent *bev, short events,
  280. void *ctx)
  281. {
  282. if (events & BEV_EVENT_CONNECTED) {
  283. // We have successfully connected to the controller
  284. char id[1] = { 'D' };
  285. bufferevent_enable(bev, EV_READ|EV_WRITE);
  286. bufferevent_write(bev, id, 1);
  287. bufferevent_setcb(bev, controllerconn_reader, NULL,
  288. controllerconn_event_cb, new DPControllerConnInfo());
  289. dpctrlstate.controller_bev = bev;
  290. } else if (events & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) {
  291. fprintf(stderr, "Closing connection to controller and exiting\n");
  292. event_base_loopbreak(bufferevent_get_base(bev));
  293. bufferevent_free(bev);
  294. }
  295. }
  296. int dpnode_main(const char *controller_host, unsigned short controller_port)
  297. {
  298. return controller_client(controller_host, controller_port,
  299. controllerconn_event_cb, false);
  300. }