Exemple #1
0
TracePlugin* FB_CARG TraceFactoryImpl::trace_create(Firebird::IStatus* status, TraceInitInfo* initInfo)
{
	Firebird::MasterInterfacePtr master;
	const char* dbname = NULL;
	try
	{
		master->upgradeInterface(initInfo, FB_TRACE_INIT_INFO_VERSION, upInfo);

		dbname = initInfo->getDatabaseName();
		if (!dbname)
			dbname = "";

		TracePluginConfig config;
		TraceCfgReader::readTraceConfiguration(initInfo->getConfigText(), dbname, config);

		TraceDatabaseConnection* connection = initInfo->getConnection();
		if (connection)
			master->upgradeInterface(connection, FB_TRACE_CONNECTION_VERSION, upInfo);

		if (!config.enabled ||
			(config.connection_id && connection &&
				(connection->getConnectionID() != SLONG(config.connection_id))))
		{
			return NULL; // Plugin is not needed, no error happened.
		}

		Firebird::AutoPtr<TraceLogWriter, Firebird::SimpleRelease<TraceLogWriter> >
			logWriter(initInfo->getLogWriter());

		if (logWriter)
			config.log_filename = "";

		return new TracePluginImpl(config, initInfo);	// Everything is ok, we created a plugin

	}
	catch (Firebird::Exception& ex)
	{
		// put error into trace log
		TraceLogWriter* logWriter = initInfo->getLogWriter();
		if (logWriter)
		{
			master->upgradeInterface(logWriter, FB_TRACE_LOG_WRITER_VERSION, upInfo);
			const char* strEx = TracePluginImpl::marshal_exception(ex);
			Firebird::string err;
			if (dbname)
				err.printf("Error creating trace session for database \"%s\":\n%s\n", dbname, strEx);
			else
				err.printf("Error creating trace session for service manager attachment:\n%s\n", strEx);

			logWriter->write(err.c_str(), err.length());
			logWriter->release();
		}
		else
			ex.stuffException(status);
	}

	return NULL;
}
Exemple #2
0
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.
 *
 **************************************/
	hInst = hThisInst;

	// We want server to crash without waiting for feedback from the user
	try
	{
		if (!Config::getBugcheckAbort())
			SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
	}
	catch (fatal_exception& e)
	{
		MessageBox(NULL, e.what(), "Firebird server failure",
			MB_OK | MB_ICONHAND | MB_SYSTEMMODAL  | MB_DEFAULT_DESKTOP_ONLY);
		return STARTUP_ERROR; // see /common/common.h
	}
	catch (status_exception& e)
	{
		TEXT buffer[BUFFER_LARGE];
		const ISC_STATUS* vector = e.value();
		if (! (vector && fb_interpret(buffer, sizeof(buffer), &vector)))
			strcpy(buffer, "Unknown internal failure");

		MessageBox(NULL, buffer, "Firebird server failure",
			MB_OK | MB_ICONHAND | MB_SYSTEMMODAL  | MB_DEFAULT_DESKTOP_ONLY);
		return STARTUP_ERROR; // see /common/common.h
	}

	// Check for missing firebird.conf
	if (Config::missFirebirdConf())
	{
		const char* anyError = "Missing master config file firebird.conf";
		Syslog::Record(Syslog::Error, anyError);
		MessageBox(NULL, anyError, "Firebird server failure",
			MB_OK | MB_ICONHAND | MB_SYSTEMMODAL  | MB_DEFAULT_DESKTOP_ONLY);
		return STARTUP_ERROR;
	}

	server_flag = 0;

	const DWORD affinity = static_cast<DWORD>(Config::getCpuAffinityMask());
	if (affinity)
		SetProcessAffinityMask(GetCurrentProcess(), affinity);

	protocol_inet[0] = 0;
	protocol_wnet[0] = 0;

	strcpy(instance, FB_DEFAULT_INSTANCE);

	const HANDLE connection_handle = parse_args(lpszArgs, &server_flag);

	// 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);
	}

	{
		Firebird::MasterInterfacePtr master;
		master->serverMode(server_flag & SRVR_multi_client ? 1 : 0);
	}

	TEXT mutex_name[MAXPATHLEN];
	fb_utils::snprintf(mutex_name, sizeof(mutex_name), SERVER_MUTEX, instance);
	fb_utils::prefix_kernel_object_name(mutex_name, sizeof(mutex_name));
	CreateMutex(ISC_get_security_desc(), FALSE, mutex_name);

	// Initialize the service

	ISC_signal_init();
	FpeControl::maskAll();

	int nReturnValue = 0;
	ISC_STATUS_ARRAY status_vector;
	fb_utils::init_status(status_vector);

	{ // scope for interface ptr
		PluginManagerInterfacePtr pi;
		Auth::registerLegacyServer(pi);
		Auth::registerSrpServer(pi);
#ifdef TRUSTED_AUTH
		Auth::registerTrustedServer(pi);
#endif
	}

	fb_shutdown_callback(0, wait_threads, fb_shut_finish, NULL);

	if (connection_handle != INVALID_HANDLE_VALUE)
	{
		rem_port* port = 0;

		try
		{
			if (server_flag & SRVR_inet)
			{
				port = INET_reconnect((SOCKET) connection_handle);

				if (port)
				{
					SRVR_multi_thread(port, server_flag);
					port = NULL;
				}
			}
			else if (server_flag & SRVR_wnet)
				port = WNET_reconnect(connection_handle);
			else if (server_flag & SRVR_xnet)
				port = XNET_reconnect((ULONG) connection_handle);

			if (port)
				service_connection(port);
		}
		catch (const Exception& ex)
		{
			iscLogException("Server error", ex);
		}

		fb_shutdown(5 * 1000 /*5 seconds*/, fb_shutrsn_no_connection);
	}
	else if (!(server_flag & SRVR_non_service))
	{
		string service_name;
		service_name.printf(REMOTE_SERVICE, instance);

		CNTL_init(start_connections_thread, instance);

		const SERVICE_TABLE_ENTRY service_table[] =
		{
			{const_cast<char*>(service_name.c_str()), CNTL_main_thread},
			{NULL, NULL}
		};

		// BRS There is a error in MinGW (3.1.0) headers
		// the parameter of StartServiceCtrlDispatcher is declared const in msvc headers
#if defined(MINGW)
		if (!StartServiceCtrlDispatcher(const_cast<SERVICE_TABLE_ENTRY*>(service_table)))
		{
#else
		if (!StartServiceCtrlDispatcher(service_table))
		{
#endif
			if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) {
				CNTL_shutdown_service("StartServiceCtrlDispatcher failed");
			}
			server_flag |= SRVR_non_service;
		}
	}
	else
	{
		start_connections_thread(0);
		nReturnValue = WINDOW_main(hThisInst, nWndMode, server_flag);
	}

#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__);
	PathName name = fb_utils::getPrefix(fb_utils::FB_DIR_LOG, "memdebug.log");
	FILE* file = fopen(name.c_str(), "w+t");
	if (file)
	{
		fprintf(file, "Global memory pool allocated objects\n");
		getDefaultMemoryPool()->print_contents(file);
		fclose(file);
	}
#endif

	return nReturnValue;
}


THREAD_ENTRY_DECLARE process_connection_thread(THREAD_ENTRY_PARAM arg)
{
/**************************************
 *
 *      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
 *
 **************************************/
	ThreadCounter counter;

	service_connection((rem_port*) arg);
	return 0;
}
int CLIB_ROUTINE main( int argc, char** argv)
{
/**************************************
 *
 *	m a i n
 *
 **************************************
 *
 * Functional description
 *	Run the server with apollo mailboxes.
 *
 **************************************/
	try
	{
		RemPortPtr port;

		// We should support 3 modes:
		// 1. Standalone single-process listener (like SS).
		// 2. Standalone listener, forking on each packet accepted (look -s switch in CS).
		// 3. Process spawned by (x)inetd (like CS).
		bool classic = false;
		bool standaloneClassic = false;
		bool super = false;

		// It's very easy to detect that we are spawned - just check fd 0 to be a socket.
		const int channel = 0;
		struct stat stat0;
		if (fstat(channel, &stat0) == 0 && S_ISSOCK(stat0.st_mode))
		{
			// classic server mode
			classic = true;
		}

		const TEXT* const* const end = argc + argv;
		argv++;
		bool debug = false;
		USHORT INET_SERVER_flag = 0;
		protocol[0] = 0;

		bool done = false;

		while (argv < end)
		{
			TEXT c;
			const TEXT* p = *argv++;

			if (*p++ == '-')
			{
				while (c = *p++)
				{
					switch (UPPER(c))
					{
					case 'D':
						debug = true;
						break;

					case 'E':
						if (argv < end)
						{
							if (ISC_set_prefix(p, *argv) == -1)
								printf("Invalid argument Ignored\n");
							else
								argv++;	// do not skip next argument if this one is invalid
						}
						else
						{
							printf("Missing argument, switch -E ignored\n");
						}
						done = true;
						break;

					case 'P':
						if (argv < end)
						{
							if (!classic)
							{
								fb_utils::snprintf(protocol, sizeof(protocol), "/%s", *argv++);
							}
							else
							{
								gds__log("Switch -P ignored in CS mode\n");
							}
						}
						else
						{
							printf("Missing argument, switch -P ignored\n");
						}
						break;

		            case 'H':
					case '?':
						printf("Firebird TCP/IP server options are:\n");
						printf("  -d        : debug on\n");
						printf("  -p <port> : specify port to listen on\n");
						printf("  -z        : print version and exit\n");
						printf("  -h|?      : print this help\n");
		                printf("\n");
		                printf("  (The following -e options used to be -h options)\n");
						printf("  -e <firebird_root_dir>   : set firebird_root path\n");
						printf("  -el <firebird_lock_dir>  : set runtime firebird_lock dir\n");
						printf("  -em <firebird_msg_dir>   : set firebird_msg dir path\n");

						exit(FINI_OK);

					case 'Z':
						printf("Firebird TCP/IP server version %s\n", FB_VERSION);
						exit(FINI_OK);

					default:
						printf("Unknown switch '%c', ignored\n", c);
						break;
					}
					if (done)
						break;
				}
			}
		}

		if (Config::getServerMode() == MODE_CLASSIC)
		{
			if (!classic)
				standaloneClassic = true;
		}
		else
		{
			if (classic)
			{
				gds__log("Server misconfigured - to start it from (x)inetd add ServerMode=Classic to firebird.conf");
				Firebird::Syslog::Record(Firebird::Syslog::Error, "Server misconfigured - add ServerMode=Classic to firebird.conf");
				exit(STARTUP_ERROR);
			}
			INET_SERVER_flag |= SRVR_multi_client;
			super = true;
		}
		{	// scope
			Firebird::MasterInterfacePtr master;
			master->serverMode(super ? 1 : 0);
		}

		if (debug)
		{
			INET_SERVER_flag |= SRVR_debug;
		}

		// activate paths set with -e family of switches
		ISC_set_prefix(0, 0);

		// ignore some signals
		set_signal(SIGPIPE, signal_handler);
		set_signal(SIGUSR1, signal_handler);
		set_signal(SIGUSR2, signal_handler);

		// First of all change directory to tmp
		if (chdir(TEMP_DIR))
		{
			// error on changing the directory
			gds__log("Could not change directory to %s due to errno %d", TEMP_DIR, errno);
		}

#ifdef FB_RAISE_LIMITS

#ifdef RLIMIT_NPROC
		raiseLimit(RLIMIT_NPROC);
#endif

#if !(defined(DEV_BUILD))
		if (Config::getBugcheckAbort())
#endif
		{
			// try to force core files creation
			raiseLimit(RLIMIT_CORE);
		}

#if (defined SOLARIS || defined HPUX || defined LINUX)
		if (super)
		{
			// Increase max open files to hard limit for Unix
			// platforms which are known to have low soft limits.

			raiseLimit(RLIMIT_NOFILE);
		}
#endif // Unix platforms

#endif // FB_RAISE_LIMITS

#ifdef HAVE_LOCALE_H
		// Pick up the system locale to allow SYSTEM<->UTF8 conversions inside the engine
		setlocale(LC_CTYPE, "");
#endif

		if (!(debug || classic))
		{
			int mask = 0; // FD_ZERO(&mask);
			mask |= 1 << 2; // FD_SET(2, &mask);
			divorce_terminal(mask);
		}

		// check firebird.conf presence - must be for server
		if (Config::missFirebirdConf())
		{
			Firebird::Syslog::Record(Firebird::Syslog::Error, "Missing master config file firebird.conf");
			exit(STARTUP_ERROR);
		}

		if (super || standaloneClassic)
		{
			try
			{
				port = INET_connect(protocol, 0, INET_SERVER_flag, 0, NULL);
			}
			catch (const Firebird::Exception& ex)
			{
				iscLogException("startup:INET_connect:", ex);
		 		Firebird::StaticStatusVector st;
				ex.stuffException(st);
				gds__print_status(st.begin());
				exit(STARTUP_ERROR);
			}
		}

		if (classic)
		{
			port = INET_server(channel);
			if (!port)
			{
				gds__log("Unable to start INET_server");
				Firebird::Syslog::Record(Firebird::Syslog::Error, "Unable to start INET_server");
				exit(STARTUP_ERROR);
			}
		}

		{ // scope for interface ptr
			Firebird::PluginManagerInterfacePtr pi;
			Auth::registerSrpServer(pi);
		}

		if (super)
		{
			// Server tries to attach to security2.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.

			ISC_STATUS_ARRAY status;
			isc_db_handle db_handle = 0L;

			const Firebird::RefPtr<Config> defConf(Config::getDefaultConfig());
			const char* path = defConf->getSecurityDatabase();
			const char dpb[] = {isc_dpb_version1, isc_dpb_sec_attach, 1, 1, isc_dpb_address_path, 0};

			isc_attach_database(status, strlen(path), path, &db_handle, sizeof dpb, dpb);
			if (status[0] == 1 && status[1] > 0)
			{
				logSecurityDatabaseError(path, status);
			}

			isc_detach_database(status, &db_handle);
			if (status[0] == 1 && status[1] > 0)
			{
				logSecurityDatabaseError(path, status);
			}
		} // end scope

		fb_shutdown_callback(NULL, closePort, fb_shut_exit, port);

		SRVR_multi_thread(port, INET_SERVER_flag);

#ifdef DEBUG_GDS_ALLOC
		// In Debug mode - this will report all server-side memory leaks due to remote access

		Firebird::PathName name = fb_utils::getPrefix(
			Firebird::IConfigManager::DIR_LOG, "memdebug.log");
		FILE* file = os_utils::fopen(name.c_str(), "w+t");
		if (file)
		{
			fprintf(file, "Global memory pool allocated objects\n");
			getDefaultMemoryPool()->print_contents(file);
			fclose(file);
		}
#endif

		// perform atexit shutdown here when all globals in embedded library are active
		// also sync with possibly already running shutdown in dedicated thread
		fb_shutdown(10000, fb_shutrsn_exit_called);

		return FINI_OK;
	}
	catch (const Firebird::Exception& ex)
	{
 		Firebird::StaticStatusVector st;
		ex.stuffException(st);

		char s[100];
		const ISC_STATUS* status = st.begin();
		fb_interpret(s, sizeof(s), &status);

		iscLogException("Firebird startup error:", ex);
		Firebird::Syslog::Record(Firebird::Syslog::Error, "Firebird startup error");
		Firebird::Syslog::Record(Firebird::Syslog::Error, s);

		exit(STARTUP_ERROR);
	}
}