maclean
2012-01-31
/*
$Header: tnsapi.c 30-dec-97.22:19:11 scotmac Exp $
*/
/*
NAME
tnsapi - Transport Network Session Application Program Interface.
DESCRIPTION
TNS engine.
PUBLIC FUNCTIONS
tnsapi()
PRIVATE FUNCTIONS
tnsdopen()
tnsdclose()
tnsdsend()
tnsdrecv()
tnsdcntl()
MODIFIED
hnellore 08/14/98 - prt_exception-709339-change tnsapi func decalration un
scotmac 11/18/97 - Handle is ALWAYS allocated on open and deallocated on
mberner 08/21/97 - fixup log information
smckinle 07/08/97 - OSD reference shouldn't be in generic file.
mberner 06/26/97 - fix bug #490613
mberner 06/18/97 - fix bug #491875
mhill 06/12/97 - clean up rcs header
jchangav 09/27/96 - Merged from NETWORK_3.0.2.0.0_SOLARIS_960926
aswang 11/25/96 - porting exception for bug#425421
jgraham 09/23/96 - fix compilation error
jgraham 09/20/96 - bug 355689
jchangav 09/10/96 - Merge NT changes from 3.0.1
*/
/*************************************************************************/
/* Include headers */
/*************************************************************************/
#include
#ifndef TNSAPI_BEFORE_V23
# ifndef SLTS_ORACLE
# include
# endif
#endif
#ifndef SNLSTD
#include
#endif
#ifndef NL
# include
#endif
#ifndef NSI
# include
#endif
#ifndef NSGBL
# include
#endif
#ifndef NNCI
# include
#endif
#ifndef NNFS_ORACLE
# include
#endif
#ifndef NRI
# include
#endif
#ifndef TNSAPI0
# include
#endif
#ifndef TNSAPI
# include
#endif
/*************************************************************************/
/* Local function prototypes */
/*************************************************************************/
/* DISABLE check_naming */
/*
* These are just mirror images of
* tnsopen()
* tnsclose()
* tnssend()
* tnsrecv()
*
* It is for the sake of implementation. We don't want to implement everything
* in just one function. See tns.h for the usage and descriptions of these
* functions.
*/
/*
TNS Do Open: initialize the connection handle
*/
STATICF sword tnsdopen ( /*_ tnshdl **handlep, const text *name _*/ );
/*
TNS Do Close: close the connection handle
*/
STATICF sword tnsdclose(/*_ tnshdl **handlep _*/);
/*
TNS Do Send: send data to the connection handle
*/
STATICF sword tnsdsend(/*_ tnshdl *handle, ub1 *data, size_t *length _*/);
/*
TNS Do Receive: receive data from the conneciton handle
*/
STATICF sword tnsdrecv(/*_ tnshdl *handle, ub1 *data, size_t *length _*/);
/*
TNS Do Cntl: control functions
*/
STATICF sword tnsdcntl VAFP((sword operation, tnshdl *hdl, ... ));
/*
TNS Do init: Initialize the NL global area
*/
STATICF dvoid *tnsdinit(/*_ void _*/);
/*
TNS Do Global Initialization: Initialize TNS API context in NPD global area
*/
STATICF void tnsdingbl(/*_ dvoid *npd, dvoid *gbhp _*/);
/*
TNS Do Terminate: symmetric to tnsdinit()
*/
STATICF void tnsdtrm(/*_ dvoid *npd _*/);
/*
TNS Do global terminate: symmetric to tnsdingbl()
*/
STATICF void tnsdtrgbl(/*_ tnsgblctx ** _*/);
/*************************************************************************/
/* Public Functions */
/*************************************************************************/
/*
TNS API: execute the TNS control operation. This is the TNS engine.
*/
#if defined(A_OSF) || defined(HPUX)
int tnsapi (operation)
int operation;
#else
int tnsapi VAFD((operation VAAELLIPSIS))
int operation VAFDAD
VAFDELLIPSIS
#endif /* A_OSF || HPUX */
{
va_list list;
tnshdl **hdlp;
tnshdl *hdl;
text *name;
sword ret;
ub1 *data;
size_t *len;
sword cmd;
VASTART(list, operation);
/*
* depending on the operation, the number and data type of argements are
* different
*/
switch(operation)
{
case TNSAPIOOPEN:
hdlp = va_arg(list, tnshdl **);
name = (text *)va_arg(list, char *);
/* sanity check. The user should not pass in a NULL tnsp */
if (hdlp)
{
ret = tnsdopen(hdlp, (text *)name);
}
else
{
ret = NULHDL_TNSAPIE;
}
break;
case TNSAPIOCLOSE:
hdlp = va_arg(list, tnshdl **);
/* sanity check. The user should not pass in a NULL tnsp */
if (hdlp)
{
ret = tnsdclose(hdlp);
}
else
{
ret = NULHDL_TNSAPIE;
}
break;
case TNSAPIOSEND:
hdl = va_arg(list, tnshdl *);
data = va_arg(list, ub1 *);
len = va_arg(list, size_t *);
/* sanity check. The user should not pass in a NULL tnsp */
if (hdl)
{
ret = tnsdsend(hdl, data, len);
}
else
{
ret = NULHDL_TNSAPIE;
}
break;
case TNSAPIORECV:
hdl = va_arg(list, tnshdl *);
data = va_arg(list, ub1 *);
len = va_arg(list, size_t *);
/* sanity check. The user should not pass in a NULL tnsp */
if (hdl)
{
ret = tnsdrecv(hdl, data, len);
}
else
{
ret = NULHDL_TNSAPIE;
}
break;
/*
* Added to test listen/anser automatically, should be removed
* in the first release
*/
/* case TNSAPIOLSN:
hdl = va_arg(list, tnshdl *);
if (hdl)
ret = tnsdcntl(TNSAPIOLSN, hdl);
else
ret = NULHDL_TNSAPIE;
break;
*/
/* end of added code */
case TNSAPICTL:
hdl = va_arg(list, tnshdl *);
cmd = va_arg(list, sword);
if (hdl)
{
ret = tnsdcntl(cmd, hdl);
}
else
{
ret = NULHDL_TNSAPIE;
}
break;
default:
/*
* Addtional control function calls, e.g., nonblocking, flushing, will
* be added in future releases.
*/
ret = INVOP_TNSAPIE;
break;
}
va_end(list);
return ((int)ret);
}
/*
*/
STATICF sword tnsdopen(handlep, name)
tnshdl **handlep;
const text *name;
{
tnshdl *hdl = *handlep;
dvoid *npd = NULL; /* NPD global */
dvoid *gbhp = NULL; /* NS per-user global */
size_t addbufl;
size_t canbufl;
sword ecode;
uword retcode = 0;
size_t namelen;
text namebuf[NNCIDNMAX];
text addbuf[NNCIDNMAX];
text canbuf[NNCIDNMAX];
/*
* Allocate the handle.
*/
if ( (hdl = (tnshdl *)snlmalc(1, sizeof(tnshdl))) == (tnshdl *)NULL)
{
return((sword)MALFAIL_TNSAPIE);
}
else
{
CLRSTRUCT(*hdl);
*handlep = hdl;
}
/*
* Check the tnsapi_nlstdgd in NPD global, if it is null, then this is
* the first connection handle of this user. We need
* to allocate the tnsapi global in NPD global area
*/
/*
* Initialization for, e.g. trace in NL global area, and get the NPD
* global
*/
if (!(npd = tnsdinit()) )
{
tnsdtrm(npd);
snlmfre((dvoid *)hdl);
*handlep = (tnshdl *)NULL;
return((sword)NLINIFAIL_TNSAPIE);
}
TNSLOCKMUTEX(npd);
if ( (hdl->gbl_tnshdl = (dvoid *)TNSGCTX(npd)) == NULL)
{
/*
* This is the first connection handle of this user
* so we need to allocate the NPD global
*/
if ( (hdl->gbl_tnshdl = (dvoid *)snlmal(sizeof(tnsgblctx))) == NULL)
{
snlmfre((dvoid *)hdl);
*handlep = (tnshdl *)NULL;
TNSUNLOCKMUTEX(npd);
return ((sword)MALFAIL_TNSAPIE);
}
TNSSCTX(npd, hdl->gbl_tnshdl);
/* Initialize the NS per-user global area, check for errors */
nsgblini(npd, &gbhp, NULLP(nsind));
/* Initialize TNS API global area, check for errors */
tnsdingbl(npd, gbhp);
}
TNSUNLOCKMUTEX(npd);
/* start connection out in blocking mode */
hdl->io_tnshdl = IO_TNSHDL_BLOCKING;
/* enable the tracing */
{
NLTRDEFINE("tnsopen", npd, NLDTTNSAPI, NLDTTDUMMY, NLDTTDUMMY);
NLTRENTER();
/*
* check if this is a client or a server, create the NV binding
* if necessary
*/
if (!name)
{
hdl->svr_tnshdl = TRUE;
hdl->service_tnshdl = NULLP(text);
}
else
{
namelen = strlen((char *)name);
/*
* In the first release, we will specify that listener has to be
* running in order to make a connection. In future enhancement,
* we are going to support the case in which the listener is not
* available. The implementation to accomodate both cases is done
* for the purpose of testing, however.
*
* If name is not NULL, it could be either client or server,
* In the case of a server, name is the listening end point.
*/
/* resolve the NV string */
if ( *name == NLNVBEGDE)
{
/* it is an explicit NVstring, so use it directly */
NLTRUSR((NLTRTRC, "Name is already an NVstring.\n"));
if( (hdl->service_tnshdl = (text *)snlmal(namelen +1))
== (text *)NULL)
{
retcode = MALFAIL_TNSAPIE;
}
else
{
DISCARD strcpy((char *)hdl->service_tnshdl,
(const char *)name);
NLTRUSR((NLTRTRC, "Name is %s.\n", hdl->service_tnshdl));
/*
* in the first release, not null name always indiate that
* this is the client
*/
hdl->svr_tnshdl = FALSE;
}
}
else
{
/* try to resolve it */
if (namelen >= NNCIDNMAX)
{
NLTRFTL((NLTRTRC, "Service name is too long.\n"));
retcode = NMTOOLONG_TNSAPIE;
}
else
{
DISCARD memcpy((dvoid *)namebuf, (const dvoid *)name,
namelen + 1);
if (ecode = nnfsn2a(npd,
namebuf, (size_t)NNCIDNMAX, &namelen,
addbuf, (size_t)NNCIADMAX, &addbufl,
canbuf, (size_t)NNCIDNMAX, &canbufl))
{
/* Signal error, write error into trace steam*/
NLTRFTL((NLTRTRC,
"Failed to resolve service name.\n"));
retcode = NMRESFAIL_TNSAPIE;
}
else
{
if ((hdl->service_tnshdl =
(text *)snlmal(strlen((const char *)addbuf)+1) )
== (text *)NULL)
{
retcode = MALFAIL_TNSAPIE;
}
else
{
DISCARD strcpy((char *)hdl->service_tnshdl,
(const char *)addbuf);
NLTRUSR((NLTRTRC,
"Name is %s.\n", hdl->service_tnshdl));
/*
* in the first release, not null name
* always indiate that this is the client
*/
hdl->svr_tnshdl = FALSE;
}
} /* if nnfsn2a */
} /* if namelen */
} /* if *name == NLNVBEDGE */
} /* if !name */
/* Increase the count in con_tnsgblctx */
if (retcode == 0)
{
TNSLOCKMUTEX(npd);
((tnsgblctx *)(hdl->gbl_tnshdl))->con_tnsgblctx++;
TNSUNLOCKMUTEX(npd);
if ((hdl->res_tnshdl=(tnsres *)snlmal(sizeof(tnsres)))
!= (tnsres *)NULL)
CLRSTRUCT(*(hdl->res_tnshdl));
else
{
retcode = MALFAIL_TNSAPIE;
}
}
if (retcode != 0 )
{
if (hdl->service_tnshdl)
{
snlmfre((dvoid *)hdl->service_tnshdl);
}
snlmfre((dvoid *)hdl);
*handlep = (tnshdl *)NULL;
}
NLTREXIT();
}
return((sword)retcode);
}
/*
* Initialize TNS API context in NPD global area
*/
STATICF void tnsdingbl(npd, gbhp)
dvoid *npd;
dvoid *gbhp;
{
tnsgblctx *ctx;
/* sanity check */
if (npd)
{
ctx = TNSGCTX(npd);
/* This should have been allocated already */
if (ctx)
{
/*
* assign the NS per user global to the corresponding field in ctx
* and initialize the number of open connectins of this user to 0
*/
ctx->gbh_tnsgblctx = (nsgbu *)gbhp;
ctx->con_tnsgblctx = 0;
ctx->npd_tnsgblctx = npd;
}
}
return;
}
/*
* Initialize the NL global area for, e.g., tracing
* return the NPD global pointer
*/
STATICF dvoid *tnsdinit()
{
dvoid *npd = NULL;
size_t curdirl;
serc se;
size_t actesize = 0;
nlstdatt init;
text curdir[TNSAPI_MFN];
text reason[TNSAPI_ERRBUFL];
/* clear the init structure */
CLRSTRUCT(init);
/* initialize parameter files: system and local, trace, ... */
init.mask_nlstdatt = NLSTDATT_SYSPARMS | NLSTDATT_TRACE |
NLSTDATT_PF_ERRORS_OK;
/* system sqlnet.ora */
init.syspdesc_nlstdatt.nlfnsname = (text *)TNSAPI_PFILENAME;
init.syspdesc_nlstdatt.nlfnssize = TNSAPI_PFILENAMEL;
init.syspdesc_nlstdatt.nlfnename = (text *)TNSAPI_PEXT;
init.syspdesc_nlstdatt.nlfnesize = TNSAPI_PEXTL;
/* trace unique */
bis(init.trcdesc_nlstdatt.nlfnflag, NLFNUNIQUE);
/* trace extension */
init.trcdesc_nlstdatt.nlfnename = (text *)TNSAPI_TEXT;
init.trcdesc_nlstdatt.nlfnesize = TNSAPI_TEXTL;
/*
* since we could not distinguish the client and the server at this stage,
* we could not name the client and server trace differently by setting up
* trcdesc_nlstdatt.nlfnsname field. The traces will be distinguished by
* their uniqueness. The default trace file would be: tnsapi.trc_
*/
init.trcdesc_nlstdatt.nlfnsname = (text *)TNSAPI_TFILENAME;
init.trcdesc_nlstdatt.nlfnssize = TNSAPI_TFILENAMEL;
/* default trace file directory is the current directory*/
DISCARD snlfncdir(&se, curdir, sizeof(curdir), &curdirl);
init.trcdesc_nlstdatt.nlfndname = (text *)curdir;
init.trcdesc_nlstdatt.nlfndsize = curdirl;
init.trcparms_nlstdatt[NLSTDGO_TRACE_FILE] = (text *)TNSAPI_TRCFNAME;
init.trcparms_nlstdatt[NLSTDGO_TRACE_DIR] = (text *)TNSAPI_TRCDNAME;
init.trcparms_nlstdatt[NLSTDGO_TRACE_LEVEL] = (text *)TNSAPI_TRCLEVEL;
#ifndef TNSAPI_BEFORE_V23
/* by default, it is thread safe */
init.threadsafe_nlstdatt = NLSTDATT_THREAD_SAFE;
#endif
if (nlstdgg(&npd, &init, reason, TNSAPI_ERRBUFL, &actesize))
{
return ((dvoid *)0);
}
return(npd);
}
/*
* Close the tns connection, reset the tns api handle.
*/
STATICF sword tnsdclose(handlep)
tnshdl **handlep;
{
tnshdl *hdl = *handlep;
tnsgblctx *ctx;
dvoid *npd;
/* sanity check */
if (hdl)
{
if (! (ctx = (tnsgblctx *)hdl->gbl_tnshdl))
{
return((sword)HDLUNINI_TNSAPIE);
}
npd = ctx->npd_tnsgblctx;
{
NLTRDEFINE("tnsclose", npd, NLDTTNSAPI, NLDTTDUMMY, NLDTTDUMMY);
NLTRENTER();
/*
* check if the connections is open.
*/
if (hdl->cxd_tnshdl)
{
/* close down this connection, and reset cxd_tnshdl */
DISCARD nsdisc(hdl->cxd_tnshdl, NSFIMM);
snlmfre((dvoid *)hdl->cxd_tnshdl);
hdl->cxd_tnshdl = (nscxd *)NULL;
}
/*
* free up the memory: service, error stack
*/
if (hdl->service_tnshdl)
snlmfre((dvoid *)hdl->service_tnshdl);
if (hdl->res_tnshdl)
snlmfre((dvoid *)hdl->res_tnshdl);
/*
* If tnsopen() succeeded but the first tnssend()/tnsrecv()
* failed, nsgbltrm(), nlstdstp() still need to be called.
*/
/* We will get a ctx back if tnsopen() succeeded */
TNSLOCKMUTEX(npd);
/* if there are other open connections of this user */
if (--ctx->con_tnsgblctx >= 0)
{
/* if this is the last open connection of this user */
if (ctx->con_tnsgblctx == 0)
{
/* Terminate NS per user global context */
nsgbltrm((dvoid *)ctx->gbh_tnsgblctx);
/* Reset the global area of TNS API in nlstdgd */
TNSSCTX(ctx->npd_tnsgblctx, NULL);
/* Terminate TNS API global context */
tnsdtrgbl((tnsgblctx **)(&(hdl->gbl_tnshdl)));
NLTREXIT();
/* Shutdown the NL facilities initialized with nlstdgg() */
tnsdtrm(npd);
npd = 0;
}
/* this is not the last open connection */
else
{
/* only decrease the global counter of pointers to
the NPD global */
nlstdtrm(&(ctx->npd_tnsgblctx));
NLTREXIT();
}
}
if (npd)
TNSUNLOCKMUTEX(npd);
/*
* Free the handle and reset
*/
snlmfre((dvoid *)hdl);
*handlep = (tnshdl *)NULL;
}
return(0);
}
}
/*
* call nlstdstp, symmetric to nlstdgg() in tnsdinit()
*/
STATICF void tnsdtrm(npd)
dvoid *npd;
{
nlstdstp(npd);
return;
}
/*
* Free up the memory, reset the pointer
*/
STATICF void tnsdtrgbl(tnsgbl)
tnsgblctx **tnsgbl;
{
snlmfre((dvoid *)(*tnsgbl));
*tnsgbl = (tnsgblctx *)NULL;
return;
}
/*
* Send data over the handle. Connection is first establised
* on the client side before data is sent. It is an error for
* the server to call tnssend() right after tnsopen()
*/
STATICF sword tnsdsend(hdl, data, length)
tnshdl *hdl;
ub1 *data;
size_t *length;
{
tnsgblctx *ctx = (tnsgblctx *)hdl->gbl_tnshdl; /* TNS API global context */
nscxd *cxd; /* NS context */
text *address = hdl->service_tnshdl; /* service name */
tnsres *tres = hdl->res_tnshdl; /* error stack */
dvoid *gbhp; /* NS per user global */
dvoid *npd; /* NPD global */
sword retcode = 0;
/* if the global handle has not been allocated, can not call this
function */
if ( ctx == (tnsgblctx *)NULL)
{
/* Signal error, write error message into trace stream */
return((sword)HDLUNINI_TNSAPIE);
}
gbhp = (dvoid *)ctx->gbh_tnsgblctx;
npd = ctx->npd_tnsgblctx;
{
NLTRDEFINE("tnssend", npd, NLDTTNSAPI, NLDTTDUMMY, NLDTTDUMMY);
NLTRENTER();
/*
* if this is the first call to tnssend(), no cxd has been
* allocated yet
*/
if ( hdl->cxd_tnshdl == (nscxd *)NULL)
{
/*
* Check if this is the client or the server,
* Client: try to establish the connection
* Server: it is an error since server must first call tnsrecv()
*/
if ( !hdl->svr_tnshdl )
{
/* This is the client */
if ((cxd = (nscxd *)snlmal(sizeof(nscxd))) == (nscxd *)NULL)
{
retcode = MALFAIL_TNSAPIE;
}
else
{
nsinfo info;
nscnd cndo, cndi;
text buf[TNSAPI_CONBUFL];
buf[0] = '';
/*
* initialize the structures: cxd, tres
*/
CLRSTRUCT(*cxd);
CLRSTRUCT(info);
CLRSTRUCT(cndo);
CLRSTRUCT(cndi);
NSSETCND(&cndo, address);
NSINICND(&cndi, buf, sizeof(buf));
NSINFENABLENA(&info);
/* making connection, with routing */
if (nricall(gbhp,
cxd,
&cndo,
&cndi,
&info,
&(cxd->nscxdres)) nscxdres
* snlmfre((dvoid *)cxd);
*/
NLTRUSR((NLTRTRC, "Client connect request failed.\n"));
CPSTRUCT(tres->ns_tnsres, cxd->nscxdres);
snlmfre((dvoid *)cxd);
retcode = tres->res_tnsres = CONFAIL_TNSAPIE;
}
else
{
hdl->cxd_tnshdl = cxd;
}
}
} /* if !hdl->svr_tnshdl */
else
{
/*
* I am the server
* server should NOT call tnsapi_send() until the connection is
* established.
* write the error message in to trace stream
* set (tnsres *res) to indicate the error
*/
NLTRUSR((NLTRTRC,
"Server should call tnsrecv() first to establish connection.\n"));
retcode = tres->res_tnsres = INVSVROP_TNSAPIE;
}
}
/* Set connection into nonblocking mode if it has been requested
by a call before the connection was actually established -
the default was blocking */
if (!retcode && (hdl->io_tnshdl == IO_TNSHDL_NONBLOCKING))
{
retcode = tnsdcntl(TNSAPICNONBLOCKING, hdl);
}
if ( !retcode )
{
/*
* Connection has been established, client/server wants to
* send data. Flush the data to transport, since the
* default flush mode in NS is not flushing on send
*/
if ((retcode =
nssend(hdl->cxd_tnshdl, NSWDATA, data, length, NSFFLUSH))
!= 0)
{
if (hdl->cxd_tnshdl->nscxdres.nsresns == NSEWOULDBLOCK)
{
/* we're in nonblocking mode and would block... */
retcode = tres->res_tnsres = WOULDBLOCK_TNSAPIE;
}
else
{
/*
* Send failed, set the TNS API error and the NS error
*/
NLTRUSR((NLTRTRC, "Underlying send command failed.\n"))
retcode = tres->res_tnsres = SDFAIL_TNSAPIE;
}
CPSTRUCT(tres->ns_tnsres, hdl->cxd_tnshdl->nscxdres);
}
}
NLTREXIT();
}
return(retcode);
}
/*
* Receive data over connection handle. Connection is first established
* on the server side before data is received. It is an error for the
* client to call tnsrecv() after tnsopen().
*/
STATICF sword tnsdrecv(hdl, data, length)
tnshdl *hdl;
ub1 *data;
size_t *length;
{
tnsgblctx *ctx = (tnsgblctx *)hdl->gbl_tnshdl; /* TNS API global context */
nscxd *cxd; /* NS context */
text *address = hdl->service_tnshdl; /* service name */
tnsres *tres = hdl->res_tnshdl; /* error stack */
dvoid *gbhp; /* NS per user global */
sword retcode = 0;
dvoid *npd; /* NPD global */
ub1 what;
/* if the global handle has not been allocated, can't call this function */
if ( ctx == (tnsgblctx *)NULL)
{
/* Signal error, write error message into trace stream */
return((sword)HDLUNINI_TNSAPIE);
}
gbhp = (dvoid *)ctx->gbh_tnsgblctx;
npd = ctx->npd_tnsgblctx;
{
NLTRDEFINE("tnsrecv", npd, NLDTTNSAPI, NLDTTDUMMY, NLDTTDUMMY);
NLTRENTER();
/*
* if this is the first call to tnsrev(), no cxd has been allocated yet
*/
if ( hdl->cxd_tnshdl == (nscxd *)NULL)
{
/*
* Check if this is the client or the server,
* Server: try to establish the connection.
* Client: it is an error since client must first call tnssend()
*/
if ( hdl->svr_tnshdl )
{
/* This is the server */
if ((cxd = (nscxd *)snlmalc(1, sizeof(nscxd)))==(nscxd *)NULL)
{
retcode = MALFAIL_TNSAPIE;
}
else
{
nsinfo info;
CLRSTRUCT(info);
NSINFENABLENA(&info);
/*
* In the first release, we will require the user
* to have listener up and and running in order to
* user this API. In the future releases, we are
* going to support the situation in which
* listener is not present. However, for the sake
* of testing, implementations for both cases have
* been done.
*/
if (address)
{
#ifdef NEVER
/* removed to improve coverage, can't be executed... */
/* Since address is not NULL, this is the listening
endpoint */
nscnd cnda;
nscxd lsncxd;
CLRSTRUCT(cnda);
NSSETCND(&cnda, address);
if (nslisten(gbhp,
&lsncxd,
&cnda,
&info,
NULLP(nsres)) nscxdres
*/
NLTRUSR((NLTRTRC,
"Server failed to listen for connection request.\n"));
/*
* though this is actually the error for
* failing to listen it is still put into
* tres just in case we want to check it
* later on
*/
CPSTRUCT(tres->ns_tnsres, lsncxd.nscxdres);
retcode = tres->res_tnsres = LSNFAIL_TNSAPIE;
}
/* nslisten succeed */
else if (nsanswer(gbhp, cxd, NULLP(nscnd), &info,
NULLP(nsres), &lsncxd) nscxdres
*/
NLTRUSR((NLTRTRC,
"Server failed to answer to connection request.\n"));
CPSTRUCT(tres->ns_tnsres, cxd->nscxdres);
DISCARD nsdisc(&lsncxd, 0);
retcode = tres->res_tnsres = ANSFAIL_TNSAPIE;
}
#endif
}
/* inherit connection from listener */
else
{
/*
* Inherit the connection from the listener
*/
if (nsinherit(gbhp,
cxd,
NULLP(nscnd),
NULLP(nscnd),
&info,
NULLP(nsres)) nscxdres
*/
NLTRUSR((NLTRTRC,
"Server failed to inherit the connection from the listener.\n"));
CPSTRUCT(tres->ns_tnsres, cxd->nscxdres);
retcode = tres->res_tnsres = INHFAIL_TNSAPIE;
}
} /* if (address) */
if (nsaccept(cxd, NULLP(nscnd)) != 0)
{
/*
* server failed in accepting connection.
* Set tres from cxd->nscxdres
*/
NLTRUSR((NLTRTRC,
"Server failed to accept the connection request.\n"));
CPSTRUCT(tres->ns_tnsres, cxd->nscxdres);
retcode = tres->res_tnsres = ACPTFAIL_TNSAPIE;
DISCARD nsdisc(cxd, 0);
}
else
{
hdl->cxd_tnshdl = cxd;
}
} /* malloc cxd */
} /* if (hdl->svr_tnshdl) */
else
{
/*
* This is the client. Client must NOT call tnsrecv()
* after tnsopen() Signal error and write error info
* into trace stream.
*/
NLTRUSR((NLTRTRC,
"Client should call tnssend() first to establish connection.\n"));
retcode = tres->res_tnsres = INVCLIOP_TNSAPIE;
}
} /* if (cxd_tnshdl == NULL) */
/* Set connection into nonblocking mode if it has been requested
by a call before the connection was actually established -
the default was blocking */
if (!retcode && (hdl->io_tnshdl == IO_TNSHDL_NONBLOCKING))
{
retcode = tnsdcntl(TNSAPICNONBLOCKING, hdl);
}
/* if no error so far */
if ( !retcode )
{
/*
* Connections has been established. Just receive the data
*/
if ((retcode = nsrecv(hdl->cxd_tnshdl, &what, data, length, 0))
!= 0)
{
if (hdl->cxd_tnshdl->nscxdres.nsresns == NSEWOULDBLOCK)
{
/* we're in nonblocking mode and would block... */
retcode = tres->res_tnsres = WOULDBLOCK_TNSAPIE;
}
else
{
/*
* Receive failed, set up the tres from cxd->nscxdres;
*/
NLTRUSR((NLTRTRC, "Underlying receive command failed.\n"));
retcode = tres->res_tnsres = RECVFAIL_TNSAPIE;
}
CPSTRUCT(tres->ns_tnsres, hdl->cxd_tnshdl->nscxdres);
}
}
NLTREXIT();
}
return(retcode);
}
/*
* In the first release, only the control operation to return the error
* status will be implemented. However, this could be easily extended.
*/
STATICF sword tnsdcntl VAFD((opcode, hdl VAAELLIPSIS))
sword opcode VAFDAD
tnshdl *hdl VAFDAD
VAFDELLIPSIS
{
tnsgblctx *ctx = (tnsgblctx *)hdl->gbl_tnshdl; /* TNS API global context */
va_list varp;
sword retcode = 0;
dvoid *npd;
dvoid *gbhp; /* NS per user global */
tnsres *tres = hdl->res_tnshdl; /* error stack */
ub2 opt;
/* if the global handle has not been allocated, cannot call this
function */
if ( ctx == (tnsgblctx *)NULL)
{
/* Signal error, write error message into trace stream */
return((sword)HDLUNINI_TNSAPIE);
}
gbhp = (dvoid *)ctx->gbh_tnsgblctx;
npd = ctx->npd_tnsgblctx;
{
NLTRDEFINE("tnscontrol", npd, NLDTTNSAPI, NLDTTDUMMY, NLDTTDUMMY);
NLTRENTER();
/*
* The handle must have been allocated already.
*/
VASTART(varp, hdl);
switch(opcode)
{
/* this is for future enhancement, take out in first release */
/*
case TNSAPIOLSN:
hdl->svr_tnshdl = TRUE;
break;
*/
case TNSAPICNONBLOCKING:
if (hdl->cxd_tnshdl)
{
/* if we're connected, do this now. Else, just set the
"nonblocking" flag and this will be implicitly done
first time we get connected */
opt = NSLDONTBLOCK;
if (nscontrol(hdl->cxd_tnshdl, NSCSETL, (dvoid *)&opt) != 0)
{
NLTRUSR((NLTRTRC, "Failed to set nonblocking mode\n"));
CPSTRUCT(tres->ns_tnsres, hdl->cxd_tnshdl->nscxdres);
retcode = tres->res_tnsres = CTLFAIL_TNSAPIE;
}
}
hdl->io_tnshdl = IO_TNSHDL_NONBLOCKING;
break;
case TNSAPICBLOCKING:
if (hdl->cxd_tnshdl)
{
opt = NSLDONTBLOCK;
if (nscontrol(hdl->cxd_tnshdl, NSCCLRL, (dvoid *)&opt) != 0)
{
NLTRUSR((NLTRTRC, "Failed to set blocking mode\n"));
CPSTRUCT(tres->ns_tnsres, hdl->cxd_tnshdl->nscxdres);
retcode = tres->res_tnsres = CTLFAIL_TNSAPIE;
}
}
hdl->io_tnshdl = IO_TNSHDL_BLOCKING;
break;
default:
/*
* All the other control functions won't be implemented in
* the first release.
*/
retcode = hdl->res_tnshdl->res_tnsres = INVCTL_TNSAPIE;
break;
}
va_end(varp);
NLTREXIT();
}
return(retcode);
}
/* ENABLE check_naming */