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.

381 lines
11KB

  1. #include "interface.h"
  2. #include <errno.h>
  3. #define return_error(fonction) do { perror(#fonction); return -1; } while(0)
  4. int char_hexa_to_uint32(const char *const argv, uint32_t *nombre) {
  5. char* error;
  6. error = (char*) argv;
  7. *nombre = (uint32_t) strtol(argv,&error,16);
  8. return (error!=argv);
  9. }
  10. int char_to_int(const char *const argv, int *nombre) {
  11. char* error;
  12. error = (char*) argv;
  13. *nombre = (int) strtol(argv,&error,10);
  14. return (error!=argv);
  15. }
  16. struct subscription_t* list_subscription_add_cell(struct list_subscription_t *list_p) {
  17. struct list_subscription_cell_t *cell_p;
  18. if((cell_p = (struct list_subscription_cell_t*) malloc(sizeof(struct list_subscription_cell_t))) == NULL) {
  19. fputs("bad alloc\n", stderr);
  20. return NULL;
  21. }
  22. if(list_p->list_p) {
  23. (list_p->list_p)->next_p->prev_p = cell_p;
  24. cell_p->next_p = (list_p->list_p)->next_p;
  25. (list_p->list_p)->next_p = cell_p;
  26. cell_p->prev_p = list_p->list_p;
  27. } else
  28. cell_p->prev_p = cell_p->next_p = cell_p;
  29. list_p->list_p = cell_p;
  30. if(!list_p->read_p)
  31. list_p->read_p = list_p->list_p;
  32. return &(cell_p->subscription);
  33. }
  34. struct subscription_t* list_subscription_search_cell(struct list_subscription_t *const list_p, uint32_t addr) {
  35. struct list_subscription_cell_t *tmp_p;
  36. tmp_p = (struct list_subscription_cell_t*) list_p->list_p;
  37. if(list_p && list_p->list_p) {
  38. do {
  39. if(tmp_p->subscription.addr == addr)
  40. return &(tmp_p->subscription);
  41. tmp_p = tmp_p->next_p;
  42. } while(tmp_p != list_p->list_p);
  43. }
  44. return NULL;
  45. }
  46. int list_subscription_remove_cell(struct list_subscription_t *list_p, struct subscription_t *subscription_p) {
  47. struct list_subscription_cell_t *cell_p;
  48. if(!list_p || !list_p->list_p || !list_p->list_p->next_p)
  49. return -1;
  50. cell_p = (struct list_subscription_cell_t*) subscription_p;
  51. cell_p->prev_p->next_p = cell_p->next_p;
  52. cell_p->next_p->prev_p = cell_p->prev_p;
  53. if(list_p->list_p == cell_p)
  54. list_p->list_p=cell_p->prev_p;
  55. if(list_p->list_p == cell_p)
  56. list_p->list_p = NULL;
  57. if(list_p->read_p == cell_p)
  58. list_p->read_p = list_p->list_p;
  59. free(cell_p);
  60. return 1;
  61. }
  62. int open_socket_listen(int port_listen) {
  63. int fd_sock;
  64. if( (fd_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
  65. return_error(socket);
  66. /* option reuseaddr et socket non blocante */
  67. {
  68. int true;
  69. true = 1;
  70. if( setsockopt(fd_sock, SOL_SOCKET, SO_REUSEADDR, &true, sizeof(struct sockaddr_in)) == -1)
  71. return_error(setsockopt);
  72. }
  73. {
  74. int opts;
  75. if ((opts = fcntl(fd_sock,F_GETFL)) < 0)
  76. return_error(fcntl);
  77. opts = (opts | O_NONBLOCK);
  78. if (fcntl(fd_sock,F_SETFL,opts) < 0)
  79. return_error(fcntl);
  80. }
  81. {
  82. struct sockaddr_in sock_command_listen;
  83. memset(&sock_command_listen, 0, sizeof(struct sockaddr_in));
  84. sock_command_listen.sin_addr.s_addr = inet_addr("127.0.0.1");
  85. sock_command_listen.sin_port = htons(port_listen);
  86. sock_command_listen.sin_family = AF_INET;
  87. if(bind(fd_sock, (struct sockaddr*) &sock_command_listen, sizeof(struct sockaddr)) == -1)
  88. return_error(bind);
  89. }
  90. if( listen(fd_sock, 0) == -1)
  91. return_error(listen);
  92. return fd_sock;
  93. }
  94. int list_subscription_init(struct list_subscription_t *list_p, int port_listen) {
  95. if((list_p->fd_command_listen = open_socket_listen(port_listen)) == -1)
  96. return -1;
  97. list_p->fd_command_client = -1;
  98. list_p->list_p=NULL;
  99. list_p->read_p=NULL;
  100. return 1;
  101. }
  102. void list_subscription_destroy(struct list_subscription_t *list_p) {
  103. if(list_p->fd_command_listen >= 0)
  104. close(list_p->fd_command_listen);
  105. list_p->fd_command_listen = -1;
  106. if(list_p->fd_command_client >= 0)
  107. close(list_p->fd_command_client);
  108. list_p->fd_command_client = -1;
  109. while(list_p->list_p) {
  110. /* on ferme la connexion */
  111. if(list_p->list_p->subscription.fd_listen >= 0)
  112. close(list_p->list_p->subscription.fd_listen);
  113. list_p->list_p->subscription.fd_listen = -1;
  114. if(list_p->list_p->subscription.fd_client >= 0)
  115. close(list_p->list_p->subscription.fd_client);
  116. list_p->list_p->subscription.fd_client = -1;
  117. list_subscription_remove_cell(list_p, &(list_p->list_p->subscription));
  118. }
  119. }
  120. int subscribe(struct list_subscription_t *list_p, uint32_t address, int port) {
  121. struct subscription_t *subscription_p;
  122. /* on vérifie que l'adresse n'est pas déjà inscrite */
  123. if(list_subscription_search_cell(list_p, address) != NULL) {
  124. fputs("il existe déjà une inscription pour cette adresse\n", stderr);
  125. return -1;
  126. }
  127. /* on ajoute l'enregistrement dans la liste chainée */
  128. if((subscription_p = list_subscription_add_cell(list_p)) == NULL ) {
  129. fputs("impossible d'ajouter l'inscription\n", stderr);
  130. return -1;
  131. }
  132. subscription_p->addr = address;
  133. subscription_p->fd_client = -1;
  134. if((subscription_p->fd_listen = open_socket_listen(port)) == -1) {
  135. list_subscription_remove_cell(list_p, subscription_p);
  136. return -1;
  137. }
  138. return 1;
  139. }
  140. int unsubscribe(struct list_subscription_t *list_p, uint32_t address) {
  141. struct subscription_t *subscription_p;
  142. /* on vérifie que l'adresse est inscrite */
  143. if((subscription_p = list_subscription_search_cell(list_p, address)) == NULL) {
  144. fputs("il n'existe pas d'inscription pour cette adresse\n", stderr);
  145. return -1;
  146. }
  147. if(subscription_p->fd_listen >= 0)
  148. close(subscription_p->fd_listen);
  149. subscription_p->fd_listen = -1;
  150. if(subscription_p->fd_client >= 0)
  151. close(subscription_p->fd_client);
  152. subscription_p->fd_client = -1;
  153. /* on supprime dans la liste chainée */
  154. if(list_subscription_remove_cell(list_p, subscription_p) == -1)
  155. return -1;
  156. return 1;
  157. }
  158. int command(struct list_subscription_t *list_p, char *command_raw_p) {
  159. char *command, *command_args;
  160. uint32_t address;
  161. int port;
  162. command = strtok_r(command_raw_p, " ", &command_args);
  163. if(strcmp(command, "new")==0) {
  164. puts("new");
  165. } else if(strcmp(command, "subscribe")==0) {
  166. /* on récupère l'adresse */
  167. if(!command_args || char_hexa_to_uint32(command_args, &address) == -1) {
  168. fputs("addresse incorrecte\n", stderr);
  169. return -1;
  170. }
  171. /* on récupère le port */
  172. strtok_r(command_args, " ", &command_args);
  173. if(!command_args || char_to_int(command_args, &port) == -1 || port <= 0 || port >= 65536) {
  174. fputs("port incorrect\n", stderr);
  175. return -1;
  176. }
  177. /* on tente l'ajout */
  178. if(subscribe(list_p, address, port) == -1)
  179. return -1;
  180. } else if(strcmp(command, "unsubscribe")==0) {
  181. /* on récupère l'adresse */
  182. if(!command_args || char_hexa_to_uint32(command_args, &address) == -1) {
  183. fputs("addresse incorrecte\n", stderr);
  184. return -1;
  185. }
  186. /* on tente la suppression */
  187. if(unsubscribe(list_p, address) == -1)
  188. return -1;
  189. } else {
  190. puts("commande inconnue");
  191. return -1;
  192. }
  193. return 1;
  194. }
  195. int send_message(struct list_subscription_t *list_p, struct message_t *message_p) {
  196. struct subscription_t *subscription_p;
  197. if(!message_p || !(message_p->data_p)) /* on ne vient pas avec un message vide */
  198. return -1;
  199. /* on vérifie que l'adresse est inscrite */
  200. if((subscription_p = list_subscription_search_cell(list_p, message_p->addr)) == NULL || subscription_p->fd_client < 0)
  201. return 0;
  202. return send(subscription_p->fd_client, message_p->data_p, message_p->length, 0);
  203. }
  204. int read_message(struct list_subscription_t *list_p, struct message_t *message_p) {
  205. fd_set fdfs;
  206. int nb_ready_fd, message_found;
  207. char buffer[512];
  208. ssize_t recv_length;
  209. if(message_p && message_p->data_p) /* on ne vient pas avec un message dont le data est alloué */
  210. return -1;
  211. message_found = 0;
  212. FD_ZERO(&fdfs);
  213. if(list_p->fd_command_listen >= 0)
  214. FD_SET(list_p->fd_command_listen, &fdfs);
  215. if(list_p->fd_command_client >= 0)
  216. FD_SET(list_p->fd_command_client, &fdfs);
  217. /* on ajoute les fd de la liste */
  218. if(list_p && list_p->list_p) {
  219. struct list_subscription_cell_t *cell_p;
  220. cell_p = list_p->list_p;
  221. do {
  222. if(cell_p->subscription.fd_listen >= 0)
  223. FD_SET(cell_p->subscription.fd_listen, &fdfs);
  224. if(cell_p->subscription.fd_client >= 0)
  225. FD_SET(cell_p->subscription.fd_client, &fdfs);
  226. cell_p = cell_p->next_p;
  227. } while(cell_p != list_p->list_p);
  228. }
  229. {
  230. struct timeval timeout = {0};
  231. nb_ready_fd = select(FD_SETSIZE, &fdfs, NULL, NULL, &timeout);
  232. }
  233. if(nb_ready_fd < 0) /* erreur */
  234. return_error(select);
  235. else if(nb_ready_fd == 0) /* timeout écoulé */
  236. return 0;
  237. /* les sockets pour les commandes */
  238. if(list_p->fd_command_client >= 0 && FD_ISSET(list_p->fd_command_client, &fdfs)) {
  239. if( (recv_length = recv(list_p->fd_command_client, buffer, sizeof(buffer), MSG_DONTWAIT)) == -1 && errno != EAGAIN && errno != EWOULDBLOCK)
  240. perror("recv");
  241. else if(recv_length == 0) {
  242. close(list_p->fd_command_client);
  243. list_p->fd_command_client = -1;
  244. } else {
  245. buffer[recv_length-1]='\0';
  246. command(list_p, buffer);
  247. }
  248. }
  249. if(list_p->fd_command_listen >= 0 && FD_ISSET(list_p->fd_command_listen, &fdfs)) {
  250. if( (list_p->fd_command_client = accept(list_p->fd_command_listen, NULL, NULL)) == -1)
  251. perror("accept");
  252. }
  253. if(list_p && list_p->list_p && message_p) {
  254. struct list_subscription_cell_t *cell_p;
  255. /* les sockets connectés */
  256. cell_p = list_p->read_p;
  257. do {
  258. if(list_p->read_p->subscription.fd_client >= 0 && FD_ISSET(list_p->read_p->subscription.fd_client, &fdfs)) {
  259. if( (recv_length = recv(list_p->read_p->subscription.fd_client, buffer, sizeof(buffer), MSG_DONTWAIT)) == -1 && errno != EAGAIN && errno != EWOULDBLOCK)
  260. perror("recv");
  261. else if(recv_length == 0) {
  262. close(list_p->read_p->subscription.fd_client);
  263. list_p->read_p->subscription.fd_client = -1;
  264. } else {
  265. /* on remplit le message */
  266. if((message_p->data_p = malloc(recv_length)) == NULL) {
  267. fputs("bad alloc\n", stderr);
  268. return -1;
  269. }
  270. memcpy(message_p->data_p, buffer, recv_length);
  271. message_p->length = recv_length;
  272. message_p->addr = list_p->read_p->subscription.addr;
  273. message_found = 1;
  274. }
  275. }
  276. list_p->read_p = list_p->read_p->next_p;
  277. } while(list_p->read_p != cell_p && !message_found);
  278. /* les sockets en écoute */
  279. cell_p = list_p->list_p;
  280. do {
  281. if(cell_p->subscription.fd_listen >= 0 && FD_ISSET(cell_p->subscription.fd_listen, &fdfs)) {
  282. if( (cell_p->subscription.fd_client = accept(cell_p->subscription.fd_listen, NULL, NULL)) == -1)
  283. perror("accept");
  284. }
  285. cell_p = cell_p->next_p;
  286. } while(list_p->list_p != cell_p);
  287. }
  288. return message_found;
  289. }
  290. /*
  291. int quit = 0;
  292. void quit_signal_handler(int signal) {
  293. quit = 1;
  294. }
  295. int main(int argc, char **argv) {
  296. struct list_subscription_t list;
  297. struct message_t message;
  298. signal(SIGINT, quit_signal_handler);
  299. if(list_subscription_init(&list, atoi(argv[1])) == -1)
  300. return 1;
  301. memset(&message, 0, sizeof(struct message_t));
  302. do {
  303. switch(read_message(&list, &message)) {
  304. case 1:
  305. ((char*)message.data_p)[message.length-1] ='\0';
  306. printf("message pour %"PRIx32" (%ld octets) : « %s »\n", message.addr, message.length, ((char*) (message.data_p)));
  307. send_message(&list, &message);
  308. free(message.data_p);
  309. message.data_p = NULL;
  310. break;
  311. case 0:
  312. puts("pas de message");
  313. break;
  314. case -1:
  315. puts("erreur");
  316. break;
  317. }
  318. } while(!quit);
  319. list_subscription_destroy(&list);
  320. return 0;
  321. }
  322. */