⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 5.t

📁 早期freebsd实现
💻 T
📖 第 1 页 / 共 5 页
字号:
address in the prototype header that is used, not the onegiven in either of those calls.  For almostall IDP applications , using SO_DEFAULT_HEADERS is easier andmore desirable than writing headers..NH 2Three-way Handshake.PPThe semantics of SPP connections indicates that a three-wayhandshake, involving changes in the datastream type, should \(embut is not absolutely required to \(em take place before a SPPconnection is closed.  Almost all SPP connections are``well-behaved'' in this manner; when communicating withany process, it is best to assume that the three-way handshakeis required unless it is known for certain that it is notrequired.  In a three-way close, the closing processindicates that it wishes to close the connection by sendinga zero-length packet with end-of-message set and withdatastream type 254.  The other side of the connectionindicates that it is OK to close by sending a zero-lengthpacket with end-of-message set and datastream type 255.  Finally,the closing process replies with a zero-length packet with substream type 255; at this point, the connection is consideredclosed.  The following code fragments are simplified examplesof how one might handle this three-way handshake at the userlevel; in the future, support for this type of close willprobably be provided as part of the C library or as part ofthe kernel.  The first code fragment below illustrates how a processmight handle three-way handshake if it sees that the process itis communicating with wants to close the connection:.DS#include <sys/types.h>#include <sys/socket.h>#include <netns/ns.h>#include <netns/sp.h> ...#ifndef SPPSST_END#define SPPSST_END 254#define SPPSST_ENDREPLY 255#endifstruct sphdr proto_sp;int s; ...read(s, buf, BUFSIZE);if (((struct sphdr *)buf)->sp_dt == SPPSST_END) {	/*	 * SPPSST_END indicates that the other side wants to	 * close.	 */	proto_sp.sp_dt = SPPSST_ENDREPLY;	proto_sp.sp_cc = SP_EM;	setsockopt(s, NSPROTO_SPP, SO_DEFAULT_HEADERS, (char *)&proto_sp,	    sizeof(proto_sp));	write(s, buf, 0);	/*	 * Write a zero-length packet with datastream type = SPPSST_ENDREPLY	 * to indicate that the close is OK with us.  The packet that we	 * don't see (because we don't look for it) is another packet	 * from the other side of the connection, with SPPSST_ENDREPLY	 * on it it, too.  Once that packet is sent, the connection is	 * considered closed; note that we really ought to retransmit	 * the close for some time if we do not get a reply.	 */	close(s);} ....DETo indicate to another process that we would like to close theconnection, the following code would suffice:.DS#include <sys/types.h>#include <sys/socket.h>#include <netns/ns.h>#include <netns/sp.h> ...#ifndef SPPSST_END#define SPPSST_END 254#define SPPSST_ENDREPLY 255#endifstruct sphdr proto_sp;int s; ...proto_sp.sp_dt = SPPSST_END;proto_sp.sp_cc = SP_EM;setsockopt(s, NSPROTO_SPP, SO_DEFAULT_HEADERS, (char *)&proto_sp,    sizeof(proto_sp));write(s, buf, 0);	/* send the end request */proto_sp.sp_dt = SPPSST_ENDREPLY;setsockopt(s, NSPROTO_SPP, SO_DEFAULT_HEADERS, (char *)&proto_sp,    sizeof(proto_sp));/* * We assume (perhaps unwisely) * that the other side will send the * ENDREPLY, so we'll just send our final ENDREPLY * as if we'd seen theirs already. */write(s, buf, 0);close(s); ....DE.NH 2Packet Exchange.PPThe Xerox standard protocols include a protocol that is bothreliable and datagram-oriented.  This protocol is known asPacket Exchange (PEX or PE) and, like SPP, is layered on topof IDP.  PEX is important for a number of things: Courierremote procedure calls may be expedited through the useof PEX, and many Xerox servers are located by doing a PEX``BroadcastForServers'' operation.  Although there is noimplementation of PEX in the kernel,it may be simulated at the user level with some clever codingand the use of one peculiar \fIgetsockopt\fP.  A PEX packetlooks like:.DS.if t .ta \w'struct  'u +\w"  struct idp"u +2.0i/* * The packet-exchange header shown here is not defined * as part of any of the system include files. */struct pex {	struct idp	p_idp;	/* idp header */	u_short	ph_id[2];	/* unique transaction ID for pex */	u_short	ph_client;	/* client type field for pex */};.DEThe \fIph_id\fP field is used to hold a ``unique id'' thatis used in duplicate suppression; the \fIph_client\fPfield indicates the PEX client type (similar to the packettype field in the IDP header).  PEX reliability stems from thefact that it is an idempotent (``I send a packet to you, yousend a packet to me'') protocol.  Processes on each side ofthe connection may use the unique id to determine if they haveseen a given packet before (the unique id field differs on eachpacket sent) so that duplicates may be detected, and to indicatewhich message a given packet is in response to.  If a packet witha given unique id is sent and no response is received in a givenamount of time, the packet is retransmitted until it is decidedthat no response will ever be received.  To simulate PEX, onemust be able to generate unique ids -- something that is hard todo at the user level with any real guarantee that the id is reallyunique.  Therefore, a means (via \fIgetsockopt\fP) has been providedfor getting unique ids from the kernel.  The following code fragmentindicates how to get a unique id:.DSlong uniqueid;int s, idsize = sizeof(uniqueid); ...s = socket(AF_NS, SOCK_DGRAM, 0); .../* get id from the kernel -- only on IDP sockets */getsockopt(s, NSPROTO_PE, SO_SEQNO, (char *)&uniqueid, &idsize); ....DEThe retransmission and duplicate suppression code required tosimulate PEX fully is left as an exercise for the reader..NH 2Inetd.PPOne of the daemons provided with 4.4BSD is \fIinetd\fP, theso called ``internet super-server.''  Having one daemon listen for requests for many daemonsinstead of having each daemon listen for its own requestsreduces the number of idle daemons and simplies their implementation..I Inetdhandlestwo types of services: standard and TCPMUX.A standard service has a well-known port assigned to it andis listed in.I /etc/services(see \f2services\f1(5));it may be a service that implements an official Internet standard or is aBSD-specific service.TCPMUX services are nonstandard and do not have awell-known port assigned to them.They are invoked from.I inetdwhen a program connects to the "tcpmux" well-known port and specifiesthe service name.This is useful for adding locally-developed servers..PP\fIInetd\fP is invoked at boottime, and determines from the file \fI/etc/inetd.conf\fP theservers for which it is to listen.  Once this information has beenread and a pristine environment created, \fIinetd\fP proceedsto create one socket for each service it is to listen for,binding the appropriate port number to each socket..PP\fIInetd\fP then performs a \fIselect\fP on all thesesockets for read availability, waiting for somebody wishinga connection to the service corresponding tothat socket.  \fIInetd\fP then performs an \fIaccept\fP onthe socket in question, \fIfork\fPs, \fIdup\fPs the newsocket to file descriptors 0 and 1 (stdin andstdout), closes other open filedescriptors, and \fIexec\fPs the appropriate server..PPServers making use of \fIinetd\fP are considerably simplified,as \fIinetd\fP takes care of the majority of the IPC workrequired in establishing a connection.  The server invokedby \fIinetd\fP expects the socket connected to its clienton file descriptors 0 and 1, and may immediately performany operations such as \fIread\fP, \fIwrite\fP, \fIsend\fP,or \fIrecv\fP.  Indeed, servers may usebuffered I/O as provided by the ``stdio'' conventions, aslong as as they remember to use \fIfflush\fP when appropriate..PPOne call which may be of interest to individuals writingservers under \fIinetd\fP is the \fIgetpeername\fP call,which returns the address of the peer (process) connectedon the other end of the socket.  For example, to log theInternet address in ``dot notation'' (e.g., ``128.32.0.4'')of a client connected to a server under\fIinetd\fP, the following code might be used:.DSstruct sockaddr_in name;int namelen = sizeof (name); ...if (getpeername(0, (struct sockaddr *)&name, &namelen) < 0) {	syslog(LOG_ERR, "getpeername: %m");	exit(1);} else	syslog(LOG_INFO, "Connection from %s", inet_ntoa(name.sin_addr)); ....DEWhile the \fIgetpeername\fP call is especially useful whenwriting programs to run with \fIinetd\fP, it can be usedunder other circumstances.  Be warned, however, that \fIgetpeername\fP willfail on UNIX domain sockets..PPStandard TCPservices are assigned unique well-known port numbers in the range of0 to 1023 by theInternet Assigned Numbers Authority (IANA@ISI.EDU).The limited number of ports in this range areassigned to official Internet protocols.The TCPMUX service allows you to addlocally-developed protocols without needing an official TCP port assignment.The TCPMUX protocol described in RFC-1078 is simple:.QP``A TCP client connects to a foreign host on TCP port 1.  It sends theservice name followed by a carriage-return line-feed <CRLF>.The service name is never case sensitive. The server replies with asingle character indicating positive ("+") or negative ("\-")acknowledgment, immediately followed by an optional message ofexplanation, terminated with a <CRLF>.  If the reply was positive,the selected protocol begins; otherwise the connection is closed.''.LPIn 4.4BSD, the TCPMUX service is built into.IR inetd ,that is,.IR inetdlistens on TCP port 1 for requests for TCPMUX services listedin \f2inetd.conf\f1..IR inetd (8)describes the format of TCPMUX entries for \f2inetd.conf\f1..PPThe following is an example TCPMUX server and its \f2inetd.conf\f1 entry.More sophisticated servers may want to do additional processingbefore returning the positive or negative acknowledgement..DS#include <sys/types.h>#include <stdio.h>main(){        time_t t;        printf("+Go\er\en");        fflush(stdout);        time(&t);        printf("%d = %s", t, ctime(&t));        fflush(stdout);}.DEThe \f2inetd.conf\f1 entry is:.DStcpmux/current_time stream tcp nowait nobody /d/curtime curtime.DEHere's the portion of the client code that handles the TCPMUX handshake:.DSchar line[BUFSIZ];FILE *fp; .../* Use stdio for reading data from the server */fp = fdopen(sock, "r");if (fp == NULL) {    fprintf(stderr, "Can't create file pointer\en");    exit(1);}/* Send service request */sprintf(line, "%s\er\en", "current_time");if (write(sock, line, strlen(line)) < 0) {    perror("write");    exit(1);}/* Get ACK/NAK response from the server */if (fgets(line, sizeof(line), fp) == NULL) {    if (feof(fp)) {        die();    } else {        fprintf(stderr, "Error reading response\en");        exit(1);    }}/* Delete <CR> */if ((lp = index(line, '\r')) != NULL) {    *lp = '\0';}switch (line[0]) {    case '+':            printf("Got ACK: %s\en", &line[1]);            break;    case '-':            printf("Got NAK: %s\en", &line[1]);            exit(0);    default:            printf("Got unknown response: %s\en", line);            exit(1);}/* Get rest of data from the server */while ((fgets(line, sizeof(line), fp)) != NULL) {    fputs(line, stdout);}.DE

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -