home *** CD-ROM | disk | FTP | other *** search
- //
- // This program is an example of an Open Data Services application. It accepts
- // requests from clients to execute stored procedures either as language
- // events or as remote stored procedure calls.
- // It may also be invoked using the Service Control Manager.
- //
-
- #include <stdlib.h>
- #include <stdio.h>
- #include <conio.h>
- #include <string.h>
- #include <ctype.h>
- #include <process.h>
- #include <srv.h>
-
- #define VERSION "6.00.01"
-
- // Globals
- //
- BOOL SrvCtrMan;
- HANDLE hServerDone;
- SRV_SERVER * gblServer = NULL;
- DBCHAR * szRegistryName = "PROCSRV"; // Default registry name
-
- SERVICE_STATUS_HANDLE NTBServiceHandle;
- CRITICAL_SECTION SCMCrtSec;
- SERVICE_STATUS NTBServiceStatus;
-
-
- // Syscharsets query from DBLIB 4.2 NT clients
- //
- #define SERVER_INFO_QUERY "exec sp_server_info 18"
-
- // Define some user message codes.
- //
- #define SRV_MAXERROR 20000
- #define SP_UNKNOWN SRV_MAXERROR + 1
- #define INVALID_SP_SYNTAX SRV_MAXERROR + 2
- #define BAD_SP_PARAMETER SRV_MAXERROR + 3
- #define BROADCAST SRV_MAXERROR + 4
- #define EXEC SRV_MAXERROR + 5
-
- // Miscellaneous defines used by sp-handling routines.
- //
- #define EXEC_CMD "exec"
- #define MAXNAME 31
- #define MAXLEN 80
- #define MAXPARAMS 4
- #define VALUE 0x0000
- #define REFERENCE 0x0001
- #define CMDSTR 7
- #define BUF_SIZE 2048
- #define XBASE_HDR_SIZE 32
- #define XBASE_MAX_COLUMNS 128
-
- // Standard error macro for reporting API errors
- //
- #define SETERROR( api, retstring ) \
- sprintf(retstring,"%s: Error %d from %s on line %d\n", \
- __FILE__, GetLastError(), api, __LINE__);
-
- // Event handlers for SP requests.
- //
- SRVRETCODE proclist(); // List SP associated with Server
- SRVRETCODE sp_exec(); // Execute the specified command string
- SRVRETCODE diskfree(); // Return the space on a given drive
- SRVRETCODE disklist(); // List available drives and their space
- SRVRETCODE scan_xbase(); // Open and read an xBase file
-
- // Stored Procedure parameter information structure.
- //
- typedef struct sp_params {
- DBCHAR name[MAXNAME]; // Parameter name
- int type; // Parameter data type
- DBINT length; // Parameter type length
- int status; // Parameter return status
- DBCHAR defaultvalue[MAXLEN *10];// Optional default value
- } SP_PARAMS;
-
- // Stored Procedure information structure.
- //
- typedef struct sp_info {
- DBCHAR name[MAXNAME]; // Procedure name
- DBCHAR usage[MAXLEN]; // Usage string
- int numparams; // Number of parameters
- SP_PARAMS params[MAXPARAMS]; // Parameter array
- SRVRETCODE (*handler)(VOID *, ...); // Pointer to function with variable arguments
- } SP_INFO;
-
- // Array of Stored Procedure handlers.
- //
- SP_INFO Sps[] =
- {
- "proclist",
- "usage: proclist",
- 0,
- {
- 0
- },
- proclist,
-
- "sp_exec", // Procedure name
- "usage: sp_exec <[@command =] command string>", // Procedure usage
- 1, // Number of parameters
- { // Parameter definitions
- "command", // Parameter name
- SRVCHAR, // Parameter type
- MAXLEN, // Parameter length (0 if fixed)
- VALUE, // Pass by value
- "dir *.*", // Default parameter value
- },
- sp_exec, // Procedure function pointer
-
- "disklist",
- "usage: disklist ",
- 0,
- {
- 0
- },
- disklist,
-
- "diskfree",
- "usage: diskfree <[@drive =] drive letter> [,] <[@space =] free space>",
- 2,
- {
- "drive",
- SRVCHAR,
- 1,
- VALUE, // pass by value
- "c",
-
- "space",
- SRVINT4,
- 8,
- REFERENCE, // pass by reference
- "0",
- },
- diskfree,
-
- "scan_xbase", // rpc name
- "usage: scan_xbase <[@file_name =] xbase file name>", // rpc usage
- 1, // number of parameters
- { // parameter definitions
- "file_name", // parameter name
- SRVCHAR, // parameter type
- MAXLEN, // parameter length (0 if fixed)
- VALUE, // pass by value
- "\\sql\\opends\\samples\\procsrv\\build\\sales.dbf", // default parameter value
- },
- scan_xbase, // rpc function pointer
-
- };
-
- #define Rpcnumber sizeof(Sps) / sizeof(SP_INFO)
-
- // Other function prototypes
- //
- void main( int argc, char **argv );
- void WINAPI ProcSrvMain( DWORD argc, char *argv[] );
- void initsignal( SRV_SERVER *, char * );
- void ctrlc_hndl( ULONG );
- void WINAPI NTBServiceCtrlHandler( DWORD );
- void completesignal( SRV_SERVER * );
- void NTBShutdown( LPVOID );
- char * get_last_error_str();
-
- SRVRETCODE chk_err( SRV_SERVER * server,
- SRV_PROC * srvproc,
- int srverror,
- BYTE severity,
- BYTE state,
- int oserrnum,
- DBCHAR * errtext,
- int errtextlen,
- DBCHAR * oserrtext,
- int oserrtextlen );
-
- SRVRETCODE init_remote(SRV_PROC * srvproc);
-
- SRVRETCODE init_server(SRV_SERVER * server);
-
- SRVRETCODE sp_execute(SRV_PROC * srvproc);
-
- SRVRETCODE exit_remote(SRV_PROC *srvproc);
-
- SRVRETCODE lang_execute(SRV_PROC *srvproc);
-
- // Miscellaneous prototypes for sp language events
- //
- SRVRETCODE lang_parser(SRV_PROC *srvproc, SP_INFO **sp,
- DBCHAR paramvalues[MAXPARAMS][MAXLEN]);
-
- DBCHAR *scan_next(DBCHAR *string, DBCHAR *word);
-
-
- // =================================== main ==================================
- //
- void main( int argc, char *argv[] )
- {
- SERVICE_TABLE_ENTRY DispatchTable[] =
- {
- "ProcSrv", ProcSrvMain,
- NULL, NULL
- };
-
- // Assume ProcSrv.exe was started from the Service Control Manager or
- // SQL Service Manager.
- //
- SrvCtrMan = TRUE;
-
- // Check for command line arguments. The following command line arguments
- // are supported:
- //
- // -c Procsrv was started from the command line. Avoids the timeout
- // delay when an attempt is made to start procsrv as a service.
- //
- // -r<registry key name>
- // Look in Registry under the <registry key name> for the ListenOn
- // values. Also assumes procsrv.exe was started from command line.
- //
- // -? Displays the command usage information.
- //
- if( argc > 2 )
- goto Usage;
-
- if( argc == 2 )
- {
- if( !strcmp(argv[1], "-?") )
- goto Usage;
-
- if( !stricmp(argv[1], "-c") )
- SrvCtrMan = FALSE;
- else if( strlen(argv[1]) < 3 )
- goto Usage;
- else if( !strnicmp(argv[1], "-r", 2) )
- {
- szRegistryName = argv[1] + 2;
- SrvCtrMan = FALSE;
- }
- else
- goto Usage;
- }
-
- if( SrvCtrMan )
- {
- // Now we will attempt to start the ProcSrv.exe as a service. The attempt
- // will time out if this process was started from the command line.
- // StartServiceCtrlDispatcher does not return until after ProcSrv has stopped.
- // The ProcSrvMain is called from Service Control Manager within
- // the context of the same process.
- //
- if( StartServiceCtrlDispatcher(DispatchTable) )
- {
- _flushall();
- return;
- }
- }
-
- // The service was started from the command line or the attempt to
- // start the service failed. We can assume that this process
- // was started from the command line.
- //
- SrvCtrMan = FALSE;
- ProcSrvMain( argc, argv );
- return;
-
- Usage:
- printf( "Usage: procsrv [-c] | [-r<registry key name>] | [-?]\n"
- " -c Procsrv was started from the command line\n"
- " -r Look in Registry under <registry key name> for ListenOn values\n"
- " -? Displays this help message\n" );
- }
-
-
- // ================================== ProcSrvMain ============================
- //
- void WINAPI ProcSrvMain( DWORD argc, char *argv[] )
- {
- SRV_CONFIG * config; // The configuration structure
- DWORD dwPathLength;
- char szPath[1024];
- char szLogBuffer[1024];
-
- if( !SrvCtrMan )
- {
- printf( "\nProcedure Server, Copyright 1994, Microsoft\n" );
- printf( " version: %s\n\n", VERSION );
- }
-
- // Allocate a configuration structure that is used to initialize
- // the Open Data Services application
- //
- config = srv_config_alloc();
-
- // Allow 20 connections at a time.
- //
- srv_config(config, (DBINT)SRV_CONNECTIONS, "20", SRV_NULLTERM);
-
- // Set the log file.
- //
- // Get the path of this process. We'll use it to constuct the path of the
- // log file.
- //
- szPath[0] = '\0';
- dwPathLength = GetModuleFileName( GetModuleHandle(NULL),
- szPath,
- sizeof(szPath) );
-
- // Stip off process name (i.e. "ProcSrv.exe")
- //
- while( dwPathLength > 1 )
- {
- --dwPathLength;
- if( szPath[dwPathLength] == '\\' || szPath[dwPathLength] == ':' )
- {
- dwPathLength++;
- szPath[dwPathLength] = '\0'; // Null terminate after back slash
- break;
- }
- }
-
- // Append "<registryname>.log" to path
- //
- strcat( szPath, szRegistryName );
- strcat( szPath, ".log" );
-
- srv_config(config, (DBINT)SRV_LOGFILE, szPath, SRV_NULLTERM);
-
- // All data source strings will be converted from ANSI to the OEM codepage
- // in order to make this application behave like SQL Server.
- //
- srv_config(config, (DBINT)SRV_ANSI_CODEPAGE, "FALSE", SRV_NULLTERM);
-
- // Install the error handler.
- //
- srv_errhandle(chk_err);
-
- // Initialize Procedure Server and save the server handle
- // so it can be used in later functions.
- //
- gblServer = srv_init(config, szRegistryName, SRV_NULLTERM);
-
- if( gblServer == NULL )
- {
- printf( "\nUnable to initialize Procedure Server. "
- "Check Event Log.\n" );
- goto Exit;
- }
-
- // Create an event flag that will tell us when ProcSrv is completely
- // shut down (srv_run() has returned)
- //
- hServerDone = CreateEvent( NULL, TRUE, FALSE, NULL );
- if( hServerDone == NULL )
- {
- sprintf( szLogBuffer,
- "Procedure Server Service Manager Failer: %s "
- "(ProcSrvMain(), line = %d), message = %s",
- szRegistryName,
- __LINE__,
- get_last_error_str() );
- srv_log( gblServer, TRUE, szLogBuffer, SRV_NULLTERM );
- printf( "\n%s\n", szLogBuffer );
- goto Exit;
- }
-
- // When starting Procedure Server, initialize the remote server structure.
- // This is done in the init_server() function.
- // All the other event handlers are also defined in the init_server()
- // function.
- //
- srv_handle( gblServer, (DBINT)SRV_START, init_server );
-
- sprintf( szLogBuffer,
- "Procedure Server Starting, name = %s",
- szRegistryName );
-
- // Now everything's ready to go with Procedure Server, so we
- // start it and keep it going until we get a stop request.
- //
- srv_log( gblServer, FALSE, " ", SRV_NULLTERM ); // insert blank line
- srv_log( gblServer, TRUE, szLogBuffer, SRV_NULLTERM );
-
- // initsignal() notifies the Service Control Manager that the
- // service has been started and sets up the signal handlers.
- //
- initsignal( gblServer, argv[0] );
-
- // completesignal() notifies the Service Control Manager that the
- // service has completed its startup process.
- //
- completesignal( gblServer );
-
- // srv_run() does not return until either a FAILure occurs or a SRV_EXIT
- // event has been issued.
- //
- if( srv_run(gblServer) == FAIL )
- {
- printf( "\nProcedure Server Failer, Check logs.\n" );
- goto Exit;
- }
-
- // Set flag indicating all processing completed
- //
- SetEvent( hServerDone );
- return;
-
- Exit:
- // initsignal() notifies the Service Control Manager that the
- // service has been started and sets up the signal handlers.
- // This must be done even though we have an "error exit" condition.
- //
- initsignal( gblServer, argv[0] );
-
- // completesignal() notifies the Service Control Manager that the
- // service has completed its startup process.
- //
- completesignal( gblServer );
-
- // NTBShutdown() sets the SQL Service Manager to "Stop" and terminates
- // the service.
- //
- SetThreadPriority( (HANDLE)_beginthread(NTBShutdown, 0, NULL),
- THREAD_PRIORITY_HIGHEST );
-
- // Set flag indicating all processing completed
- //
- SetEvent( hServerDone );
- }
-
-
- // This section defines all the Open Data Services event handler functions for
- // the Procedure Server application. The procedures implemented are:
- //
- //
- // PROCLIST Returns all the supported procedures and their usuage.
- //
- // SP_EXEC Executes a command string and returns output as a rows
- // of text.
- //
- // DISKFREE Returns the amount the amount of available space for a given
- // drive.
- //
- // DISKLIST Returns a row for each defined drive containing its name
- // and the amount of disk space available.
- //
- // SCAN_XBASE Reads an xBase file and sends it to the client as if it
- // were a SQL Server query result set (the equivalent of a
- // 'SELECT * FROM tablename' SQL statement).
- //
- //
- // ================================== init_server ============================
- //
- // INIT_SERVER
- // Initialize the server on a SRV_START event.
- // Event handlers for the server are installed.
- //
- // Parameters:
- // server - Pointer to SRV_SERVER structure
- //
- // Returns:
- // SRV_CONTINUE
- //
- SRVRETCODE init_server( SRV_SERVER *server )
- {
- char log_buffer[256];
-
- // When we get a connection request from a client, we want to
- // call "init_remote()" to make a connection to the remote
- // server.
- //
- srv_handle(server, (DBINT)SRV_CONNECT, init_remote);
-
- // When the client issues a language request, call
- // "lang_execute()" to send the SQL statement to the remote DBMS.
- //
- srv_handle(server, (DBINT)SRV_LANGUAGE, lang_execute);
-
- // When the client issues an RSP, call "sp_execute()"
- // to send the RSP to the remote DBMS (the SQL Server).
- //
- srv_handle(server, (DBINT)SRV_RPC, sp_execute);
-
- // When a disconnect request is issued, call "exit_remote()"
- // to close the connection to the remote DBMS.
- //
- srv_handle(server, (DBINT)SRV_DISCONNECT, exit_remote);
-
- // Log Server information to log file
- //
- sprintf(log_buffer, "Client connections allowed = %s",
- srv_sfield(server, SRV_CONNECTIONS, (int *)NULL));
-
- srv_log(server, FALSE, log_buffer, SRV_NULLTERM);
- printf("%s\n", log_buffer);
-
- return SRV_CONTINUE;
- }
-
-
- // ================================== init_remote ============================
- //
- // INIT_REMOTE
- // Event handler for a SRV_CONNECT event.
- // A connection is made to the procedure server.
- //
- // Parameters:
- // srvproc - the handle to the client connection that got the SRV_CONNECT.
- //
- // Returns:
- // SRV_CONTINUE
- //
- // Side Effects:
- // If the connection to the remote dbms cannot be made, then issue
- // a SRV_DISCONNECT request.
- //
- //
- SRVRETCODE init_remote( SRV_PROC *srvproc )
- {
- char *string;
- int len;
-
- // Set server name
- //
- srvproc->serverlen = (BYTE)strlen(szRegistryName);
- srvproc->servername = srv_alloc((DBINT)srvproc->serverlen);
- strcpy(srvproc->servername, szRegistryName);
-
- // Display info on console
- //
- string = srv_pfield(srvproc, SRV_CPID, &len);
- string[len] = '\0';
- printf("\nClient process ID: %s\n", string);
-
- string = srv_pfield(srvproc, SRV_USER, &len);
- string[len] = '\0';
- printf("User name: %s\n", string);
-
- string = srv_pfield(srvproc, SRV_APPLNAME, &len);
- string[len] = '\0';
- if (len > 0)
- printf("Application program name: %s\n", string);
-
- string = srv_pfield(srvproc, SRV_RMTSERVER, &len);
- string[len] = '\0';
- if (len > 0)
- printf("Remote Server: %s\n", string);
-
- return SRV_CONTINUE;
- }
-
-
- // ================================ lang_execute =============================
- //
- // LANG_EXECUTE
- // Execute a client language request on the procedure server.
- //
- // Parameters:
- // srvproc - process handle to the current client connection.
- //
- // Returns:
- // SRV_CONTINUE
- //
- SRVRETCODE lang_execute( SRV_PROC *srvproc )
- {
- int i;
- DBCHAR paramvalues[MAXPARAMS][MAXLEN];
- BYTE convertvalues[MAXPARAMS][MAXLEN];
- SP_INFO *sp = NULL;
-
- // Initialize parameter storage
- //
- for (i = 0; i < MAXPARAMS; i++) {
- memset(paramvalues[i], 0, MAXLEN);
- memset(convertvalues[i], 0, MAXLEN);
- }
- if (lang_parser(srvproc, &sp, paramvalues) == SUCCEED) {
- for (i = 0; i < sp->numparams; i++) {
- if (sp->params[i].status == REFERENCE) {
- srv_sendstatus(srvproc, 1);
- srv_sendmsg(srvproc, SRV_MSG_ERROR, INVALID_SP_SYNTAX,
- SRV_INFO, (DBTINYINT)0, NULL, 0, 0,
- "Procedure contains a return parameter.\
- Unable to execute as a language event.",
- SRV_NULLTERM);
- srv_senddone(srvproc, (SRV_DONE_ERROR | SRV_DONE_FINAL), 0,
- 0);
- return SRV_CONTINUE;
-
- }
- if (strlen(paramvalues[i]) == 0 &&
- strlen(sp->params[i].defaultvalue) == 0) {
- srv_sendstatus(srvproc, 1);
- srv_sendmsg(srvproc, SRV_MSG_ERROR, INVALID_SP_SYNTAX,
- SRV_INFO, (DBTINYINT)0, NULL, 0, 0, sp->usage,
- SRV_NULLTERM);
- srv_senddone(srvproc, (SRV_DONE_ERROR | SRV_DONE_FINAL), 0,
- 0);
- return SRV_CONTINUE;
- }
- if (strlen(paramvalues[i]) == 0 &&
- strlen(sp->params[i].defaultvalue) != 0)
- strcpy(paramvalues[i], sp->params[i].defaultvalue);
-
- // convert parameters from character string to parmeter type
- //
- srv_convert(srvproc, SRVCHAR, paramvalues[i], -1,
- sp->params[i].type, &convertvalues[i],
- sp->params[i].length);
- }
-
- // Execute the procedure
- //
- (sp->handler)((VOID *)srvproc, &convertvalues[0], &convertvalues[1],
- &convertvalues[2], &convertvalues[3]);
- }
- return SRV_CONTINUE;
- }
-
-
- // ================================= lang_parser =============================
- //
- // LANG_PARSER
- // A procedure server specific language event parser.
- //
- // Parameters:
- // srvproc - process handle to the current client connection.
- // sp - Pointer to the stored procedure structure
- // paramvalues - An array of the values of the parameters.
- //
- // Returns:
- // SUCCEED
- //
- SRVRETCODE lang_parser( SRV_PROC *srvproc,
- SP_INFO **sp,
- DBCHAR paramvalues[MAXPARAMS][MAXLEN] )
- {
- DBCHAR *query; // pointer to language buffer
- int i;
- int numparams;
- DBCHAR msg[MAXLEN *5];
- DBINT msgnum;
- DBCHAR spname[MAXLEN];
- BOOL paramsyntax = FALSE;
- DBCHAR paramname[MAXLEN];
- DBCHAR equalstring[2];
- DBCHAR *paramvalue = NULL;
-
- query = srv_langptr(srvproc);
-
- // Ignore the syscharsets query from DBLIB 4.2 NT clients
- //
- if (!strncmp(query, SERVER_INFO_QUERY, strlen(SERVER_INFO_QUERY))){
- srv_senddone(srvproc, SRV_DONE_FINAL, 0, 0);
- return FAIL;
- }
-
- query = scan_next(query, spname);
- if (strlen(spname) == 0) {
- srv_senddone(srvproc, SRV_DONE_FINAL, 0, 0);
- return FAIL;
- }
- if (strnicmp(spname, EXEC_CMD, (sizeof(EXEC_CMD) - 1)) == 0) {
- // stored procedure name
- //
- query = scan_next(query, spname);
- if (strlen(spname) == 0)
- goto syntax_error;
- }
-
- // Check for existence
- //
- for (i = 0; i < Rpcnumber; i++)
- if (strcmp(Sps[i].name, spname) == 0) {
- *sp = &Sps[i];
- break;
- }
- if (*sp == NULL) {
- sprintf(msg, "Procedure \'%s \' not found.", spname);
- msgnum = SP_UNKNOWN;
- goto error;
- }
-
- // Parameters
- //
- numparams = 0;
- while (*query != '\0') {
- if (++numparams > (*sp)->numparams) {
- sprintf(msg, (*sp)->usage);
- msgnum = INVALID_SP_SYNTAX;
- goto error;
- }
- if (!paramsyntax && *query == '@')
- paramsyntax = TRUE; // parameter name mode
-
- if (!paramsyntax)
- if (paramvalue == NULL)
- paramvalue = paramvalues[0];
- else
- paramvalue += MAXLEN;
-
- if (paramsyntax) {
- if (*query != '@') {
- sprintf( msg,
- "Once the form '@name = value' has been used, "
- "all subsequent parameters must be passed in "
- "the form '@name = value'." );
- msgnum = INVALID_SP_SYNTAX;
- goto error;
- } else
- query++;
-
- query = scan_next(query,
- paramname);
- if (strlen(paramname) == 0)
- goto syntax_error;
-
- // Get parameter index
- //
- paramvalue = NULL;
- for (i = 0; i < (*sp)->numparams; i++)
- if (strcmp((*sp)->params[i].name, paramname) == 0) {
- paramvalue = paramvalues[i];
- break;
- }
- if (paramvalue == NULL) {
- sprintf( msg,
- "Procedure '%s' does not recognize parameter name: %s",
- spname, paramname );
- msgnum = BAD_SP_PARAMETER;
- goto error;
- }
-
- // Already assigned value
- //
- if (strlen(paramvalue) > 0)
- goto syntax_error;
-
- // Check for '='
- //
- query = scan_next(query,
- equalstring);
- if (*equalstring != '=')
- goto syntax_error;
-
- }
- query = scan_next(query,
- paramvalue);
- if (strlen(paramvalue) == 0)
- goto syntax_error;
-
- if (*query == ',') {
- query++;
- while (*query == ' ' || *query == '\t')
- query++;
- }
- }
- return SUCCEED;
-
- syntax_error:
- sprintf(msg, "Incorrect syntax found near '%s'.", query);
- msgnum = INVALID_SP_SYNTAX;
-
- error:
- srv_sendstatus(srvproc, 1);
- srv_sendmsg(srvproc, SRV_MSG_ERROR, msgnum, SRV_INFO, (DBTINYINT)0, NULL,
- 0, 0, msg, SRV_NULLTERM);
- srv_senddone(srvproc, (SRV_DONE_ERROR | SRV_DONE_FINAL), 0, 0);
- return FAIL;
- }
-
-
- // ================================= scan_next ===============================
- //
- // SCAN_NEXT
- // Reads the next token in a string, ignoring whitespace.
- //
- // Parameters:
- // string - The language event string
- // word - The next token in the string
- //
- // Returns:
- // The string incremented passed the token.
- //
- DBCHAR *scan_next( DBCHAR *string, DBCHAR *word )
- {
- DBCHAR *p;
-
- word[0] = '\0';
- if (*string == '\"' || *string == '\'') {
- // check for unclosed quote
- //
- p = strchr(string + 1,
- *string);
- if (p == NULL)
- return string;
- strncpy(word, string + 1, p - (string + 1));
- word[p - (string + 1)] = '\0';
- string += 2;
- } else {
- // clear proceeding white space
- //
- while (*string == ' ' || *string == '\t' || *string == '\n' ||
- *string == '\r')
- string++;
- sscanf(string, "%s", word);
-
- // ignore comments
- //
- while (strncmp(word, "/*", 2) == 0) {
- string = strstr(string,
- "*/");
- if (string != NULL) {
- string += 2;
- word[0] = '\0';
- while (*string == ' ' || *string == '\t' || *string == '\n' ||
- *string == '\r')
- string++;
- sscanf(string, "%s", word);
- } else
- return string;
- }
- }
- if (strlen(word) > 0)
- string += strlen(word);
-
- // clear trailing white space
- //
- while (*string == ' ' || *string == '\t' || *string == '\n' ||
- *string == '\r')
- string++;
-
- return string;
- }
-
-
- // ================================== sp_execute =============================
- //
- // SP_EXECUTE
- // Execute a client stored procedure.
- //
- // Scans the list of defined stored procedures, checks the parameters and
- // executes the procedure. If results are returned it is the responsiblity
- // of the underlying proedure.
- //
- // Parameters:
- // srvproc - The process handle to use to send results to the client.
- //
- // Returns:
- // SRV_CONTINUE
- //
- SRVRETCODE sp_execute( SRV_PROC *srvproc )
- {
- int i;
- int x;
- int y;
- int len;
- int numparams;
- SP_INFO *sp = NULL;
- DBCHAR msg[MAXLEN];
- DBINT msgnum;
- DBCHAR paramvalues[MAXPARAMS][MAXLEN];
- BOOL paramnamemode = FALSE;
- DBCHAR *paramname;
- DBINT paramtype;
- DBCHAR *value;
- DBINT type;
- DBINT status;
-
- // Initialize parameter storage
- //
- for( i = 0; i < MAXPARAMS; i++ )
- memset( paramvalues[i], 0, MAXLEN );
-
- for( i = 0; i < Rpcnumber; i++ )
- {
- // Create name generated by calling server
- //
- if( strcmp(Sps[i].name, srv_rpcname(srvproc, (int *)NULL)) == 0 )
- {
- sp = &Sps[i];
- break;
- }
- }
-
- if( sp == NULL )
- {
- sprintf( msg,
- "Procedure \'%s \' not found.",
- srv_rpcname(srvproc, (int *)NULL) );
-
- msgnum = SP_UNKNOWN;
- goto error;
- }
-
- numparams = srv_rpcparams( srvproc );
-
- if( srv_paramname(srvproc, 1, &len) && len > 0 )
- paramnamemode = TRUE;
-
- for( y = 1; y <= numparams; y++ )
- {
- // Find parameter number
- //
- if( paramnamemode )
- {
- paramname = srv_paramname( srvproc,
- y,
- &len );
-
- if( strlen(paramname) == 0 )
- goto parameter_error;
-
- if( *paramname == '@' )
- paramname++;
- else
- goto parameter_error;
-
- value = NULL
- ;
- for( x = 0; x < sp->numparams; x++ )
- {
- if( strcmp(sp->params[x].name, paramname) == 0 )
- {
- value = paramvalues[x];
- type = sp->params[x].type;
- status = sp->params[x].status;
- break;
- }
- }
-
- if( value == NULL )
- goto parameter_error;
- }
- else // if( paramnamemode )
- {
- value = paramvalues[y - 1];
- type = sp->params[y - 1].type;
- status = sp->params[y - 1].status;
- }
-
- // Check parameters for correct type
- //
- paramtype = srv_paramtype( srvproc, y );
-
- switch( paramtype )
- {
- case SRVVARCHAR: // Type sent by Servers instead of SRVCHAR
- paramtype = SRVCHAR;
- break;
- case SRVINTN: // Type sent by Servers instead of SRVINT
- paramtype = SRVINT4;
- break;
- default:
- break;
- }
-
- if( type != paramtype )
- {
- if( paramnamemode )
- sprintf( msg, "Parameter \'%s \' is incorrect type.",
- paramname );
- else
- sprintf( msg, "Parameter \'%d \' is incorrect type.", y );
-
- msgnum = BAD_SP_PARAMETER;
- goto error;
- }
-
- // Check parameters for correct status
- //
- if( (DBINT)srv_paramstatus(srvproc, y) != status )
- {
- if( paramnamemode )
- sprintf( msg, "Parameter \'%s \' has incorrect status.",
- paramname);
- else
- sprintf( msg, "Parameter \'%d \' had incorrect status.", y );
-
- msgnum = BAD_SP_PARAMETER;
- goto error;
- }
-
- // Move SP parameters to local variables
- //
- srv_bmove( srv_paramdata(srvproc, y), value, srv_paramlen(srvproc, y) );
- value[srv_paramlen(srvproc, y)] = '\0';
-
- }
-
- // If unspecified, use default value
- //
- for( i = 0; i < sp->numparams; i++ )
- {
- if( strlen(paramvalues[i]) == 0
- && strlen(sp->params[i].defaultvalue) == 0 )
- {
- strcpy( msg, sp->usage );
- msgnum = INVALID_SP_SYNTAX;
- goto error;
- }
-
- if( strlen(paramvalues[i]) == 0
- && strlen(sp->params[i].defaultvalue) != 0 )
- strcpy(paramvalues[i], sp->params[i].defaultvalue);
- }
-
- // Execute procedure
- //
- (*sp->handler)( (VOID *)srvproc,
- paramvalues[0],
- paramvalues[1],
- paramvalues[2],
- paramvalues[3] );
-
- return SRV_CONTINUE;
-
- parameter_error:
- sprintf( msg, "Procedure '%s' does not recognize parameter name: %s",
- sp->name, paramname );
- msgnum = BAD_SP_PARAMETER;
-
- error:
- srv_sendstatus( srvproc, 1 );
- srv_sendmsg( srvproc, SRV_MSG_ERROR, msgnum, SRV_INFO, (DBTINYINT)0, NULL,
- 0, 0, msg, SRV_NULLTERM );
- srv_senddone( srvproc, (SRV_DONE_ERROR | SRV_DONE_FINAL), 0, 0 );
- return SRV_CONTINUE;
- }
-
-
- // ================================= exit_remote =============================
- //
- // EXIT_REMOTE
- // Handler for SRV_DISCONNECT events.
- //
- // The code to disconnect from the procedure server.
- //
- // Parameters:
- // srvproc - the handle to the client connection
- //
- // Returns:
- // SRV_DISCONNECT
- ///
- SRVRETCODE exit_remote( SRV_PROC *srvproc )
- {
- char *string;
- int len;
-
- // Display info on console
- //
- string = srv_pfield(srvproc, SRV_CPID, &len);
- string[len] = '\0';
- printf("\nClient connection closed, process ID: %s\n", string);
-
- return SRV_CONTINUE;
- }
-
-
- // ================================== chk_err =================================================
- //
- // CHK_ERR
- // Print out errors.
- //
- // Parameters:
- // server - pointer to procedure server server structure.
- // srvproc - pointer to client connection structure
- // errornum - error number.
- // severity - error severity.
- // state - error state.
- // oserrnum - operating system error number, if any.
- // errtext - the text of the error message.
- // errtextlen - length of the errtext message
- // oserrtext - the text of the operating system error message.
- // oserrtextlen - length of the errtext message
- //
- // Returns:
- // SRV_CONTINUE, SRV_CANCEL, or SRV_EXIT_PROGRAM
- //
-
- SRVRETCODE chk_err( SRV_SERVER *server,
- SRV_PROC *srvproc,
- int errornum,
- BYTE severity,
- BYTE state,
- int oserrnum,
- DBCHAR *errtext,
- int errtextlen,
- DBCHAR *oserrtext,
- int oserrtextlen )
- {
- char log_buffer[256];
- char error[256];
- char oserror[256];
-
- memcpy(error, errtext, errtextlen);
- error[errtextlen] = '\0';
- memcpy(oserror, oserrtext, oserrtextlen);
- oserror[oserrtextlen] = '\0';
-
- // Strip out resource information. Get the actual error number.
- errornum = (errornum & 0x0000FFFF);
-
- // Operating system error?
- //
- if (oserrnum != SRV_ENO_OS_ERR) {
- sprintf(log_buffer, "SERVER OS ERROR: %d: %s.", oserrnum, oserror);
- if (server)
- srv_log(server, TRUE, log_buffer, SRV_NULLTERM);
- else // If application not initialized log to screen
- printf ("%s\n", log_buffer);
- }
-
- // Is this a fatal error for the server?
- //
- if (severity >= SRV_FATAL_SERVER) {
- sprintf(log_buffer,
- "SERVER: FATAL SERVER ERROR: errornum = %d, "
- "severity = %d, state = %d: %s.",
- errornum, severity, state, error);
-
- if (server)
- srv_log(server, TRUE, log_buffer, SRV_NULLTERM);
- else // If application not initialized log to screen
- printf ("%s\n", log_buffer);
- return SRV_EXIT;
- } else {
- //
- // Did the "srvproc" get a fatal error?
- //
- if (severity >= SRV_FATAL_PROCESS) {
- sprintf(log_buffer,
- "SERVER: FATAL CONNECT ERROR: errornum = %d, "
- "severity = %d, state = %d: %s.",
- errornum, severity, state, error);
-
- if (server)
- srv_log(server, TRUE, log_buffer, SRV_NULLTERM);
- else // If application not initialized log to screen
- printf ("%s\n", log_buffer);
-
- return SRV_CANCEL;
- }
- }
-
- // A non-fatal error or an information message received.
- // We'll pass it through to the client.
- //
- if (srvproc != (SRV_PROC *)NULL && (server != NULL))
- if (severity < 10) { // if informational message
- srv_sendmsg(srvproc, SRV_MSG_INFO, (DBINT)errornum, severity, 0,
- NULL, 0, 0, error, SRV_NULLTERM);
- } else { // must be an error message
- srv_sendmsg(srvproc, SRV_MSG_ERROR, (DBINT)errornum, severity, 0,
- NULL, 0, 0, error, SRV_NULLTERM);
- } else {
- sprintf(log_buffer, "ODS ERROR: errornum = %d, severity = %d: %s",
- errornum, severity, error);
- if (server)
- srv_log(server, TRUE, log_buffer, SRV_NULLTERM);
- else // If application not initialized log to screen
- printf ("%s\n", log_buffer);
- }
- return SRV_CONTINUE;
- }
-
-
- // The following are the supported store procedure functions
- //
- // ================================== proclist ===============================
- //
- // PROCLIST
- // Returns the usage for all defined stored procedures
- //
- // Parameters:
- // srvproc - the handle to the client connection that got the SRV_CONNECT.
- //
- // Returns:
- // SUCCEED
- //
- // Side Effects:
- // Returns a result set to client
- //
- SRVRETCODE proclist( SRV_PROC *srvproc )
- {
- DBCHAR colname1[MAXNAME];
- DBCHAR colname2[MAXNAME];
- int i;
-
- sprintf(colname1, "spname");
- srv_describe(srvproc, 1, colname1, SRV_NULLTERM, SRVCHAR, MAXNAME,
- SRVCHAR, 0, NULL);
-
- sprintf(colname2, "spusage");
- srv_describe(srvproc, 2, colname2, SRV_NULLTERM, SRVCHAR, MAXLEN, SRVCHAR,
- 0, NULL);
-
- // Return each SP handler as a row
- //
- for (i = 0; i < Rpcnumber; i++) {
- srv_setcoldata(srvproc, 1, Sps[i].name);
- srv_setcollen(srvproc, 1, strlen(Sps[i].name));
-
- srv_setcoldata(srvproc, 2, Sps[i].usage);
- srv_setcollen(srvproc, 2, strlen(Sps[i].usage));
-
- srv_sendrow(srvproc);
- }
- srv_senddone(srvproc, (SRV_DONE_COUNT | SRV_DONE_FINAL), 0, i);
-
- return SUCCEED;
- }
-
-
- // ================================== sp_exec ================================
- //
- // SP_EXEC
- // Execute a given command string and returns any output as rows of
- // text.
- //
- // Parameters:
- // srvproc - the handle to the client connection that got the SRV_CONNECT.
- // command - the command string to execute
- //
- // Returns:
- // SUCCEED or FAIL
- //
- // Side Effects:
- // Returns messages and/or a result set to client
- //
- SRVRETCODE sp_exec( SRV_PROC *srvproc, DBCHAR *command )
- {
-
- DBCHAR bReadBuffer[MAXLEN];
- DBCHAR bErrorMsg[80];
- int cbReadBuffer;
-
- DBINT cnt;
- DBINT rows = 0;
- DBCHAR *paramvalue;
- DBINT paramlength;
- DBINT cmdlength;
- BOOL fSuccess;
-
- STARTUPINFO si;
- PROCESS_INFORMATION pi;
-
- SECURITY_ATTRIBUTES saPipe;
- HANDLE hReadPipe;
- HANDLE hWritePipe;
-
- // Allocation local storage for command string.
- //
- paramlength = strlen( command );
- cmdlength = paramlength + CMDSTR + 1;
- paramvalue = (DBCHAR *)malloc( cmdlength );
-
- if( !paramvalue )
- {
- SETERROR( "Malloc", bErrorMsg );
- srv_sendstatus( srvproc, 1 );
- srv_sendmsg( srvproc, SRV_MSG_ERROR, EXEC, SRV_INFO, (DBTINYINT)0,
- NULL, 0, 0, bErrorMsg, SRV_NULLTERM );
- srv_senddone( srvproc, (SRV_DONE_ERROR | SRV_DONE_FINAL), 0, 0 );
- return FAIL;
- }
-
- // Cancatenate "cmd /c " to command string so child process will
- // execute the given command and exit. Move command string to
- // local variable.
- //
- memset( paramvalue, 0, cmdlength );
- srv_bmove( "cmd /c ", paramvalue, CMDSTR );
- srv_bmove( command, ¶mvalue[CMDSTR], paramlength );
-
- // Create child process to execute the command string. Use an
- // anonymous pipe to read the output from the command and send
- // any results to the client.
-
- // In order for the child process to be able to write
- // to the anonymous pipe, the handle must be marked as
- // inheritable by child processes by setting the
- // SECURITY_ATTRIBUTES.bInheritHandle flag to TRUE.
- //
- saPipe.nLength = sizeof( SECURITY_ATTRIBUTES );
- saPipe.lpSecurityDescriptor = NULL;
- saPipe.bInheritHandle = TRUE;
-
- fSuccess = CreatePipe( &hReadPipe, // read handle
- &hWritePipe, // write handle
- &saPipe, // security descriptor
- 0 ); // use default pipe buffer size
- if( !fSuccess )
- {
- SETERROR( "CreatePipe", bErrorMsg );
- srv_sendstatus( srvproc, 1 );
- srv_sendmsg( srvproc, SRV_MSG_ERROR, EXEC, SRV_INFO, (DBTINYINT)0,
- NULL, 0, 0, bErrorMsg, SRV_NULLTERM );
- srv_senddone( srvproc, (SRV_DONE_ERROR | SRV_DONE_FINAL), 0, 0 );
- free( paramvalue );
- return FAIL;
- }
-
- // Now we must set standard out and standard error to the
- // write end of the pipe. Once standard out and standard
- // error are set to the pipe handle, we must close the pipe
- // handle so that when the child process dies, the write end
- // of the pipe will close, setting an EOF condition on the pipe.
- //
- memset( &si, 0, sizeof(si) );
-
- si.cb = sizeof(si);
- si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
- si.wShowWindow = SW_HIDE;
- si.hStdOutput = hWritePipe;
- si.hStdError = hWritePipe;
-
- // Set the fInheritHandles parameter to TRUE so that open
- // file handles will be inheritied. We can close the child
- // process and thread handles as we won't be needing them.
- // The child process will not die until these handles are
- // closed.
- //
- fSuccess = CreateProcess( NULL, // filename
- paramvalue, // command line for child
- NULL, // process security descriptor
- NULL, // thread security descriptor
- TRUE, // inherit handles?
- 0, // creation flags
- NULL, // inherited environment address
- NULL, // startup dir; NULL = start in current
- &si, // pointer to startup info (input)
- &pi ); // pointer to process info (output)
- if( !fSuccess )
- {
- SETERROR( "CreateProcess", bErrorMsg );
- srv_sendstatus( srvproc, 1 );
- srv_sendmsg( srvproc, SRV_MSG_ERROR, EXEC, SRV_INFO, (DBTINYINT)0,
- NULL, 0, 0, bErrorMsg, SRV_NULLTERM );
- srv_senddone( srvproc, (SRV_DONE_ERROR | SRV_DONE_FINAL), 0, 0 );
- free( paramvalue );
- return FAIL;
- }
-
- CloseHandle( pi.hThread );
- CloseHandle( pi.hProcess );
-
- // We need to close our instance of the inherited pipe write
- // handle now that it's been inherited so that it will actually
- // close when the child process ends. This will put an EOF
- // condition on the pipe which we can then detect.
- //
- fSuccess = CloseHandle( hWritePipe );
-
- if( !fSuccess )
- {
- SETERROR( "CloseHandle", bErrorMsg );
-
- srv_sendstatus( srvproc, 1 );
- srv_sendmsg( srvproc, SRV_MSG_ERROR, EXEC, SRV_INFO, (DBTINYINT)0,
- NULL, 0, 0, bErrorMsg, SRV_NULLTERM );
- srv_senddone( srvproc, (SRV_DONE_ERROR | SRV_DONE_FINAL), 0, 0 );
-
- free( paramvalue );
- return FAIL;
- }
-
- // Now read from the pipe until EOF condition reached.
- //
- do
- {
- cnt = 0;
-
- while( fSuccess = ReadFile( hReadPipe, // read handle
- &bReadBuffer[cnt], // buffer for incoming data
- 1, // number of bytes to read
- &cbReadBuffer, // number of bytes actually read
- NULL))
- {
- if( !fSuccess )
- {
- if( GetLastError() == ERROR_BROKEN_PIPE )
- break; // child has died
- else
- {
- SETERROR( "CloseHandle", bErrorMsg );
-
- srv_sendstatus( srvproc, 1 );
- srv_sendmsg( srvproc, SRV_MSG_ERROR, EXEC, SRV_INFO,
- (DBTINYINT)0, NULL, 0, 0, bErrorMsg,
- SRV_NULLTERM );
- srv_senddone( srvproc, (SRV_DONE_ERROR | SRV_DONE_FINAL),
- 0, 0 );
-
- free( paramvalue );
- return FAIL;
- }
- }
-
- if (bReadBuffer[cnt] == '\n')
- break;
- else
- cnt++;
- }
-
- if( fSuccess && cbReadBuffer )
- {
- if( rows == 0 )
- {
- // Describe result row: it will be one column of size
- // sizeof(buf) We do this in the retrieval loop to
- // ensure that the row description will occur only if
- // there are rows to be outputted.
- //
- srv_describe( srvproc,
- 1,
- ¶mvalue[CMDSTR],
- SRV_NULLTERM,
- SRVCHAR,
- sizeof(bReadBuffer),
- SRVCHAR,
- sizeof(bReadBuffer),
- bReadBuffer );
- }
-
- // Make sure we have at least one data
- //
- if( !cnt )
- {
- bReadBuffer[0] = ' ';
- cnt = 1;
- }
-
- // Remove carriage return if it exists
- //
- if( bReadBuffer[cnt-1] == 0x0D )
- cnt--;
-
- // Send result rows back to client.
- //
- srv_setcollen( srvproc, 1, cnt );
- srv_sendrow( srvproc );
- rows++;
- }
- } while( fSuccess && cbReadBuffer );
-
- // close the trace file, pipe handles
- //
- CloseHandle( hReadPipe );
-
- if( rows == 0 )
- {
- srv_sendstatus( srvproc, 0 );
- srv_sendmsg( srvproc, SRV_MSG_INFO, EXEC, SRV_INFO, (DBTINYINT)0, NULL,
- 0, 0, "Command executed successfully", SRV_NULLTERM );
- }
-
- srv_senddone( srvproc, (SRV_DONE_COUNT | SRV_DONE_FINAL), 0, rows );
- free( paramvalue );
- return SUCCEED;
- }
-
-
- // =================================== disklist ==============================
- //
- // DISKLIST
- // Returns a row for each defined drive containing its name and the
- // amount of disk space available.
- //
- // Parameters:
- // srvproc - the handle to the client connection that got the SRV_CONNECT.
- //
- // Returns:
- // SUCCEED
- //
- // Side Effects:
- // Returns a result set to client
- //
- SRVRETCODE disklist( SRV_PROC *srvproc )
- {
- DBCHAR colname1[MAXNAME];
- DBCHAR colname2[MAXNAME];
- DBCHAR drivename;
- DBCHAR rootname[16];
- int drivenum;
- unsigned secPerCluster;
- unsigned bytesPerSector;
- unsigned freeClusters;
- unsigned totalClusters;
- int drivenums;
- int space_remaining;
- int i = 0;
-
- sprintf( colname1, "drive" );
- srv_describe( srvproc, 1, colname1, SRV_NULLTERM, SRVCHAR, 1, SRVCHAR, 1,
- (BYTE *)&drivename );
-
- sprintf( colname2, "Kbytes free" );
- srv_describe( srvproc, 2, colname2, SRV_NULLTERM, SRVINT4, 4, SRVINT4, 4,
- (BYTE *)&space_remaining );
-
- drivenums = GetLogicalDrives();
-
- drivenums >>= 2; // Ignore drives A and B
- for( drivename = 'C', drivenum = 3; drivename <= 'Z';
- drivename++, drivenum++ )
- {
- if( drivenums & 1 )
- {
- i++;
-
- sprintf( rootname, "%c:\\", drivename );
- GetDiskFreeSpace( rootname, &secPerCluster, &bytesPerSector,
- &freeClusters, &totalClusters );
-
- space_remaining = secPerCluster * bytesPerSector * (freeClusters/1000) ;
-
- srv_sendrow( srvproc );
- }
-
- drivenums >>= 1;
- }
-
- srv_senddone( srvproc, (SRV_DONE_COUNT | SRV_DONE_FINAL), 0, i );
- return SUCCEED;
- }
-
-
- // ================================== diskfree ===============================
- //
- // DISKFREE
- // Returns the amount of space available on a given drive. The value
- // is placed into the defined return parameter of the stored procedure.
- //
- // NOTE: This routine can not be called via a language event.
- //
- // Parameters:
- // srvproc - the handle to the client connection that got the SRV_CONNECT.
- // drive - the drive letter to check
- //
- // Returns:
- // SUCCEED
- //
- // Side Effects:
- // Returns messages and/or a result set to client. Returns a value in the
- // defined return parameter.
- //
- SRVRETCODE diskfree( SRV_PROC *srvproc, DBCHAR *drive )
- {
- DBCHAR colname1[MAXNAME];
- int drivenum;
- DBCHAR rootname[16];
- int drivenums;
- int secPerCluster;
- int bytesPerSector;
- int freeClusters;
- int totalClusters;
- int space_remaining = -1;
- int i = 0;
-
- drive = strupr( drive );
-
- sprintf( colname1, "drive" );
- srv_describe( srvproc, 1, colname1, SRV_NULLTERM, SRVCHAR, 1, SRVCHAR, 1,
- (BYTE *)drive );
- srv_sendrow( srvproc );
- srv_senddone( srvproc, (SRV_DONE_COUNT | SRV_DONE_MORE), 0, 1 );
-
- drivenums = GetLogicalDrives();
-
- drivenum = drive[0] - 'A' + 1;
-
- drivenums >>= drivenum - 1; //Ignore drives A and B
- if( drivenums & 0x01 )
- {
- sprintf( rootname, "%c:\\", drive[0] );
- GetDiskFreeSpace( rootname, &secPerCluster, &bytesPerSector,
- &freeClusters, &totalClusters );
-
- space_remaining = secPerCluster * freeClusters * bytesPerSector;
-
- }
-
- // Process return parameter
- //
- if( srv_paramstatus(srvproc, 2) & 0x0001 )
- srv_paramset( srvproc, 2, (BYTE *)&space_remaining, 4 );
-
- srv_senddone( srvproc, SRV_DONE_FINAL, 0, 0 );
- return SUCCEED;
- }
-
-
- // ================================== scan_xbase =============================
- //
- // SCAN_XBASE
- // Reads an xBase file and sends it to the client as if it were a SQL
- // Server query result set (the equivalent of a 'SELECT * FROM
- // tablename' SQL statement).
- //
- // Parameters:
- // srvproc - the handle to the client connection that got the SRV_CONNECT.
- // szFileName - dbase file path name
- //
- // Returns:
- // SUCCEED or FAIL
- //
- // Side Effects:
- // Returns messages and/or a result set to client
- //
- SRVRETCODE scan_xbase( SRV_PROC *srvproc, char *filename )
- {
- FILE *xbasefile;
- size_t count;
- char buffer[BUF_SIZE];
- short numrecords;
- short headerlength;
- short recordlength;
- short lengthlist[XBASE_MAX_COLUMNS];
- int i;
- short j;
- short position;
- short numcolumns;
-
- // now read the database header info
- //
- if ((xbasefile = fopen(filename, "r")) == NULL) {
- srv_sendstatus(srvproc, 1);
- srv_sendmsg(srvproc, SRV_MSG_ERROR, EXEC, SRV_INFO, (DBTINYINT)0,
- NULL, 0, 0, "Error reading xBase file", SRV_NULLTERM);
- srv_senddone(srvproc, (SRV_DONE_ERROR | SRV_DONE_FINAL), 0, 0);
- return FAIL;
- }
- count = fread(buffer,
- XBASE_HDR_SIZE,
- 1,
- xbasefile);
-
- if (count == 0) {
- srv_sendstatus(srvproc, 1);
- srv_sendmsg(srvproc, SRV_MSG_ERROR, EXEC, SRV_INFO, (DBTINYINT)0,
- NULL, 0, 0, "Error reading xBase file", SRV_NULLTERM);
- srv_senddone(srvproc, (SRV_DONE_ERROR | SRV_DONE_FINAL), 0, 0);
- fclose(xbasefile);
- return FAIL;
- }
- numrecords = *((short *)&buffer[4]);
- headerlength = *((short *)&buffer[8]);
- recordlength = *((short *)&buffer[10]);
- numcolumns = (headerlength - 32 - 1) / 32;
-
- // now get the column header information
- //
- for (j = 0; j < numcolumns; j++) {
- count = fread(buffer, XBASE_HDR_SIZE, 1, xbasefile);
- if (count == 0) {
- srv_sendstatus(srvproc, 1);
- srv_sendmsg(srvproc, SRV_MSG_ERROR, EXEC, SRV_INFO, (DBTINYINT)0,
- NULL, 0, 0, "Error reading xBase file", SRV_NULLTERM);
- srv_senddone(srvproc, (SRV_DONE_ERROR | SRV_DONE_FINAL), 0, 0);
- fclose(xbasefile);
- return FAIL;
- }
-
- // we need to NULL terminate the column name (if it is a
- // full 11 characters int)
- //
- buffer[11] = '\0';
-
- // now find our the column length for this data buffer
- //
- lengthlist[j] = (short)buffer[16];
-
- // now 'describe' this column
- //
- srv_describe( srvproc, j + 1, // column number
- buffer, // pointer to column name
- SRV_NULLTERM, // column name is NULL terminated
- SRVCHAR, // datatype is char (xBase numbers are ASCII)
- lengthlist[j], // column length
- SRVCHAR, // destination datatype is also char
- lengthlist[j], // destination column length
- NULL); // pointer to where the data will be
-
- }
-
- // now read the one byte 'column header seperator'
- //
- count = fread(buffer, 1, 1, xbasefile);
- if (count == 0) {
- srv_sendstatus(srvproc, 1);
- srv_sendmsg(srvproc, SRV_MSG_ERROR, EXEC, SRV_INFO, (DBTINYINT)0,
- NULL, 0, 0, "Error reading xBase file", SRV_NULLTERM);
- srv_senddone(srvproc, (SRV_DONE_ERROR | SRV_DONE_FINAL), 0, 0);
- fclose(xbasefile);
- return FAIL;
- }
- for (i = 0; i < numrecords; i++) {
- count = fread(buffer, recordlength, 1, xbasefile);
- if (count == 0 && !feof(xbasefile)) {
- srv_sendstatus(srvproc, 1);
- srv_sendmsg(srvproc, SRV_MSG_ERROR, EXEC, SRV_INFO, (DBTINYINT)0,
- NULL, 0, 0, "Error reading xBase file", SRV_NULLTERM);
- srv_senddone(srvproc, (SRV_DONE_ERROR | SRV_DONE_FINAL), 0, 0);
- fclose(xbasefile);
- return FAIL;
- }
-
- // check to see if this is a deleted row
- //
- if (buffer[0] == '*')
- break;
-
- // Now set the length and data pointers for each column
- //
- for (j = 0, position = 1; j < numcolumns; j++) {
- srv_setcollen(srvproc, j + 1, lengthlist[j]);
- srv_setcoldata(srvproc, j + 1, &buffer[position]);
- position += lengthlist[j];
- }
-
- // send the row to the client.
- //
- srv_sendrow(srvproc);
- }
- srv_senddone(srvproc, SRV_DONE_COUNT | SRV_DONE_FINAL, 0, i);
- fclose(xbasefile);
- return SUCCEED;
- }
-
-
- // The following section defines the Service Control Manager support functions.
- //
- // ================================== initsignal =============================
- //
- // initsignal -- Install signal handlers for NTB Server.
- //
- void initsignal( SRV_SERVER * server, char * szServiceName )
- {
- char szLogBuffer[1024];
-
- if( SrvCtrMan ) // if started from Service Control Manager
- {
- // Use RegisterServiceCtrlHandler() to communicate with
- // the Service Control Manager.
- //
- NTBServiceHandle = RegisterServiceCtrlHandler( "ProcSrv",
- NTBServiceCtrlHandler );
- InitializeCriticalSection( &SCMCrtSec );
-
- // Now send a START_PENDING message
- //
- NTBServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
- NTBServiceStatus.dwCurrentState = SERVICE_START_PENDING;
-
- NTBServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP
- | SERVICE_ACCEPT_PAUSE_CONTINUE
- | SERVICE_ACCEPT_SHUTDOWN;
-
- NTBServiceStatus.dwWin32ExitCode = NO_ERROR;
- NTBServiceStatus.dwServiceSpecificExitCode = 0;
- NTBServiceStatus.dwCheckPoint = 1;
- NTBServiceStatus.dwWaitHint = 20000L; // 20 seconds
-
- if( !SetServiceStatus(NTBServiceHandle, &NTBServiceStatus) )
- {
- sprintf( szLogBuffer,
- "Procedure Server Service Manager Failer: %s "
- "(initsignal(), line = %d), message = %s",
- szServiceName,
- __LINE__,
- get_last_error_str() );
- srv_log( server, TRUE, szLogBuffer, SRV_NULLTERM );
-
- // Flush all file buffers
- //
- _flushall();
- ExitProcess( 1 );
- }
-
- // We need to increment checkpoint field in the above structure
- // regularly in order to notify Service Control Manager that
- // we aren't hung.
- //
- ++(NTBServiceStatus.dwCheckPoint);
-
- } // if( SrvCtrMan )
-
- // Don't display a message box for hard errors, return the error back
- // to the application instead.
- //
- SetErrorMode( SEM_FAILCRITICALERRORS );
-
- // Install Ctrl-C handler
- //
- if( !SrvCtrMan )
- {
- if( SetConsoleCtrlHandler((PHANDLER_ROUTINE)ctrlc_hndl, TRUE)
- != TRUE )
- {
- sprintf( szLogBuffer,
- "Procedure Server Service Manager Failer: %s "
- "(SetConsoleCtrlHandler(), line = %d), message = %s",
- szServiceName,
- __LINE__,
- get_last_error_str() );
- srv_log( server, TRUE, szLogBuffer, SRV_NULLTERM );
- }
- }
- return;
- }
-
-
- // ================================== ctrlc_hndl =============================
- //
- // ctrlc_hndl(ulong) -- Handles Ctrl-C and Ctrl-Break events received
- // by NTB Server.
- //
- void ctrlc_hndl( ULONG CtrlTyp )
- {
- char c;
- char szLogBuffer[1024];
-
- switch( CtrlTyp )
- {
- case CTRL_C_EVENT:
- case CTRL_BREAK_EVENT:
-
- printf( "Terminate Procedure Server? (y/n): ");
-
- do
- {
- c = getch();
- } while( c != 'y' && c != 'Y' && c != 'n' && c != 'N' );
-
- printf( "%c\n", c );
-
- if( c == 'y' || c == 'Y' )
- {
- sprintf( szLogBuffer,
- "Procedure Server terminated by Ctrl-C or Ctrl-Break, name = %s",
- szRegistryName );
-
- if( gblServer ) {
- srv_log( gblServer, TRUE, szLogBuffer, SRV_NULLTERM );
- srv_setevent( gblServer, SRV_EXIT );
- }
- WaitForSingleObject(hServerDone, INFINITE );
-
- _flushall();
- ExitProcess( 0 );
- }
-
- break;
-
- default:
- break;
- }
- return;
- }
-
-
- // ============================== NTBServiceCtrlHandler ======================
- //
- // NTBServiceCtrlHandler(DWORD) -- Responds to START, STOP, etc..
- // requests of Service Control Manager.
- //
- void WINAPI NTBServiceCtrlHandler( DWORD dwCtrl )
- {
- char szLogBuffer[1024];
-
- switch( dwCtrl )
- {
- case SERVICE_CONTROL_SHUTDOWN:
- //
- // NT is shutting down.
- //
- // Fall through
-
- case SERVICE_CONTROL_STOP:
-
- EnterCriticalSection( &SCMCrtSec );
-
- NTBServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
- NTBServiceStatus.dwWin32ExitCode = NO_ERROR;
- NTBServiceStatus.dwServiceSpecificExitCode = 0;
- NTBServiceStatus.dwCheckPoint = 1;
- NTBServiceStatus.dwWaitHint = 60000L; // 60 seconds
-
- SetServiceStatus( NTBServiceHandle, &NTBServiceStatus );
- LeaveCriticalSection( &SCMCrtSec );
-
- // NTBShutdown() sets the SQL Service Manager to "Stop" and terminates
- // the service.
- //
- SetThreadPriority( (HANDLE)_beginthread(NTBShutdown, 0, NULL),
- THREAD_PRIORITY_HIGHEST );
- break;
-
- case SERVICE_CONTROL_INTERROGATE:
-
- // Serialize with increment signal thread
- //
- EnterCriticalSection( &SCMCrtSec );
-
- SetServiceStatus( NTBServiceHandle, &NTBServiceStatus );
- LeaveCriticalSection( &SCMCrtSec );
- break;
-
- case SERVICE_CONTROL_PAUSE:
-
- // Serialize with increment signal thread
- //
- EnterCriticalSection( &SCMCrtSec );
-
- srv_setevent( gblServer, SRV_SLEEP );
-
- NTBServiceStatus.dwCurrentState = SERVICE_PAUSED;
- NTBServiceStatus.dwWin32ExitCode = NO_ERROR;
- NTBServiceStatus.dwServiceSpecificExitCode = 0;
- NTBServiceStatus.dwCheckPoint = 1;
- NTBServiceStatus.dwWaitHint = 60000L; // 60 seconds
-
- SetServiceStatus( NTBServiceHandle, &NTBServiceStatus );
- LeaveCriticalSection( &SCMCrtSec );
-
- sprintf( szLogBuffer,
- "Procedure Server PAUSED, name = %s",
- szRegistryName );
-
- if( gblServer )
- srv_log( gblServer, TRUE, szLogBuffer, SRV_NULLTERM );
- break;
-
- case SERVICE_CONTROL_CONTINUE:
-
- EnterCriticalSection( &SCMCrtSec );
-
- srv_setevent( gblServer, SRV_RESTART );
-
- NTBServiceStatus.dwCurrentState = SERVICE_RUNNING;
- NTBServiceStatus.dwWin32ExitCode = NO_ERROR;
- NTBServiceStatus.dwServiceSpecificExitCode = 0;
- NTBServiceStatus.dwCheckPoint = 1;
- NTBServiceStatus.dwWaitHint = 60000L; // 60 seconds
-
- SetServiceStatus(NTBServiceHandle, &NTBServiceStatus);
- LeaveCriticalSection( &SCMCrtSec );
-
- sprintf( szLogBuffer,
- "Procedure Server CONTINUED, name = %s",
- szRegistryName );
-
- if( gblServer )
- srv_log( gblServer, TRUE, szLogBuffer, SRV_NULLTERM );
- break;
-
- default:
- // Values 128-255 can be user app defined
- //
- ;
- } // switch( dwCtrl )
-
- return;
- }
-
-
- // ================================= completesignal ==========================
- //
- // completesignal() -- Notifies Service Control Manager that NTB Server
- // has started.
- //
- void completesignal( SRV_SERVER * server )
- {
- char szLogBuffer[1024];
-
- if( !SrvCtrMan )
- return;
-
- EnterCriticalSection( &SCMCrtSec );
-
- NTBServiceStatus.dwCurrentState = SERVICE_RUNNING;
- NTBServiceStatus.dwCheckPoint = 0;
- NTBServiceStatus.dwWaitHint = 0;
-
- if( !SetServiceStatus(NTBServiceHandle, &NTBServiceStatus) )
- {
- sprintf( szLogBuffer,
- "Procedure Server Service Manager Failer: %s, (completesignal(), line = %d), message = %s",
- szRegistryName,
- __LINE__,
- get_last_error_str() );
-
- srv_log( server, TRUE, szLogBuffer, SRV_NULLTERM );
- }
-
- LeaveCriticalSection( &SCMCrtSec );
- return;
- }
-
-
- // ==================================== NTBShutdown ==========================
- //
- // NTBShutdown() -- This routine notifies ODS to terminate. After ODS has terminate,
- // the Service Control Manager is notified that everything has shut down.
- //
- void NTBShutdown( LPVOID notused )
- {
- char szLogBuffer[1024];
-
- // Flush all file buffers
- //
- _flushall();
-
- // Tell ODS to terminate...
- //
- srv_setevent( gblServer, SRV_EXIT );
-
- do
- {
- // Start the checkpoint incrementer
- //
- ++(NTBServiceStatus.dwCheckPoint);
-
- } while( WaitForSingleObject(hServerDone, 1000) == WAIT_TIMEOUT );
-
- sprintf( szLogBuffer,
- "Procedure Server STOPPED, name = %s",
- szRegistryName );
-
- if( gblServer )
- srv_log( gblServer, TRUE, szLogBuffer, SRV_NULLTERM );
-
- _flushall();
-
- EnterCriticalSection( &SCMCrtSec );
-
- NTBServiceStatus.dwCurrentState = SERVICE_STOPPED;
- NTBServiceStatus.dwWin32ExitCode = NO_ERROR;
- NTBServiceStatus.dwServiceSpecificExitCode = 0;
- NTBServiceStatus.dwCheckPoint = 0;
- NTBServiceStatus.dwWaitHint = 0;
-
- SetServiceStatus( NTBServiceHandle, &NTBServiceStatus );
- LeaveCriticalSection( &SCMCrtSec );
-
- // Flush all file buffers
- //
- _flushall();
-
- ExitProcess( 0 );
- }
-
-
- // ============================== get_last_error_str =========================
- //
- // This function returns the Operating System message text and length
- // associated with the error value sent to it.
- //
- // Inputs:
- // iOSerror = value of message to be returned
- //
- // Outputs:
- // pointer to message string (NULL if message not found)
- //
- char * get_last_error_str()
- {
- static char * szBuffer = NULL;
- DWORD dwLastError = GetLastError();
-
- if( szBuffer )
- LocalFree( szBuffer );
-
- szBuffer = NULL;
-
- // Attempt retrieving the message from system resource table
- //
- FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_ALLOCATE_BUFFER,
- NULL,
- dwLastError,
- (DWORD)GetSystemDefaultLangID(),
- (LPSTR)&szBuffer,
- 255, // maximum message length allowed
- (LPVOID)NULL );
- return szBuffer;
- }
-