📄 courier.tbl.me
字号:
.i courier.hdefines the symbol SPPMAXDATA as 534..sh 2 "Receiving Bulk Data".ppTo make receiving bulk data simple, the routine BDTread() performs checks forvarious conditions on receipt of each packet. BDTread() will return thecount of the number of bytes actually read in each packet (skipping emptypackets), or 0 to indicate end of data. If an error or BDT abort messageoccurs, BDTread() will return -1; if this occurs, the receiver should immediately stop reading BDT data..ppTypical code for receiving bulk data on the socket described by ``bdtconnection'' anddepositing it in the file opened for buffered ouput as ``destfile''might be:.sp 1.nf CourierConnection *bdtconnection; /* BDT source descriptor */ FILE *destfile; /* output file */ char sppdata[SPPMAXDATA]; ... count = BDTread(bdtconnection, sppdata, SPPMAXDATA); while (count > 0) { /* actually read data */ if (fwrite(sppdata, 1, count, destfile) == 0) { /* error while writing */ BDTabort(bdtconnection); break; } count = BDTread(bdtconnection, sppdata, SPPMAXDATA); } if (count == 0) { /* successful */ ....fi.sp 1.sh 2 "StreamOf declarations".ppFrequently, data to be sent on a Bulk Data connection will be describedby a StreamOfSomething declaration in the courier specification. Forexample, in Clearinghouse several routines are documented as returninga StreamOfObjectName; unfortunately, a StreamOf declaration is recursive,and so is not immediately translatable into automatic packing and unpackingroutines which need to know in advance how much space to allocate for theresult. As a kludge, we translate such types as if the recursivepart of the declaration were a null record. Consider:.sp 1.nfStreamOfObjectName: TYPE = CHOICE OF { nextSegment (0) => RECORD [ segment: SEQUENCE OF ObjectName, restOfStream: StreamOfObjectName ], lastSegment (1) => SEQUENCE OF ObjectName};.fi.sp 1.lpIn the above declaration, the ``restOfStream is effectively ignored.Given this declaration, the following routine may be passed to aremote procedure as the Bulk Data actor..sp 1.nf#include "Clearinghouse_support.c" /* get internalize_* routines */#define MAXPACKS 5GetData(conn) CourierConnection *conn;{ int count, i; Unspecified buffer[MAXWORDS*MAXPACKS], *bp, *bufend; StreamOfObjectName obnames; bufend = buffer; bp = buffer+MAXWORDS*(MAXPACKS-1); /* end of available space */ while (count = BDTread(conn, (char*)bufend, MAXWORDS*sizeof(Unspecified)) ) { bufend += count/sizeof(Unspecified); if (bufend > bp) { fprintf(stderr,"BDT read too big to fit\en"); BDTabort(conn); /* should clear out stuff here if we knew how much */ } } bp = buffer; while (bp < bufend) { bp += internalize_StreamOfObjectName(&obnames,bp); if (0 == (int) obnames.designator) for (i = 0; i < obnames.nextSegment_case.segment.length; i++) ProcessObjectName( obnames.nextSegment_case.segment.sequence[i]); else { for (i = 0; i < obnames.lastSegment_case.length; i++) ProcessObjectName( obnames.lastSegment_case.sequence[i]); return; } }}.fi.sp 1.lpNote that this code is very awkward, and that it requires that the wholebulk data transfer be stored in memory before it is unpacked. Staytuned; we intend to modify the compiler to make the handling of suchstreams much easier, at the cost of incompatibility with the existingscheme, of course!.sh 2 "Encapsulated Protocols".ppSome courier programs use what might be termed ``encapsulated protocols''as a method of type punning to escape from the restrictions of the Courierlanguage. For example, in Filing.sp 1.nf Attribute: RECORD [ type: AttributeType, value: SEQUENCE OF UNSPECIFIED ]; checksum: AttributeType = 0; Checksum: TYPE = CARDINAL; createdBy: AttributeType = 1; CreatedBy: TYPE = User;.fi.sp 1Depending on the value of the type subfield, the data in the value fieldis intended to be interpreted as either a CARDINAL or a User name..ppSuch encapsulation is in general bad design unless a very compellingneed for it exists. It is also awkward to support in a C program. Thebest way to handle such types is to write functions to code and decodethe encapsulated value using the low level packing and unpacking routinesprovided by the Courier compiler. For example:.sp 1.nf Filing4_User AttrToUser(attr) Filing4_Attribute *attr; { Unspecified buf[2049], *bp; /* space for biggest attribute */ Cardinal len; Filing4_User retval; /* useful fact: Item: TYPE = SEQUENCE OF UNSPECIFIED; */ externalize_Clearinghouse2_Item(&(attr->value), buf); bp = buf; bp += internalize_Cardinal(&len, bp); bp += internalize_Filing4_User(&retval, bp); return(retval); } UserToAttr(id, attr) Filing4_User id; Filing4_Attribute *attr; { Unspecified buf[2049], *bp; Cardinal len; /* don't know length yet, so leave space for it */ bp = buf + sizeof_Cardinal(len); len = externalize_Filing4_User(&id, bp); (void) externalize_Cardinal(&len, buf); internalize_Clearinghouse2_Item(&(attr->value), buf); return; }.fi.sp 1Since the SEQUENCE OF UNSPECIFIED may have undergone arbitrarytransformationsduring deserialization, translating it to a User record consists of firstreserializing it into an array of char, then deserializing it using thelow-level routine appropriate to the encapsulated type. Translating toan encapsulated type is an almost precise inverse..sh 1 "Example I: Passwd.cr".ppThis section contains a Courier program which implements remote lookup in.i "/etc/passwd"(the UNIX database of user names, passwords, home directories, and soon).It does not utilize Bulk Data Transfer, but does illustrate most otherfeatures of this courier implementation.The applications programmer would first write .i PasswordLookup.cr ,the description of the courier interface for the service, then mightwrite.i PasswordLookup.c ,containing the routines needed to implement a server for this courierprogram, or might write.i lookup.c ,a typical client of this service..bp.sh 2 "The specification (PasswordLookup.cr)".sp 1.nfPasswordLookup : PROGRAM 754 VERSION 1 =BEGIN -- This is a translation of the passwd structure in <pwd.h> Passwd : TYPE = RECORD [ pw_name, pw_passwd : STRING, pw_uid, pw_gid, pw_quota : LONG CARDINAL, pw_comment, pw_gecos, pw_dir, pw_shell : STRING ]; -- Remote Errors NoSuchUser : ERROR = 0; OtherError : ERROR [ errorstring: STRING ] = 1; -- Remote entry points. LookupUid : PROCEDURE [ uid : CARDINAL ] RETURNS [ passwd : Passwd ] REPORTS [ NoSuchUser ] = 0; LookupUser : PROCEDURE [ user : STRING ] RETURNS [ passwd : Passwd, forward : STRING ] REPORTS [ NoSuchUser, OtherError ] = 1;END..fi.sp 2.sh 2 "PasswordLookup_defs.h".sp 1.nf/* * Declarations for Courier program PasswordLookup. */#include <courier.h>#include <except.h>typedef struct { String pw_name; String pw_passwd; LongCardinal pw_uid; LongCardinal pw_gid; LongCardinal pw_quota; String pw_comment; String pw_gecos; String pw_dir; String pw_shell;} Passwd;#define NoSuchUser 0#define OtherError 1typedef struct { String errorstring;} OtherErrorArg;typedef struct { Passwd passwd;} LookupUidResult;typedef struct { Passwd passwd; String forward;} LookupUserResult;extern LookupUidResult LookupUid();extern LookupUserResult LookupUser();.fi.sp 2.sh 2 "Makefile".sp 1.nfCFLAGS = -OUSEROBJS = lookup.o PasswordLookup_client.oSRVROBJS = PasswordLookup.o PasswordLookup_server.oLIBS = -lcrDESTDIR = /usr/lib/courierall: lookup PasswordLookuplookup: $(USEROBJS) cc -o lookup $(USEROBJS) $(LIBS)PasswordLookup: $(SRVROBJS) cc -o PasswordLookup $(SRVROBJS) $(LIBS)$(USEROBJS) $(SRVROBJS): PasswordLookup_defs.hPasswordLookup_defs.h \ePasswordLookup_server.c \ePasswordLookup_client.c: PasswordLookup.cr courier PasswordLookup.crinstall: all install -s PasswordLookup $(DESTDIR)clean: -rm -f *.o PasswordLookup_*.c PasswordLookup_defs.h.fi.bp.sh 2 "The server procedures (PasswordLookup.c)".sp 1.nf#include <stdio.h>#include "PasswordLookup_defs.h"extern Passwd *getpwnam(), *getpwuid();LookupUidResultLookupUid(CourierConnection,CourierBDTProc,uid) CourierConnection *CourierConnection, CourierBDTProc; Cardinal uid;{ Passwd *pw; pw = getpwuid(uid); if (pw == NULL) raise(NoSuchUser,NULL); else { return (*(LookupUidResult*) &pw); }}LookupUserResultLookupUser(CourierConnection,CourierBDTProc,user) CourierConnection *CourierConnection, CourierBDTProc; String user;{ LookupUserResult result; Passwd *pw; FILE *fwdfd; static char forward[100]; pw = getpwnam(user); if (pw == NULL) raise (NoSuchUser,NULL); else { sprintf(forward,"%s/.forward",pw->pw_dir); if ((fwdfd = fopen(forward,"r")) == NULL) { forward[0] = '\e0'; else { fgets(forward,100,fwdfd); fclose(fwdfd); if (strlen(forward) < 2) ( static OtherErrorArg randomerr = { "invalid forwarding file"}; raise(OtherError,&randomerr)); } result.password = *pw; result.forward = forward; return (result); }}.fi.bp.sh 2 "The user program (lookup.c)".sp 1.nf/* * Sample program to access remote password lookup. * Usage: lookup machine username */#include <stdio.h>#include "PasswordLookup_defs.h"main(argc, argv) int argc; char **argv;{ LookupUserResult result; Passwd passwd; CourierConnection *connection; if (argc < 3 || (destaddr = getXNSaddr(argv[1])) == NULL)) { fprintf(stderr,"Usage: %s machine file ...\en",argv[0]); exit(1); } if ((connection = CourierOpen(destaddr)) == NULL) { fprintf(stderr,"Can't open connection to %s\en",argv[1]); exit(1); } DURING result = LookupUser(connection,NULL,argv[2]); HANDLER switch(Exception.Code) { case Courier_reject: fprintf("Connection rejected, code = %d\en", CourierErrArgs(rejectionDetails,designator) ); exit(1); case NoSuchUser: printf("User %s unknown on %s.\en", argv[2], argv[1]); exit(0); case OtherError: fprintf(stderr,"Remote error %s\en", CourierErrArgs(OtherErrorArg,errorstring) ); exit(1); } END_HANDLER; displaypwd(& result.passwd); displayfwd(result.forward); CourierClose(connection);}displaypwd(p) Passwd *p;{ printf("%s:%s:%d:%d:%s:%s:%s\en", p->pw_name, p->pw_passwd, p->pw_uid, p->pw_gid, p->pw_gecos, p->pw_dir, p->pw_shell);}displayfwd(s) String s;{ if (*s) printf("Mail forwarding to %s\en",s); else printf("Mail is not forwarded\en");}.fi.bp.sh 1 "Example II: PrintFile".ppThis example is a very simple application of Bulk Data Transfer..sh 2 "PrintFile.cr".sp 1.nfPrintFile: PROGRAM 756 VERSION 1 =BEGIN DEPENDS UPON BulkData (0) VERSION 1; -- Remote errors. CantPrint: ERROR = 0; -- Remote entry points. RPrint: PROCEDURE [ s: BulkData.Source ] REPORTS [ CantPrint ];END..fi.sp 1.sh 2 "A typical client (remoteprint.c)".lp.sp 1
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -