#ifndef MHSHMNETWORK_H #define MHSHMNETWORK_H #include #include #include #include #include #include #include #include #include #include #include #include struct mhshm_net_singlemod { unsigned long offset; unsigned char data; }; #define MHSHM_NBMODS_NET 150 struct mhshm_net_mod { unsigned long nb_mod; struct mhshm_net_singlemod mod[MHSHM_NBMODS_NET]; }; enum pkttype { SENDMOD, /* un démon informe le serveur d'une mod */ DISPMOD, /* le serveur informe les démons d'une mod */ NEWDAEMON, /* un nouveau démon s'annonce au serveur */ DIEDAEMON, /* un démon informe le serveur qu'il quitte */ INITPAGE, /* la page entiere pour un nouveau démon */ SERVQUIT, /* le serveur informe les démons qu'il quitte */ ERROR /* une erreur est survenue */ }; struct mhshm_net_packet { enum pkttype type; unsigned int port; union { struct mhshm_net_mod moddata; unsigned char page[4096]; } data; }; inline char *pkt2str (enum pkttype type) { char *ret; switch (type) { case SENDMOD: ret = "Nouvelle modification pour le serveur"; break; case DISPMOD: ret = "Nouvelle modification pour les démons"; break; case NEWDAEMON: ret = "Nouveau démon"; break; case DIEDAEMON: ret = "Un démon disparait..."; break; case INITPAGE: ret = "Le contenu initial de la page"; break; case SERVQUIT: ret = "Le serveur se termine"; break; case ERROR: ret = "Message d'erreur"; break; default: ret = "Message inconnu !"; } return ret; } inline int listen_socket (int listen_port) { struct sockaddr_in a; int s; int i; if ((s = socket (AF_INET, SOCK_STREAM, 0)) < 0) { fprintf (stderr, "Error: socket: %s\n", strerror (errno)); return -1; } i = 1; if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR, (char*)&i, sizeof (i)) < 0) { fprintf (stderr, "Error: setsockopt: %s\n", strerror (errno)); close (s); return -1; } if (fcntl (s, F_SETFL, O_NONBLOCK) < 0) { fprintf (stderr, "Error: fcntl: %s\n", strerror (errno)); close (s); return -1; } memset (&a, 0, sizeof (a)); a.sin_port = htons (listen_port); a.sin_family = AF_INET; if (bind (s, (struct sockaddr *)&a, sizeof (a)) < 0) { fprintf (stderr, "Error: bind: %s\n", strerror (errno)); close (s); return -1; } listen (s, 10); return s; } inline int connect_socket (struct in_addr ia, int port) { struct sockaddr_in a; int s; if ((s = socket (AF_INET, SOCK_STREAM, 0)) < 0) { fprintf (stderr, "Error: socket: %s\n", strerror (errno)); return -1; } memset (&a, 0, sizeof (a)); a.sin_port = htons (port); a.sin_family = AF_INET; memcpy (&a.sin_addr.s_addr, &ia, sizeof (ia)); if (connect (s, (struct sockaddr *)&a, sizeof (a)) < 0) { fprintf (stderr, "Error: connect: %s\n", strerror (errno)); shutdown (s, SHUT_RDWR); close (s); return -1; } return s; } inline int connect_socket_byname (char *host, int hostport) { struct hostent *phe; struct in_addr ia; if (!(phe = gethostbyname (host))) { fprintf (stderr, "Error: gethostbyname: %s\n", hstrerror (h_errno)); return -1; } memcpy (&ia, phe->h_addr_list[0], sizeof (ia)); return connect_socket (ia, hostport); } inline int send_packet (char *host, int port, struct mhshm_net_packet *packet) { unsigned int i; int r; int sock; fd_set WR; struct timeval tv; fprintf (stderr, "Envoi ŕ %s:%d un paquet %s\n", host, port, pkt2str (packet->type)); /* connection au serveur*/ sock = connect_socket_byname (host, port); if (sock == -1) return 1; /* envoi du paquet */ i = 0; while (i < sizeof(*packet)) { FD_ZERO (&WR); FD_SET (sock, &WR); tv.tv_sec = 10; tv.tv_usec = 0; r = select (sock + 1, NULL, &WR, NULL, &tv); if (r == -1 && errno == EINTR) continue; if (r < 0) { fprintf (stderr, "Error: select: %s\n", strerror (errno)); break; } if (!r) { fprintf (stderr, "Error: write to %s timeout\n", host); break; } if (FD_ISSET (sock, &WR)) { r = write (sock, ((void *)packet) + i, sizeof (*packet) - i); if (r == -1) { if (errno == EAGAIN || errno == EINTR) continue; fprintf (stderr, "Error: write: %s\n", strerror (errno)); break; } if (r == 0) break; i += r; } } shutdown (sock, SHUT_RDWR); close (sock); return (i == sizeof (*packet)) ? 0 : 1 ; } int read_packet (int sock, struct mhshm_net_packet *packet) { unsigned int i; int r; fd_set RD; struct timeval tv; /* reception du paquet */ i = 0; while (i < sizeof(*packet)) { FD_ZERO (&RD); FD_SET (sock, &RD); tv.tv_sec = 10; tv.tv_usec = 0; r = select (sock + 1, &RD, NULL, NULL, &tv); if (r == -1 && errno == EINTR) continue; if (r < 0) { fprintf (stderr, "Error: select: %s\n", strerror (errno)); break; } if (!r) { fprintf (stderr, "Error: read timeout\n"); break; } if (FD_ISSET (sock, &RD)) { r = read (sock, ((void *)packet) + i, sizeof (*packet) - i); if (r == -1) { if (errno == EAGAIN || errno == EINTR) continue; fprintf (stderr, "Error: read: %s\n", strerror (errno)); break; } if (r == 0) break; i += r; } } shutdown (sock, SHUT_RDWR); close (sock); fprintf (stderr, "Reception d'un paquet %s\n", pkt2str (packet->type)); return (i == sizeof (*packet)) ? 0 : 1 ; } #endif