8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-24 19:23:02 +01:00
firebird-mirror/src/remote/inet_server.cpp
2003-02-14 02:23:18 +00:00

641 lines
14 KiB
C++

/*
* PROGRAM: JRD Remote Server
* MODULE: inet_server.c
* DESCRIPTION: Internet remote server.
*
* 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): ______________________________________.
* Added TCP_NO_DELAY option for superserver on Linux
* FSG 16.03.2001
*
* 2002.10.28 Sean Leyne - Code cleanup, removed obsolete "MPEXL" port
* 2002.10.28 Sean Leyne - Code cleanup, removed obsolete "DecOSF" port
* 2002.10.28 Sean Leyne - Code cleanup, removed obsolete "SGI" port
*
* 2002.10.29 Sean Leyne - Removed obsolete "Netware" port
*
* 2002.10.30 Sean Leyne - Removed support for obsolete "PC_PLATFORM" define
*
*/
/*
$Id: inet_server.cpp,v 1.22 2003-02-14 02:23:18 brodsom Exp $
*/
#include "firebird.h"
#include "../jrd/ib_stdio.h"
#include <stdlib.h>
#include "../jrd/common.h"
#include "../jrd/isc_proto.h"
#include "../jrd/divorce.h"
#include "../common/config/config.h"
#if !(defined VMS)
#include <sys/param.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else
# if HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_SYS_WAIT_H
# include <sys/wait.h>
#endif
#ifndef WEXITSTATUS
# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
#endif
#ifndef WIFEXITED
# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef WINDOWS_ROUTER
#define MAX_ARGS 6
#endif /* WINDOWS_ROUTER */
#ifdef VMS
#include <descrip.h>
#endif
#ifdef SUPERSERVER
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <errno.h>
#include "../jrd/gds.h"
#include "../jrd/jrd_pwd.h"
#endif
#include "../remote/remote.h"
#include "../jrd/license.h"
#include "../jrd/thd.h"
#include "../jrd/file_params.h"
#include "../remote/inet_proto.h"
#include "../remote/serve_proto.h"
#include "../jrd/gds_proto.h"
#include "../jrd/sch_proto.h"
#ifdef UNIX
#ifdef NETBSD
#include <signal.h>
#else
#include <sys/signal.h>
#endif
#endif
#ifndef hpux
#define sigvector sigvec
#endif
#ifndef NBBY
#define NBBY 8
#endif
#ifndef SV_INTERRUPT
#define SV_INTERRUPT 0
#endif
#ifndef NFDBITS
#define NFDBITS (sizeof(SLONG) * NBBY)
#if !(defined DARWIN)
#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
#define FD_ZERO(p) memset((SCHAR *)(p), 0, sizeof(*(p)))
#endif
#endif
#ifdef SUPERSERVER
#ifndef WIN_NT
#define TEMP_DIR "/tmp"
#define CHANGE_DIR chdir
#endif
#define INTERBASE_USER_NAME "interbase"
#define INTERBASE_USER_SHORT "interbas"
#define FIREBIRD_USER_NAME "firebird"
#endif
extern "C" {
static int assign(SCHAR *);
static void name_process(UCHAR *);
static void signal_handler(void);
#ifdef SUPERSERVER
static void signal_sigpipe_handler(void);
#endif
static void set_signal(int, FPTR_VOID);
#ifdef WINDOWS_ROUTER
static int atov(UCHAR *, UCHAR **, SSHORT);
#endif /* WINDOWS_ROUTER */
#ifdef SUPERSERVER
extern SLONG free_map_debug;
extern SLONG trace_pools;
#endif
static TEXT protocol[128];
static int INET_SERVER_start = 0;
static USHORT INET_SERVER_flag = 0;
#ifdef WINDOWS_ROUTER
int PASCAL WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
#else /* WINDOWS_ROUTER */
int CLIB_ROUTINE main( int argc, char **argv)
#endif /* WINDOWS_ROUTER */
{
/**************************************
*
* m a i n
*
**************************************
*
* Functional description
* Run the server with apollo mailboxes.
*
**************************************/
int n, clients;
PORT port;
int child, debug, channel, standalone, multi_threaded, multi_client;
TEXT *p, **end, c;
int done = FALSE;
#if !(defined VMS)
fd_set mask;
#endif
#ifdef WINDOWS_ROUTER
/*
* Construct an argc, argv so we can use the old parse code.
*/
int argc;
char **argv, *argv2[MAX_ARGS];
argv = argv2;
argv[0] = "IB_server";
argc = 1 + atov(lpszCmdLine, argv + 1, MAX_ARGS - 1);
#endif /* WINDOWS_ROUTER */
#ifdef VMS
argc = VMS_parse(&argv, argc);
#endif
end = argc + argv;
argv++;
debug = standalone = INET_SERVER_flag = FALSE;
channel = 0;
protocol[0] = 0;
multi_client = multi_threaded = FALSE;
#ifdef SUPERSERVER
INET_SERVER_flag |= SRVR_multi_client;
multi_client = multi_threaded = standalone = TRUE;
#endif
clients = 0;
while (argv < end) {
p = *argv++;
if (*p++ == '-')
while (c = *p++) {
switch (UPPER(c)) {
case 'D':
INET_SERVER_flag |= SRVR_debug;
debug = standalone = TRUE;
#ifdef SUPERSERVER
free_map_debug = 1;
#endif
break;
#ifndef SUPERSERVER
case 'M':
INET_SERVER_flag |= SRVR_multi_client;
if (argv < end)
if (clients = atoi(*argv))
argv++;
multi_client = standalone = TRUE;
break;
case 'S':
standalone = TRUE;
break;
case 'I':
standalone = FALSE;
break;
case 'T':
multi_threaded = TRUE;
break;
case 'U':
multi_threaded = FALSE;
break;
#endif /* SUPERSERVER */
case 'E':
if (ISC_get_prefix(p) == -1)
ib_printf("Invalid argument Ignored\n");
else
argv++; /* donot skip next argument if this one
is invalid */
done = TRUE;
break;
case 'P':
sprintf(protocol, "/%s", *argv++);
break;
case 'H':
case '?':
ib_printf("Firebird TCP/IP server options are:\n");
ib_printf(" -d : debug on\n");
#ifdef SUPERSERVER
// These options only applicable to super server
ib_printf(" -m : multiclient - on\n");
ib_printf(" -s : standalone - true\n");
ib_printf(" -i : standalone - false\n");
ib_printf(" -t : multithread - true (non pc only)\n");
ib_printf(" -u : multithread - false (pc only)\n");
ib_printf(" -t : multithread (non pc only\n");
#endif
ib_printf(" -p<protocol> : specify protocol\n");
ib_printf(" -h|? : print this help\n");
ib_printf("\n");
ib_printf(" (The following -e options used to be -h options)\n");
ib_printf(" -e<firebird_root_dir> : set firebird_root path\n");
ib_printf(" -el<firebird_lock_dir> : set runtime firebird_lock dir\n");
ib_printf(" -em<firebird_msg_dir> : set firebird_msg dir path\n");
ib_printf(" -z : print version\n");
exit(FINI_OK);
case 'Z':
ib_printf("Firebird TCP/IP server version %s\n",
GDS_VERSION);
exit(FINI_OK);
}
if (done)
break;
}
}
#if (defined SUPERSERVER && defined UNIX )
set_signal(SIGPIPE, signal_sigpipe_handler);
set_signal(SIGUSR1, signal_handler);
set_signal(SIGUSR2, signal_handler);
#endif
/* Fork off a server, wait for it to die, then fork off another,
but give up after 100 tries */
#if !(defined SUPERSERVER || defined VMS)
if (multi_client && !debug) {
set_signal(SIGUSR1, signal_handler);
for (n = 0; n < 100; n++) {
INET_SERVER_start = 0;
if (!(child = fork()))
break;
while (wait(0) != child)
if (INET_SERVER_start) {
n = 0; /* reset error counter on "real" signal */
break;
}
gds__log("INET_SERVER/main: gds_inet_server restarted");
}
set_signal(SIGUSR1, (void(*)()) SIG_DFL);
}
#endif
if (standalone) {
if (multi_client) {
#ifdef SUPERSERVER
// Remove restriction on username, for DEV builds
// restrict only for production builds. MOD 21-July-2002
#ifndef DEV_BUILD
TEXT user_name[256]; /* holds the user name */
/* check user id */
ISC_get_user(user_name, NULL, NULL, NULL, NULL, NULL, NULL);
if (strcmp(user_name, "root") &&
strcmp(user_name, FIREBIRD_USER_NAME) &&
strcmp(user_name, INTERBASE_USER_NAME) &&
strcmp(user_name, INTERBASE_USER_SHORT)) {
/* invalid user -- bail out */
ib_fprintf(ib_stderr,
"%s: Invalid user (must be %s, %s, %s or root).\n",
"fbserver", FIREBIRD_USER_NAME,
INTERBASE_USER_NAME, INTERBASE_USER_SHORT);
exit(STARTUP_ERROR);
}
#endif
#else
if (setreuid(0, 0) < 0)
ib_printf("Inet_server: couldn't set uid to superuser.\n");
#endif
INET_set_clients(clients);
}
if (!debug) {
FD_ZERO(&mask);
FD_SET(2, &mask);
divorce_terminal((int) &mask);
}
{
STATUS status_vector[ISC_STATUS_LENGTH];
THREAD_ENTER;
port = INET_connect(protocol, 0, status_vector, INET_SERVER_flag,
0, 0);
THREAD_EXIT;
if (!port) {
gds__print_status(status_vector);
exit(STARTUP_ERROR);
}
}
}
else {
#ifdef VMS
channel = assign("SYS$INPUT");
#endif
THREAD_ENTER;
port = INET_server(channel);
THREAD_EXIT;
if (!port) {
ib_fprintf(ib_stderr, "fbserver: Unable to start INET_server\n");
exit(STARTUP_ERROR);
}
}
#ifdef SUPERSERVER
/* before starting the superserver stuff change directory to tmp */
if (CHANGE_DIR(TEMP_DIR)) {
char err_buf[1024];
/* error on changing the directory */
sprintf(err_buf, "Could not change directory to %s due to errno %d",
TEMP_DIR, errno);
gds__log(err_buf);
}
/* Server tries to attash to security.fdb to make sure everything is OK
This code fixes bug# 8429 + all other bug of that kind - from
now on the server exits if it cannot attach to the database
(wrong or no license, not enough memory, etc.
*/
{
TEXT path[MAXPATHLEN];
STATUS status[ISC_STATUS_LENGTH];
isc_db_handle db_handle = 0L;
gds__prefix(path, USER_INFO_NAME);
isc_attach_database(status, strlen(path), path, &db_handle, 0, NULL);
if (status[0] == 1 && status[1] > 0) {
gds__log_status(USER_INFO_NAME, status);
isc_print_status(status);
exit(STARTUP_ERROR);
}
isc_detach_database(status, &db_handle);
if (status[0] == 1 && status[1] > 0) {
gds__log_status(USER_INFO_NAME, status);
isc_print_status(status);
exit(STARTUP_ERROR);
}
}
trace_pools = Config::getTraceMemoryPools();
#endif
if (multi_threaded)
SRVR_multi_thread(port, INET_SERVER_flag);
else
#ifdef WINDOWS_ROUTER
SRVR_WinMain(port, INET_SERVER_flag, hInstance, hPrevInstance,
nCmdShow);
#else
SRVR_main(port, INET_SERVER_flag);
#endif
#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
exit(FINI_OK);
}
#ifdef WINDOWS_ROUTER
static int atov( UCHAR * str, UCHAR ** vec, SSHORT len)
{
/**************************************
*
* a t o v
*
**************************************
*
* Functional description
* Take a string and convert it to a vector.
* White space delineates, but things in quotes are
* kept together.
*
**************************************/
int i = 0, qt = 0, qq;
char *p1, *p2;
vec[0] = str;
for (p1 = p2 = str; i < len; i++) {
while (*p1 == ' ' || *p1 == '\t')
p1++;
while (qt || (*p1 != ' ' && *p1 != '\t')) {
qq = qt;
if (*p1 == '\'')
if (!qt)
qt = -1;
else if (qt == -1)
qt = 0;
if (*p1 == '"')
if (!qt)
qt = 1;
else if (qt == 1)
qt = 0;
if (*p1 == '\0' || *p1 == '\n') {
*p2++ = '\0';
vec[++i] = 0;
return i;
}
if (qq == qt)
*p2++ = *p1;
p1++;
}
p1++;
*p2++ = '\0';
vec[i + 1] = p2;
}
*p2 = '\0';
vec[i] = 0;
return i - 1;
}
#endif /* WINDOWS_ROUTER */
#ifdef VMS
static int assign( SCHAR * string)
{
/**************************************
*
* a s s i g n
*
**************************************
*
* Functional description
* Assign a channel for communications.
*
**************************************/
SSHORT channel;
int status;
struct dsc$descriptor_s desc;
desc.dsc$b_dtype = DSC$K_DTYPE_T;
desc.dsc$b_class = DSC$K_CLASS_S;
desc.dsc$w_length = strlen(string);
desc.dsc$a_pointer = string;
status = sys$assign(&desc, &channel, NULL, NULL);
return (status & 1) ? channel : 0;
}
#endif
#if !(defined VMS)
static void set_signal( int signal_number, void (*handler) (void))
{
/**************************************
*
* s e t _ s i g n a l
*
**************************************
*
* Functional description
* Establish signal handler.
*
**************************************/
#ifdef SYSV_SIGNALS
sigset(signal_number, handler);
#else
#ifndef HAVE_SIGACTION
struct sigvec vec;
struct sigvec old_vec;
vec.sv_handler = handler;
vec.sv_mask = 0;
vec.sv_flags = SV_INTERRUPT;
sigvector(signal_number, &vec, &old_vec);
#else
struct sigaction vec, old_vec;
vec.sa_handler = (SIG_FPTR) handler;
memset(&vec.sa_mask, 0, sizeof(vec.sa_mask));
vec.sa_flags = 0;
sigaction(signal_number, &vec, &old_vec);
#endif
#endif
}
#endif
static void signal_handler(void)
{
/**************************************
*
* s i g n a l _ h a n d l e r
*
**************************************
*
* Functional description
* Dummy signal handler.
*
**************************************/
++INET_SERVER_start;
}
#if (defined SUPERSERVER && defined UNIX )
static void signal_sigpipe_handler(void)
{
/****************************************************
*
* s i g n a l _ s i g p i p e _ h a n d l e r
*
****************************************************
*
* Functional description
* Dummy signal handler.
*
**************************************/
++INET_SERVER_start;
gds__log
("Super Server/main: Bad client socket, send() resulted in SIGPIPE, caught by server\n client exited improperly or crashed ????");
}
#endif
} // extern "C"