updates for 4.3 from lapsley
[unix-history] / usr / src / share / doc / psd / 21.ipc / 4.t
CommitLineData
d60e8dff
MK
1.\" Copyright (c) 1986 Regents of the University of California.
2.\" All rights reserved. The Berkeley software License Agreement
3.\" specifies the terms and conditions for redistribution.
4.\"
5.\" @(#)4.t 1.2 (Berkeley) %G%
6.\"
200989e9
MK
7.ds RH "Client/Server Model
8.bp
9.nr H1 4
10.nr H2 0
d60e8dff 11.sp 8i
200989e9
MK
12.bp
13.LG
14.B
15.ce
164. CLIENT/SERVER MODEL
17.sp 2
18.R
19.NL
20.PP
21The most commonly used paradigm in constructing distributed applications
22is the client/server model. In this scheme client applications request
23services from a server process. This implies an asymmetry in establishing
24communication between the client and server which has been examined
25in section 2. In this section we will look more closely at the interactions
26between client and server, and consider some of the problems in developing
27client and server applications.
28.PP
d60e8dff 29The client and server require a well known set of conventions before
200989e9
MK
30service may be rendered (and accepted). This set of conventions
31comprises a protocol which must be implemented at both ends of a
32connection. Depending on the situation, the protocol may be symmetric
33or asymmetric. In a symmetric protocol, either side may play the
34master or slave roles. In an asymmetric protocol, one side is
d60e8dff 35immutably recognized as the master, with the other as the slave.
200989e9
MK
36An example of a symmetric protocol is the TELNET protocol used in
37the Internet for remote terminal emulation. An example
38of an asymmetric protocol is the Internet file transfer protocol,
39FTP. No matter whether the specific protocol used in obtaining
40a service is symmetric or asymmetric, when accessing a service there
41is a \*(lqclient process\*(rq and a \*(lqserver process\*(rq. We
42will first consider the properties of server processes, then
43client processes.
44.PP
d60e8dff
MK
45A server process normally listens at a well known address for
46service requests. That is, the server process remains dormant
47until a connection is requested by a client's connection
48to the server's address. At such a time
49the server process ``wakes up'' and services the client,
50performing whatever appropriate actions the client requests of it.
51.PP
52Alternative schemes which use a service server
200989e9 53may be used to eliminate a flock of server processes clogging the
d60e8dff
MK
54system while remaining dormant most of the time. For Internet
55servers in 4.3BSD,
56this scheme has been implemented via \fIinetd\fP, the so called
57``internet super-server.'' \fIInetd\fP listens at a variety
58of ports, determined at start-up by reading a configuration file.
59When a connection is requested to a port on which \fIinetd\fP is
60listening, \fIinetd\fP executes the appropriate server program to handle the
61client. With this method, clients are unaware that an
62intermediary such as \fIinetd\fP has played any part in the
63connection. \fIInetd\fP will be described in more detail in
64section 5.
65.PP
66A similar alternative scheme is used by most Xerox services. In general,
67the Courier dispatch process (if used) accepts connections from
68processes requesting services of some sort or another. The client
69processes request a particular <program number, version number, procedure
70number> triple. If the dispatcher knows of such a program, it is
71started to handle the request; if not, an error is reported to the
72client. In this way, only one port is required to service a large
73variety of different requests. Again, the Courier facilities are
74not available without the use and installation of the Courier
75compiler. The information presented in this section applies only
76to NS clients and services that do not use Courier.
200989e9
MK
77.NH 2
78Servers
79.PP
d60e8dff
MK
80In 4.3BSD most servers are accessed at well known Internet addresses
81or UNIX domain names. For
200989e9
MK
82example, the remote login server's main loop is of the form shown
83in Figure 2.
84.KF
d60e8dff
MK
85.if t .ta .5i 1.0i 1.5i 2.0i 2.5i 3.0i 3.5i
86.if n .ta .7i 1.4i 2.1i 2.8i 3.5i 4.2i 4.9i
87.sp 0.5i
200989e9
MK
88.DS
89main(argc, argv)
90 int argc;
d60e8dff 91 char *argv[];
200989e9
MK
92{
93 int f;
94 struct sockaddr_in from;
95 struct servent *sp;
96
97 sp = getservbyname("login", "tcp");
98 if (sp == NULL) {
99 fprintf(stderr, "rlogind: tcp/login: unknown service\en");
100 exit(1);
101 }
102 ...
103#ifndef DEBUG
d60e8dff 104 /* Disassociate server from controlling terminal */
200989e9 105 ...
d60e8dff
MK
106#endif
107
108 sin.sin_port = sp->s_port; /* Restricted port -- see section 5 */
200989e9
MK
109 ...
110 f = socket(AF_INET, SOCK_STREAM, 0);
111 ...
d60e8dff 112 if (bind(f, (struct sockaddr *) &sin, sizeof (sin)) < 0) {
200989e9
MK
113 ...
114 }
115 ...
116 listen(f, 5);
117 for (;;) {
118 int g, len = sizeof (from);
119
d60e8dff 120 g = accept(f, (struct sockaddr *) &from, &len);
200989e9
MK
121 if (g < 0) {
122 if (errno != EINTR)
d60e8dff 123 syslog(LOG_ERR, "rlogind: accept: %m");
200989e9
MK
124 continue;
125 }
126 if (fork() == 0) {
127 close(f);
128 doit(g, &from);
129 }
130 close(g);
131 }
132}
133.DE
134.ce
135Figure 2. Remote login server.
d60e8dff 136.sp 0.5i
200989e9
MK
137.KE
138.PP
139The first step taken by the server is look up its service
140definition:
141.sp 1
142.nf
143.in +5
144.if t .ta .5i 1.0i 1.5i 2.0i
145.if n .ta .7i 1.4i 2.1i 2.8i
146sp = getservbyname("login", "tcp");
147if (sp == NULL) {
148 fprintf(stderr, "rlogind: tcp/login: unknown service\en");
149 exit(1);
150}
151.sp 1
152.in -5
153.fi
d60e8dff
MK
154The result of the \fIgetservbyname\fP call
155is used in later portions of the code to
200989e9
MK
156define the Internet port at which it listens for service
157requests (indicated by a connection).
d60e8dff 158.KS
200989e9
MK
159.PP
160Step two is to disassociate the server from the controlling
d60e8dff
MK
161terminal of its invoker:
162.DS
163 for (i = 0; i < 3; ++i)
164 close(i);
165
166 open("/", O_RDONLY);
167 dup2(0, 1);
168 dup2(0, 2);
169
170 i = open("/dev/tty", O_RDWR);
171 if (i >= 0) {
172 ioctl(i, TIOCNOTTY, 0);
173 close(i);
174 }
175.DE
176.KE
177This step is important as the server will
200989e9 178likely not want to receive signals delivered to the process
d60e8dff
MK
179group of the controlling terminal. Note, however, that
180once a server has disassociated itself it can no longer
181send reports of errors to a terminal, and must log errors
182via \fIsyslog\fP.
200989e9
MK
183.PP
184Once a server has established a pristine environment, it
185creates a socket and begins accepting service requests.
186The \fIbind\fP call is required to insure the server listens
d60e8dff
MK
187at its expected location. It should be noted that the
188remote login server listens at a restricted port number, and must
189therefore be run
190with a user-id of root.
191This concept of a ``restricted port number'' is 4BSD
192specific, and is covered in section 5.
193.PP
194The main body of the loop is fairly simple:
200989e9
MK
195.DS
196.if t .ta .5i 1.0i 1.5i 2.0i
197.if n .ta .7i 1.4i 2.1i 2.8i
198for (;;) {
199 int g, len = sizeof (from);
200
d60e8dff 201 g = accept(f, (struct sockaddr *)&from, &len);
200989e9
MK
202 if (g < 0) {
203 if (errno != EINTR)
d60e8dff 204 syslog(LOG_ERR, "rlogind: accept: %m");
200989e9
MK
205 continue;
206 }
d60e8dff 207 if (fork() == 0) { /* Child */
200989e9
MK
208 close(f);
209 doit(g, &from);
210 }
d60e8dff 211 close(g); /* Parent */
200989e9
MK
212}
213.DE
214An \fIaccept\fP call blocks the server until
215a client requests service. This call could return a
216failure status if the call is interrupted by a signal
217such as SIGCHLD (to be discussed in section 5). Therefore,
218the return value from \fIaccept\fP is checked to insure
d60e8dff
MK
219a connection has actually been established, and
220an error report is logged via \fIsyslog\fP if an error
221has occurred.
222.PP
223With a connection
200989e9
MK
224in hand, the server then forks a child process and invokes
225the main body of the remote login protocol processing. Note
226how the socket used by the parent for queueing connection
227requests is closed in the child, while the socket created as
d60e8dff 228a result of the \fIaccept\fP is closed in the parent. The
200989e9
MK
229address of the client is also handed the \fIdoit\fP routine
230because it requires it in authenticating clients.
231.NH 2
232Clients
233.PP
234The client side of the remote login service was shown
235earlier in Figure 1.
236One can see the separate, asymmetric roles of the client
237and server clearly in the code. The server is a passive entity,
238listening for client connections, while the client process is
239an active entity, initiating a connection when invoked.
240.PP
241Let us consider more closely the steps taken
d60e8dff 242by the client remote login process. As in the server process,
200989e9
MK
243the first step is to locate the service definition for a remote
244login:
245.DS
246sp = getservbyname("login", "tcp");
247if (sp == NULL) {
248 fprintf(stderr, "rlogin: tcp/login: unknown service\en");
249 exit(1);
250}
251.DE
252Next the destination host is looked up with a
253\fIgethostbyname\fP call:
254.DS
255hp = gethostbyname(argv[1]);
256if (hp == NULL) {
257 fprintf(stderr, "rlogin: %s: unknown host\en", argv[1]);
258 exit(2);
259}
260.DE
261With this accomplished, all that is required is to establish a
262connection to the server at the requested host and start up the
263remote login protocol. The address buffer is cleared, then filled
264in with the Internet address of the foreign host and the port
d60e8dff 265number at which the login process resides on the foreign host:
200989e9 266.DS
d60e8dff
MK
267bzero((char *)&server, sizeof (server));
268bcopy(hp->h_addr, (char *) &server.sin_addr, hp->h_length);
269server.sin_family = hp->h_addrtype;
270server.sin_port = sp->s_port;
200989e9 271.DE
d60e8dff
MK
272A socket is created, and a connection initiated. Note
273that \fIconnect\fP implicitly performs a \fIbind\fP
274call, since \fIs\fP is unbound.
200989e9
MK
275.DS
276s = socket(hp->h_addrtype, SOCK_STREAM, 0);
277if (s < 0) {
278 perror("rlogin: socket");
279 exit(3);
280}
281 ...
d60e8dff 282if (connect(s, (struct sockaddr *) &server, sizeof (server)) < 0) {
200989e9
MK
283 perror("rlogin: connect");
284 exit(4);
285}
286.DE
287The details of the remote login protocol will not be considered here.
288.NH 2
289Connectionless servers
290.PP
291While connection-based services are the norm, some services
292are based on the use of datagram sockets. One, in particular,
293is the \*(lqrwho\*(rq service which provides users with status
294information for hosts connected to a local area
295network. This service, while predicated on the ability to
296\fIbroadcast\fP information to all hosts connected to a particular
297network, is of interest as an example usage of datagram sockets.
298.PP
299A user on any machine running the rwho server may find out
300the current status of a machine with the \fIruptime\fP(1) program.
301The output generated is illustrated in Figure 3.
302.KF
303.DS B
304.TS
305l r l l l l l.
306arpa up 9:45, 5 users, load 1.15, 1.39, 1.31
307cad up 2+12:04, 8 users, load 4.67, 5.13, 4.59
308calder up 10:10, 0 users, load 0.27, 0.15, 0.14
309dali up 2+06:28, 9 users, load 1.04, 1.20, 1.65
310degas up 25+09:48, 0 users, load 1.49, 1.43, 1.41
311ear up 5+00:05, 0 users, load 1.51, 1.54, 1.56
312ernie down 0:24
313esvax down 17:04
314ingres down 0:26
315kim up 3+09:16, 8 users, load 2.03, 2.46, 3.11
316matisse up 3+06:18, 0 users, load 0.03, 0.03, 0.05
317medea up 3+09:39, 2 users, load 0.35, 0.37, 0.50
318merlin down 19+15:37
319miro up 1+07:20, 7 users, load 4.59, 3.28, 2.12
320monet up 1+00:43, 2 users, load 0.22, 0.09, 0.07
321oz down 16:09
322statvax up 2+15:57, 3 users, load 1.52, 1.81, 1.86
323ucbvax up 9:34, 2 users, load 6.08, 5.16, 3.28
324.TE
325.DE
326.ce
327Figure 3. ruptime output.
328.sp
329.KE
330.PP
331Status information for each host is periodically broadcast
332by rwho server processes on each machine. The same server
333process also receives the status information and uses it
334to update a database. This database is then interpreted
335to generate the status information for each host. Servers
336operate autonomously, coupled only by the local network and
337its broadcast capabilities.
338.PP
339The rwho server, in a simplified form, is pictured in Figure
3404. There are two separate tasks performed by the server. The
341first task is to act as a receiver of status information broadcast
342by other hosts on the network. This job is carried out in the
343main loop of the program. Packets received at the rwho port
344are interrogated to insure they've been sent by another rwho
345server process, then are time stamped with their arrival time
346and used to update a file indicating the status of the host.
347When a host has not been heard from for an extended period of
348time, the database interpretation routines assume the host is
349down and indicate such on the status reports. This algorithm
350is prone to error as a server may be down while a host is actually
351up, but serves our current needs.
352.KF
353.DS
354.if t .ta .5i 1.0i 1.5i 2.0i
355.if n .ta .7i 1.4i 2.1i 2.8i
356main()
357{
358 ...
359 sp = getservbyname("who", "udp");
360 net = getnetbyname("localnet");
361 sin.sin_addr = inet_makeaddr(INADDR_ANY, net);
362 sin.sin_port = sp->s_port;
363 ...
364 s = socket(AF_INET, SOCK_DGRAM, 0);
365 ...
d60e8dff
MK
366 on = 1;
367 if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {
368 syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
369 exit(1);
370 }
371 bind(s, (struct sockaddr *) &sin, sizeof (sin));
200989e9 372 ...
d60e8dff 373 signal(SIGALRM, onalrm);
200989e9
MK
374 onalrm();
375 for (;;) {
376 struct whod wd;
377 int cc, whod, len = sizeof (from);
378
d60e8dff
MK
379 cc = recvfrom(s, (char *)&wd, sizeof (struct whod), 0,
380 (struct sockaddr *)&from, &len);
200989e9
MK
381 if (cc <= 0) {
382 if (cc < 0 && errno != EINTR)
d60e8dff 383 syslog(LOG_ERR, "rwhod: recv: %m");
200989e9
MK
384 continue;
385 }
386 if (from.sin_port != sp->s_port) {
d60e8dff 387 syslog(LOG_ERR, "rwhod: %d: bad from port",
200989e9
MK
388 ntohs(from.sin_port));
389 continue;
390 }
391 ...
392 if (!verify(wd.wd_hostname)) {
d60e8dff 393 syslog(LOG_ERR, "rwhod: malformed host name from %x",
200989e9
MK
394 ntohl(from.sin_addr.s_addr));
395 continue;
396 }
397 (void) sprintf(path, "%s/whod.%s", RWHODIR, wd.wd_hostname);
d60e8dff 398 whod = open(path, O_RDONLY | O_CREAT | O_TRUNC, 0666);
200989e9
MK
399 ...
400 (void) time(&wd.wd_recvtime);
401 (void) write(whod, (char *)&wd, cc);
402 (void) close(whod);
403 }
404}
405.DE
406.ce
407Figure 4. rwho server.
d60e8dff 408.sp
200989e9
MK
409.KE
410.PP
411The second task performed by the server is to supply information
412regarding the status of its host. This involves periodically
413acquiring system status information, packaging it up in a message
414and broadcasting it on the local network for other rwho servers
415to hear. The supply function is triggered by a timer and
416runs off a signal. Locating the system status
417information is somewhat involved, but uninteresting. Deciding
d60e8dff
MK
418where to transmit the resultant packet
419is somewhat problematical, however.
200989e9 420.PP
d60e8dff 421Status information must be broadcast on the local network.
200989e9
MK
422For networks which do not support the notion of broadcast another
423scheme must be used to simulate or
424replace broadcasting. One possibility is to enumerate the
d60e8dff
MK
425known neighbors (based on the status messages received
426from other rwho servers). This, unfortunately,
427requires some bootstrapping information,
428for a server will have no idea what machines are its
429neighbors until it receives status messages from them.
430Therefore, if all machines on a net are freshly booted,
431no machine will have any
200989e9
MK
432known neighbors and thus never receive, or send, any status information.
433This is the identical problem faced by the routing table management
434process in propagating routing status information. The standard
435solution, unsatisfactory as it may be, is to inform one or more servers
436of known neighbors and request that they always communicate with
437these neighbors. If each server has at least one neighbor supplied
d60e8dff 438to it, status information may then propagate through
200989e9
MK
439a neighbor to hosts which
440are not (possibly) directly neighbors. If the server is able to
441support networks which provide a broadcast capability, as well as
442those which do not, then networks with an
443arbitrary topology may share status information*.
444.FS
445* One must, however, be concerned about \*(lqloops\*(rq.
446That is, if a host is connected to multiple networks, it
447will receive status information from itself. This can lead
448to an endless, wasteful, exchange of information.
449.FE
450.PP
d60e8dff 451It is important that software operating in a distributed
200989e9
MK
452environment not have any site-dependent information compiled into it.
453This would require a separate copy of the server at each host and
d60e8dff 454make maintenance a severe headache. 4.3BSD attempts to isolate
200989e9 455host-specific information from applications by providing system
d60e8dff 456calls which return the necessary information*.
200989e9 457.FS
d60e8dff 458* An example of such a system call is the \fIgethostname\fP(2)
200989e9
MK
459call which returns the host's \*(lqofficial\*(rq name.
460.FE
d60e8dff
MK
461A mechanism exists, in the form of an \fIioctl\fP call,
462for finding the collection
463of networks to which a host is directly connected.
464Further, a local network broadcasting mechanism
465has been implemented at the socket level.
466Combining these two features allows a process
467to broadcast on any directly connected local
468network which supports the notion of broadcasting
469in a site independent manner. This allows 4.3BSD
470to solve the problem of deciding how to propagate
471status information in the case of \fIrwho\fP, or
472more generally in broadcasting:
473Such status information is broadcast to connected
474networks at the socket level, where the connected networks
475have been obtained via the appropriate \fIioctl\fP
476calls.
477The specifics of
478such broadcastings are complex, however, and will
479be covered in section 5.