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