No Description
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.

tsock_v4.c 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. /* librairie standard ... */
  2. #include <stdlib.h>
  3. /* pour getopt */
  4. #include <unistd.h>
  5. /* déclaration des types de base */
  6. #include <sys/types.h>
  7. /* constantes relatives aux domaines, types et protocoles */
  8. #include <sys/socket.h>
  9. /* constantes et structures propres au domaine UNIX */
  10. #include <sys/un.h>
  11. /* constantes et structures propres au domaine INTERNET */
  12. #include <netinet/in.h>
  13. /* structures retournées par les fonctions de gestion de la base de
  14. données du réseau */
  15. #include <netdb.h>
  16. /* pour les entrées/sorties */
  17. #include <stdio.h>
  18. /* pour la gestion des erreurs */
  19. #include <errno.h>
  20. #define QUEUE_SIZE 5 // Taille de la file d'attente du listen()
  21. // Remplit le message de lg caractères motif
  22. void construire_message(char* message, char motif, int lg, int numero_envoi);
  23. // Affichage distinct entre envoi et reception pour une facilité d'utilisation
  24. void afficher_message_envoi(char *message, int lg, int numero_envoi);
  25. void afficher_message_reception(char *message, int lg, int numero_envoi);
  26. // Affiche l'usage de l'outil
  27. void print_usage(char* arg0);
  28. int main (int argc, char **argv)
  29. {
  30. int c;
  31. extern char *optarg;
  32. extern int optind;
  33. int nb_message = -1; /* Nb de messages à envoyer ou à recevoir, par défaut : 10 en émission, infini en réception */
  34. int source = -1 ; /* 0=puits, 1=source */
  35. int udp = 0; /* 0=TCP, 1=UDP */
  36. int lg = -1; /* Longueur des messages à envoyer ou recevoir: par défaut 30 octets */
  37. int client = 0; /* 0 not client, 1 client */
  38. int serveur = 0; /* 0 not server, 1 server */
  39. int emetteur = 0; /* 0 not sender, 1 sender */
  40. int recepteur = 0; /* 0 not receiver, 1 receiver */
  41. while ((c = getopt(argc, argv, "pn:sul:CSer")) != -1) {
  42. switch (c) {
  43. case 'p':
  44. if (source == 1) {
  45. print_usage(argv[0]);
  46. exit(1);
  47. }
  48. source = 0;
  49. break;
  50. case 's':
  51. if (source == 0) {
  52. print_usage(argv[0]);
  53. exit(1) ;
  54. }
  55. source = 1;
  56. break;
  57. case 'n':
  58. nb_message = atoi(optarg);
  59. // Packets are numerotated with 5 figures, which means the number of
  60. // packets send can't be bigger than (or equal) 10 ** 6
  61. if(nb_message >= 100000 || nb_message <= 0) {
  62. print_usage(argv[0]);
  63. exit(1);
  64. }
  65. break;
  66. case 'u':
  67. udp=1;
  68. break;
  69. case 'l':
  70. lg=atoi(optarg);
  71. // A TCP packet is roughly 1500 bytes. We allow for some overhead.
  72. // We provide an MTU of 1400 bytes.
  73. // We also to send at least a message of 5 characters length for indice packet
  74. if(lg >= 1400 || lg < 5) {
  75. print_usage(argv[0]);
  76. exit(1);
  77. }
  78. break;
  79. /* -c and -e options stand only for TCP exchange */
  80. case 'C':
  81. client=1;
  82. if (udp || serveur) {
  83. print_usage(argv[0]);
  84. exit(0);
  85. }
  86. break;
  87. case 'S':
  88. serveur = 1;
  89. if (udp || client) {
  90. print_usage(argv[0]);
  91. exit(0);
  92. }
  93. break;
  94. case 'e':
  95. emetteur=1;
  96. if (udp || recepteur) {
  97. print_usage(argv[0]);
  98. exit(0);
  99. }
  100. break;
  101. case 'r':
  102. recepteur=1;
  103. if (udp || emetteur) {
  104. print_usage(argv[0]);
  105. exit(0);
  106. }
  107. break;
  108. default:
  109. print_usage(argv[0]);
  110. break;
  111. }
  112. }
  113. // Little verification of TCP arguments.
  114. // Machine must be a server or a client as once,
  115. // as well as a sender or receiver.
  116. if (!udp) {
  117. if ((!recepteur && !emetteur) || (!serveur && !client)) {
  118. print_usage(argv[0]);
  119. exit(0);
  120. }
  121. }
  122. // Variable qui va stocker le nom logique de la machine avec qui on communique
  123. char* nom_machine_distante;
  124. //Allocation de la variable stockant un message, il est de la taille donnée en paramètre
  125. char* message = malloc(lg * sizeof(char));
  126. // Recuperation du port
  127. int port=atoi(argv[argc-1]);
  128. // Default set of packet length : 30 bytes
  129. if (lg == -1) {
  130. lg=30;
  131. }
  132. // If number of messages is not fixed for the source, it is set to 10 messages
  133. if (nb_message == -1 && (source || !udp)) {
  134. nb_message = 10 ;
  135. }
  136. //Affichage des informations de communication initiée
  137. if (source || emetteur) {
  138. //Recuperation du nom logique
  139. nom_machine_distante=argv[argc-2];
  140. printf("SOURCE:lg_mesg_emis=%d,port=%d,nb_envois=%d,TP=%s",
  141. lg,port,nb_message,(udp)?"UDP":"TCP");
  142. if (client) {
  143. printf(",dest=%s",nom_machine_distante);
  144. }
  145. printf("\n");
  146. } else {
  147. printf("PUITS:lg_mesg-lu=%d,port=%d,nb_receptions=",lg,port);
  148. if (nb_message!=-1 && !source) {
  149. printf("infini");
  150. }
  151. else {
  152. printf("%d",nb_message);
  153. }
  154. printf(", TP=%s\n",(udp)?"UDP":"TCP");
  155. }
  156. /*******************************UDP COMMUNICATION*************************************/
  157. if (udp==1){
  158. // Creation du socket local
  159. int sock= socket(AF_INET,SOCK_DGRAM,0);
  160. if (source==1) {
  161. // Creation de l'adresse du socket distant
  162. struct hostent *hp ;
  163. struct sockaddr_in adr_dest;
  164. int longueur_adr_dest = sizeof(adr_dest);
  165. int longueur_message = lg;
  166. memset((char *)& adr_dest, 0, sizeof(adr_dest)) ;
  167. adr_dest.sin_family=AF_INET;
  168. adr_dest.sin_port=port;
  169. if ((hp = gethostbyname(nom_machine_distante)) == NULL) {
  170. printf("erreur gethostbyname\n") ;
  171. exit(1) ;
  172. }
  173. memcpy( (char*)&(adr_dest.sin_addr.s_addr),
  174. hp->h_addr,
  175. hp->h_length ) ;
  176. for (int i = 0; i < nb_message; i++) {
  177. // Construction du message
  178. construire_message(message, 'a' + (i % 26), lg, i+1);
  179. // Envoi du message
  180. afficher_message_envoi(message,lg,i+1);
  181. sendto(sock,message,longueur_message,0,(struct sockaddr*)&adr_dest,longueur_adr_dest);
  182. }
  183. }
  184. else {
  185. // Creation de l'adresse du socket distant
  186. struct sockaddr_in adr_locale;
  187. int longueur_adr_locale = sizeof(adr_locale);
  188. memset((char *)& adr_locale, 0, sizeof(adr_locale)) ;
  189. adr_locale.sin_family=AF_INET;
  190. adr_locale.sin_port=port;
  191. adr_locale.sin_addr.s_addr = INADDR_ANY;
  192. // Bind the local socket to any local address (ie any available interface)
  193. if (bind(sock, (struct sockaddr *) &adr_locale, longueur_adr_locale) == -1) {
  194. printf("failed to bind\n");
  195. exit(1);
  196. }
  197. // Suivi du numéro de message reçu
  198. int k=0;
  199. while (recvfrom(sock, message, lg, 0, NULL, NULL)) {
  200. k++;
  201. // Afficher notre seule et unique triste message
  202. afficher_message_reception(message, lg, k);
  203. }
  204. }
  205. }
  206. /*******************************TCP COMMUNICATION*************************************/
  207. else{
  208. // Creation du socket local
  209. int sock= socket(AF_INET,SOCK_STREAM,0);
  210. //The server shall establish the connexion
  211. if (client) {
  212. // Creation de l'adresse du socket distant
  213. struct hostent *hp ;
  214. struct sockaddr_in adr_dest;
  215. int longueur_adr_dest = sizeof(adr_dest);
  216. int longueur_message = lg;
  217. memset((char *)& adr_dest, 0, sizeof(adr_dest)) ;
  218. adr_dest.sin_family=AF_INET;
  219. adr_dest.sin_port=port;
  220. if ((hp = gethostbyname(nom_machine_distante)) == NULL) {
  221. printf("erreur gethostbyname\n") ;
  222. exit(1) ;
  223. }
  224. memcpy( (char*)&(adr_dest.sin_addr.s_addr),
  225. hp->h_addr,
  226. hp->h_length ) ;
  227. // Demande de connexion
  228. int succ;
  229. if ((succ=connect(sock,(struct sockaddr*) &adr_dest,longueur_adr_dest))!=0){
  230. printf("Echec connect");
  231. exit(1);
  232. }
  233. // Envoi ou reception des messages
  234. for (int i = 0; i < nb_message; i++) {
  235. if (emetteur){
  236. // Construction du message
  237. construire_message(message, 'a' + (i % 26), lg, i+1);
  238. afficher_message_envoi(message,lg,i+1);
  239. // Envoi du message
  240. write(sock,message,longueur_message);
  241. }
  242. if (recepteur) {
  243. if ((read(sock, message, longueur_message)) < 0){
  244. printf("échec du read\n") ; exit(1) ;}
  245. afficher_message_reception(message, longueur_message,i+1) ;
  246. }
  247. }
  248. // Close socket to avoid dangling connections
  249. close(sock);
  250. }
  251. // The server shall accept the connexion
  252. if (serveur) {
  253. // Creation de l'adresse du socket local
  254. struct sockaddr_in adr_locale;
  255. socklen_t longueur_adr_locale = sizeof(adr_locale);
  256. int longueur_message = lg;
  257. memset((char *)& adr_locale, 0, sizeof(adr_locale)) ;
  258. adr_locale.sin_family=AF_INET;
  259. adr_locale.sin_port=port;
  260. adr_locale.sin_addr.s_addr = INADDR_ANY;
  261. // Bind the local socket to any local address (ie any available interface)
  262. if (bind(sock, (struct sockaddr *) &adr_locale, longueur_adr_locale) == -1) {
  263. printf("failed to bind\n");
  264. exit(1);
  265. }
  266. // Set listening queue size
  267. if (listen(sock, QUEUE_SIZE) == -1) {
  268. printf("échec et mat listen\n");
  269. exit(1);
  270. }
  271. int sock_bis;
  272. while(1) {
  273. // Accept a single connection on the main thread
  274. if ((sock_bis = accept( sock, (struct sockaddr *)&adr_locale, &longueur_adr_locale)) == -1){
  275. printf("échec du accept\n") ;
  276. exit(1) ;
  277. }
  278. // On crée un processus pour chaque connexion TCP acceptée
  279. switch (fork() ) {
  280. case - 1 : /* il y a une erreur */
  281. printf("erreur fork\n") ; exit(1) ;
  282. case 0 : /* on est dans le proc. fils */
  283. close(sock) ; /* fermeture socket du proc. père */
  284. for (int i=0 ; i < nb_message ; i ++) {
  285. // Server sends packets with -e
  286. if (emetteur){
  287. // Construction du message
  288. construire_message(message, 'a' + (i % 26), lg, i+1);
  289. afficher_message_envoi(message,lg,i+1);
  290. // Envoi du message
  291. write(sock_bis,message,longueur_message);
  292. }
  293. // Server receives packets with -r
  294. if (recepteur) {
  295. if ((read(sock_bis, message, longueur_message)) < 0){
  296. printf("échec du read\n") ; exit(1) ;}
  297. afficher_message_reception(message, longueur_message,i+1) ;
  298. }
  299. }
  300. close(sock_bis);
  301. exit(0) ;
  302. default : /* on est dans le proc. père */
  303. close(sock_bis) ; /* fermeture socket du proc. fils
  304. Connexion stay opened for further exchanges */
  305. }
  306. }
  307. }
  308. }
  309. exit(0);
  310. }
  311. void construire_message(char *message, char motif, int lg, int numero_envoi) {
  312. int i;
  313. snprintf(message, lg,"% 5d",numero_envoi);
  314. for (i=5;i<lg;i++) message[i] = motif;
  315. }
  316. void afficher_message_envoi(char *message, int lg, int numero_envoi) {
  317. int i;
  318. printf("SOURCE: Envoi n°%d (%d) [",numero_envoi,lg);
  319. for (i=0;i<lg;i++){
  320. printf("%c", message[i]);
  321. }
  322. printf("]\n");
  323. }
  324. void afficher_message_reception(char *message, int lg, int numero_envoi) {
  325. int i;
  326. printf("PUITS: Reception n°%d (%d) [",numero_envoi,lg);
  327. for (i=0;i<lg;i++){
  328. printf("%c", message[i]);
  329. }
  330. printf("]\n");
  331. }
  332. void print_usage(char* arg0) {
  333. printf("usage: %s [-psuCSer] [-n nb_messages] [-l mess_length] [host] <port>\n", arg0);
  334. printf("parameters: host With -s or -C, address of the host to connect to. Required with -s or -C.\n");
  335. printf(" port Port to connect or bind to. Required.\n");
  336. printf("options: -l mess_length Size of the messages to send. Min 5. Max 1400. Default 30.\n");
  337. printf(" -n nb_messages Number of messages to send. Min 1. Default 10. Ignored with -p.\n");
  338. printf(" -p Runs a TCP/UDP sink. Incompatible with -s.\n");
  339. printf(" -s Runs a TCP/UDP faucet. Incompatible with -p.\n");
  340. printf(" -C Client of a TCP connexion. Incompatible with -S and -u. Requires -e or -r.\n");
  341. printf(" -S Server of a TCP connexion. Incompatible with -C and -u. Requires -e or -r.\n");
  342. printf(" -e Packets issuer of a TCP connexion. Incompatible with -r and -u.\n");
  343. printf(" -r Packets receiver of a TCP connexion. Incompatible with -e and -u.\n");
  344. }