You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

mini-slamd.c 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. /*
  2. * mini-slamd
  3. * (c) 2002 Eric Biederman
  4. */
  5. #include <string.h>
  6. #include <errno.h>
  7. #include <stdio.h>
  8. #include <stdint.h>
  9. #include <stdlib.h>
  10. #include <sys/types.h>
  11. #include <sys/poll.h>
  12. #include <sys/socket.h>
  13. #include <sys/stat.h>
  14. #include <netinet/ip.h>
  15. #include <netinet/in.h>
  16. #include <fcntl.h>
  17. #include <unistd.h>
  18. #include <arpa/inet.h>
  19. /*
  20. * To specify the default interface for multicast packets use:
  21. * route add -net 224.0.0.0 netmask 240.0.0.0 dev eth1
  22. * This server is stupid and does not override the default.
  23. */
  24. /* Sever states.
  25. *
  26. * Waiting for clients.
  27. * Sending data to clients.
  28. * Pinging clients for data.
  29. *
  30. */
  31. #define SLAM_PORT 10000
  32. #define SLAM_MULTICAST_IP ((239<<24)|(255<<16)|(1<<8)|(1<<0))
  33. #define SLAM_MULTICAST_PORT 10000
  34. #define SLAM_MULTICAST_TTL 1
  35. #define SLAM_MULTICAST_LOOPBACK 1
  36. #define SLAM_MAX_CLIENTS 10
  37. #define SLAM_PING_TIMEOUT 100 /* ms */
  38. /*** Packets Formats ***
  39. * Data Packet:
  40. * transaction
  41. * total bytes
  42. * block size
  43. * packet #
  44. * data
  45. *
  46. * Status Request Packet
  47. * transaction
  48. * total bytes
  49. * block packets
  50. *
  51. * Status Packet
  52. * received packets
  53. * requested packets
  54. * received packets
  55. * requested packets
  56. * ...
  57. * received packets
  58. * requested packtes
  59. * 0
  60. */
  61. #define MAX_HDR (7 + 7 + 7) /* transaction, total size, block size */
  62. #define MIN_HDR (1 + 1 + 1) /* transaction, total size, block size */
  63. #define MAX_DATA_HDR (MAX_HDR + 7) /* header, packet # */
  64. #define MIN_DATA_HDR (MAX_HDR + 1) /* header, packet # */
  65. /* ETH_MAX_MTU 1500 - sizeof(iphdr) 20 - sizeof(udphdr) 8 = 1472 */
  66. #define SLAM_MAX_NACK (1500 - (20 + 8))
  67. /* ETH_MAX_MTU 1500 - sizeof(iphdr) 20 - sizeof(udphdr) 8 - MAX_HDR = 1451 */
  68. #define SLAM_BLOCK_SIZE (1500 - (20 + 8 + MAX_HDR))
  69. /* Define how many debug messages you want
  70. * 1 - sparse but useful
  71. * 2 - everything
  72. */
  73. #ifndef DEBUG
  74. #define DEBUG 0
  75. #endif
  76. static int slam_encode(
  77. unsigned char **ptr, unsigned char *end, unsigned long value)
  78. {
  79. unsigned char *data = *ptr;
  80. int bytes;
  81. bytes = sizeof(value);
  82. while ((bytes > 0) && ((0xff & (value >> ((bytes -1)<<3))) == 0)) {
  83. bytes--;
  84. }
  85. if (bytes <= 0) {
  86. bytes = 1;
  87. }
  88. if (data + bytes >= end) {
  89. return -1;
  90. }
  91. if ((0xe0 & (value >> ((bytes -1)<<3))) == 0) {
  92. /* packed together */
  93. *data = (bytes << 5) | (value >> ((bytes -1)<<3));
  94. } else {
  95. bytes++;
  96. *data = (bytes << 5);
  97. }
  98. bytes--;
  99. data++;
  100. while(bytes) {
  101. *(data++) = 0xff & (value >> ((bytes -1)<<3));
  102. bytes--;
  103. }
  104. *ptr = data;
  105. return 0;
  106. }
  107. static unsigned long slam_decode(unsigned char **ptr, unsigned char *end, int *err)
  108. {
  109. unsigned long value;
  110. unsigned bytes;
  111. if (*ptr >= end) {
  112. *err = -1;
  113. }
  114. bytes = ((**ptr) >> 5) & 7;
  115. if ((bytes == 0) || (bytes > sizeof(unsigned long))) {
  116. *err = -1;
  117. return 0;
  118. }
  119. if ((*ptr) + bytes >= end) {
  120. *err = -1;
  121. }
  122. value = (**ptr) & 0x1f;
  123. bytes--;
  124. (*ptr)++;
  125. while(bytes) {
  126. value <<= 8;
  127. value |= **ptr;
  128. (*ptr)++;
  129. bytes--;
  130. }
  131. return value;
  132. }
  133. static struct sockaddr_in client[SLAM_MAX_CLIENTS];
  134. static int clients;
  135. void del_client(struct sockaddr_in *old)
  136. {
  137. int i;
  138. for(i = 0; i < clients; i++) {
  139. if ((client[i].sin_family == old->sin_family) &&
  140. (client[i].sin_addr.s_addr == old->sin_addr.s_addr) &&
  141. (client[i].sin_port == old->sin_port)) {
  142. memmove(&client[i], &client[i+1],
  143. (clients - (i+1))*sizeof(client[0]));
  144. clients--;
  145. }
  146. }
  147. }
  148. void add_client(struct sockaddr_in *new)
  149. {
  150. del_client(new);
  151. if (clients >= SLAM_MAX_CLIENTS)
  152. return;
  153. memcpy(&client[clients], new, sizeof(*new));
  154. clients++;
  155. }
  156. void push_client(struct sockaddr_in *new)
  157. {
  158. del_client(new);
  159. if (clients >= SLAM_MAX_CLIENTS) {
  160. clients--;
  161. }
  162. memmove(&client[1], &client[0], clients*sizeof(*new));
  163. memcpy(&client[0], new, sizeof(*new));
  164. clients++;
  165. }
  166. void next_client(struct sockaddr_in *next)
  167. {
  168. /* Find the next client we want to ping next */
  169. if (!clients) {
  170. next->sin_family = AF_UNSPEC;
  171. return;
  172. }
  173. /* Return the first client */
  174. memcpy(next, &client[0], sizeof(*next));
  175. }
  176. int main(int argc, char **argv)
  177. {
  178. char *filename;
  179. uint8_t nack_packet[SLAM_MAX_NACK];
  180. int nack_len;
  181. uint8_t request_packet[MAX_HDR];
  182. int request_len;
  183. uint8_t data_packet[MAX_DATA_HDR + SLAM_BLOCK_SIZE];
  184. int data_len;
  185. uint8_t *ptr, *end;
  186. struct sockaddr_in master_client;
  187. struct sockaddr_in sa_src;
  188. struct sockaddr_in sa_mcast;
  189. uint8_t mcast_ttl;
  190. uint8_t mcast_loop;
  191. int sockfd, filefd;
  192. int result;
  193. struct pollfd fds[1];
  194. int state;
  195. #define STATE_PINGING 1
  196. #define STATE_WAITING 2
  197. #define STATE_RECEIVING 3
  198. #define STATE_TRANSMITTING 4
  199. off_t size;
  200. struct stat st;
  201. uint64_t transaction;
  202. unsigned long packet;
  203. unsigned long packet_count;
  204. unsigned slam_port, slam_multicast_port;
  205. struct in_addr slam_multicast_ip;
  206. slam_port = SLAM_PORT;
  207. slam_multicast_port = SLAM_MULTICAST_PORT;
  208. slam_multicast_ip.s_addr = htonl(SLAM_MULTICAST_IP);
  209. if (argc != 2) {
  210. fprintf(stderr, "Bad argument count\n");
  211. fprintf(stderr, "Usage: mini-slamd filename\n");
  212. exit(EXIT_FAILURE);
  213. }
  214. filename = argv[1];
  215. filefd = -1;
  216. size = 0;
  217. transaction = 0;
  218. /* Setup the udp socket */
  219. sockfd = socket(PF_INET, SOCK_DGRAM, 0);
  220. if (sockfd < 0) {
  221. fprintf(stderr, "Cannot create socket\n");
  222. exit(EXIT_FAILURE);
  223. }
  224. memset(&sa_src, 0, sizeof(sa_src));
  225. sa_src.sin_family = AF_INET;
  226. sa_src.sin_port = htons(slam_port);
  227. sa_src.sin_addr.s_addr = INADDR_ANY;
  228. result = bind(sockfd, &sa_src, sizeof(sa_src));
  229. if (result < 0) {
  230. fprintf(stderr, "Cannot bind socket to port %d\n",
  231. ntohs(sa_src.sin_port));
  232. exit(EXIT_FAILURE);
  233. }
  234. /* Setup the multicast transmission address */
  235. memset(&sa_mcast, 0, sizeof(sa_mcast));
  236. sa_mcast.sin_family = AF_INET;
  237. sa_mcast.sin_port = htons(slam_multicast_port);
  238. sa_mcast.sin_addr.s_addr = slam_multicast_ip.s_addr;
  239. if (!IN_MULTICAST(ntohl(sa_mcast.sin_addr.s_addr))) {
  240. fprintf(stderr, "Not a multicast ip\n");
  241. exit(EXIT_FAILURE);
  242. }
  243. /* Set the multicast ttl */
  244. mcast_ttl = SLAM_MULTICAST_TTL;
  245. setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL,
  246. &mcast_ttl, sizeof(mcast_ttl));
  247. /* Set the multicast loopback status */
  248. mcast_loop = SLAM_MULTICAST_LOOPBACK;
  249. setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, &mcast_loop, sizeof(mcast_loop));
  250. state = STATE_WAITING;
  251. packet = 0;
  252. packet_count = 0;
  253. fds[0].fd = sockfd;
  254. fds[0].events = POLLIN;
  255. fds[0].revents = 0;
  256. for(;;) {
  257. switch(state) {
  258. case STATE_PINGING:
  259. state = STATE_WAITING;
  260. next_client(&master_client);
  261. if (master_client.sin_family == AF_UNSPEC) {
  262. break;
  263. }
  264. #if DEBUG
  265. printf("Pinging %s:%d\n",
  266. inet_ntoa(master_client.sin_addr),
  267. ntohs(master_client.sin_port));
  268. fflush(stdout);
  269. #endif
  270. /* Prepare the request packet, it is all header */
  271. ptr = request_packet;
  272. end = &request_packet[sizeof(request_packet) -1];
  273. slam_encode(&ptr, end, transaction);
  274. slam_encode(&ptr, end, size);
  275. slam_encode(&ptr, end, SLAM_BLOCK_SIZE);
  276. request_len = ptr - request_packet;
  277. result = sendto(sockfd, request_packet, request_len, 0,
  278. &master_client, sizeof(master_client));
  279. /* Forget the client I just asked, when the reply
  280. * comes in we will remember it again.
  281. */
  282. del_client(&master_client);
  283. break;
  284. case STATE_WAITING:
  285. {
  286. int timeout;
  287. int from_len;
  288. timeout = -1;
  289. if (master_client.sin_family != AF_UNSPEC) {
  290. timeout = SLAM_PING_TIMEOUT;
  291. }
  292. result = poll(fds, sizeof(fds)/sizeof(fds[0]), timeout);
  293. if (result == 0) {
  294. /* On a timeout try the next client */
  295. state = STATE_PINGING;
  296. break;
  297. }
  298. if (result > 0) {
  299. from_len = sizeof(master_client);
  300. result = recvfrom(sockfd,
  301. nack_packet, sizeof(nack_packet), 0,
  302. &master_client, &from_len);
  303. if (result < 0)
  304. break;
  305. nack_len = result;
  306. #if DEBUG
  307. printf("Received Nack from %s:%d\n",
  308. inet_ntoa(master_client.sin_addr),
  309. ntohs(master_client.sin_port));
  310. fflush(stdout);
  311. #endif
  312. #if DEBUG
  313. {
  314. ptr = nack_packet;
  315. end = ptr + result;
  316. packet = 0;
  317. result = 0;
  318. while(ptr < end) {
  319. packet += slam_decode(&ptr, end, &result);
  320. if (result < 0) break;
  321. packet_count = slam_decode(&ptr, end, &result);
  322. if (result < 0) break;
  323. printf("%d-%d ",
  324. packet, packet + packet_count -1);
  325. }
  326. printf("\n");
  327. fflush(stdout);
  328. }
  329. #endif
  330. /* Forget this client temporarily.
  331. * If the packet appears good they will be
  332. * readded.
  333. */
  334. del_client(&master_client);
  335. ptr = nack_packet;
  336. end = ptr + nack_len;
  337. result = 0;
  338. packet = slam_decode(&ptr, end, &result);
  339. if (result < 0)
  340. break;
  341. packet_count = slam_decode(&ptr, end, &result);
  342. if (result < 0)
  343. break;
  344. /* We appear to have a good packet, keep
  345. * this client.
  346. */
  347. push_client(&master_client);
  348. /* Reopen the file to transmit */
  349. if (filefd != -1) {
  350. close(filefd);
  351. }
  352. filefd = open(filename, O_RDONLY);
  353. if (filefd < 0) {
  354. fprintf(stderr, "Cannot open %s: %s\n",
  355. filename, strerror(errno));
  356. break;
  357. }
  358. size = lseek(filefd, 0, SEEK_END);
  359. if (size < 0) {
  360. fprintf(stderr, "Seek failed on %s: %s\n",
  361. filename, strerror(errno));
  362. break;
  363. }
  364. result = fstat(filefd, &st);
  365. if (result < 0) {
  366. fprintf(stderr, "Stat failed on %s: %s\n",
  367. filename, strerror(errno));
  368. break;
  369. }
  370. transaction = st.st_mtime;
  371. state = STATE_TRANSMITTING;
  372. break;
  373. }
  374. break;
  375. }
  376. case STATE_RECEIVING:
  377. /* Now clear the queue of received packets */
  378. {
  379. struct sockaddr_in from;
  380. int from_len;
  381. uint8_t dummy_packet[SLAM_MAX_NACK];
  382. state = STATE_TRANSMITTING;
  383. result = poll(fds, sizeof(fds)/sizeof(fds[0]), 0);
  384. if (result < 1)
  385. break;
  386. from_len = sizeof(from);
  387. result = recvfrom(sockfd,
  388. dummy_packet, sizeof(dummy_packet), 0,
  389. &from, &from_len);
  390. if (result <= 0)
  391. break;
  392. #if DEBUG
  393. printf("Received Nack from %s:%d\n",
  394. inet_ntoa(from.sin_addr),
  395. ntohs(from.sin_port));
  396. fflush(stdout);
  397. #endif
  398. /* Receive packets until I don't get any more */
  399. state = STATE_RECEIVING;
  400. /* Process a packet */
  401. if (dummy_packet[0] == '\0') {
  402. /* If the first byte is null it is a disconnect
  403. * packet.
  404. */
  405. del_client(&from);
  406. }
  407. else {
  408. /* Otherwise attempt to add the client. */
  409. add_client(&from);
  410. }
  411. break;
  412. }
  413. case STATE_TRANSMITTING:
  414. {
  415. off_t off;
  416. off_t offset;
  417. ssize_t bytes;
  418. uint8_t *ptr2, *end2;
  419. /* After I transmit a packet check for packets to receive. */
  420. state = STATE_RECEIVING;
  421. /* Find the packet to transmit */
  422. offset = packet * SLAM_BLOCK_SIZE;
  423. /* Seek to the desired packet */
  424. off = lseek(filefd, offset, SEEK_SET);
  425. if ((off < 0) || (off != offset)) {
  426. fprintf(stderr, "Seek failed on %s:%s\n",
  427. filename, strerror(errno));
  428. break;
  429. }
  430. /* Encode the packet header */
  431. ptr2 = data_packet;
  432. end2 = data_packet + sizeof(data_packet);
  433. slam_encode(&ptr2, end2, transaction);
  434. slam_encode(&ptr2, end2, size);
  435. slam_encode(&ptr2, end2, SLAM_BLOCK_SIZE);
  436. slam_encode(&ptr2, end2, packet);
  437. data_len = ptr2 - data_packet;
  438. /* Read in the data */
  439. bytes = read(filefd, &data_packet[data_len],
  440. SLAM_BLOCK_SIZE);
  441. if (bytes <= 0) {
  442. fprintf(stderr, "Read failed on %s:%s\n",
  443. filename, strerror(errno));
  444. break;
  445. }
  446. data_len += bytes;
  447. /* Write out the data */
  448. result = sendto(sockfd, data_packet, data_len, 0,
  449. &sa_mcast, sizeof(sa_mcast));
  450. if (result != data_len) {
  451. fprintf(stderr, "Send failed %s\n",
  452. strerror(errno));
  453. break;
  454. }
  455. #if DEBUG > 1
  456. printf("Transmitted: %d\n", packet);
  457. fflush(stdout);
  458. #endif
  459. /* Compute the next packet */
  460. packet++;
  461. packet_count--;
  462. if (packet_count == 0) {
  463. packet += slam_decode(&ptr, end, &result);
  464. if (result >= 0)
  465. packet_count = slam_decode(&ptr, end, &result);
  466. if (result < 0) {
  467. /* When a transmission is done close the file,
  468. * so it may be updated. And then ping then start
  469. * pinging clients to get the transmission started
  470. * again.
  471. */
  472. state = STATE_PINGING;
  473. close(filefd);
  474. filefd = -1;
  475. break;
  476. }
  477. }
  478. break;
  479. }
  480. }
  481. }
  482. return EXIT_SUCCESS;
  483. }