/* S E R V . U D P * * This is an example program that demonstrates the use of * datagram sockets as an BSD Sockets mechanism. This contains * the server, and is intended to operate in conjunction with the * client program found in client.udp. Together, these two * programs demonstrate many of the features of sockets, as well * a good conventions for using these features. NOTE: This example * is valid only if the /etc/hosts file is being used to lookup * host names. * * This program provides a service called "example". It is an * example of a simple name server. In order for * it to function, an entry for it needs to exist in the * /etc/services file. The port address for this service can be * any port number that is likely to be unused, such as 22375, * for example. The host on which the client will be running * must also have the same entry (same port number) in its * /etc/services file. * */ #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <stdio.h> #include <netdb.h> int s; /* socket descriptor */ #define BUFFERSIZE 1024 /* max size of packets to be received */ int cc; /* contains the number of bytes read */ char buffer[BUFFERSIZE]; /* buffer for packets to be read into */ struct hostent *hp; /* pointer to info of requested host */ struct servent *sp; /* pointer to service information */ struct sockaddr_in myaddr_in; /* for local socket address */ struct sockaddr_in clientaddr_in;/* for client's socket address */ struct in_addr reqaddr; /* for requested host's address */ #define ADDRNOTFOUND 0xffffffff /* return address for unfound host */ /* * M A I N * * This routine starts the server. It forks, leaving the child * to do all the work, so it does not have to be run in the * background. It sets up the socket, and for each incoming * request, it returns an answer. Each request consists of a * host name for which the requester desires to know the * internet address. The server will look up the name in its * /etc/hosts file, and return the internet address to the * client. An internet address value of all ones will be returned * if the host name is not found. NOTE: This example is valid * only if the /etc/hosts file is being used to lookup host names. * */ main(argc, argv) int argc; char *argv[]; { int addrlen; /* clear out address structures */ memset ((char *)&myaddr_in, 0, sizeof(struct sockaddr_in)); memset ((char *)&clientaddr_in, 0, sizeof(struct sockaddr_in)); /* Set up address structure for the socket. */ myaddr_in.sin_family = AF_INET; /* The server should receive on the wildcard address, * rather than its own internet address. This is * generally good practice for servers, because on * systems which are connected to more than one * network at once will be able to have one server * listening on all networks at once. Even when the * host is connected to only one network, this is good * practice, because it makes the server program more * portable. */ myaddr_in.sin_addr.s_addr = INADDR_ANY; /* Find the information for the "example" server * in order to get the needed port number. */ sp = getservbyname ("example", "udp"); if (sp == NULL) { printf("%s: host not found", argv[0]); exit(1); } myaddr_in.sin_port = sp->s_port; /* Create the socket. */ s = socket (AF_INET, SOCK_DGRAM, 0); if (s == -1) { perror(argv[0]); printf("%s: unable to create socket\n", argv[0]); exit(1); } /* Bind the server's address to the socket. */ if (bind(s, &myaddr_in, sizeof(struct sockaddr_in)) == -1) { perror(argv[0]); printf("%s: unable to bind address\n", argv[0]); exit(1); } /* Now, all the initialization of the server is * complete, and any user errors will have already * been detected. Now we can fork the daemon and * return to the user. We need to do a setpgrp * so that the daemon will no longer be associated * with the user's control terminal. This is done * before the fork, so that the child will not be * a process group leader. Otherwise, if the child * were to open a terminal, it would become associated * with that terminal as its control terminal. It is * always best for the parent to do the setpgrp. */ setpgrp(); switch (fork()) { case -1: /* Unable to fork, for some reason. */ perror(argv[0]); printf("%s: unable to fork daemon\n", argv[0]); exit(1); case 0: /* The child process (daemon) comes here. */ /* Close stdin, stdout, and stderr so they will * not be kept open. From now on, the daemon will * not report any error messages. This daemon * will loop forever, waiting for requests and * responding to them. */ fclose(stdin); fclose(stdout); fclose(stderr); /* This will open the /etc/hosts file and keep * it open. This will make accesses to it faster. * If the host has been configured to use the NIS * server or name server (BIND), it is desirable * not to call sethostent(1), because a STREAM * socket is used instead of datagrams for each * call to gethostbyname(). */ sethostent(1); for(;;) { /* Note that addrlen passed as a pointer * so that the recvfrom call can return * the size of the returned address. */ addrlen = sizeof(struct sockaddr_in); /* This call will block until a new * request arrives. Then, it will * return the address of the client, * and a buffer containing its request. * BUFFERSIZE - 1 bytes are read so that * room is left at the end of the buffer * for a null character. */ cc = recvfrom(s, buffer, BUFFERSIZE - 1, 0, &clientaddr_in, &addrlen); if ( cc == -1) exit(1); /* Make sure the message received is * null terminated. */ buffer[cc]='\0'; /* Treat the message as a string * containing a hostname. Search * fot the name in /etc/hosts. */ hp = gethostbyname (buffer); if (hp == NULL) { /* Name was not found. Return * a special value signifying * the error. */ reqaddr.s_addr = ADDRNOTFOUND; } else { /* Copy address of host * into the return buffer. */ reqaddr.s_addr = ((struct in_addr *)(hp->h_addr))->s_addr; } /* Send the response back to the * requesting client. The address is * sent in network byte order. All * errors are ignored. The client * will retry if it does not receive * the response. */ sendto (s, &reqaddr, sizeof(struct in_addr), 0, &clientaddr_in, addrlen); } default: /* Parent process comes here. */ exit(0); } } /* * C L I E N T . U D P * * This is an example program that demonstrates the use of * datagram sockets as an BSD Sockets mechanism. This contains * the client, and is intended to operate in conjunction with the * server program found in serv.udp. Together, these two programs * demonstrate many of the features of sockets, as well as good * conventions for using these features. * * This program requests a service called "example". In order for * it to function, an entry for it needs to exist in the * /etc/services file. The port address for this service can be * any port number that is likely to be unused, such as 22375, * for example. The host on which the server will be runnin * must also have the same entry (same port number) in its * /etc/services file. * * The "example" service is an example of a simple name server * application. The host that is to provide this service is * required to be in the /etc/hosts file. Also, the host providing * this service presumably knows the internet addresses of many * hosts which the local host does not. Therefore, this program * will request the internet address of a target host by name from * the serving host. The serving host will return the requested * internet address as a response, and will return an address of * all ones if it does not recognize the host name. * */ #include <sys/types.h> #include <sys/socket.h> #include <sys/errno.h> #include <netinet/in.h> #include <stdio.h> #include <signal.h> #include <netdb.h> extern int errno; int s; /* socket descriptor */ struct hostent *hp; /* pointer to info for nameserver host */ struct servent *sp; /* pointer to service information */ struct sockaddr_in myaddr_in; /* for local socket address */ struct sockaddr_in servaddr_in;/* for server socket addres */ struct in_addr reqaddr; /* for returned internet address */ #define ADDRNOTFOUND 0xffffffff /* value returned for unknown host */ #define RETRIES 5 /* # of times to retry before giving up */ /* * H A N D L E R * * This routine is the signal handler for the alarm signal. * It simply re-installs itself as the handler and returns. */ handler() { signal(SIGALRM, handler); } /* * M A I N * * This routine is the client which requests service from * the remote "example server". It will send a message to the * remote nameserver requesting the internet address corresponding * to a given hostname. The server will look up the name, and * return its internet address. The returned address will be * written to stdout. * * The name of the system to which the requests will be sent is * given as the first parameter to the command. The second * parameter should be the name of the target host for which the * internet address is sought. */ main(argc, argv) int argc; char *argv[]; { int i; int retry = RETRIES; /* holds the retry count */ char *inet_ntoa(); if (argc != 3) { fprintf(stderr, "Usage: %s <nameserver> <target>\n", argv[0]); exit(1); } /* clear out address structures */ memset ((char *)&myaddr_in, 0, sizeof(struct sockaddr_in)); memset ((char *)&servaddr_in, 0, sizeof(struct sockaddr_in)); /* Set up the server address. */ servaddr_in.sin_family = AF_INET; /* Get the host info for the server's hostname that the * user passed in. */ hp = gethostbyname (argv[1]); if (hp == NULL) { fprintf(stderr, "%s: %s not found in /etc/hosts\n", argv[0], argv[1]); exit(1); } servaddr_in.sin_addr.s_addr = ((struct in_addr *) (hp->h_addr))->s_addr; /* Find the information for the "example" server * in order to get the needed port number. */ sp = getservbyname ("example", "udp"); if (sp == NULL) { fprintf(stderr, "%s: example not found in /etc/services\n", argv[0]); exit(1); } servaddr_in.sin_port = sp->s_port; /* Create the socket. */ s = socket (AF_INET, SOCK_DGRAM, 0); if (s == -1) { perror(argv[0]); fprintf(stderr, "%s: unable to create socket\n", argv[0]); exit(1); } /* Bind socket to some local address so that the * server can send the reply back. A port number * of zero will be used so that the system will * assign any available port number. An address * of INADDR_ANY will be used so we do not have to * look up the internet address of the local host. */ myaddr_in.sin_family = AF_INET; myaddr_in.sin_port = 0; myaddr_in.sin_addr.s_addr = INADDR_ANY; if (bind(s, &myaddr_in, sizeof(struct sockaddr_in)) == -1) { perror(argv[0]); fprintf(stderr, "%s: unable to bind socket\n", argv[0]); exit(1); } /* Set up alarm signal handler. */ signal(SIGALRM, handler); /* Send the request to the nameserver. */ again: if (sendto (s, argv[2], strlen(argv[2]), 0, &servaddr_in, sizeof(struct sockaddr_in)) == -1) { perror(argv[0]); fprintf(stderr, "%s: unable to send request\n", argv[0]); exit(1); } /* Set up a timeout so I don't hang in case the packet * gets lost. After all, UDP does not guarantee * delivery. */ alarm(5); /* Wait for the reply to come in. We assume that * no messages will come from any other source, * so that we do not need to do a recvfrom nor * check the responder's address. */ if (recv (s, &reqaddr, sizeof(struct in_addr), 0) == -1) { if (errno == EINTR) { /* Alarm went off & aborted the receive. * Need to retry the request if we have * not already exceeded the retry limit. */ if (—retry) { goto again; } else { printf("Unable to get response from"); printf(" %s after %d attempts.\n", argv[1], RETRIES); exit(1); } } else { perror(argv[0]); fprintf(stderr, "%s: unable to receive response\n", argv[0]); exit(1); } } alarm(0); /* Print out response. */ if (reqaddr.s_addr == ADDRNOTFOUND) { printf("Host %s unknown by nameserver %s.\n", argv[2], argv[1]); exit(1); } else { printf("Address for %s is %s.\n", argv[2], inet_ntoa(reqaddr)); } } |