dpnode.cc 9.5 KB

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