/** Fully implemented server for the distributed mutual exclusion algorithm * @author Marko Mäkelä (Marko.Makela@HUT.FI) */ #include #include #include #include #ifndef MSG_NOSIGNAL # define MSG_NOSIGNAL 0 #endif #if defined __osf__ typedef size_t socklen_t; #endif #if defined __sgi typedef int socklen_t; #endif /** Messages originated by the clients */ enum client_msg { res_req, rel_req }; /** Messages originated by the server */ enum server_msg { res_rej, res_ack, rel_ack }; /** Display diagnostics of a client * */ static void diag (const struct sockaddr_in* addr, const char* msg) { unsigned long ip = ntohl (addr->sin_addr.s_addr); unsigned short port = ntohs (addr->sin_port); fprintf (stderr, "client %u.%u.%u.%u:%u: %s\n", (unsigned) (ip >> 24) & 0xff, (unsigned) (ip >> 16) & 0xff, (unsigned) (ip >> 8) & 0xff, (unsigned) (ip) & 0xff, port, msg); } int main (int argc, char** argv) { /** the datagram socket */ int s; /** the listening address */ static struct sockaddr_in addr; /** the address of the active client */ static struct sockaddr_in addr_active; addr_active.sin_family = 0; if (argc != 2) { fputs ("usage: server portnumber\n", stderr); return 1; } else { char* endp; unsigned long port = strtoul (argv[1], &endp, 0); if (!argv[1] || *endp || port > 65535) { fputs ("invalid port number \"", stderr); fputs (argv[1], stderr); fputs ("\"\n", stderr); return 1; } addr.sin_family = AF_INET; addr.sin_port = htons (port); addr.sin_addr.s_addr = INADDR_ANY; s = socket (PF_INET, SOCK_DGRAM, 0); if (s < 0) { perror ("socket"); return 2; } if (bind (s, (struct sockaddr*) &addr, sizeof addr)) { perror ("bind"); return 2; } } for (;;) { char c; static struct sockaddr_in addr_from; static socklen_t addrlen; int len; addrlen = sizeof addr_from; len = recvfrom (s, &c, 1, MSG_TRUNC | MSG_NOSIGNAL, (struct sockaddr*) &addr_from, &addrlen); if (len < 0) perror ("recvfrom"); else if (addrlen != sizeof addr_from || addr_from.sin_family != AF_INET || len != 1) fputs ("ignoring unexpected packet\n", stderr); else { switch (c) { default: diag (&addr_from, "ignoring unknown PDU"); break; case res_req: if (!addr_active.sin_family) { c = res_ack; addr_active.sin_family = AF_INET; addr_active.sin_addr.s_addr = addr_from.sin_addr.s_addr; addr_active.sin_port = addr_from.sin_port; diag (&addr_from, "res_req->res_ack"); } else { c = addr_from.sin_addr.s_addr != addr_active.sin_addr.s_addr || addr_from.sin_port != addr_active.sin_port ? res_rej : res_ack; diag (&addr_from, c == res_ack ? "re-res_req->res_ack" : "res_req->res_rej"); } sendto (s, &c, 1, MSG_NOSIGNAL, (struct sockaddr*) &addr_from, addrlen); break; case rel_req: if (addr_from.sin_addr.s_addr != addr_active.sin_addr.s_addr || addr_from.sin_port != addr_active.sin_port) diag (&addr_from, "bogus rel_req"); else { addr_active.sin_family = 0; diag (&addr_from, "rel_req"); } c = rel_ack; sendto (s, &c, 1, MSG_NOSIGNAL, (struct sockaddr*) &addr_from, addrlen); } } } }