dpnode.cc 9.2 KB

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