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