;; Socket listener code from Descent.;; Much of this listener is based off of the listener code found in;; the DTS sample.  Credit goes to:;_________________________________________________________________________; Socket Listener Sample;; 3/92 Jim Luther,  Apple DTS;; ©1992 Apple Computer, Inc.;_________________________________________________________________________    INCLUDE    'Quickdraw.a'    INCLUDE    'ToolUtils.a'    INCLUDE    'Appletalk.a'	INCLUDE	   'Traps.a'    INCLUDE    'Errors.a'APPLETALK_MAX_DATA_SIZE	EQU	586;; equates for DDP structureslapDstAdr	EQU	0lapSrcAdr	EQU	1lapType		EQU	2lapHdSz		EQU	3ddpHopCnt	EQU	0ddpLength	EQU	0ddpChecksum	EQU	2ddpDstNet	EQU	4ddpSrcNet	EQU	6ddpDstNode	EQU	8ddpSrcNode	EQU	9ddpDstSkt	EQU	10ddpSrcSkt	EQU	11ddpType		EQU	12sddpDstSkt	EQU	2sddpSrcSkt	EQU	3sddpType	EQU	4ddphSzLong	EQU	13ddphSzShort	EQU	5ddpLenMask	EQU	$3FFshortDDP	EQU	$01longDDP		EQU	$02toRHA		EQU	1;;; Record Types;;_________________________________________________________________________MyQHdr                RECORD    0qFlags                DS.W      1qHead                 DS.L      1qTail                 DS.L      1                      ENDRPacketBuffer          RECORD    0qLink			DS.L      1qType			DS.W      1packet_type		DS.W      1            ; DDP Typedest_nodeid		DS.W      1            ; Destination nodesrc_addr		DS.L      1            ; Source address in AddrBlock formatlength			DS.W      1            ; length of DDP datagramdata			DS.B      APPLETALK_MAX_DATA_SIZE   ; the DDP datagram                      ENDRTHE_LISTENER		PROC	EXPORT	BRA.S		TheListener	BRA.S		SL_InitSktListener			; branch to init code;_________________________________________________________________________;; Local Variables;;_________________________________________________________________________free_queue        DC.L    0      ; pointer to freeQ QHdr - init'd by InitSktListenerused_queue        DC.L    0      ; pointer to usedQ QHdr - init'd by InitSktListenercurrent_qelem     DC.L    0      ; pointer to current PacketBuffer record                                 ; initialized by InitSktListener, then                                 ; set by socket listener after every packet.                                 ; NIL if no buffer is available.;_________________________________________________________________________; Function SL_InitSktListener(freeQ, usedQ: QHdrPtr): OSErr;StackFrame     RECORD    {A6Link},DECR     ; build a stack frame recordResult1        DS.W      1                 ; function's result returned to callerParamBegin     EQU       *                 ; start parameters after this pointfreeQ          DS.L      1                 ; freeQ parameterusedQ          DS.L      1                 ; usedQ parameterParamSize      EQU       ParamBegin-*      ; size of all the passed parametersRetAddr        DS.L      1                 ; placeholder for return addressA6Link         DS.L      1                 ; placeholder for A6 linkLocalSize      EQU       *                 ; size of all the local variables               ENDRSL_InitSktListener:    WITH       StackFrame,MyQHdr           ; use these record types    LINK       A6,#LocalSize               ; allocate our local stack frame; copy queue header pointers into our local storage for use in the listener    LEA        used_queue,A0               ; copy usedQ into used_queue    MOVE.L     usedQ(A6),(A0)    LEA        free_queue,A0               ; copy freeQ into free_queue    MOVE.L     freeQ(A6),(A0); dequeue the first buffer record from freeQ and set current_qelem to it    MOVEA.L    freeQ(A6),A1                ; A1 = ^freeQ    LEA        current_qelem, A0           ; copy freeQ.qHead into                                            ; current_qelem    MOVE.L     qHead(A1),(A0)    MOVEA.L    qHead(A1),A0                ; A0 = freeQ.qHead    _Dequeue    MOVE.W     D0,Result1(A6)              ; Return status@1  UNLK       A6                          ; destroy the link    MOVEA.L    (SP)+,A0                    ; pull off the return address    ADDA.L     #ParamSize,SP               ; strip all of the caller's                                            ; parameters    JMP        (A0)                        ; return to the caller;_________________________________________________________________________;; SL_TheListner - process packets received at the designated socket;;    Input:;     D0 (byte) = packet's destination socket number;     D1 (word) = number of bytes left to read in packet;     A0 points to the bytes to checksum;     A1 points to the bytes to checksum;     A2 points to MPP's local variables;     A3 points to next free byte in Read Header Area;     A4 points to ReadPacket and ReadRest jump table;;    Return:;     D0 is modified;     D3 (word) = accumulated checksum;_________________________________________________________________________	IMPORT	SL_DoChksum	: codeTheListener:    WITH    PacketBuffer; get pointer to current PacketBufferGetBuffer:    LEA       current_qelem,A3          ; get the pointer to the PacketBuffer to use    MOVE.L    (A3),A3    MOVE.L    A3,D0                     ; if no PacketBuffer    BEQ.S     NoBuffer                  ; then ignore packet; read rest of packet into PacketBuffer.datagramData    MOVE.L    D1,D3                     ; read rest of packet    LEA       data(A3),A3  		        ; A3 = ^bufferData    JSR       2(A4)                     ; ReadRest    BEQ.S     ProcessPacket             ; If no error, continue    BRA       RcvRTS                    ; there was an error, so ignore packet; No buffer; ignore the packetNoBuffer      CLR D3                    ; Set to ignore packet (buffer size = 0)    JSR       2(A4)                     ; ReadRest    BRA.S     GetNextBuffer             ; We missed this packet, but maybe there                                        ; will be a buffer for the next packetÉ; Process the packet you just read in.; ReadRest has been called so registers A0-A3 and D0-D3 are free to use.; We'll use registers this way:PktBuff         EQU    A0        ; the current PacketBufferMPPLocals       EQU    A2        ; pointer to MPP's local variables (still set up                                  ;  from entry to socket listener)DatagramLength  EQU    D1        ; used to determine the datagram lengthSourceNetAddr   EQU    D2        ; used to build the source network addressProcessPacket:    LEA        current_qelem,PktBuff          ; PktBuff = current_qelem    MOVE.L     (PktBuff),PktBuff; do everything that's common to both long and short DDP headers; first, clear buffer_Type and buffer_NodeID to ensure their high bytes are 0    CLR.W      packet_type(PktBuff)           ; clear buffer_Type    CLR.W      dest_nodeid(PktBuff)         ; clear buffer_NodeID; clear SourceNetAddr to prepare to build network address    MOVEQ      #0,SourceNetAddr               ; build the network address in                                              ; SourceNetAddr; get the packet length (including the DDP header)    MOVE.W     toRHA+lapHdSz+ddpLength(MPPLocals),DatagramLength ; Get length field    ANDI.W     #ddpLenMask,DatagramLength     ; Mask off the hop count bits; now, find out if the DDP header is long or short    MOVE.B     toRHA+lapType(MPPLocals),D3    ; Get LAP type    CMPI.B     #shortDDP,D3                   ; is this a long or short DDP header?    BEQ.S      IsShortHdr                     ; skip if short DDP header; it's a long DDP header    MOVE.B     toRHA+lapHdSz+ddpType(MPPLocals),packet_type+1(PktBuff) ; get DDP type    MOVE.B     toRHA+lapHdSz+ddpDstNode(MPPLocals),dest_nodeid+1(PktBuff)                                               ; get destination node from LAP header    MOVE.L     toRHA+lapHdSz+ddpSrcNet(MPPLocals),SourceNetAddr                                               ; source network in hi word                                              ; source node in lo byte    LSL.W      #8,SourceNetAddr               ; shift source node up to high byte of low word                                              ; get source socket from DDP header    MOVE.B     toRHA+lapHdSz+ddpSrcSkt(MPPLocals),SourceNetAddr     SUB.W      #ddpType+1,DatagramLength      ; DatagramLength = number of bytes in                                              ; datagram    BRA.S      MoveToBuffer; it's a short DDP headerIsShortHdr:                                              ; get DDP type    MOVE.B     toRHA+lapHdSz+sddpType(MPPLocals),packet_type+1(PktBuff)                                              ; get destination node from LAP header    MOVE.B     toRHA+lapDstAdr(MPPLocals),dest_nodeid+1(PktBuff)                                              ; get source node from LAP header    MOVE.B     toRHA+lapSrcAdr(MPPLocals),SourceNetAddr    LSL.W      #8,SourceNetAddr               ; shift src node up to high byte of                                              ; low word                                              ; get source socket from short DDP                                               ;  header    MOVE.B     toRHA+lapHdSz+sddpSrcSkt(MPPLocals),SourceNetAddr                                               ; DatagramLength = number of bytes in                                               ; datagram    SUB.W      #sddpType+1,DatagramLengthMoveToBuffer:                                      ;move source network address into PacketBuffer    MOVE.L     SourceNetAddr,src_addr(PktBuff)                                       ; move datagram length into PacketBuffer    MOVE.W     DatagramLength,length(PktBuff) ; Now that we're done with the PacketBuffer, enqueue it into the usedQ and get; another buffer from the freeQ for the next packet.    LEA        used_queue,A1                   ; A1 = ^used_queue    MOVE.L     (A1),A1                         ; A1 = used_queue (pointer to usedQ)    _Enqueue                                    ; put the PacketBuffer in the usedQGetNextBuffer:    LEA        free_queue,A1                   ; A1 = ^free_queue    MOVE.L     (A1),A1                         ; A1 = free_queue (pointer to freeQ)    LEA        current_qelem, A0               ; copy freeQ.qHead into current_qelem    MOVE.L     qHead(A1),(A0)	BEQ.S      RcvRTS                          ; if 0, then no more free queue elements    MOVEA.L    qHead(A1),A0                    ; A0 = freeQ.qHead    _DequeueRcvRTS:    RTS                                        ; return to callerENDWITH	ENDP	END