/* dglistener2.c UDP "server" skeleton */ #include #include #include #include #include #include #include #include #include #include #define MAXBUFLEN 2000 #define MAXHOSTNAMELEN 60 #define MAXPEERS 80 /* compare two addresses */ #define sameaddr(a, b) ( (a.sin_port == b.sin_port) && \ (a.sin_addr.s_addr == b.sin_addr.s_addr) ) /* this macro can be used to check errors, see server.c for examples */ #define ERRORCHECK(var, value, command) if (var == value) { \ perror(command); \ exit(1); \ } int main(int argc, char *argv[]) { int sock; struct sockaddr_in own_addr; /* my address information */ struct sockaddr_in remote_addr; /* connector's address information */ struct sockaddr_in addresses[MAXPEERS]; char knownhosts[MAXPEERS*MAXHOSTNAMELEN] = ""; char newhost[MAXHOSTNAMELEN]; char hello[MAXHOSTNAMELEN] = "Hello\n"; int knownpeers = 0, i; int nbytes; char buf[MAXBUFLEN]; fd_set read_fds, orig_fds; int fdmax; int port = 54321; /* default port */ int stat; unsigned int sin_size = sizeof(struct sockaddr_in); /* port as optional parameter */ if (argc > 1) port = atoi(argv[1]); /* socket */ sock = socket(AF_INET, SOCK_DGRAM, 0); ERRORCHECK(sock, -1, "socket"); /* bind to my address */ own_addr.sin_family = AF_INET; own_addr.sin_port = htons(port); own_addr.sin_addr.s_addr = INADDR_ANY; memset(&(own_addr.sin_zero), '\0', 8); stat = bind(sock, (struct sockaddr *)&own_addr, sin_size); ERRORCHECK(stat, -1, "bind"); /* fd vector dor select */ FD_ZERO(&orig_fds); /* insert socket and stdin */ FD_SET(sock, &orig_fds); FD_SET(STDIN_FILENO, &orig_fds); fdmax = (sock < STDIN_FILENO) ? STDIN_FILENO : sock; /* copy is used for select() */ FD_ZERO(&read_fds); while(strncmp(hello, "quit", 4)) { /* 10 seconds */ struct timeval wt; wt.tv_sec = 10; wt.tv_usec = 0; /* copy tempory set */ read_fds = orig_fds; /* use NULL instead of &wt to wait forever (not print .'s) */ stat = select(fdmax+1, &read_fds, NULL, NULL, &wt); ERRORCHECK(stat, -1, "select"); /* is socket ready for revcfrom? */ if (FD_ISSET(sock, &read_fds)) { nbytes=recvfrom(sock, buf, MAXBUFLEN-1, 0, (struct sockaddr *)&remote_addr, &sin_size); ERRORCHECK(nbytes, -1, "recvfrom"); /* check whether we have stored address already */ /* in real-life application we should use hash */ for (i = 0; i < knownpeers; i++) if (sameaddr(remote_addr, addresses[i])) break; if (i < knownpeers) printf("Old address\n"); else { /* store new address */ printf("New address\n"); addresses[knownpeers++] = remote_addr; /* sockaddr array */ sprintf(newhost, " %s:%d ", /* string of hosts */ inet_ntoa(remote_addr.sin_addr), ntohs(remote_addr.sin_port)); strcat(knownhosts, newhost); } printf("got message from %s, port %d\n", inet_ntoa(remote_addr.sin_addr), ntohs(remote_addr.sin_port)); printf("message is %d bytes long\n",nbytes); buf[nbytes] = '\0'; printf("message contains \"%s\"\n",buf); /* return by a message of hello text and list of known hosts */ sprintf(buf, "%s\nKnown hosts: %s\n", hello, knownhosts); nbytes = sendto(sock, buf, strlen(buf), 0, (struct sockaddr *)&remote_addr, sin_size); ERRORCHECK(nbytes, -1, "sendto"); printf("Sent:%s\n", buf); } /* if FD_ISSET(sock */ /* if stdin is ready for read */ if (FD_ISSET(STDIN_FILENO, &read_fds)) { /* read new hello text */ fgets(hello, MAXHOSTNAMELEN, stdin); } printf(".\n"); } /* while */ close(sock); return 0; }