/* $Header: tnsapi.c 30-dec-97.22:19:11 scotmac Exp $ */ /* Copyright (c) 1995, 1996, 1997 by Oracle Corporation. All rights reserved. */ /* 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] = '\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)) < 0) { /* * write error to trace * error handling, setup the error stack * (tnsres *res) from cxd->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)) < 0) { /* * listen failed. * write error into trace stream * set up tres from cxd->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) < 0) { /* * answer failed * set up tres from cxd->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)) < 0 ) { /* * server failed in inheriting connection * from listener set tres error stack from * cxd->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 */