/* $Header: /netrcs/RCS/oracle/network/tns/tnsapi/RCS/tnsapifd.c,v 1.2 1995/09/11 21:49:37 mhill Exp $ */ /* Copyright (c) 1995 by Oracle Corporation. All rights reserved. */ /* NAME tnsapifd - SQL*Net Open - finger server ("daemon") demo */ /* This demo implements a simple "finger" server to work with the finger client program in tnsapifc.c, using the SQL*Net Open API. This server is implemented for Unix and was tested on Solaris - it simply invokes the finger program. If you're not on Unix, you may want to implement something analogous to this using this program as a template. */ #ifdef WIN32 #include #endif #include /* For non-Solaris operating systems you may need to change this pathname */ #define TNSAPIFD_FINGER_PROGRAM "finger.exe" static short get_string_length(); char **build_arg_array(); static void free_arg_array(); #ifdef WIN32 int main(argc, argv) int argc; char **argv; { void *handle = 0; /* connection handle I get from tnslsnr */ char reply[256]; /* work buffer */ char *work; /* pointer into work buffer */ int rc = 0; int length, rcvd, sent = 0; HANDLE hPipeRead, hPipeWrite ; /* read/write handle for pipe */ SECURITY_ATTRIBUTES stSecAttrib ; /* pick up connection from tnslsnr (service name is null because we're on server side */ rc = tnsopen(&handle, (const char *)0); if (rc) goto error; /* set security attributes for pipe */ stSecAttrib.nLength = sizeof(SECURITY_ATTRIBUTES) ; stSecAttrib.bInheritHandle = TRUE ; stSecAttrib.lpSecurityDescriptor = NULL ; /* read and process the argument string. we get this in two pieces. first read four bytes, which gives us enough information to get the length of the argument list - then read the argument list */ length = 4; work = reply; while(length) { rcvd = length; rc = tnsrecv(handle, work, &rcvd); if (rc) goto error; length -= rcvd; work += rcvd; } length = (int)get_string_length(reply); memset(reply, 0, sizeof(reply)) ; work = reply; /* now read the argument string into the reply buffer */ while(length) { rcvd = length; rc = tnsrecv(handle, work, &rcvd); if (rc) goto error; length -= rcvd; work += rcvd; } /* create a pipe to communicate with child process */ if(! CreatePipe(&hPipeRead, &hPipeWrite, &stSecAttrib, 0) ) goto error ; /* start the child process - finger.exe */ if(! SpawnChild(reply, hPipeWrite)) goto error ; Sleep(1000) ; /* close write handle */ if(! CloseHandle(hPipeWrite)) goto error ; /* read from child through pipe */ memset(reply, 0, sizeof(reply)) ; while (TRUE) { if(! ReadFile(hPipeRead, reply, sizeof(reply), &rcvd, NULL)) { rc = GetLastError() ; break ; } if(!rcvd) break ; while (rcvd) { sent = rcvd; rc = tnssend(handle, reply, &sent); if (rc) goto error; rcvd -= sent; } } rc = tnsclose(&handle); if (rc) goto error; /* done */ return(0) ; error: if (rc) { if (rc != RECVFAIL_TNSAPIE) (void) printf("error code %d\n", rc); } else { perror("sfingerd"); } exit(1); } BOOL SpawnChild(char *args, HANDLE hPipeWrite) { PROCESS_INFORMATION stProcInfo ; STARTUPINFO stStartInfo ; char szCmd[256] ; stStartInfo.cb = sizeof(STARTUPINFO) ; stStartInfo.lpReserved = NULL ; stStartInfo.lpReserved2 = NULL ; stStartInfo.cbReserved2 = 0 ; stStartInfo.lpDesktop = NULL ; stStartInfo.dwFlags = STARTF_USESTDHANDLES ; stStartInfo.hStdOutput = hPipeWrite ; stStartInfo.hStdError = hPipeWrite ; memset(szCmd, 0, sizeof(szCmd)) ; sprintf(szCmd, "%s %s", TNSAPIFD_FINGER_PROGRAM, args) ; return CreateProcess( NULL, szCmd, /* command line */ NULL, /* security */ NULL, /* main thread security */ TRUE, /* inherit handles */ 0, /* creation flags */ NULL, /* use parent env */ NULL, /* use parent current dir */ &stStartInfo, &stProcInfo ) ; } #else /* WIN32 */ int main(argc, argv) int argc; char **argv; { void *handle; /* connection handle I get from tnslsnr */ char reply[256]; /* work buffer */ char *work; /* pointer into work buffer */ int rc = 0; int p[2]; int length, rcvd, sent = 0; char **args; /* pick up connection from tnslsnr (service name is null because we're on server side */ rc = tnsopen(&handle, (const char *)0); if (rc) goto error; if (pipe(p)) goto error; /* read and process the argument string. we get this in two pieces. first read four bytes, which gives us enough information to get the length of the argument list - then read the argument list */ length = 4; work = reply; while(length) { rcvd = length; rc = tnsrecv(handle, work, &rcvd); if (rc) goto error; length -= rcvd; work += rcvd; } length = (int)get_string_length(reply); *reply = '\0'; work = reply; /* now read the argument string into the reply buffer */ while(length) { rcvd = length; rc = tnsrecv(handle, work, &rcvd); if (rc) goto error; length -= rcvd; work += rcvd; } switch(fork()) { case 0: /* this is the forked off process (actual finger program) */ /* dup my stdout onto the pipe so that the parent process can read it */ (void) close(p[0]); (void) dup2(p[1], 1); (void) close(p[1]); /* build an array of arguments out of the string we read */ args = build_arg_array(reply); args[0] = TNSAPIFD_FINGER_PROGRAM; if (execv(TNSAPIFD_FINGER_PROGRAM, args) < 0) perror("execv"); free_arg_array(args); exit(0); case -1: goto error; default: /* this is the parent process, read output from finger and send it */ (void) close(p[1]); while ((rcvd = read(p[0], reply, sizeof(reply)) ) > 0 && rcvd) { while (rcvd) { sent = rcvd; rc = tnssend(handle, reply, &sent); if (rc) goto error; rcvd -= sent; } } rc = tnsclose(&handle); if (rc) goto error; exit(0); } error: if (rc) { if (rc != RECVFAIL_TNSAPIE) (void) printf("error code %d\n", rc); } else { perror("sfingerd"); } exit(1); } #endif /* WIN32 */ /* get length of the argument list to be read from first four bytes of the data that was read. This is the counterpart to build_arg_string in tnsapifc.c */ static short get_string_length(buf) char *buf; { char *work = buf; short one; short result; char *resultb = (char *)&result; memcpy(&one, buf, 2); if (one == 1) { /* same data representation */ memcpy(&result, buf + 2, 2); return(result); } else { /* swap bytes */ *(resultb) = *(buf + 3); *(resultb + 1) = *(buf + 2); return(result); } } char **build_arg_array(buf) char *buf; { char **array; char *work = buf; int entry = 0; /* allocate "enough" space, not actually sure how many entries we have */ #define max_arguments 10 array = (char **)malloc(4 * max_arguments); entry++; /* reserve first slot for program name */ if (*work) { array[entry++] = work++; /* set up first pointer */ } else { array[entry] = (char *)0; return(array); } for (; *work; ) { if (*work == ' ') { *work++ = '\0'; array[entry++] = work; } else { work++; } } array[entry] = (char *)0; return(array); } void free_arg_array(args) char **args; { free(args); return; }