TweetFollow Us on Twitter

ATalk Server
Volume Number:1
Issue Number:10
Column Tag:C Workshop

"Dial a Fortune Apple Talk Server"

By Robert B. Denny, Timothy T. Coad, Alisa Systems, Inc., MacTutor Editorial Board

It's been about six months since the AppleTalk network was released. Yet there seems to be little software available which uses this network. One reason is that the market is too small as yet and developers can't see enough potential to risk the investment. Another reason is that AppleTalk applications appear difficult to implement, requiring a great deal of knowledge and understanding that is not easy to obtain. Last, but certainly not least, Apple has failed to complete the basic services that history has shown are required for successful introduction of a computer network.

About six or seven months ago, Apple released a publication called Inside AppleTalk, available from the same source as Inside Macintosh. In addition, most developers who subscribed to the Apple "Software Supplement" have received The AppleTalk Manager: A Programmer's Guide, a part of Inside AppleTalk. These documents do a fairly good job of describing the network architecture and the details of using the AppleTalk services. If you have no experience with local area networks, however, you may get lost in the jargon and fail to "see the forest through the trees".

This month's C Workshop is devoted to AppleTalk. It includes a complete server application called Confucious which, when run on a Mac connected to the network, provides a "guru" service. A Mac Pascal client application is described by Alan Wootton in a separate article in this issue of Mac Tutor. The Pascal client, running on another Mac, locates the C server and makes requests for pearls of wisdom, which the server gladly sends back.

In order to keep this article's size reasonable, we assume that (1) you understand how to use the Mac's I/O services and (2) you have access to (at least) the AppleTalk Manager Programmer's Guide. The article describes the overall architecture of the AppleTalk network, and concludes with a listing of the server's code, written mostly in C. We'll look at programming details next month.

Fig. 1 - AppleTalk Components

NOTE: The descriptions given in this article are simplified so as to make it easier to understand the overall architecture of AppleTalk. Please consult the Apple documentation for full details.

Protocols and Layers

The lifeblood of any network is its suite of protocols that are used to negotiate and communicate. Usually, there are two agents in a network operation, the client and the server. The operation consists of a set of information exchanges between the client and the server, according to a protocol.

In order to bring some order to the chaos that would be created by a multitude of protocols, some of which are clients of other protocols and servers to yet others, network designers use the concepts of layers and interfaces. A layer implements a set of services via an interface. For example, the file system on the Mac has a layer that handles "raw" disk I/O (the device manager), and a layer on top of that which handles the organization of data on the disk into files and directories (the file manager). This separation of functions makes it possible to handle both hard disks and floppies with the same file manager routines. The file manager uses a defined interface to the device manager for its requests. Finally, the organization of data on the disk as files and directories is a sort of "spatial protocol".

Network architectures are normally divided into seven layers, according to the ISO "Open Systems Interconnection" convention adopted about five years ago. These layers, from lowest to highest are:

Physical: Electrical and mechanical aspects of communication circuits.

Data Link: Data and frame formats, bus access & contention protocols, error detection, other low level link services.

Network: Addressing and routing of messages between "sockets" transparently across multiple data links.

Transport: Error and flow control between sockets. Exchanges of information between routing agents on special sockets.

Session: Opening and closing logical links between sockets. Starting up remote servers on request. Naming of entities and name services.

Presentation: Cryptosystems, code conversion (e.g., ASCII to EBCDIC), other transformations needed for the native application environment.

Application: Protocols used between specific applications.

AppleTalk Architecture

Apple Computer has so far defined and published protocols for the physical through the transport layers of AppleTalk. Generally speaking, AppleTalk has a bus oriented, packet-based architecture, supporting internetworking, named objects, adaptive routing and a transaction-oriented transport service.

Services are implemented in a pair of I/O drivers and associated resources which are opened permanently on 512K Macs, and live in the system heap. On 128K Macs, applications which want to use the network must manually open the drivers, loading them into the application heap. This means that no "detached" service processes in the system heap can be supported on the smaller systems. Figure 1 shows the breakdown of AppleTalk functions and the drivers that implement them.

Physical & Data Link Layers: ALAP

The physical layer consists of a bus topology twisted-pair cable carrying electrical signals conforming to the EIA RS-422 standard. The Mac hardware has a "serial communications controller" (SCC) which is capable of being software configured as a standard async or sync port, or as an AppleTalk port. AppleTalk uses the printer port on the Mac.

The data link layer is implemented in software and uses the "AppleTalk Link Access Protocol" (ALAP) to manage usage of the common bus and to detect transmission errors between physically connected Mac systems. ALAP uses a frame format which is similar to that used by several well known block-oriented protocols such as HDLC. The algorithms used to manage multiple access to the bus are specific to AppleTalk, and fall into the category of "Carrier Sense Multiple Access" (CSMA).

Simply stated, the rules of CSMA are: (1) talk if no one else is talking; (2) if you want to talk and some one else is already talking, go away and try again later; (3) if two of you start talking at the same time, yell "Abort!" so everyone else knows, then both of you go away and try again later.

One other thing to note: The assignment of node numbers to each station on a network is not done by the user. Rather, the ALAP software tries to assign a random node number when the Mac is booted, then shouts it out over the net. If no one else objects, that is the node number to be used. Otherwise, another try is made.As an application developer, you'll rarely deal directly with ALAP.

Network Layer: DDP

The network layer uses the "Datagram Delivery Protocol" (DDP), which defines the format of the address header which is included in each packet and which stays with the packet between cooperating processes through communication endpoints called sockets. The path between sockets may span several physical links, and may go through intermediate systems. One Mac may have several AppleTalk connections open at a time, so the node number is not enough to identify a network address.

An address must consist of at least a node number and a socket number. In fact, AppleTalk considers a socket to be the one and only network-visible entity. Socket numbers fall into two groups. The "well-known" sockets (1-127) are assigned by Apple for specific generic network services and experimentation. The others (128-254) are called "dynamic" sockets. They are assigned temporarily and are often associated with a name managed by the Name Binding service of AppleTalk (see below).

Individual AppleTalk networks may be tied together to form an internetwork. Node numbers are unique only within a single physical network, so DDP requires that each network be assigned a network number. Figure 2 (see top of next page) shows a three-net internetwork. The Networks are connected by either a full bridge or a pair of half-bridges. The full bridge attaches directly to two physical networks and provides datagram routing from one to the other. The pair of half bridges does the same thing, but they use an intermediate transmission medium such as a long-distance telephone line.

Fig. 2 - An AppleTalk Internetwork

DDP defines an internet address consisting of a net number, a node number and a socket number. One might argue that the net number is superfluous, since the node number could be made unique within the entire internet. True, but the early local net designers at Xerox PARC decided that routing overhead should be minimized.

The key to their idea is that many nodes are attached to a single network, and that getting the packet to the proper local network is all that's needed to get it to the destination node. Normally, there are far fewer networks than nodes, so the routers have a much easier task. AppleTalk incorporates this network-oriented routing system.

The basic service provided by DDP is to "try its best" to get a packet from the source to the destination. If there is a problem somewhere, the packet is vaporized. DDP doesn't care about the details of link management or signalling, it only needs some sort of link service to it's neighbors in the net. Application developers rarely use the datagram services directly.

Routing Services: RTMP

The DDP internet routing process requires information as to the topology (interconnect configuration) of the internet. Each router involved in getting a DDP datagram from the source to the destination net must know where to send the datagram next. The routers use a set of routing tables to maintain this information.

The tables consist of a list of net numbers paired with the local node number of the bridge through which the shortest path to that net exists. These tables are dynamically constructed and maintained, with no need for a network manager to describe the topology. Automatic routing table maintenance is done by the routers carrying on a continuous chit-chat, proclaiming themselves as routers and broadcasting routing information for other routers, using the Routing Table Maintenance Protocol (RTMP).

Routing information exchange uses DDP at its communication medium, via socket number 1. Each Mac has a small RTMP-speaking process that keeps track of the nearest router and the network number of the local net. Bridges have a full-function RTMP-speaking process which engages in the prescribed chit-chat to maintain their routing tables. Bridges use this routing table to relay DDP datagrams according to their destination network number.

Transport Layer: ATP

The transport layer protocols are used to control the flow of data between sockets, and for end-to-end error recovery. Clients of the transport layer are offered some sort of "logical link" or "virtual circuit" service between themselves and other network visible entities.

Most networks are fairly similar in the first three layers, up through the network layer. Above that, however, their architectures begin to diverge. The transport layer is usually the first to reflect the main purpose for which the network was designed. AppleTalk is quite unusual in this respect.

Typically, the transport layer supports a two-way link between clients. Some sort of higher level protocol handles the opening of the link, and the transport layer provides error and flow control. The clients at each end can act as though they have an error-free hardwired line between them. AppleTalk does not support this sort of protocol.

Instead, AppleTalk has a transaction-oriented transport protocol, called AppleTalk Transaction Protocol (ATP). Here, one end acts as a requestor and the other acts as a responder. The responder usually sets itself up on a "permanent" socket. Requestors can "pop up" anywhere, at any time, and send requests. The example application at the end of this article is a responder.

The requestor sends a request which may carry with it up to 578 bytes of data in a single segment. The responder may send back up to eight such segments, for 4624 bytes total. If the request arrives in error, it is simply discarded. The requestor keeps trying until it receives a response. Response segments that are damaged are re-transmitted. This selective retransmission is handled by the ATP protocol, invisible to ATP clients.

Sometimes it is important that a request be serviced once and only once. An example of such a request would be to backspace a record in a remote file. Remember that the requestor repeatedly requests until it receives a response.

ATP provides a special class of transaction service called "exactly once". Each request is tagged with a transaction ID. The responder ATP has the logic needed to assure that the request with a given transaction ID is executed only once. The penalty for such service is extra overhead.

Named Entities: NBP

Recall that the only network-visible entities are sockets (socket clients, actually). Communication between processes on AppleTalk takes place between socket clients. A key feature of the network is that most objects are accessible by name rather than by address. Node numbers and dynamic socket numbers are assigned randomly. People prefer names.

The Name Binding Protocol (NBP) defines a set of services that applications can use to register names for their sockets, and to locate named entities. AppleTalk names consist of three fields: the object name, the type name and the zone name. The object name is the "name" as we usually think of it. The type indicates what sort of object it is. The zone field is not currently supported by AppleTalk and is always set to the value "*", meaning "this zone". The format of a name is:

object:type@zone

The object and type fields in a name may contain the wildcard character "=" which stands for "all possible values". Thus the name "=:printer@*" means "all printers in this zone", or simply "all printers" since the zone concept is not yet supported.

Usually, a server will make itself available to the network by opening an ATP-responding socket, then registering itself by name, associating the name with its network address (net/node/socket). Then a client may lookup the server by name, or it may look up all servers of that type (using the "=" wildcard) then choose a particular one for use.

Limitations of AppleTalk

Now that we have an overview of the network architecture, let's look at the limitations of AppleTalk, especially its unusual transport layer protocol, ATP. Understanding these limitations is very important to you, as a developer. Unless Apple faces up to these limitations, you will be saddled with the responsibility of creating your own "session" oriented service, either on top of ATP or in addition to it. Let's see why.

Recall that ATP provides a transaction-oriented service. There is no provision for sequencing or otherwise grouping transactions. There is no "private wire" service between cooperating applications.

Consider a file server, whose ATP responding socket is visible to the whole network. Anyone, at any time, is free to issue an ATP request to the server's socket, and to expect a response. But file service implies a "context" spanning several transactions: an open file with a current file position.

This means that the file server must remember what's going on for each client who has a file open on that server. And a single client may have more than one file open, further complicating matters. The client and server need to set up a conversation which will continue across several transactions.

An open file is typical of a general class of network operations which require a private "session" to be maintained between the client and the server. This is the domain of the ISO session layer. AppleTalk has no session layer support.

You may say, "Well, at least ATP handles error and flow control; I can build sessions myself". But layering a session protocol on top of a "reliable transaction" protocol creates other problems. If we believe in internetworking, systems of interconnected AppleTalk bus networks, then we must face the problem of transport delay.

Suppose we want to set up an internet session, between sockets on nodes which are on different physical networks, separated by several bridges and perhaps a backbone network. The connection between client and server has plenty of speed capacity, but packets may be delayed up to 100 milliseconds in bridges and routers. ATP requires completion of a transaction before another can start. With a 100 mS delay from one end to the other, our transport protocol is capable of one transaction every 200 mS, or 5 transactions per second! Without the transport delay, the Macintosh ATP implementation is capable of hundreds of transactions per second.

It is important to understand that the degradation is not due to speed limits of the transmission medium, but instead due to the transport delay from one end to the other and ATP's need to complete a transaction before the next can be started. In an internetworking environment such as AppleTalk, transport delays are a fact of life. ATP is poorly suited as a transport protocol in such situations.

Another aspect of ATP is its asymmetry. An ATP request may carry up to 578 bytes of data. The response, on the other hand, can carry 8 times that amount of data. The responding socket is more or less permanent, the requesting socket is opened and closed for each request. The responder has no way of delivering an asynchronous message to the requestor. Data flow from the requestor to the responder has a higher overhead than that in the opposite direction.

These facts have caused some developers to set up responding sockets at each end of a client-server connection. This approach uses two sockets at each end (temporary requestor, permanent responder). But there is a limit to the total number of ATP sockets that may be open in the current version of AppleTalk, 6 requestors and 6 responders. So sockets are a precious quantity and this approach wastes sockets unnecessarily.

AppleTalk has no session layer, a severe architectural deficiency which will promote multiple "private" session protocols, some of which may be poorly designed for the internet environment. Session protocols are among the most difficult to design and test. Often, the theoretical behavior of the network used as the basis for protocol design turns out to be inaccurate. Error recovery in the session layer is probably the most complex design issue in networking.

There is another limitation that took me by surprise. AppleTalk does not support transactions between sockets on the same node. At first this might not seem to be too serious but, as any networking veteran will tell you, it is serious. If your node happens to be the one with a server you need, you can't get to it. Keep this in mind when designing AppleTalk applications: your application must handle the case where the server and client are on the same node.

A Sample AppleTalk Server

The rest of this article contains the sources for an example AppleTalk "Dial-A-Fortune" Server. Note that the main program is fairly simple, and that most of the AppleTalk access functions are broken out separately and written for general use. (See fig. 3 on the previous page.)

There is not room for explanation of the details, but much of the information you'll need to understand this program is covered in Alan Wootton's article in this issue. I will explain its operation next month, along with more about AppleTalk.

One last item: You do NOT have a copy of the file ATALK.H, which contains the structure definitions and constant definitions needed for AppleTalk I/O. The items required for this program will be published next month. The full ATALK.H will be available on a MacTutor Source Disk. Also, look for some interesting AppleTalk developer's tools from Consulair soon.

Resource File in RMaker Format
*
* DFServer.R - RMAKER source.
*
Dev:DFServer
APPL????
* Load linker output
Include Dev:DFServer.Rsrc
*
* Define the DIAL-A-FORTUNE SERVER Modal dialog.
*
Type DLOG
   ,128
 No Title
40 96 240 416
Visible
1
0
128

Type DITL
   ,128
6

Button
175 20 195 90
Fortune

Button
175 230 195 300
Quit

StaticText Disabled
5 80 20 310
AppleTalk Dial-A-Fortune

StaticText Disabled
20 72 35 310
^0

StaticText Disabled
45 110 60 310
Confucious Say: 

StaticText Disabled
70 20 170 310
Press FORTUNE to get your Fortune or QUIT to ++ shutdown the AppleTalk 
Dial-A-Fortune Server.

*
* Entity string components
*
Type STR 
   ,128
Confucious

Type STR 
   ,129
Dial-A-Fortune

Type STR 
   ,130
\2A

*
* Number of fortunes and the fortunes themselves.
*
TYPE DATA = GNRL
   ,128
.H
nnnn

Type STR 
   ,131
One of the greatest sources of energy is pride in ++
what you are doing.

Type STR
   ,132
Take a cannibal to lunch.

( more fortune strings ...)

Type STR
   ,150
Every successful person has had failures but repeated failure is no ++
guarantee of eventual success.

END



/*
  *Dial-A-Fortune AppleTalk™ Server Application
  *
  *Written by:   Timothy T. Coad, Alisa Systems, Inc.
  *June, 1985
  *Written for:  Apple Computer MDS Development System and Consulair 
Mac C™
  *This program uses specific features of the MDS system and Mac C
  *and will almost certainly require modifications for other systems.
  *
  *  LINKER COMMAND FILE (uses Mac C minimum library, output is read 
by RMaker)
  *--
  * !Start
  *
  * /Output Dev:DFServer.Rsrc
  * /Type 'RSRC'
  * 
  * MacCLib
  * DFServer
  *
  * $
  *--
  *
  *Copyright (C) 1985, MacTutor Magazine
  *
  *Permission granted to use only for non-commercial purposes.  This 
notice must be
  *included in any copies made hereof.  All rights otherwise reserved.
  *
  *Warning: This code was edited for publication and may possibly contain 
minor errors
  */

#define VERSION  "\032Experimental version 1.0.A"

#include"Lib:MacDefs.H"   /* The usual collection of Mac definitions 
*/
#include"Lib:QuickDraw.H"
#include"Lib:Window.h"
#include  "Lib:TextEdit.H"
#include"Lib:Dialog.h"
#include"Lib:Events.H"
#include  "Lib:PBDefs.H"

#include"Lib:ATalk.H"/* AppleTalk definitions  to be published next month 
*/

#define FALSE    0
#define TRUE1

#define DIALOG_ID128
#define FORTUNE_DI 6 /* Dialog Item number of Fortune item */

#define NUMOFSTRINGS_ID 128 /* Resource ID of fortune string count ('DATA') 
*/
#define FIRSTSTR_ID131  /* Resource ID of first fortune string ('STR') 
*/

/*
  * Resource IDs of the three parts of server's Network Entity Name.
  */
#define OBJECT_ID128 /* Object name (Confucious) */
#define TYPE_ID  129 /* Object type (Dial-A-Fortune) */
#define ZONE_ID  130 /* Our zone ('*' = 'This zone') */

/*
  *Global Variables
  */

NBPElem *ourName;/* -> Our registered name/skt (locked block) */
ATPBlockATPGetReq, ATPResp; /* Statically allocated I/O parameter blocks 
*/
BDSRespBDS; /* Buffer Descriptor Structure for response */
char    ReqPkt[256]; /* Buffer to receive incoming requests */
char    RespPkt[256];/* Buffer for responses (fortune text) */
unsigned short NumOfStrings;/* Number of fortune string resources */
Handle  Fortuneitem; /* Handle to currently selected fortune string */

extern shortatpOpenSkt();
extern shortatpCloseSkt();
extern intGetReqComplete();
extern intFilterGlue();

/*
  * Dial-A-Fortune Main Program
  */
main()
 {
 unsigned short button, i;/* Locals, usage is obvious except as noted 
*/
 Handle handle;
 DialogPtr dlog;
 unsigned short type;
 Rect rect;
 char fortune[256];
 
 InitDialogs (0);/* No restart function */
 InitCursor ();  /* Make arrow cursor */
 SaveA5();/* Save our A5 for async completion routines */

 /*
   * Allocate a non-relocatable NBPElem structure, request for an ephemeral 
responding socket 
   * and register ourselves on the net.
   */
 ourName = (NBPElem *)NewPtr (sizeof(NBPElem));
 ourName->tuple.addr.skt = 0;
 ourName->tuple.addr.net = 0;
 if(atpOpenSkt(&(ourName->tuple.addr.skt)))
 { /* Can't open a socket */
 DisposPtr (ourName);/* Release tuple storage */
 return;/* and exit. */
 }
 /*
   * Get the three parts of the Network Entity Name and register ourselves 
using NBP.
   */
 handle = (Handle)GetResource ('STR ', OBJECT_ID);
 i = pstrcpy(ourName->tuple.entity, *handle);
 ReleaseResource (handle);
 handle = (Handle)GetResource ('STR ', TYPE_ID);
 i += pstrcpy(ourName->tuple.entity + i, *handle);
 ReleaseResource (handle);
 handle = (Handle)GetResource ('STR ', ZONE_ID);
 pstrcpy(ourName->tuple.entity + i, *handle);
 ReleaseResource (handle);
 if(NBPRegister(2, 8, ourName))    /* Registration error? */
 { 
 atpCloseSkt(ourName->tuple.addr.skt); /* Yes, free the socket and ... 
*/
 DisposPtr (ourName);/* ... release tuple storage. */
 return;/* Exit */
 }
 /* 
   * The number of fortunes is stored in a resource to make it possible 
to add new ones.
   */
 handle = (Handle)GetResource ('DATA', NUMOFSTRINGS_ID); 
 NumOfStrings = (unsigned short)(*((unsigned short *)(*handle)));
 ReleaseResource (handle);

 /*
   * Prime the pump with the initial asynchronous ATP Get Request.
   */
 GetATPRequest(&ATPGetReq, ourName->tuple.addr.skt, ReqPkt, 256, GetReqComplete);

 /*
   * Put up our dialog box.  Use a modal dialog filter procedure to handle 
the completion of the
   *  GetATPRequest.  The GetATPRequest completion routine posts an event 
which is filtered
   * and processed by the modaldialog filter procedure.
   */
 dlog = (DialogPtr)GetNewDialog (DIALOG_ID, 0, -1);
 GetDItem (dlog, FORTUNE_DI, &type, &Fortuneitem, &rect);
 ParamText (VERSION, "", "", "");
 button = 0;
 while(button != cancel)
 {
 ModalDialog (FilterGlue, &button);
 if(button == oK)/* Fortune button pressed? */
 { /* Yes, put up a fortune */
 GetFortune(fortune);
 SetIText (Fortuneitem, fortune);
 }
 }
 DisposeDialog (dlog);    /* Dispose of dialog */
 NBPRemove(ourName->tuple.entity); /* Remove us from net */
 atpCloseSkt(ourName->tuple.addr.skt); /* Free the socket */
 }

/*
  * SendFortune
  *
  * Get a random STR resource, display in the server's dialog box, ship 
it back to the 
  * requestor as an ATP response packet and finally re-arm ourselves 
for another request.
  */
SendFortune()
 {
 GetFortune(RespPkt);
 SetIText (Fortuneitem, RespPkt);
 SendATPResp(&ATPResp, &ATPGetReq.csParam.atpGetRequest.addr, 
 ourName->tuple.addr.skt, RespPkt, 256, &RespBDS,              
 ATPGetReq.csParam.atpGetRequest.transID, 0);
 GetATPRequest(&ATPGetReq, ourName->tuple.addr.skt, ReqPkt, 256, GetReqComplete);
 }

/*
  * GetFortune
  *
  * Get a random STR resource, modulo number of strings.  Return pointer 
to string in memory.
  */
GetFortune(fortune)
char *fortune;
 {
 Handle string;
 unsigned short index;
 
 index = FIRSTSTR_ID + ((unsigned short)Random ()) % NumOfStrings;
 string = (Handle)GetResource ('STR ', index);
 pstrcpy(fortune, *string);
 ReleaseResource (string);
 }

/*
  * AppleTalk Name Binding Protocol (NBP) Low Level I/O Routines
  */

/*
  * nbpRegister - Register an element with AppleTalk.
  *
  * Returns the I/O result.
  */
short nbpRegister(interval, count, elem)
unsigned char interval;   /* Retry interval, ticks */
unsigned char count; /* Number of retries */
NBPElem *elem;   /* -> Element with name to register */
 {
 MPPBlock block;
 
 block.ioRefNum = mppRefNum;/* I/O is to the MPP driver */
 block.csCode = _nbpRegister; /* Function is "Register name" */
 block.csParam.nbpRegister.retry.interval = interval;    /* Fill in retry 
interval */
 block.csParam.nbpRegister.retry.count = count;    /* Fill in retry count 
*/
 block.csParam.nbpRegister.verify = 1; /* Enable name clash checking 
*/
 block.csParam.nbpRegister.elem = elem;/* Fill in -> name to register 
*/
 return(PBControl(&block, 0));/* DO IT, return the result */
 }

/*
  * nbpRemove - Remove an entity from AppleTalk Registry.
  *
  * Return the I/O result code.
  */
short nbpRemove(entity)
Entity *entity;  /* -> Entity string for name to remove */
 {
 MPPBlock block; /* I/O parameter block */
 
 block.ioRefNum = mppRefNum;/* I/O to .MPP driver */
 block.csCode = _nbpRemove; /* Function is "Remove name" */
 block.csParam.nbpRemove.entity = entity;          /* Fill in -> to entity 
string */
 return(PBControl(&block, 0));/* DO IT and return result */
 }


/*
  * AppleTalk Transaction Protocol (ATP) Low Level I/O Routines.
  */

/*
  * atpOpenSkt - Open an dynamic ATP responding socket.
  *
  * Socket number set to 0 if it fails.  Returns the I/O result code.
  */
short atpOpenSkt(skt)
unsigned char *skt;/* -> byte to receive assigned socket number */
 {
 ATPBlock block; /* I/O Parameter block */
 
 block.ioRefNum = atpRefNum;/* I/O is for .ATP driver */
 block.csCode = _atpOpenSkt;/* Func is "Open Responding Socket */
 block.csParam.atpOpenSkt.skt = 0; /* Socket=0 for dynamically assigned 
*/
 block.csParam.atpOpenSkt.addr.net = 0;/* Zero internet fields */
 block.csParam.atpOpenSkt.addr.node = 0;
 block.csParam.atpOpenSkt.addr.skt = 0;
 *skt = PBControl(&block, 0) ? 0 : block.csParam.atpOpenSkt.skt; /* OPEN 
IT */
 return(block.ioResult);  /* Return result */
 }

/*
  * atpCloseSkt - Close an ATP responding socket.
  *
  * Returns I/O result code.
  */
short atpCloseSkt(skt)
unsigned char skt; /* Number of ATP socket to close */
 {
 ATPBlock block;
 
 block.ioRefNum = atpRefNum;/* I/O is for .ATP driver */
 block.csCode = _atpCloseSkt; /* Function is "Close Resp. Socket" */
 block.csParam.atpCloseSkt.skt = skt;/* Fill in socket to close */
 return(PBControl(&block, 0));/* DO IT and return result */
 }

/*
  * SendATPResp - Send a single-packet ATP response. 
  *
  * Currently, this routine only supports responses consisting of a single 
ATP packet.
  * The I/O parameter block is allocated statically because the I/O may 
be  asynchronous,
  * thus the block must stay around after this routine exits.  Same goes 
for the BDS,
  * which gets filled in here.
  */
SendATPResp(ATPSendResp, Dest_NetAddr, SourceSkt, Resp, RespSize,
 atpRespBDS, TransID, asynch)
ATPBlock *ATPSendResp;    /* -> Statically allocated I/O parameter block 
*/
AddrBlock *Dest_NetAddr;  /* -> Destination network address for response 
*/
byte SourceSkt;  /* Local responding socket number */
char *Resp; /* -> response data */
unsigned short RespSize;  /* Length in bytes of response data */
BDS *atpRespBDS; /* Statically allocated Buffer Descriptor Scructure 
*/
unsigned short TransID;   /* ID of transcation being replied to */
short asynch;    /* Boolean defining whether or not it is async. */
 {
 unsigned short atpBDS();

 ATPSendResp->ioRefNum = atpRefNum;/* I/O is for .ATP driver */
 ATPSendResp->csCode = _atpSendResponse;     /* Function is "Send Response 
*/
 /*
   * Copy Requestor's net address into parameter block
   */
 bcopy(&((ATPSendResp->csParam).atpSendResponse.addr), Dest_NetAddr, 

 sizeof(AddrBlock));
 (ATPSendResp->csParam).atpSendResponse.skt = SourceSkt;       /* Responding 
Skt. */
 (ATPSendResp->csParam).atpSendResponse.bdsPtr = atpRespBDS;   /* Fill 
in -> BDS */
 (ATPSendResp->csParam).atpSendResponse.bdsSize = 1;           /* 1-packet 
resp. */
 (ATPSendResp->csParam).atpSendResponse.numOfBuffs = 1;        /* (same) 
*/
 (ATPSendResp->csParam).atpSendResponse.flags = atpEOM;        /* 1st 
has EOM */
 (ATPSendResp->csParam).atpSendResponse.transID = TransID;     /* 
 atpBDS(atpRespBDS, Resp, RespSize); /* Fill in the BDS */
 if(asynch) /* Only 1/0 legal in PBControl */
 PBControl(ATPSendResp, 1); /* Do it asynchronously */
 else
 PBControl(ATPSendResp, 0); /* Do it synchronously */
 return(ATPSendResp->ioResult);    /* Return result code */
 }

/*
  * GetATPRequest - Get an ATP Request
  *
  * Issue an ATP "GetRequest".  If a non-NULL completion routine address 
is supplied, issue the
  * request asynchronously.
  */
GetATPRequest(ATPGetReq, skt, ReqPkt, ReqPktSize, ioCompletion)
ATPBlock *ATPGetReq; /* Statically allocated I/O parameter block */
byte skt; /* Local responding socket on which to accept request */
byte *ReqPkt;    /* -> buffer to get filled in with request data */
unsigned short ReqPktSize;/* Size of request buffer, bytes */
ProcPtr ioCompletion;/* -> entry point of completion routine or NULL 
*/
 {
 ATPGetReq->ioRefNum = atpRefNum;  /* I/O is for .ATP driver */
 ATPGetReq->csCode = _atpGetRequest; /* Function is "Get Request" */
 (ATPGetReq->csParam).atpGetRequest.reqPtr = ReqPkt;     /* Fill in buffer 
data */
 (ATPGetReq->csParam).atpGetRequest.reqSize = ReqPktSize;
 (ATPGetReq->csParam).atpGetRequest.skt = skt;     /* Socket on which 
to receive req. */
 /*
   * Fill in completion routine address, and if non-NULL, issue asynch 
I/O otherwise
   * issue it synchronously.
   */
 if((ATPGetReq->ioCompletion = ioCompletion)) != NULL)   
 PBControl(ATPGetReq, 1);
 else
 PBControl(ATPGetReq, 0);
 return(ATPGetReq->ioResult); /* Return I/O result code */
 }

/*
  * Miscellaneous Low-Level Routines
 */

/*
  * GetReqComplete
  *
  * ATP Get Request Completion Routine simply posts an event with a unique 
event/message pair.
  * When the event is identified by the modal dialog filter procedure, 
a fortune is returned to the
  * requestor and another GetRequest is issued.  Registers must be preserved 
because this routine
  * runs asynchronously, and may interrupt some other process, including 
a local fortune fetch.
  * It's written in assembler 
  */
GetReqComplete()
 {
 #asm
 Movem.La0-a6/d0-d7,-(sp) ; Save registers
 Move.L _SavedA5,a5; Restore A5 context
 Move.W #MouseDown,-(sp)  ; Event type = Mouse Down
 Pea    ATPGetReq; Event message is pointer to GetReq block
 _PostEvent ; Post it
 Movem.L(sp)+,a0-a6/d0-d7 ; Restore registers
 #endasm
 }

/*
  * FilterGlue - Interface for ModalDialog Filter Proc. Callback
  *
  * This is a glue routine to get back into C.  It is called back from 
ModalDialog() with 
  * (naturally) Pascal-flavored arguments on the stack.  See the C Workshop 
in MacTutor
  * Vol. 1, No. 7 (June, 1985) and Inside Macintosh for more information 
on ModalDialog
  * event filter procedures.
  */
FilterGlue()
 {
 #asm
 ;
 ; Inputs (Pascal callfrom ModalDialog):
 ;      4(SP)      Address of word to fill in with item number
 ;      8(SP)      Address of the event record
 ;     12(SP)      Dialog (window) pointer
 ;
 Link   a6,#0    ; no local automatics
 Movem.Ld1-d7/a1-a4,-(sp) ; Save regs
 Move.L 8(a6),d0 ; D0 -> Item number word
 Move.L 12(a6),d1; D1 -> Event record
 Move.L 16(a6),d2; D2 -> Window record
 Jsr    filter   ; Call C for dirty work
 Movem.L(sp)+,d1-d7/a1-a4 ; Restore regs
 Unlk   a6; "standard" Pascal routine exit
 Move.l (sp)+,a0 ; A0 -> return point
 Addq.L #6,sp    ; Pop args
 Addq.L #6,sp
 Move.B d0,(sp)  ; Copy C result to Pascal return
 Jmp    (a0); Return
 #endasm
 }

/*
  * filter - "Real" ModalDialog filter function
  *
  * If there is a "phoney" mouse down event (with message = address of 
our GetReq block)
  * then we have received a fortune request.  In that case, send a fortune 
back to the requestor.
  */
filter(ip, ep, wp)
short *ip;/* -> Word to receive dialog item code */
EventRecord *ep; /* -> Event record */
WindowPtr wp;    /* -> Window record for modal dialog */
 {
 if(ep->what == mouseDown && ep->message == (long)&ATPGetReq)
 {
 SendFortune();  /* Send a responding fortune */
 *ip = 0; /* No item was hit */
 return(TRUE);   /* Indicate that we handled the event */
 }
 return(FALSE);  /* We didn't handle this event */
 }

/*
  * atpBDS- Setup an ATP Buffer Descriptor Structure.
  *
  * Given a buffer-load of data to send, fill in a BDS which describes 
the buffer as possibly 
  * several ATP packets.  Return the number of ATP packets required to 
send the data as
  * a response.
  */
unsigned short atpBDS(bds, buf, size)
BDS *bds; /* -> Buffer Descriptor Structure to fill in */
unsigned char *buf;/* -> Response data buffer */
short size; /* Size (bytes) of response data */
 {
 unsigned short i; /* Counts number of segments */
 
 i = 0;
 while(size > 0) /* Loop till enough packets set up */
 {
 bds->buffSize = (size > atpMaxData) ? atpMaxData : size;      /* Size 
of this packet */
 bds->buffPtr = buf; /* Fill in -> to this segment/packet */
 buf += atpMaxData;/* Advance segment pointer */
 size -= atpMaxData; /* Count down segment size */
 bds++; /* Advance BDS pointer to next seg. */
 i++;   /* Count a segment */ }
 return(i); /* Return segment count */
 }

/*
  * pstrcpy - Pascal String Copy routine.
  *
  * Returns number of bytes copied, including count byte.
  */
pstrcpy(d, s)
char *d;/* -> Destination string */
char *s;/* -> Source string */
 {
 bcopy(d, s, *s + 1);
 return(*s + 1);
 }

/*
  * bcopy -  General purpose byte copy routine.
  */
bcopy(d, s, n)
char *d;/* Destination address */
char *s;/* Source address */
short n;/* Number of bytes to copy */
 {
 #asm
 Move.L d0,a0    ; A0 -> Destination
 Move.L d1,a1    ; A1 -> Source 
 Bra.S  @1; Jump past to correct for dumb DBRA inst.
@0 Move.B (a1)+,(a0)+; Copy a byte
@1 Dbra.W d2,@0  ; Loop till done
 #endasm
 }

/*
  * SaveA5
  */
SaveA5()
{
#asm
 Lea    _SavedA5,a0  ; A0 -> Save cell 
 Move.l a5,(a0)     ; Save A5 
 Rts       ; Return
 
_SavedA5Dc.l0  ; Storage area for A5
#endasm
}
 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Latest Forum Discussions

See All

Aether Gazer unveils Chapter 16 of its m...
After a bit of maintenance, Aether Gazer has released Chapter 16 of its main storyline, titled Night Parade of the Beasts. This big update brings a new character, a special outfit, some special limited-time events, and, of course, an engaging... | Read more »
Challenge those pesky wyverns to a dance...
After recently having you do battle against your foes by wildly flailing Hello Kitty and friends at them, GungHo Online has whipped out another surprising collaboration for Puzzle & Dragons. It is now time to beat your opponents by cha-cha... | Read more »
Pack a magnifying glass and practice you...
Somehow it has already been a year since Torchlight: Infinite launched, and XD Games is celebrating by blending in what sounds like a truly fantastic new update. Fans of Cthulhu rejoice, as Whispering Mist brings some horror elements, and tests... | Read more »
Summon your guild and prepare for war in...
Netmarble is making some pretty big moves with their latest update for Seven Knights Idle Adventure, with a bunch of interesting additions. Two new heroes enter the battle, there are events and bosses abound, and perhaps most interesting, a huge... | Read more »
Make the passage of time your plaything...
While some of us are still waiting for a chance to get our hands on Ash Prime - yes, don’t remind me I could currently buy him this month I’m barely hanging on - Digital Extremes has announced its next anticipated Prime Form for Warframe. Starting... | Read more »
If you can find it and fit through the d...
The holy trinity of amazing company names have come together, to release their equally amazing and adorable mobile game, Hamster Inn. Published by HyperBeard Games, and co-developed by Mum Not Proud and Little Sasquatch Studios, it's time to... | Read more »
Amikin Survival opens for pre-orders on...
Join me on the wonderful trip down the inspiration rabbit hole; much as Palworld seemingly “borrowed” many aspects from the hit Pokemon franchise, it is time for the heavily armed animal survival to also spawn some illegitimate children as Helio... | Read more »
PUBG Mobile teams up with global phenome...
Since launching in 2019, SpyxFamily has exploded to damn near catastrophic popularity, so it was only a matter of time before a mobile game snapped up a collaboration. Enter PUBG Mobile. Until May 12th, players will be able to collect a host of... | Read more »
Embark into the frozen tundra of certain...
Chucklefish, developers of hit action-adventure sandbox game Starbound and owner of one of the cutest logos in gaming, has released their roguelike deck-builder Wildfrost. Created alongside developers Gaziter and Deadpan Games, Wildfrost will... | Read more »
MoreFun Studios has announced Season 4,...
Tension has escalated in the ever-volatile world of Arena Breakout, as your old pal Randall Fisher and bosses Fred and Perrero continue to lob insults and explosives at each other, bringing us to a new phase of warfare. Season 4, Into The Fog of... | Read more »

Price Scanner via MacPrices.net

New today at Apple: Series 9 Watches availabl...
Apple is now offering Certified Refurbished Apple Watch Series 9 models on their online store for up to $80 off MSRP, starting at $339. Each Watch includes Apple’s standard one-year warranty, a new... Read more
The latest Apple iPhone deals from wireless c...
We’ve updated our iPhone Price Tracker with the latest carrier deals on Apple’s iPhone 15 family of smartphones as well as previous models including the iPhone 14, 13, 12, 11, and SE. Use our price... Read more
Boost Mobile will sell you an iPhone 11 for $...
Boost Mobile, an MVNO using AT&T and T-Mobile’s networks, is offering an iPhone 11 for $149.99 when purchased with their $40 Unlimited service plan (12GB of premium data). No trade-in is required... Read more
Free iPhone 15 plus Unlimited service for $60...
Boost Infinite, part of MVNO Boost Mobile using AT&T and T-Mobile’s networks, is offering a free 128GB iPhone 15 for $60 per month including their Unlimited service plan (30GB of premium data).... Read more
$300 off any new iPhone with service at Red P...
Red Pocket Mobile has new Apple iPhones on sale for $300 off MSRP when you switch and open up a new line of service. Red Pocket Mobile is a nationwide MVNO using all the major wireless carrier... Read more
Clearance 13-inch M1 MacBook Airs available a...
Apple has clearance 13″ M1 MacBook Airs, Certified Refurbished, available for $759 for 8-Core CPU/7-Core GPU/256GB models and $929 for 8-Core CPU/8-Core GPU/512GB models. Apple’s one-year warranty is... Read more
Updated Apple MacBook Price Trackers
Our Apple award-winning MacBook Price Trackers are continually updated with the latest information on prices, bundles, and availability for 16″ and 14″ MacBook Pros along with 13″ and 15″ MacBook... Read more
Every model of Apple’s 13-inch M3 MacBook Air...
Best Buy has Apple 13″ MacBook Airs with M3 CPUs in stock and on sale today for $100 off MSRP. Prices start at $999. Their prices are the lowest currently available for new 13″ M3 MacBook Airs among... Read more
Sunday Sale: Apple iPad Magic Keyboards for 1...
Walmart has Apple Magic Keyboards for 12.9″ iPad Pros, in Black, on sale for $150 off MSRP on their online store. Sale price for online orders only, in-store price may vary. Order online and choose... Read more
Apple Watch Ultra 2 now available at Apple fo...
Apple has, for the first time, begun offering Certified Refurbished Apple Watch Ultra 2 models in their online store for $679, or $120 off MSRP. Each Watch includes Apple’s standard one-year warranty... Read more

Jobs Board

DMR Technician - *Apple* /iOS Systems - Haml...
…relevant point-of-need technology self-help aids are available as appropriate. ** Apple Systems Administration** **:** Develops solutions for supporting, deploying, Read more
Omnichannel Associate - *Apple* Blossom Mal...
Omnichannel Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Operations Associate - *Apple* Blossom Mall...
Operations Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Cashier - *Apple* Blossom Mall - JCPenney (...
Cashier - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Blossom Mall Read more
IT Systems Engineer ( *Apple* Platforms) - S...
IT Systems Engineer ( Apple Platforms) at SpaceX Hawthorne, CA SpaceX was founded under the belief that a future where humanity is out exploring the stars is Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.