00001 #include <stdio.h>
00002 #include <stdlib.h>
00003 #include <unistd.h>
00004 #include <netinet/in.h>
00005 #include <sys/socket.h>
00006 #include <sys/time.h>
00007 #include <string.h>
00008 #include <arpa/inet.h>
00009 #include <stdbool.h>
00010 #include <sys/ioctl.h>
00011 #include <errno.h>
00012
00013 #define MAX_SIZE 256
00014 #define NUMPORT 6666 // Le port où les utilisateurs se connecteront
00015 #define BACKLOG 14 // Nombre maxi de connexions acceptées en file d'attente
00016
00017 void error(char * msg);
00018
00019
00020 #undef max
00021 #define max(x,y) ((x) > (y) ? (x) : (y)) // Calcul du maximum
00022
00023 #ifndef FD_COPY
00024 # define FD_COPY(p, q) memcpy((q), (p), sizeof(fd_set))
00025 #endif
00026
00027 extern int errno;
00028 void traitement(int sockfd, bool * close_conn) {
00029 char requete[MAX_SIZE], reponse[MAX_SIZE] = "Nonnnnnnnnn !";
00030 size_t taille_rep = strlen(reponse)+1;
00031
00032 ssize_t n = recv(sockfd, requete, MAX_SIZE-1, 0);
00033 if (n < 0) {
00034 if (errno != EWOULDBLOCK) { perror("[recv]"); *close_conn = true; }
00035 return;
00036 }
00037 if (n == 0) { *close_conn = true; return; }
00038 requete[MAX_SIZE-1] = '\0';
00039 printf(" - Requête reçue: <%s> (%ld octets reçus)\n", requete, (long) n);
00040
00041 size_t taille_reste = taille_rep;
00042 while (taille_reste > 0) {
00043 n = send(sockfd, reponse, taille_reste, 0);
00044 if (n == -1) {
00045 perror("[send]");
00046 *close_conn = true;
00047 return;
00048 } else
00049 taille_reste -= n;
00050 }
00051 }
00052 int main()
00053 {
00054 int listenfd, connfd, i, max_fd = 0;
00055 struct sockaddr_in serv_addr, cl_addr;
00056 socklen_t len = sizeof(struct sockaddr_in);
00057 struct timeval timeout = { 1*60, 0 };
00058 bool end_server = false;
00059
00060 memset(&serv_addr, 0, sizeof(serv_addr));
00061 serv_addr.sin_family = AF_INET;
00062 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
00063 serv_addr.sin_port = htons(NUMPORT);
00064
00065
00066 if ((listenfd = socket(PF_INET,SOCK_STREAM,0)) < 0) error("[socket]");
00067 const int on = 1;
00068 if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
00069 error("[setsockopt(SO_REUSEADDR)]");
00070
00071 if (ioctl(listenfd, FIONBIO, &on) < 0) error("[ioctl]");
00072 if (bind(listenfd, (struct sockaddr *) &serv_addr, len) < 0) error("[bind]");
00073 if (listen(listenfd, BACKLOG) < 0) error("[listen]");
00074 printf("Serveur: en écoute à l'adresse %s sur le port %d\n",
00075 inet_ntoa(serv_addr.sin_addr), ntohs(serv_addr.sin_port));
00076
00077 fd_set master_set, working_set;
00078 FD_ZERO(&master_set); FD_ZERO(&working_set);
00079 FD_SET(listenfd, &master_set);
00080 max_fd = max(max_fd, listenfd);
00081
00082 do {
00083 FD_COPY(&master_set, &working_set);
00084
00085 int r = select(max_fd+1, &working_set, NULL, NULL, &timeout);
00086 if (r < 0) error("[select]");
00087 if (r == 0) {
00088 fprintf(stderr, "Timeout sur select() atteint: fin du programme\n");
00089 break;
00090 }
00091
00092 for (i=0; (i <= max_fd) && (r > 0); i++) {
00093 if (FD_ISSET(i, &working_set)) {
00094 r--;
00095 if (i == listenfd) {
00096 printf("La socket d'écoute %d est prête en lecture...\n",i);
00097 do {
00098 connfd = accept(listenfd,(struct sockaddr *)&cl_addr, &len);
00099 if (connfd < 0) {
00100 if (errno != EWOULDBLOCK) {
00101 perror("[accept]");
00102 end_server = true;
00103 }
00104 break;
00105 }
00106 printf("Connexion %d acceptée avec %s:%d\n", connfd,
00107 inet_ntoa(cl_addr.sin_addr), ntohs(cl_addr.sin_port));
00108 FD_SET(connfd, &master_set);
00109 max_fd = max(max_fd, connfd);
00110 } while (connfd != -1);
00111 } else {
00112 bool close_conn = false;
00113 traitement(i, &close_conn);
00114 if (close_conn == true) {
00115 close(i);
00116 FD_CLR(i, &master_set);
00117 if (i == max_fd)
00118 while(!FD_ISSET(max_fd, &master_set)) max_fd--;
00119 }
00120 }
00121 }
00122 }
00123 } while (end_server == false);
00124
00125 for (i=0; i < max_fd; i++)
00126 if (FD_ISSET(i, &master_set)) close(i);
00127 return EXIT_SUCCESS;
00128 }
00129
00130 void error(char * msg) {
00131 perror(msg);
00132 exit(EXIT_FAILURE);
00133 }