#include "spx_app.h"int t_connect ( int spxFd, struct t_call *sndcall, struct t_call *rcvcall )
spxFd
sndcall
spxFd
is an SPXII /dev/nspx2 file descriptor, then the sndcall structure can contain an option structure (SPX2_OPTIONS) to change the current options.
rcvcall
rcvcall
spxFd
is an SPXII /dev/nspx2 file descriptor, then the rcvcall structure will contain an option structure (SPX2_OPTIONS) with the current options.
See t_connect(3xti) and ``Programming with the X/Open Transport Interface (XTI)'' for other possible errors.
SPX/SPXII supports both synchronous and asynchronous modes according to the specifications in ``Programming with the X/Open Transport Interface (XTI)''.
In the synchronous mode, the call waits for the server's response before returning control to the client. In asynchronous mode, the call initiates connection establishment but returns control to the client before a response arrives. The t_rcvconnect function must be used to complete an asynchronous connection.
The t_call structure has the following format:
struct t_call { struct netbuf addr; struct netbuf opt; struct netbuf udata; int sequence; };The SPXII driver does not use the udata structure. Its fields should be initialized. You must set the
udata.len
and udata.maxlen
fields to zero and set the udata.buf
field to NULL.
The SPXII driver does not use the sequence
field.
The netbuf structure has the following format:
struct netbuf { unsigned int maxlen; unsigned int len; char *buf; };For standard information about the t_call and netbuf structures, see ``Programming with the X/Open Transport Interface (XTI)''.
The t_connect call uses the following t_call structures:
sndcall.addr.len
and sndcall.addr.maxlen
fields must be initialized to the size of an ipxAddr_t or equivalent structure. The sndcall.addr.buf
field must point to an ipxAddr_t structure. The ipxAddr_t structure must be initialized to the server's IPX address.
The ipxAddr_t structure has the following format:
typedef struct ipxAddress{ uint8 net[4]; uint8 node[6]; uint8 sock[2]; } ipxAddr_t;All information passed in the ipxAddr_t structure must be in hi-lo byte order. See Figure 4-1 on page 46 for an illustration of byte order.
The sndcall.opt.len
and sndcall.opt.maxlen
fields must be initialized either to the size of a valid option structure or to zero. SPXII supports two different option structures, one for SPX (SPX_OPTS) and the other for SPXII (SPX2_OPTIONS).
See page 206 for the t_optmgmt option structure formats.
The SPX_OPTS structure has the following format:
typedef struct spxopt_s { unsigned char spx_connectionID[2]; unsigned char spx_allocationNumber[2]; } SPX_OPTS;Both endpoints must support orderly release before an application can use the orderly release calls. Although older versions of SPX did not support orderly release, the
spxIISessionFlags
can be used to determine whether both endpoints support orderly release. The spxIISessionFlags
in the opt (SPX2_OPTIONS) structure should be saved if the application wants to use orderly release. See t_sndrel on page 230 for further information.
The t_connect call sends an SPX/SPXII connection request to the IPX address specified in sndcall.addr
.
If the rcvcall structure is passed in t_connect, the server's address and connection information are returned.
If an rcvcall structure is passed, the maxlen
and buf
variables must be set appropriately to receive the ipxAddr_t and option structures.
The server's IPX address is returned in the rcvcall.addr.buf
field, while the server's connection ID and allocation number are passed back in the rcvcall.opt.buf
field.
Example 1 below is for an SPXII connection request, while Example 2 is for SPX.
{ char *spx2Device = "/dev/nspx2"; int spxFd; uint32 spxIISessionFlags; ipxAddr_t *serversAddress; struct t_call *sndcall; struct t_call *rcvcall; SPX2_OPTIONS *reqOpts; SPX2_OPTIONS *retOpts;...
/* Open an spxII device */ if ((spxFd = t_open(spx2Device, O_RDWR, &spxInfo)) <0) { t_error("t_open failed"); exit(-1); }
/* Bind to dynamic socket */ if ((t_bind(spxFd, NULL, NULL)) < 0) { t_error( "t_bind failed"); exit(-1); }
/* Allocate call structures */ if ((sndcall = (struct t_call *)t_alloc(spxFd, T_CALL, T_ALL))==NULL) { t_error( "t_alloc of T_CALL failed"); exit(-1); }
if ((rcvcall = (struct t_call *)t_alloc(spxFd, T_CALL, T_ALL))==NULL) { t_error( "t_alloc of T_CALL failed"); exit(-1); }
/* The first step in making a connection is to obtain the address of ** the SPXII user you want to establish the connection with. There are ** three approaches to obtaining an address. ** 1. You can query a NetWare bindery for the server type you want. ** ( This method assumes that you have established a connection with ** a NetWare file server. Use the NWScanProperty function with ** NET_ADDRESS as the searchPropertyName. ) ** 2. You can create a file that maps a server name to an address.
** 3. You can use any appropriate method for discovering the endpoint's ** address, for example, the SAP APIs. ** You must allocate an ipxAddr_t structure and initialize the ** fields to the endpoint's address before making the t_connect ** call. The following example code assumes that the server has ** the following address: network = 0x0101038B, node = 0x01, ** socket = 0xDEAD.*/
serversAddress = (ipxAddr_t*)sndcall->addr,buf; serversAddress.net[0] = 0x01; serversAddress.net[1] = 0x01; serversAddress.net[2] = 0x03; serversAddress.net[3] = 0x8B; serversAddress.node[0] = 0x00; serversAddress.node[1] = 0x00; serversAddress.node[2] = 0x00; serversAddress.node[3] = 0x00; serversAddress.node[4] = 0x00; serversAddress.node[5] = 0x01; serversAddress.sock[0] = 0xDE; serversAddress.sock[1] = 0xAD; sndcall->addr.len = sndcall->addr.maxlen;
/* ** Change SPXII options on t_connect */ reqOpts = (SPX2_OPTIONS *)sndcall->opt.buf; reqOpts->versionNumber = OPTIONS_VERSION; reqOpts->spxIIOptionNegotiate = SPX2_NEGOTIATE_OPTIONS; reqOpts->spxIIRetryCount = 7; reqOpts->spxIIMinimumRetryDelay = 500; /* 1/2 second */ reqOpts->spxIIMaximumRetryDelta = 2000; /* 2 seconds */ reqOpts->spxIILocalWindowSize = 10; sndcall->opt.len = sndcall->opt.maxlen;
if ((t_connect(spxFd, sndcall, rcvcall)) < 0) { t_error( "t_connect failed"); if (t_errno == TLOOK) { lookVal = t_look(spxFd); printLookVal(lookVal); } exit(-1); } /* ** Upon successful completion, rcvcall->opt.buf will have the ** connection identification number of the server and the current ** options. */
retOpts = (SPX2_OPTIONS *)rcvcall->opt.buf; retOpts = (SPX2_OPTIONS *)rcvcall->opt.buf;
/* Save spxII session flags, needed for orderly release */ spxIISessionFlags = retOpts->spxIISessionFlags;
fprintf(stderr,"Servers Window size:----------- %06d\n", retOpts->spxIIRemoteWindowSize); fprintf(stderr,"Servers connection ID Number:-- %06d\n", GETINT16(retOpts->spxIIConnectionID)); fprintf(stderr,"Inbound Packet size:----------- %06d\n", retOpts->spxIIInboundPacketSize); fprintf(stderr,"Outbound Packet size:---------- %06d\n", retOpts->spxIIOutboundPacketSize); fprintf(stderr,"SPXII Session Flags: ---------- 0x%04X\n", retOpts->spxIISessionFlags);
t_free((char *)rcvcall, T_CALL); t_free((char *)sndcall, T_CALL); }
{ char *spxDevice = "/dev/nspx"; int spxFd; ipxAddr_t serversAddress; struct t_call *call; SPX_OPTS *ret_Opts; uint16 connectionId; .../* Open an spx device */ if ((spxFd = t_open(spxDevice, O_RDWR, &spxInfo)) <0) { t_error( "t_open failed"); exit(-1); }
/* Bind to dynamic socket */ if ((t_bind(spxFd, NULL, NULL)) < 0) { t_error( "t_bind failed"); exit(-1); }
if ((spxFd=t_open( spxDevice, O_RDWR, &spxInfo))<0) { t_error( "t_open failed" ); ... }
/* Allocate call structure */ if ((call = (struct t_call *)t_alloc(spxFd, T_CALL, T_ALL))==NULL) { t_error( "t_alloc of T_CALL failed"); exit(-1); }
serversAddress = (ipxAddr_t*)call->addr,buf; serversAddress.net[0] = 0x01; serversAddress.net[1] = 0x01; serversAddress.net[2] = 0x03; serversAddress.net[3] = 0x8B; serversAddress.node[0] = 0x00; serversAddress.node[1] = 0x00; serversAddress.node[2] = 0x00; serversAddress.node[3] = 0x00; serversAddress.node[4] = 0x00; serversAddress.node[5] = 0x01; serversAddress.sock[0] = 0xDE; serversAddress.sock[1] = 0xAD;
call->addr.len = call->addr.maxlen call->opt.len = 0; call->opt.buf = NULL;
/* ** We pass the address of the call structure for both the request ** and return fields so that the call->opt.buf field will be filled ** in with the server's information. */ if ((t_connect(spxFd, call, call)) < 0) { t_error( "t_connect failed"); if (t_errno == TLOOK) { lookVal = t_look(spxFd); printLookVal(lookVal); } exit(-1); }
/* ** Upon successful completion, call->opt.buf will have the ** connection identification number of the server. */ ret_Opts = (SPX_OPTS *)call->opt.buf; memcpy(&connectionId, ret_Opts->spx_connectionID, sizeof(connectionId)); fprintf(stderr,"Servers connection ID number: %06d\n", GETINT16(connectionId)); t_free((char *)call, T_CALL); }