mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-26 07:23:08 +01:00
659 lines
16 KiB
C++
659 lines
16 KiB
C++
/************* 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 <stdlib.h>
|
|
#include <windows.h>
|
|
#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<DWORD>(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<FPTR_INT_VOID_PTR>
|
|
(inet_connect_wait_thread), 0, THREAD_medium, 0,
|
|
0);
|
|
}
|
|
if (server_flag & SRVR_wnet) {
|
|
gds__thread_start(reinterpret_cast<FPTR_INT_VOID_PTR>
|
|
(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<FPTR_INT_VOID_PTR>
|
|
(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<FPTR_INT_VOID_PTR>
|
|
(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<FPTR_INT_VOID_PTR>
|
|
(inet_connect_wait_thread), 0, THREAD_medium, 0, 0);
|
|
}
|
|
if (server_flag & SRVR_wnet) {
|
|
gds__thread_start(reinterpret_cast<FPTR_INT_VOID_PTR>
|
|
(wnet_connect_wait_thread), 0, THREAD_medium, 0, 0);
|
|
}
|
|
if (server_flag & SRVR_ipc) {
|
|
const int bFailed =
|
|
gds__thread_start(reinterpret_cast<FPTR_INT_VOID_PTR>
|
|
(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;
|
|
}
|