/************* history ************ * * COMPONENT: REMOTE MODULE: SRVR_W32.C * generated by Marion V2.5 2/6/90 * from dev db on 26-JAN-1996 ***************************************************************** * * 20927 klaus 26-JAN-1996 * Call ICS_enter at start * * 20858 klaus 17-JAN-1996 * Get rid of extraneous header file * * 20841 klaus 12-JAN-1996 * Add interprocess comm under remote component * * 20804 RCURRY 9-JAN-1996 * Change priority for NP threads to normal * * 20768 klaus 20-DEC-1995 * More xnet driver work * * 20729 klaus 8-DEC-1995 * Begin adding xnet protocol * * 20716 jmayer 6-DEC-1995 * Update to not show NamedPipes as supported on Win95. * * 20690 jmayer 4-DEC-1995 * Change to start the IPC protocol when running as a service. * * 20682 jmayer 3-DEC-1995 * Update to write to logfile and display msg box as a non-service. * * 20373 RCURRY 24-OCT-1995 * Fix bug with license checking * * 20359 RMIDEKE 23-OCT-1995 * add a semicollin * * 20356 rcurry 23-OCT-1995 * Add more license file checking * * 20350 RCURRY 20-OCT-1995 * add license file checking for remote protocols * * 20281 RCURRY 13-OCT-1995 * fix multi thread scheduler problem * * 20198 RCURRY 27-SEP-1995 * Make Windows95 and Windows NT have the same defaults * * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy * of the License at http://www.Inprise.com/IPL.html * * Software distributed under the License is distributed on an * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express * or implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code was created by Inprise Corporation * and its predecessors. Portions created by Inprise Corporation are * Copyright (C) Inprise Corporation. * * All Rights Reserved. * Contributor(s): ______________________________________. * * 2001.11.20: Claudio Valderrama: Honor -b in SS for high priority. * */ /* * PROGRAM: JRD Remote Server * MODULE: nt_server.c * DESCRIPTION: Windows NT remote server. * * copyright (c) 1993, 1996 by Borland International */ #include "firebird.h" #include "../jrd/ib_stdio.h" #include #include #include "../remote/remote.h" #include "gen/codes.h" #include "../jrd/license.h" #include "../jrd/thd.h" #include "../jrd/license.h" #include "../utilities/install_nt.h" #include "../remote/cntl_proto.h" #include "../remote/inet_proto.h" #include "../remote/serve_proto.h" #include "../remote/window_proto.h" #include "../remote/wnet_proto.h" #include "../remote/window.rh" #include "../remote/xnet_proto.h" #include "../jrd/gds_proto.h" #include "../jrd/license.h" #include "../jrd/sch_proto.h" #include "../jrd/svc_proto.h" #include "../jrd/isc_proto.h" #include "../jrd/thd_proto.h" #include "../jrd/jrd_proto.h" #include "../jrd/isc_i_proto.h" #include "../jrd/isc_s_proto.h" #include "../jrd/file_params.h" #include "../common/config/config.h" static void THREAD_ROUTINE process_connection_thread(PORT); static void THREAD_ROUTINE inet_connect_wait_thread(void *); static void THREAD_ROUTINE ipc_connect_wait_thread(void *); static void service_connection(PORT); static void THREAD_ROUTINE start_connections_thread(int); static void THREAD_ROUTINE wnet_connect_wait_thread(void *); static HANDLE parse_args(LPSTR, USHORT *); static HINSTANCE hInst; static TEXT protocol_inet[128]; static TEXT protocol_wnet[128]; static USHORT server_flag; static SERVICE_TABLE_ENTRY service_table[] = { {REMOTE_SERVICE, (LPSERVICE_MAIN_FUNCTION) CNTL_main_thread}, {NULL, NULL} }; static const int SIGSHUT = 666; static int shutdown_pid = 0; /* put into ensure that we have a parent port for the XNET connections */ static int xnet_server_set = FALSE; int WINAPI WinMain(HINSTANCE hThisInst, HINSTANCE hPrevInst, LPSTR lpszArgs, int nWndMode) { /************************************** * * W i n M a i n * ************************************** * * Functional description * Run the server with NT named * pipes and/or TCP/IP sockets. * **************************************/ ISC_STATUS_ARRAY status_vector; HANDLE connection_handle; PORT port; int nReturnValue = 0; hInst = hThisInst; #ifdef SUPERSERVER server_flag = SRVR_multi_client; #else server_flag = 0; #endif #ifdef SUPERSERVER if (ISC_is_WinNT()) { /* True - NT, False - Win95 */ /* CVC: This operating system call doesn't exist for W9x. */ typedef BOOL (__stdcall *PSetProcessAffinityMask)(HANDLE, DWORD); PSetProcessAffinityMask SetProcessAffinityMask; SetProcessAffinityMask = (PSetProcessAffinityMask) GetProcAddress(GetModuleHandle("KERNEL32.DLL"), "SetProcessAffinityMask"); if (SetProcessAffinityMask) { /* Mike Nordell - 11 Jun 2001: CPU affinity. */ (*SetProcessAffinityMask)(GetCurrentProcess(), static_cast(Config::getCpuAffinityMask())); } } else { server_flag |= SRVR_non_service; } #endif if (server_flag & SRVR_multi_client) { gds__thread_enable(-1); } protocol_inet[0] = 0; protocol_wnet[0] = 0; connection_handle = parse_args(lpszArgs, &server_flag); if (shutdown_pid) { ISC_kill(shutdown_pid, SIGSHUT, 0); return 0; } if ((server_flag & (SRVR_inet | SRVR_wnet | SRVR_ipc | SRVR_xnet))==0) { if (ISC_is_WinNT()) /* True - NT, False - Win95 */ server_flag |= SRVR_wnet; server_flag |= SRVR_inet; #ifdef SUPERSERVER server_flag |= SRVR_xnet; server_flag |= SRVR_ipc; #endif } #ifdef SUPERSERVER // get priority class from the config file int priority = Config::getProcessPriorityLevel(); // override it, if necessary if (server_flag & SRVR_high_priority) { priority = 1; } // set priority class if (priority > 0) { SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); } else if (priority < 0) { SetPriorityClass(GetCurrentProcess(), IDLE_PRIORITY_CLASS); } #endif /* Initialize the service and Setup sig_mutex for the process */ ISC_signal_init(); #ifdef SUPERSERVER ISC_enter(); #endif if (connection_handle != INVALID_HANDLE_VALUE) { THREAD_ENTER; if (server_flag & SRVR_inet) port = INET_reconnect(connection_handle, 0, status_vector); else if (server_flag & SRVR_wnet) port = WNET_reconnect(connection_handle, 0, status_vector); THREAD_EXIT; if (port) { service_connection(port); } } else if (!(server_flag & SRVR_non_service)) { CNTL_init((FPTR_VOID) start_connections_thread, REMOTE_SERVICE); if (!StartServiceCtrlDispatcher(service_table)) { if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) { CNTL_shutdown_service("StartServiceCtrlDispatcher failed"); } server_flag |= SRVR_non_service; } } else { if (server_flag & SRVR_inet) { gds__thread_start(reinterpret_cast (inet_connect_wait_thread), 0, THREAD_medium, 0, 0); } if (server_flag & SRVR_wnet) { gds__thread_start(reinterpret_cast (wnet_connect_wait_thread), 0, THREAD_medium, 0, 0); } /* No need to waste a thread if we are running as a window. Just start * the IPC communication */ if (Config::getCreateInternalWindow()) { nReturnValue = WINDOW_main(hThisInst, nWndMode, server_flag); } else { HANDLE hEvent = ISC_make_signal(TRUE, TRUE, GetCurrentProcessId(), SIGSHUT); WaitForSingleObject(hEvent, INFINITE); THREAD_ENTER; JRD_shutdown_all(); } } #ifdef DEBUG_GDS_ALLOC /* In Debug mode - this will report all server-side memory leaks * due to remote access */ //gds_alloc_report(0, __FILE__, __LINE__); char name[MAXPATHLEN]; gds__prefix(name, "memdebug.log"); FILE* file = fopen(name, "w+b"); if (file) { fprintf(file,"Global memory pool allocated objects\n"); getDefaultMemoryPool()->print_contents(file); fclose(file); } #endif return nReturnValue; } ULONG SRVR_xnet_start_thread(ULONG client_pid) { /************************************** * * S R V R _ x n e t _ s t a r t _ t h r e a d * ************************************** * * Functional description * Start an interprocess thread. This allocates * the next available chunk of the mapped file and * tells the client where it is. * **************************************/ PORT port; ULONG response; /* get a port */ port = XNET_start_thread(client_pid, &response); /* Ensure that the main port is set with this new port if we are the first * XNET connection */ if (!xnet_server_set) { USHORT flags = ((USHORT) SRVR_xnet | (USHORT) SRVR_multi_client | (USHORT) SRVR_thread_per_port); PORT xnet_header_port = (PORT) ALLR_alloc(sizeof(struct port)); if (xnet_header_port) *xnet_header_port = *port; else return FALSE; xnet_server_set = TRUE; (void) set_server(xnet_header_port, flags); } /* start the thread for this client */ gds__thread_start(reinterpret_cast (process_connection_thread), port, THREAD_medium, 0, 0); /* return combined mapped area and number */ return response; } static void THREAD_ROUTINE process_connection_thread( PORT port) { /************************************** * * p r o c e s s _ c o n n e c t i o n _ t h r e a d * ************************************** * * Functional description * **************************************/ void *thread; if (!(server_flag & SRVR_non_service)) { thread = CNTL_insert_thread(); } service_connection(port); if (!(server_flag & SRVR_non_service)) { CNTL_remove_thread(thread); } } static void THREAD_ROUTINE inet_connect_wait_thread( void *dummy) { /************************************** * * i n e t _ c o n n e c t _ w a i t _ t h r e a d * ************************************** * * Functional description * **************************************/ void *thread; ISC_STATUS_ARRAY status_vector; PORT port; if (!(server_flag & SRVR_non_service)) thread = CNTL_insert_thread(); THREAD_ENTER; port = INET_connect(protocol_inet, 0, status_vector, server_flag, 0, 0); THREAD_EXIT; if (port) SRVR_multi_thread(port, server_flag); else gds__log_status(0, status_vector); if (!(server_flag & SRVR_non_service)) CNTL_remove_thread(thread); } static void THREAD_ROUTINE wnet_connect_wait_thread( void *dummy) { /************************************** * * w n e t _ c o n n e c t _ w a i t _ t h r e a d * ************************************** * * Functional description * **************************************/ void *thread; ISC_STATUS_ARRAY status_vector; if (!(server_flag & SRVR_non_service)) { thread = CNTL_insert_thread(); } while (TRUE) { THREAD_ENTER; PORT port = WNET_connect(protocol_wnet, 0, status_vector, server_flag); THREAD_EXIT; if (!port) { if (status_vector[1] != gds_io_error || status_vector[6] != gds_arg_win32 || status_vector[7] != ERROR_CALL_NOT_IMPLEMENTED) { gds__log_status(0, status_vector); } break; } gds__thread_start(reinterpret_cast (process_connection_thread), port, THREAD_medium, 0, 0); } if (!(server_flag & SRVR_non_service)) { CNTL_remove_thread(thread); } } static void THREAD_ROUTINE ipc_connect_wait_thread( void *dummy) { /************************************** * * i p c _ c o n n e c t _ w a i t _ t h r e a d * ************************************** * * Functional description * **************************************/ void *thread; if (!(server_flag & SRVR_non_service)) thread = CNTL_insert_thread(); if (Config::getCreateInternalWindow()) { WINDOW_main(hInst, SW_NORMAL, server_flag); } if (!(server_flag & SRVR_non_service)) CNTL_remove_thread(thread); } static void service_connection( PORT port) { /************************************** * * s e r v i c e _ c o n n e c t i o n * ************************************** * * Functional description * **************************************/ SRVR_main(port, (USHORT) (server_flag & ~SRVR_multi_client)); } static void THREAD_ROUTINE start_connections_thread( int flag) { /************************************** * * s t a r t _ c o n n e c t i o n s _ t h r e a d * ************************************** * * Functional description * **************************************/ HANDLE ipc_thread_handle = 0; if (server_flag & SRVR_inet) { gds__thread_start(reinterpret_cast (inet_connect_wait_thread), 0, THREAD_medium, 0, 0); } if (server_flag & SRVR_wnet) { gds__thread_start(reinterpret_cast (wnet_connect_wait_thread), 0, THREAD_medium, 0, 0); } if (server_flag & SRVR_ipc) { const int bFailed = gds__thread_start(reinterpret_cast (ipc_connect_wait_thread), 0, THREAD_medium, 0, &ipc_thread_handle); if (bFailed || WaitForSingleObject(ipc_thread_handle, 2000) != WAIT_TIMEOUT) { /* If the IPC thread did not time out, then it must have finished. * * the only way for it to have finished in 2 seconds is for it to * * not have succeeded. IE. It already exists. */ if (!bFailed && ipc_thread_handle) { CloseHandle(ipc_thread_handle); } CNTL_shutdown_service("Could not start service"); return; } } } static HANDLE parse_args( LPSTR lpszArgs, USHORT * pserver_flag) { /************************************** * * p a r s e _ a r g s * ************************************** * * Functional description * WinMain gives us a stupid command string, not * a cool argv. Parse through the string and * set the options. * Returns * a connection handle if one was passed in, * INVALID_HANDLE_VALUE otherwise. * **************************************/ TEXT *p, c; TEXT buffer[32]; HANDLE connection_handle; connection_handle = INVALID_HANDLE_VALUE; p = lpszArgs; while (*p) { if (*p++ == '-') while ((*p) && (c = *p++) && (c != ' ')) switch (UPPER(c)) { case 'A': *pserver_flag |= SRVR_non_service; break; case 'B': *pserver_flag |= SRVR_high_priority; break; case 'D': *pserver_flag |= (SRVR_debug | SRVR_non_service); break; #ifndef SUPERSERVER case 'H': while (*p && *p == ' ') p++; if (*p) { char *pp = buffer; while (*p && *p != ' ') { *pp++ = *p++; } *pp++ = '\0'; connection_handle = (HANDLE) atol(buffer); } break; #endif case 'I': *pserver_flag |= SRVR_inet; break; case 'K': while (*p && *p == ' ') p++; if (*p) { char *pp = buffer; while (*p && *p != ' ') { *pp++ = *p++; } *pp++ = '\0'; shutdown_pid = atoi(buffer); } break; #ifdef SUPERSERVER case 'L': *pserver_flag |= SRVR_ipc; break; #endif case 'N': *pserver_flag |= SRVR_no_icon; break; case 'P': /* Specify a port or named pipe other than the default */ while (*p && *p == ' ') p++; if (*p) { char *pi = protocol_inet, *pw = protocol_wnet; *pi++ = '/'; *pw++ = '\\'; *pw++ = '\\'; *pw++ = '.'; *pw++ = '@'; while (*p && *p != ' ') { *pi++ = *p; *pw++ = *p++; } *pi++ = '\0'; *pw++ = '\0'; } break; case 'R': *pserver_flag &= ~SRVR_high_priority; break; case 'W': *pserver_flag |= SRVR_wnet; break; case 'X': *pserver_flag |= SRVR_xnet; break; case 'Z': ib_printf("Firebird remote server version %s\n", FB_VERSION); exit(FINI_OK); default: /* In case of something unrecognized, just * continue, since we have already taken it off * of p. */ break; } } return connection_handle; }