Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

slam.c 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541
  1. #if 0
  2. /*
  3. * IMPORTANT
  4. *
  5. * This file should be rewritten to avoid the use of a bitmap. Our
  6. * buffer routines can cope with being handed blocks in an arbitrary
  7. * order, duplicate blocks, etc. This code could be substantially
  8. * simplified by taking advantage of these features.
  9. *
  10. */
  11. #define SLAM_PORT 10000
  12. #define SLAM_MULTICAST_IP ((239<<24)|(255<<16)|(1<<8)|(1<<0))
  13. #define SLAM_MULTICAST_PORT 10000
  14. #define SLAM_LOCAL_PORT 10000
  15. /* Set the timeout intervals to at least 1 second so
  16. * on a 100Mbit ethernet can receive 10000 packets
  17. * in one second.
  18. *
  19. * The only case that is likely to trigger all of the nodes
  20. * firing a nack packet is a slow server. The odds of this
  21. * happening could be reduced being slightly smarter and utilizing
  22. * the multicast channels for nacks. But that only improves the odds
  23. * it doesn't improve the worst case. So unless this proves to be
  24. * a common case having the control data going unicast should increase
  25. * the odds of the data not being dropped.
  26. *
  27. * When doing exponential backoff we increase just the timeout
  28. * interval and not the base to optimize for throughput. This is only
  29. * expected to happen when the server is down. So having some nodes
  30. * pinging immediately should get the transmission restarted quickly after a
  31. * server restart. The host nic won't be to baddly swamped because of
  32. * the random distribution of the nodes.
  33. *
  34. */
  35. #define SLAM_INITIAL_MIN_TIMEOUT (TICKS_PER_SEC/3)
  36. #define SLAM_INITIAL_TIMEOUT_INTERVAL (TICKS_PER_SEC)
  37. #define SLAM_BASE_MIN_TIMEOUT (2*TICKS_PER_SEC)
  38. #define SLAM_BASE_TIMEOUT_INTERVAL (4*TICKS_PER_SEC)
  39. #define SLAM_BACKOFF_LIMIT 5
  40. #define SLAM_MAX_RETRIES 20
  41. /*** Packets Formats ***
  42. * Data Packet:
  43. * transaction
  44. * total bytes
  45. * block size
  46. * packet #
  47. * data
  48. *
  49. * Status Request Packet
  50. * transaction
  51. * total bytes
  52. * block size
  53. *
  54. * Status Packet
  55. * received packets
  56. * requested packets
  57. * received packets
  58. * requested packets
  59. * ...
  60. * received packets
  61. * requested packtes
  62. * 0
  63. */
  64. #define MAX_HDR (7 + 7 + 7) /* transaction, total size, block size */
  65. #define MIN_HDR (1 + 1 + 1) /* transactino, total size, block size */
  66. #define MAX_SLAM_REQUEST MAX_HDR
  67. #define MIN_SLAM_REQUEST MIN_HDR
  68. #define MIN_SLAM_DATA (MIN_HDR + 1)
  69. static struct slam_nack {
  70. struct iphdr ip;
  71. struct udphdr udp;
  72. unsigned char data[ETH_MAX_MTU -
  73. (sizeof(struct iphdr) + sizeof(struct udphdr))];
  74. } nack;
  75. struct slam_state {
  76. unsigned char hdr[MAX_HDR];
  77. unsigned long hdr_len;
  78. unsigned long block_size;
  79. unsigned long total_bytes;
  80. unsigned long total_packets;
  81. unsigned long received_packets;
  82. struct buffer *buffer;
  83. unsigned char *image;
  84. unsigned char *bitmap;
  85. } state;
  86. static void init_slam_state(void)
  87. {
  88. state.hdr_len = sizeof(state.hdr);
  89. memset(state.hdr, 0, state.hdr_len);
  90. state.block_size = 0;
  91. state.total_packets = 0;
  92. state.received_packets = 0;
  93. state.image = 0;
  94. state.bitmap = 0;
  95. }
  96. struct slam_info {
  97. struct sockaddr_in server;
  98. struct sockaddr_in local;
  99. struct sockaddr_in multicast;
  100. int sent_nack;
  101. struct buffer *buffer;
  102. };
  103. #define SLAM_TIMEOUT 0
  104. #define SLAM_REQUEST 1
  105. #define SLAM_DATA 2
  106. static int await_slam(int ival __unused, void *ptr,
  107. unsigned short ptype __unused, struct iphdr *ip,
  108. struct udphdr *udp, struct tcphdr *tcp __unused)
  109. {
  110. struct slam_info *info = ptr;
  111. if (!udp) {
  112. return 0;
  113. }
  114. /* I can receive two kinds of packets here, a multicast data packet,
  115. * or a unicast request for information
  116. */
  117. /* Check for a data request packet */
  118. if ((ip->dest.s_addr == arptable[ARP_CLIENT].ipaddr.s_addr) &&
  119. (ntohs(udp->dest) == info->local.sin_port) &&
  120. (nic.packetlen >=
  121. ETH_HLEN +
  122. sizeof(struct iphdr) +
  123. sizeof(struct udphdr) +
  124. MIN_SLAM_REQUEST)) {
  125. return SLAM_REQUEST;
  126. }
  127. /* Check for a multicast data packet */
  128. if ((ip->dest.s_addr == info->multicast.sin_addr.s_addr) &&
  129. (ntohs(udp->dest) == info->multicast.sin_port) &&
  130. (nic.packetlen >=
  131. ETH_HLEN +
  132. sizeof(struct iphdr) +
  133. sizeof(struct udphdr) +
  134. MIN_SLAM_DATA)) {
  135. return SLAM_DATA;
  136. }
  137. #if 0
  138. printf("#");
  139. printf("dest: %@ port: %d len: %d\n",
  140. ip->dest.s_addr, ntohs(udp->dest), nic.packetlen);
  141. #endif
  142. return 0;
  143. }
  144. static int slam_encode(
  145. unsigned char **ptr, unsigned char *end, unsigned long value)
  146. {
  147. unsigned char *data = *ptr;
  148. int bytes;
  149. bytes = sizeof(value);
  150. while ((bytes > 0) && ((0xff & (value >> ((bytes -1)<<3))) == 0)) {
  151. bytes--;
  152. }
  153. if (bytes <= 0) {
  154. bytes = 1;
  155. }
  156. if (data + bytes >= end) {
  157. return -1;
  158. }
  159. if ((0xe0 & (value >> ((bytes -1)<<3))) == 0) {
  160. /* packed together */
  161. *data = (bytes << 5) | (value >> ((bytes -1)<<3));
  162. } else {
  163. bytes++;
  164. *data = (bytes << 5);
  165. }
  166. bytes--;
  167. data++;
  168. while(bytes) {
  169. *(data++) = 0xff & (value >> ((bytes -1)<<3));
  170. bytes--;
  171. }
  172. *ptr = data;
  173. return 0;
  174. }
  175. static int slam_skip(unsigned char **ptr, unsigned char *end)
  176. {
  177. int bytes;
  178. if (*ptr >= end) {
  179. return -1;
  180. }
  181. bytes = ((**ptr) >> 5) & 7;
  182. if (bytes == 0) {
  183. return -1;
  184. }
  185. if (*ptr + bytes >= end) {
  186. return -1;
  187. }
  188. (*ptr) += bytes;
  189. return 0;
  190. }
  191. static unsigned long slam_decode(unsigned char **ptr, unsigned char *end,
  192. int *err)
  193. {
  194. unsigned long value;
  195. unsigned bytes;
  196. if (*ptr >= end) {
  197. *err = -1;
  198. }
  199. bytes = ((**ptr) >> 5) & 7;
  200. if ((bytes == 0) || (bytes > sizeof(unsigned long))) {
  201. *err = -1;
  202. return 0;
  203. }
  204. if ((*ptr) + bytes >= end) {
  205. *err = -1;
  206. }
  207. value = (**ptr) & 0x1f;
  208. bytes--;
  209. (*ptr)++;
  210. while(bytes) {
  211. value <<= 8;
  212. value |= **ptr;
  213. (*ptr)++;
  214. bytes--;
  215. }
  216. return value;
  217. }
  218. static long slam_sleep_interval(int exp)
  219. {
  220. long range;
  221. long divisor;
  222. long interval;
  223. range = SLAM_BASE_TIMEOUT_INTERVAL;
  224. if (exp < 0) {
  225. divisor = RAND_MAX/SLAM_INITIAL_TIMEOUT_INTERVAL;
  226. } else {
  227. if (exp > SLAM_BACKOFF_LIMIT)
  228. exp = SLAM_BACKOFF_LIMIT;
  229. divisor = RAND_MAX/(range << exp);
  230. }
  231. interval = random()/divisor;
  232. if (exp < 0) {
  233. interval += SLAM_INITIAL_MIN_TIMEOUT;
  234. } else {
  235. interval += SLAM_BASE_MIN_TIMEOUT;
  236. }
  237. return interval;
  238. }
  239. static unsigned char *reinit_slam_state(
  240. unsigned char *header, unsigned char *end)
  241. {
  242. unsigned long total_bytes;
  243. unsigned long block_size;
  244. unsigned long bitmap_len;
  245. unsigned long max_packet_len;
  246. unsigned char *data;
  247. int err;
  248. #if 0
  249. printf("reinit\n");
  250. #endif
  251. data = header;
  252. state.hdr_len = 0;
  253. err = slam_skip(&data, end); /* transaction id */
  254. total_bytes = slam_decode(&data, end, &err);
  255. block_size = slam_decode(&data, end, &err);
  256. if (err) {
  257. printf("ALERT: slam size out of range\n");
  258. return 0;
  259. }
  260. state.block_size = block_size;
  261. state.total_bytes = total_bytes;
  262. state.total_packets = (total_bytes + block_size - 1)/block_size;
  263. state.hdr_len = data - header;
  264. state.received_packets = 0;
  265. data = state.hdr;
  266. slam_encode(&data, &state.hdr[sizeof(state.hdr)], state.total_packets);
  267. max_packet_len = data - state.hdr;
  268. memcpy(state.hdr, header, state.hdr_len);
  269. #if 0
  270. printf("block_size: %ld\n", block_size);
  271. printf("total_bytes: %ld\n", total_bytes);
  272. printf("total_packets: %ld\n", state.total_packets);
  273. printf("hdr_len: %ld\n", state.hdr_len);
  274. printf("max_packet_len: %ld\n", max_packet_len);
  275. #endif
  276. if (state.block_size > ETH_MAX_MTU - (
  277. sizeof(struct iphdr) + sizeof(struct udphdr) +
  278. state.hdr_len + max_packet_len)) {
  279. printf("ALERT: slam blocksize to large\n");
  280. return 0;
  281. }
  282. bitmap_len = (state.total_packets + 1 + 7)/8;
  283. state.image = phys_to_virt ( state.buffer->addr );
  284. /* We don't use the buffer routines properly yet; fake it */
  285. state.buffer->fill = total_bytes;
  286. state.bitmap = state.image + total_bytes;
  287. if ((unsigned long)state.image < 1024*1024) {
  288. printf("ALERT: slam filesize to large for available memory\n");
  289. return 0;
  290. }
  291. memset(state.bitmap, 0, bitmap_len);
  292. return header + state.hdr_len;
  293. }
  294. static int slam_recv_data(unsigned char *data)
  295. {
  296. unsigned long packet;
  297. unsigned long data_len;
  298. int err;
  299. struct udphdr *udp;
  300. udp = (struct udphdr *)&nic.packet[ETH_HLEN + sizeof(struct iphdr)];
  301. err = 0;
  302. packet = slam_decode(&data, &nic.packet[nic.packetlen], &err);
  303. if (err || (packet > state.total_packets)) {
  304. printf("ALERT: Invalid packet number\n");
  305. return 0;
  306. }
  307. /* Compute the expected data length */
  308. if (packet != state.total_packets -1) {
  309. data_len = state.block_size;
  310. } else {
  311. data_len = state.total_bytes % state.block_size;
  312. }
  313. /* If the packet size is wrong drop the packet and then continue */
  314. if (ntohs(udp->len) != (data_len + (data - (unsigned char*)udp))) {
  315. printf("ALERT: udp packet is not the correct size\n");
  316. return 1;
  317. }
  318. if (nic.packetlen < data_len + (data - nic.packet)) {
  319. printf("ALERT: Ethernet packet shorter than data_len\n");
  320. return 1;
  321. }
  322. if (data_len > state.block_size) {
  323. data_len = state.block_size;
  324. }
  325. if (((state.bitmap[packet >> 3] >> (packet & 7)) & 1) == 0) {
  326. /* Non duplicate packet */
  327. state.bitmap[packet >> 3] |= (1 << (packet & 7));
  328. memcpy(state.image + (packet*state.block_size), data, data_len);
  329. state.received_packets++;
  330. } else {
  331. #ifdef MDEBUG
  332. printf("<DUP>\n");
  333. #endif
  334. }
  335. return 1;
  336. }
  337. static void transmit_nack(unsigned char *ptr, struct slam_info *info)
  338. {
  339. int nack_len;
  340. /* Ensure the packet is null terminated */
  341. *ptr++ = 0;
  342. nack_len = ptr - (unsigned char *)&nack;
  343. build_udp_hdr(info->server.sin_addr.s_addr, info->local.sin_port,
  344. info->server.sin_port, 1, nack_len, &nack);
  345. ip_transmit(nack_len, &nack);
  346. #if defined(MDEBUG) && 0
  347. printf("Sent NACK to %@ bytes: %d have:%ld/%ld\n",
  348. info->server_ip, nack_len,
  349. state.received_packets, state.total_packets);
  350. #endif
  351. }
  352. static void slam_send_nack(struct slam_info *info)
  353. {
  354. unsigned char *ptr, *end;
  355. /* Either I timed out or I was explicitly
  356. * asked for a request packet
  357. */
  358. ptr = &nack.data[0];
  359. /* Reserve space for the trailling null */
  360. end = &nack.data[sizeof(nack.data) -1];
  361. if (!state.bitmap) {
  362. slam_encode(&ptr, end, 0);
  363. slam_encode(&ptr, end, 1);
  364. }
  365. else {
  366. /* Walk the bitmap */
  367. unsigned long i;
  368. unsigned long len;
  369. unsigned long max;
  370. int value;
  371. int last;
  372. /* Compute the last bit and store an inverted trailer */
  373. max = state.total_packets;
  374. value = ((state.bitmap[(max -1) >> 3] >> ((max -1) & 7) ) & 1);
  375. value = !value;
  376. state.bitmap[max >> 3] &= ~(1 << (max & 7));
  377. state.bitmap[max >> 3] |= value << (max & 7);
  378. len = 0;
  379. last = 1; /* Start with the received packets */
  380. for(i = 0; i <= max; i++) {
  381. value = (state.bitmap[i>>3] >> (i & 7)) & 1;
  382. if (value == last) {
  383. len++;
  384. } else {
  385. if (slam_encode(&ptr, end, len))
  386. break;
  387. last = value;
  388. len = 1;
  389. }
  390. }
  391. }
  392. info->sent_nack = 1;
  393. transmit_nack(ptr, info);
  394. }
  395. static void slam_send_disconnect(struct slam_info *info)
  396. {
  397. if (info->sent_nack) {
  398. /* A disconnect is a packet with just the null terminator */
  399. transmit_nack(&nack.data[0], info);
  400. }
  401. info->sent_nack = 0;
  402. }
  403. static int proto_slam(struct slam_info *info)
  404. {
  405. int retry;
  406. long timeout;
  407. init_slam_state();
  408. state.buffer = info->buffer;
  409. retry = -1;
  410. rx_qdrain();
  411. /* Arp for my server */
  412. if (arptable[ARP_SERVER].ipaddr.s_addr != info->server.sin_addr.s_addr) {
  413. arptable[ARP_SERVER].ipaddr.s_addr = info->server.sin_addr.s_addr;
  414. memset(arptable[ARP_SERVER].node, 0, ETH_ALEN);
  415. }
  416. /* If I'm running over multicast join the multicast group */
  417. join_group(IGMP_SERVER, info->multicast.sin_addr.s_addr);
  418. for(;;) {
  419. unsigned char *header;
  420. unsigned char *data;
  421. int type;
  422. header = data = 0;
  423. timeout = slam_sleep_interval(retry);
  424. type = await_reply(await_slam, 0, info, timeout);
  425. /* Compute the timeout for next time */
  426. if (type == SLAM_TIMEOUT) {
  427. /* If I timeouted recompute the next timeout */
  428. if (retry++ > SLAM_MAX_RETRIES) {
  429. return 0;
  430. }
  431. } else {
  432. retry = 0;
  433. }
  434. if ((type == SLAM_DATA) || (type == SLAM_REQUEST)) {
  435. /* Check the incomming packet and reinit the data
  436. * structures if necessary.
  437. */
  438. header = &nic.packet[ETH_HLEN +
  439. sizeof(struct iphdr) + sizeof(struct udphdr)];
  440. data = header + state.hdr_len;
  441. if (memcmp(state.hdr, header, state.hdr_len) != 0) {
  442. /* Something is fishy reset the transaction */
  443. data = reinit_slam_state(header, &nic.packet[nic.packetlen]);
  444. if (!data) {
  445. return 0;
  446. }
  447. }
  448. }
  449. if (type == SLAM_DATA) {
  450. if (!slam_recv_data(data)) {
  451. return 0;
  452. }
  453. if (state.received_packets == state.total_packets) {
  454. /* We are done get out */
  455. break;
  456. }
  457. }
  458. if ((type == SLAM_TIMEOUT) || (type == SLAM_REQUEST)) {
  459. /* Either I timed out or I was explicitly
  460. * asked by a request packet
  461. */
  462. slam_send_nack(info);
  463. }
  464. }
  465. slam_send_disconnect(info);
  466. /* Leave the multicast group */
  467. leave_group(IGMP_SERVER);
  468. /* FIXME don't overwrite myself */
  469. /* load file to correct location */
  470. return 1;
  471. }
  472. static int url_slam ( char *url __unused, struct sockaddr_in *server,
  473. char *file, struct buffer *buffer ) {
  474. struct slam_info info;
  475. /* Set the defaults */
  476. info.server = *server;
  477. info.multicast.sin_addr.s_addr = htonl(SLAM_MULTICAST_IP);
  478. info.multicast.sin_port = SLAM_MULTICAST_PORT;
  479. info.local.sin_addr.s_addr = arptable[ARP_CLIENT].ipaddr.s_addr;
  480. info.local.sin_port = SLAM_LOCAL_PORT;
  481. info.buffer = buffer;
  482. info.sent_nack = 0;
  483. if (file[0]) {
  484. printf("\nBad url\n");
  485. return 0;
  486. }
  487. return proto_slam(&info);
  488. }
  489. struct protocol slam_protocol __protocol = {
  490. .name = "x-slam",
  491. .default_port = SLAM_PORT,
  492. .load = url_slam,
  493. };
  494. #endif