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.
 
 
 

556 lines
16 KiB

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <time.h>
  5. #include <unistd.h>
  6. #include <pthread.h>
  7. #include <signal.h>
  8. #include <errno.h>
  9. #include <sys/types.h>
  10. #include <sys/socket.h>
  11. #include <netinet/in.h>
  12. #include <arpa/inet.h>
  13. #include <inttypes.h>
  14. #define UDP_LISTEN_PORT 4242
  15. #define UDP_DEFAULT_CONNECT_ADDR "127.0.0.1"
  16. #define UDP_DEFAULT_CONNECT_PORT 4242
  17. #define MY_ADDR 0xabcd0123
  18. #define TRAME_MAX_LENGTH 65503 /* la taille totale de la trame est sur 16 bits, on ne peut pas dépasser 65507 octets à cause d'udp */
  19. #define DEFAULT_TIME_BEFORE_DISCOVERY 1
  20. #define NB_TURN_BEFORE_DISCOVERY 5
  21. /*
  22. trame
  23. |00|01|02|03|04|05|06|07||08|09|10|11|12|13|14|15||16|17|18|19|20|21|22|23||24|25|26|27|28|29|30|31|
  24. | 0 || 1 || 2 || 3 |
  25. | type || taille totale || données…
  26. paquet
  27. |00|01|02|03|04|05|06|07||08|09|10|11|12|13|14|15||16|17|18|19|20|21|22|23||24|25|26|27|28|29|30|31|
  28. | 0 || 1 || 2 || 3 |
  29. | adresse destination |
  30. | adresse source |
  31. | taille du paquet entete comprise || taille du message |
  32. | numéro du paquet || type || somme de controle sur les données |
  33. | données_ |
  34. */
  35. enum boolean {false, true};
  36. struct watch_stat_t {
  37. enum boolean received_trame;
  38. unsigned int time_before_discovery;
  39. };
  40. enum trame_type_t {
  41. TRAME_TOKEN,
  42. TRAME_DISCOVERY
  43. };
  44. struct trame_t {
  45. enum trame_type_t type;
  46. u_int16_t length;
  47. void *data;
  48. };
  49. enum packet_type_t {
  50. PACKET_DATA,
  51. PACKET_DISCOVERY, /* paquet d'une trame discovery */
  52. PACKET_JOIN, /* paquet qui demande le branchement d'un cable */
  53. PACKET_LEAVE /* paquet qui demande le débranchement d'un cable */
  54. };
  55. struct packet_t {
  56. u_int32_t addr_dest;
  57. u_int32_t addr_src;
  58. u_int16_t packet_length;
  59. u_int16_t message_length;
  60. u_int8_t fragment;
  61. enum packet_type_t type;
  62. u_int16_t checksum;
  63. void *data;
  64. };
  65. /* variables globales */
  66. pthread_mutex_t mutex_in, mutex_out, mutex_stat;
  67. enum boolean quit;
  68. int fd_sock;
  69. struct sockaddr_in sock_listen, sock_in, sock_out;
  70. struct watch_stat_t watch_stat;
  71. char buffer_in[TRAME_MAX_LENGTH], buffer_out[TRAME_MAX_LENGTH];
  72. /* prototype */
  73. void quit_signal_handler(int sig);
  74. void* watchdog_discovery(void *argv);
  75. int send_trame(const struct trame_t *const trame_p);
  76. int recv_trame(struct trame_t *const trame_p, enum boolean extract_data);
  77. int add_packet(struct trame_t *const trame_p, const struct packet_t *const packet_p);
  78. int retr_packet(struct trame_t *trame_p, struct packet_t **packet_pp, enum boolean extract_data);
  79. u_int16_t checksum(const struct packet_t *const packet);
  80. /* couches :
  81. 1 : niveau physique : gestion de l'anneau par sockets udp
  82. 2 : circulation de la trame
  83. 3 : encapsulation de paquets dans la trame
  84. */
  85. void quit_signal_handler(int sig) {
  86. sig = 0; /* pour compiler sans warning en pedantic */
  87. quit = true;
  88. }
  89. void* watchdog_discovery(void *argv) {
  90. unsigned int time_to_sleep;
  91. enum boolean send_discovery;
  92. struct trame_t trame_discovery;
  93. struct packet_t packet_discovery;
  94. argv=NULL; /* pour compiler sans warning en pedantic */
  95. /* on prépare la trame */
  96. trame_discovery.type = TRAME_DISCOVERY;
  97. trame_discovery.length = 3;
  98. trame_discovery.data = NULL;
  99. /* on prépare le paquet qu'on met dans la trame */
  100. packet_discovery.addr_dest = MY_ADDR;
  101. packet_discovery.addr_src = MY_ADDR;
  102. packet_discovery.packet_length = 16;
  103. packet_discovery.message_length = 0;
  104. packet_discovery.fragment = 0;
  105. packet_discovery.type = PACKET_DISCOVERY;
  106. packet_discovery.checksum = checksum(&packet_discovery);
  107. packet_discovery.data = NULL;
  108. /* on insère le paquet dans la trame */
  109. if(add_packet(&trame_discovery, &packet_discovery) == -1) {
  110. #ifdef debug
  111. fputs("impossible d'ajouter le paquet de discovery dans la trame\n", stderr);
  112. #endif
  113. quit = 1;
  114. pthread_exit(NULL); /* il faudrait peut etre retourner une erreur */
  115. }
  116. do {
  117. pthread_mutex_lock(&mutex_stat);
  118. time_to_sleep = watch_stat.time_before_discovery;
  119. watch_stat.received_trame = false;
  120. pthread_mutex_unlock(&mutex_stat);
  121. sleep(time_to_sleep);
  122. pthread_mutex_lock(&mutex_stat);
  123. send_discovery = !watch_stat.received_trame;
  124. pthread_mutex_unlock(&mutex_stat);
  125. if(send_discovery) {
  126. #ifdef debug
  127. fputs("envoie d'une trame de discovery\n", stderr);
  128. #endif
  129. send_trame(&trame_discovery);
  130. }
  131. } while(!quit);
  132. pthread_exit(NULL);
  133. }
  134. int send_trame(const struct trame_t *const trame_p) {
  135. int res;
  136. u_int16_t length;
  137. pthread_mutex_lock(&mutex_out);
  138. /* on remplit le buffer */
  139. length = htons(trame_p->length);
  140. memcpy(buffer_out, &(trame_p->type), 1);
  141. memcpy(buffer_out+1, &(length), 2);
  142. memcpy(buffer_out+3, trame_p->data, (size_t) ((trame_p->length)-3)); /* on enlève les 3 octets d'entete */
  143. /* on envoie la trame */
  144. if(( res = sendto(fd_sock, buffer_out, trame_p->length, 0, (struct sockaddr*)&sock_out, sizeof(struct sockaddr_in))) == -1) {
  145. #ifdef debug
  146. perror("sendto()");
  147. #endif
  148. }
  149. pthread_mutex_unlock(&mutex_out);
  150. return res;
  151. }
  152. int recv_trame(struct trame_t *const trame_p, enum boolean extract_data) {
  153. static time_t previous_time = 0;
  154. socklen_t sock_length;
  155. ssize_t recvfrom_length;
  156. pthread_mutex_lock(&mutex_in);
  157. /* on reçoit la trame */
  158. if((recvfrom_length = recvfrom(fd_sock, buffer_in, sizeof(buffer_in)-1, 0, (struct sockaddr*)&sock_in, &sock_length)) == -1) {
  159. #ifdef debug
  160. perror("recvfrom()");
  161. #endif
  162. pthread_mutex_unlock(&mutex_in);
  163. return -1;
  164. }
  165. /* on retient qu'on a reçu une trame et on adapte le temps d'attente du watchdog */
  166. pthread_mutex_lock(&mutex_stat);
  167. watch_stat.received_trame = true;
  168. /* adaptation du temps d'attente */
  169. if(previous_time)
  170. watch_stat.time_before_discovery = NB_TURN_BEFORE_DISCOVERY*( (watch_stat.time_before_discovery+(time(NULL)-previous_time))/2 );
  171. previous_time = time(NULL);
  172. pthread_mutex_unlock(&mutex_stat);
  173. /* on initialise la trame */
  174. memset(trame_p, 0, sizeof(struct trame_t));
  175. /* on lit les champs de l'entete */
  176. memcpy(&(trame_p->type), buffer_in, 1);
  177. memcpy(&(trame_p->length), buffer_in+1, 2);
  178. trame_p->length = ntohs(trame_p->length);
  179. /* on vérifie la taille */
  180. if(recvfrom_length != trame_p->length ) {
  181. #ifdef debug
  182. fputs("taille de trame invalide\n", stderr);
  183. #endif
  184. pthread_mutex_unlock(&mutex_in);
  185. return -1;
  186. }
  187. /* s'il y a des donées, on les récupère */
  188. if(extract_data && trame_p->length > 3) { /* taille de l'entete de la trame*/
  189. if((trame_p->data = realloc(trame_p->data,(trame_p->length)-3)) == NULL) {
  190. #ifdef debug
  191. fputs("bad alloc\n", stderr);
  192. #endif
  193. pthread_mutex_unlock(&mutex_in);
  194. return -1;
  195. }
  196. memcpy(trame_p->data, buffer_in+3, (size_t) ((trame_p->length)-3));
  197. } else
  198. trame_p->data = NULL;
  199. pthread_mutex_unlock(&mutex_in);
  200. return 1;
  201. }
  202. int add_packet(struct trame_t *const trame_p, const struct packet_t *const packet_p) {
  203. char *new_data;
  204. u_int16_t size;
  205. u_int32_t addr_dest;
  206. u_int32_t addr_src;
  207. u_int16_t packet_length;
  208. u_int16_t message_length;
  209. u_int16_t checksum;
  210. size = (trame_p->length-3) + packet_p->packet_length;
  211. if(size > TRAME_MAX_LENGTH-3) {
  212. #ifdef debug
  213. fputs("trame too long\n", stderr);
  214. #endif
  215. return -1;
  216. }
  217. if( (new_data = realloc(trame_p->data, size)) == NULL) {
  218. #ifdef debug
  219. fputs("bad alloc\n", stderr);
  220. #endif
  221. return -1;
  222. }
  223. trame_p->data = new_data;
  224. new_data = ((char*)trame_p->data)+trame_p->length-3;
  225. trame_p->length += packet_p->packet_length;
  226. addr_dest = htonl(packet_p->addr_dest);
  227. addr_src = htonl(packet_p->addr_src);
  228. packet_length = htons(packet_p->packet_length);
  229. message_length = htons(packet_p->message_length);
  230. checksum = htons(packet_p->checksum);
  231. memcpy(new_data, &(addr_dest), 4);
  232. new_data += 4;
  233. memcpy(new_data, &(addr_src), 4);
  234. new_data += 4;
  235. memcpy(new_data, &(packet_length), 2);
  236. new_data += 2;
  237. memcpy(new_data, &(message_length), 2);
  238. new_data += 2;
  239. memcpy(new_data, &(packet_p->fragment), 1);
  240. new_data += 1;
  241. memcpy(new_data, &(packet_p->type), 1);
  242. new_data += 1;
  243. memcpy(new_data, &(checksum), 2);
  244. new_data += 2;
  245. memcpy((char*)new_data, packet_p->data, packet_p->packet_length-16);
  246. return 1;
  247. }
  248. int retr_packet(struct trame_t *trame_p, struct packet_t **packet_pp, enum boolean extract_data) {
  249. int nb_packet, i;
  250. char *ptr, *ptr_move, *limit;
  251. struct trame_t tmp_trame;
  252. struct packet_t tmp_packet, *new_packet_p;
  253. nb_packet = 0;
  254. *packet_pp = NULL;
  255. if(!trame_p->data || trame_p->length <= 3)
  256. return 0;
  257. /* on copie la trame, en cas d'erreur, on ne se retrouvera pas dans un état incohérent */
  258. tmp_trame = *trame_p;
  259. if( (tmp_trame.data = malloc(tmp_trame.length-3)) == NULL) {
  260. return -1;
  261. }
  262. memcpy(tmp_trame.data, trame_p->data, tmp_trame.length-3);
  263. /* on regarde l'adresse de dest de chaque paquet, si le paquet n'est pas pour moi, on décale dans la trame, sinon on recopie dans un struct packet_t */
  264. limit = (void*) (((char*) tmp_trame.data) + tmp_trame.length - 3);
  265. ptr_move = ptr = tmp_trame.data;
  266. while(ptr < limit) {
  267. /* on extrait l'entete destination */
  268. memset(&tmp_packet, 0, sizeof(struct packet_t));
  269. memcpy(&(tmp_packet.addr_dest), ptr, 4);
  270. ptr += 4;
  271. tmp_packet.addr_dest = ntohl(tmp_packet.addr_dest);
  272. memcpy(&(tmp_packet.addr_src), ptr, 4);
  273. ptr += 4;
  274. tmp_packet.addr_src = ntohl(tmp_packet.addr_src);
  275. memcpy(&(tmp_packet.packet_length), ptr, 2);
  276. ptr += 2;
  277. tmp_packet.packet_length = ntohs(tmp_packet.packet_length);
  278. memcpy(&(tmp_packet.message_length), ptr, 2);
  279. ptr += 2;
  280. tmp_packet.message_length = ntohs(tmp_packet.message_length);
  281. memcpy(&(tmp_packet.fragment), ptr++, 1);
  282. memcpy(&(tmp_packet.type), ptr++, 1);
  283. memcpy(&(tmp_packet.checksum), ptr, 2);
  284. ptr += 2;
  285. tmp_packet.checksum = ntohs(tmp_packet.checksum);
  286. if(tmp_packet.addr_dest == MY_ADDR) {
  287. /* on retire le paquet de la trame */
  288. if((new_packet_p = realloc(*packet_pp, ((size_t) (nb_packet+1))*sizeof(struct packet_t))) == NULL) {
  289. #ifdef debug
  290. fputs("bad alloc\n", stderr);
  291. #endif
  292. /* on désalloue tout */
  293. for(i = 0 ; i<nb_packet ; i++) {
  294. if(packet_pp[i]->data)
  295. free(packet_pp[i]->data);
  296. }
  297. free(*packet_pp);
  298. *packet_pp = NULL;
  299. return -1;
  300. }
  301. *packet_pp = new_packet_p;
  302. /* on recopie le paquet temporaire dans le tableau et on réaffecte la taille de la trame */
  303. *(packet_pp[nb_packet]) = tmp_packet;
  304. if(extract_data && tmp_packet.packet_length > 16)
  305. memcpy(&(packet_pp[nb_packet]->data), ptr, tmp_packet.packet_length-16);
  306. nb_packet++;
  307. tmp_trame.length -= tmp_packet.packet_length;
  308. } else {
  309. /* on décale le paquet */
  310. if(ptr-16 != ptr_move) {
  311. memmove(ptr_move, ptr-16, tmp_packet.packet_length);
  312. ptr = ptr_move+16;
  313. }
  314. ptr_move += tmp_packet.packet_length;
  315. }
  316. /* on se place sur le paquet suivant */
  317. ptr += (tmp_packet.packet_length-16);
  318. }
  319. free(trame_p->data);
  320. *trame_p = tmp_trame;
  321. return nb_packet;
  322. }
  323. u_int16_t checksum(const struct packet_t *const packet) {
  324. u_int16_t res, res1;
  325. res = 0;
  326. res += (u_int16_t) (htonl(packet->addr_dest) >> 16);
  327. res += (u_int16_t) htonl(packet->addr_dest);
  328. res += (u_int16_t) (htonl(packet->addr_src) >> 16);
  329. res += (u_int16_t) htonl(packet->addr_src);
  330. res += htons(packet->packet_length);
  331. res += htons(packet->message_length);
  332. res1 = (packet->fragment << 8);
  333. res1 += packet->type;
  334. res += res1;
  335. return (res^0xffff);
  336. }
  337. int main(int argc, char** argv) {
  338. pthread_t watchdog_discovery_thread;
  339. socklen_t sock_length;
  340. int trame_max_length, nb_packet;
  341. struct trame_t trame;
  342. struct packet_t *packet_p;
  343. trame_max_length = TRAME_MAX_LENGTH;
  344. sock_length = sizeof(struct sockaddr_in);
  345. /* on initialise le mutex */
  346. if(pthread_mutex_init(&mutex_in, NULL) || pthread_mutex_init(&mutex_out, NULL) || pthread_mutex_init(&mutex_stat, NULL)) {
  347. #ifdef debug
  348. fputs("erreur lors de l'initialisation des mutex\n", stderr);
  349. #endif
  350. exit(1);
  351. }
  352. /* on paramètre à qui on va envoyer nos trames */
  353. sock_out.sin_family = AF_INET;
  354. switch(argc) {
  355. case 1:
  356. #ifdef debug
  357. fprintf(stderr, "les trames seront envoyées à %s sur le port %d\n", UDP_DEFAULT_CONNECT_ADDR, UDP_DEFAULT_CONNECT_PORT);
  358. #endif
  359. sock_out.sin_addr.s_addr = inet_addr(UDP_DEFAULT_CONNECT_ADDR);
  360. sock_out.sin_port = htons(UDP_DEFAULT_CONNECT_PORT);
  361. break;
  362. case 3:
  363. #ifdef debug
  364. fprintf(stderr, "les trames seront envoyées à %s sur le port %d\n", argv[1], atoi(argv[2]));
  365. #endif
  366. sock_out.sin_addr.s_addr = inet_addr(argv[1]);
  367. sock_out.sin_port = htons(atoi(argv[2]));
  368. break;
  369. default:
  370. fprintf(stderr, "usage: %s [ip port]\n", argv[0]);
  371. exit(2);
  372. }
  373. /* on ouvre le socket */
  374. if((fd_sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
  375. #ifdef debug
  376. perror("socket()");
  377. #endif
  378. exit(errno);
  379. }
  380. /* on agrandit le buffer d'udp pour pouvoir envoyer et recevoir de grandes trames (sinon on est bloqué à 9216 octets) */
  381. if(setsockopt(fd_sock, SOL_SOCKET, SO_SNDBUF, &trame_max_length, sock_length) == -1 || setsockopt(fd_sock, SOL_SOCKET, SO_RCVBUF, &trame_max_length, sock_length) == -1) {
  382. #ifdef debug
  383. perror("setsockopt()");
  384. #endif
  385. close(fd_sock);
  386. exit(errno);
  387. }
  388. /* on se met en écoute */
  389. memset(&sock_listen, 0, sizeof(struct sockaddr_in));
  390. sock_listen.sin_addr.s_addr = htonl(INADDR_ANY);
  391. sock_listen.sin_family = AF_INET;
  392. sock_listen.sin_port = htons(UDP_LISTEN_PORT);
  393. if(bind(fd_sock, (struct sockaddr*) &sock_listen, sizeof(sock_listen)) == -1) {
  394. #ifdef debug
  395. perror("bind()");
  396. #endif
  397. close(fd_sock);
  398. exit(errno);
  399. }
  400. /* on initialise la valeur de quit et on paramètre un signal pour quitter */
  401. quit = false;
  402. signal(SIGINT, quit_signal_handler);
  403. /* on démarre le watchdog */
  404. watch_stat.received_trame = false;
  405. watch_stat.time_before_discovery = DEFAULT_TIME_BEFORE_DISCOVERY;
  406. if(pthread_create(&watchdog_discovery_thread, NULL, watchdog_discovery, NULL)) {
  407. #ifdef debug
  408. fputs("erreur lors de la création du thread\n", stderr);
  409. #endif
  410. close(fd_sock);
  411. exit(3);
  412. }
  413. /* boucle de traitement */
  414. do {
  415. wait_trame:
  416. /* on attend de recevoir une trame */
  417. if(recv_trame(&trame, true) == -1) {
  418. #ifdef debug
  419. fputs("erreur lors de la réception de la trame\n", stderr);
  420. #endif
  421. goto wait_trame;
  422. }
  423. #ifdef debug
  424. fprintf(stderr, "trame reçue : type:%d taille:%d\n", trame.type, trame.length);
  425. #endif
  426. if( (nb_packet = retr_packet(&trame, &packet_p, true)) == -1) {
  427. /* on a une erreur donc on renvoie la trame telle quelle */
  428. #ifdef debug
  429. fputs("erreur lors de l'analyse des paquets de la trame\n", stderr);
  430. #endif
  431. goto send_trame;
  432. }
  433. switch(trame.type) {
  434. case TRAME_TOKEN:
  435. break;
  436. case TRAME_DISCOVERY:
  437. break;
  438. }
  439. /* on free les paquets reçus */
  440. while(nb_packet > 0) {
  441. if(packet_p[--nb_packet].data)
  442. free(packet_p[nb_packet].data);
  443. }
  444. if(packet_p)
  445. free(packet_p);
  446. /*
  447. printf("dest : %"PRIx32"\n", packet_p[0].addr_dest);
  448. printf("src : %"PRIx32"\n", packet_p[0].addr_src);
  449. printf("packet length : %"PRIu16"\n", packet_p[0].packet_length);
  450. printf("message length : %"PRIu16"\n", packet_p[0].message_length);
  451. printf("fragment : %"PRIu8"\n", packet_p[0].fragment);
  452. printf("type : %"PRIu8"\n", packet_p[0].type);
  453. printf("checksum : %"PRIx16"\n", packet_p[0].checksum);
  454. */
  455. send_trame:
  456. /* on renvoie la trame */
  457. if(send_trame(&trame) == -1) {
  458. #ifdef debug
  459. fputs("erreur lors de l'émission de la trame\n", stderr);
  460. #endif
  461. }
  462. } while(!quit);
  463. if(trame.data)
  464. free(trame.data);
  465. pthread_join(watchdog_discovery_thread, NULL);
  466. pthread_mutex_destroy(&mutex_in);
  467. pthread_mutex_destroy(&mutex_out);
  468. pthread_mutex_destroy(&mutex_stat);
  469. close(fd_sock);
  470. #ifdef debug
  471. fputs("exited\n", stderr);
  472. #endif
  473. return 0;
  474. }