Most servers are accessed at well-known Internet port numbers or UNIX domain names. Example 2-7 illustrates the main loop of a remote-login server.
Example 2-8 shows how the server getting its service definition.
sp = getservbyname("login", "tcp"); if (sp == (struct servent *) NULL) { fprintf(stderr, "rlogind: tcp/login: unknown service\n"); exit(1); } |
The result from getservbyname() is used later to define the Internet port at which the program listens for service requests. Some standard port numbers are in /usr/include/netinet/in.h.
Example 2-9 shows the server dissociates from the controlling terminal of its invoker in the non-DEBUG mode of operation.
(void) close(0); (void) close(1); (void) close(2); (void) open("/", O_RDONLY); (void) dup2(0, 1); (void) dup2(0, 2); setsid(); |
This prevents the server from receiving signals from the process group of the controlling terminal. After a server has dissociated itself, it cannot send reports of errors to a terminal and must log errors with syslog().
A server next creates a socket and listens for service requests. bind() ensures that the server listens at the expected location. (The remote login server listens at a restricted port number, so it runs as super-user.)
Example 2-10 illustrates the main body of the loop.
while(TRUE) { int g, len = sizeof(from); if (g = accept(f, (struct sockaddr *) &from, &len) == -1) { if (errno != EINTR) syslog(LOG_ERR, "rlogind: accept: %m"); continue; } if (fork() == 0) { /* Child */ close(f); doit(g, &from); } close(g); /* Parent */ } |
accept() blocks messages until a client requests service. accept() returns a failure indication if it is interrupted by a signal, such as SIGCHLD. The return value from accept() is checked and an error is logged with syslog() if an error has occurred.
The server then forks a child process and invokes the main body of the remote login protocol processing. The socket used by the parent to queue connection requests is closed in the child. The socket created by accept() is closed in the parent. The address of the client is passed to doit() for authenticating clients.