t_connect(3xti_spx)


t_connect -- establish a connection with an SPX/SPXII server application at a specified destination

Synopsis

#include "spx_app.h" 

int t_connect ( int spxFd, struct t_call *sndcall, struct t_call *rcvcall )

Parameters

(IN) spxFd
Passes the file descriptor of the local transport endpoint.

(IN) sndcall
Passes a pointer to a t_call structure that contains the IPX(TM) address of the server to which the SPX/SPXII client wants to connect. If spxFd is an SPXII /dev/nspx2 file descriptor, then the sndcall structure can contain an option structure (SPX2_OPTIONS) to change the current options.

(IN) rcvcall
Passes a pointer to a t_call structure that will contain the server's connection information upon successful completion of the call.

(OUT) rcvcall
Receives the server's connection information: network address, node address, socket number, connection ID, and allocation number. If spxFd is an SPXII /dev/nspx2 file descriptor, then the rcvcall structure will contain an option structure (SPX2_OPTIONS) with the current options.

Return values

0
Successful

-1
Unsuccessful
The SPXII driver tries to connect with the remote transport endpoint. After trying a given number of times without receiving an acknowledgment, the SPXII driver generates a disconnection indication of TLI_SPX_CONNECTION_FAILED (refer to t_rcvdis). If this error occurs, the state of the stream is set to T_IDLE.

See t_connect(3xti) and ``Programming with the X/Open Transport Interface (XTI)'' for other possible errors.

Remarks

A client SPX/SPXII application uses the t_connect call to request a connection to an SPX/SPXII server application at a specified destination. This call may be executed in either synchronous or asynchronous mode.

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:

The 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.

Example 1

   { 
      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); }

Example 2

   { 
      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); }

State

The state after a successful connection establishment is T_DATAXFER for both the client and server. The state after an unsuccessful connection establishment is T_IDLE.

References

t_accept(3xti_spx), t_connect(3xti), t_listen(3xti_spx), t_open(3xti_spx), t_optmgmt(3xti_spx), t_sndrel(3xti_spx)
30 January 1998
© 1998 The Santa Cruz Operation, Inc. All rights reserved.