svc.cpp (Firebird-3.0.2.32703-0.tar.bz2) | : | svc.cpp (Firebird-3.0.4.33054-0.tar.bz2) | ||
---|---|---|---|---|
skipping to change at line 138 | skipping to change at line 138 | |||
namespace { | namespace { | |||
// Generic mutex to synchronize services | // Generic mutex to synchronize services | |||
GlobalPtr<Mutex> globalServicesMutex; | GlobalPtr<Mutex> globalServicesMutex; | |||
// All that we need to shutdown service threads when shutdown in progress | // All that we need to shutdown service threads when shutdown in progress | |||
typedef Array<Jrd::Service*> AllServices; | typedef Array<Jrd::Service*> AllServices; | |||
GlobalPtr<AllServices> allServices; // protected by globalServicesMut ex | GlobalPtr<AllServices> allServices; // protected by globalServicesMut ex | |||
volatile bool svcShutdown = false; | volatile bool svcShutdown = false; | |||
class ThreadCollect | ||||
{ | ||||
public: | ||||
ThreadCollect(MemoryPool& p) | ||||
: threads(p) | ||||
{ } | ||||
void join() | ||||
{ | ||||
// join threads to be sure they are gone when shutdown is | ||||
complete | ||||
// no need locking something cause this is expected to ru | ||||
n when services are closing | ||||
waitFor(threads); | ||||
} | ||||
void add(Thread::Handle& h) | ||||
{ | ||||
// put thread into completion wait queue when it finished | ||||
running | ||||
MutexLockGuard g(threadsMutex, FB_FUNCTION); | ||||
threads.add(h); | ||||
} | ||||
void houseKeeping() | ||||
{ | ||||
if (!threads.hasData()) | ||||
return; | ||||
// join finished threads | ||||
AllThreads t; | ||||
{ // mutex scope | ||||
MutexLockGuard g(threadsMutex, FB_FUNCTION); | ||||
t.assign(threads); | ||||
threads.clear(); | ||||
} | ||||
waitFor(t); | ||||
} | ||||
private: | ||||
typedef Array<Thread::Handle> AllThreads; | ||||
static void waitFor(AllThreads& thr) | ||||
{ | ||||
while (thr.hasData()) | ||||
{ | ||||
Thread::Handle h(thr.pop()); | ||||
Thread::waitForCompletion(h); | ||||
} | ||||
} | ||||
AllThreads threads; | ||||
Mutex threadsMutex; | ||||
}; | ||||
GlobalPtr<ThreadCollect> threadCollect; | ||||
void spbVersionError() | void spbVersionError() | |||
{ | { | |||
ERR_post(Arg::Gds(isc_bad_spb_form) << | ERR_post(Arg::Gds(isc_bad_spb_form) << | |||
Arg::Gds(isc_wrospbver)); | Arg::Gds(isc_wrospbver)); | |||
} | } | |||
} // anonymous namespace | } // anonymous namespace | |||
using namespace Jrd; | using namespace Jrd; | |||
skipping to change at line 257 | skipping to change at line 312 | |||
case isc_spb_command_line: | case isc_spb_command_line: | |||
spb.getString(svc_command_line); | spb.getString(svc_command_line); | |||
break; | break; | |||
case isc_spb_expected_db: | case isc_spb_expected_db: | |||
spb.getPath(svc_expected_db); | spb.getPath(svc_expected_db); | |||
break; | break; | |||
case isc_spb_address_path: | case isc_spb_address_path: | |||
spb.getString(svc_address_path); | spb.getData(svc_address_path); | |||
{ | { | |||
ClumpletReader address_stack(ClumpletReader::UnTa gged, | ClumpletReader address_stack(ClumpletReader::UnTa gged, | |||
spb.getBytes(), spb.getClumpLength()); | spb.getBytes(), spb.getClumpLength()); | |||
while (!address_stack.isEof()) | while (!address_stack.isEof()) | |||
{ | { | |||
if (address_stack.getClumpTag() != isc_dp b_address) | if (address_stack.getClumpTag() != isc_dp b_address) | |||
{ | { | |||
address_stack.moveNext(); | address_stack.moveNext(); | |||
continue; | continue; | |||
} | } | |||
skipping to change at line 565 | skipping to change at line 620 | |||
} | } | |||
unsigned int Service::getAuthBlock(const unsigned char** bytes) | unsigned int Service::getAuthBlock(const unsigned char** bytes) | |||
{ | { | |||
*bytes = svc_auth_block.hasData() ? svc_auth_block.begin() : NULL; | *bytes = svc_auth_block.hasData() ? svc_auth_block.begin() : NULL; | |||
return svc_auth_block.getCount(); | return svc_auth_block.getCount(); | |||
} | } | |||
void Service::fillDpb(ClumpletWriter& dpb) | void Service::fillDpb(ClumpletWriter& dpb) | |||
{ | { | |||
const char* providers = "Providers=" CURRENT_ENGINE; | dpb.insertString(isc_dpb_config, EMBEDDED_PROVIDERS, fb_strlen(EMBEDDED_P | |||
dpb.insertString(isc_dpb_config, providers, fb_strlen(providers)); | ROVIDERS)); | |||
if (svc_address_path.hasData()) | if (svc_address_path.hasData()) | |||
{ | { | |||
dpb.insertString(isc_dpb_address_path, svc_address_path); | dpb.insertData(isc_dpb_address_path, svc_address_path); | |||
} | } | |||
if (svc_utf8) | if (svc_utf8) | |||
{ | { | |||
dpb.insertTag(isc_dpb_utf8_filename); | dpb.insertTag(isc_dpb_utf8_filename); | |||
} | } | |||
if (svc_crypt_callback) | if (svc_crypt_callback) | |||
{ | { | |||
// That's not DPB-related, but anyway should be done before attac h/create DB | // That's not DPB-related, but anyway should be done before attac h/create DB | |||
ISC_STATUS_ARRAY status; | ISC_STATUS_ARRAY status; | |||
if (fb_database_crypt_callback(status, svc_crypt_callback) != 0) | if (fb_database_crypt_callback(status, svc_crypt_callback) != 0) | |||
skipping to change at line 653 | skipping to change at line 707 | |||
svc_resp_len(0), svc_flags(SVC_finished), svc_user_flag(0), svc_spb_versi on(0), | svc_resp_len(0), svc_flags(SVC_finished), svc_user_flag(0), svc_spb_versi on(0), | |||
svc_do_shutdown(false), svc_shutdown_in_progress(false), svc_timeout(fals e), | svc_do_shutdown(false), svc_shutdown_in_progress(false), svc_timeout(fals e), | |||
svc_username(getPool()), svc_sql_role(getPool()), svc_auth_block(getPool( )), | svc_username(getPool()), svc_sql_role(getPool()), svc_auth_block(getPool( )), | |||
svc_expected_db(getPool()), svc_trusted_role(false), svc_utf8(false), | svc_expected_db(getPool()), svc_trusted_role(false), svc_utf8(false), | |||
svc_switches(getPool()), svc_perm_sw(getPool()), svc_address_path(getPool ()), | svc_switches(getPool()), svc_perm_sw(getPool()), svc_address_path(getPool ()), | |||
svc_command_line(getPool()), | svc_command_line(getPool()), | |||
svc_network_protocol(getPool()), svc_remote_address(getPool()), svc_remot e_process(getPool()), | svc_network_protocol(getPool()), svc_remote_address(getPool()), svc_remot e_process(getPool()), | |||
svc_remote_pid(0), svc_trace_manager(NULL), svc_crypt_callback(crypt_call back), | svc_remote_pid(0), svc_trace_manager(NULL), svc_crypt_callback(crypt_call back), | |||
svc_existence(FB_NEW_POOL(*getDefaultMemoryPool()) SvcMutex(this)), | svc_existence(FB_NEW_POOL(*getDefaultMemoryPool()) SvcMutex(this)), | |||
svc_stdin_size_requested(0), svc_stdin_buffer(NULL), svc_stdin_size_prelo ad(0), | svc_stdin_size_requested(0), svc_stdin_buffer(NULL), svc_stdin_size_prelo ad(0), | |||
svc_stdin_preload_requested(0), svc_stdin_user_size(0) | svc_stdin_preload_requested(0), svc_stdin_user_size(0), svc_thread(0) | |||
#ifdef DEV_BUILD | #ifdef DEV_BUILD | |||
, svc_debug(false) | , svc_debug(false) | |||
#endif | #endif | |||
{ | { | |||
initStatus(); | initStatus(); | |||
{ // scope | { // scope | |||
// Account service block in global array | // Account service block in global array | |||
MutexLockGuard guard(globalServicesMutex, FB_FUNCTION); | MutexLockGuard guard(globalServicesMutex, FB_FUNCTION); | |||
checkForShutdown(); | checkForShutdown(); | |||
skipping to change at line 978 | skipping to change at line 1032 | |||
{ | { | |||
globalServicesMutex->leave(); | globalServicesMutex->leave(); | |||
Thread::sleep(1); | Thread::sleep(1); | |||
globalServicesMutex->enter(FB_FUNCTION); | globalServicesMutex->enter(FB_FUNCTION); | |||
pos = 0; | pos = 0; | |||
continue; | continue; | |||
} | } | |||
++pos; | ++pos; | |||
} | } | |||
threadCollect->join(); | ||||
} | } | |||
ISC_STATUS Service::query2(thread_db* /*tdbb*/, | ISC_STATUS Service::query2(thread_db* /*tdbb*/, | |||
USHORT send_item_length, | USHORT send_item_length, | |||
const UCHAR* send_items, | const UCHAR* send_items, | |||
USHORT recv_item_length, | USHORT recv_item_length, | |||
const UCHAR* recv_items, | const UCHAR* recv_items, | |||
USHORT buffer_length, | USHORT buffer_length, | |||
UCHAR* info) | UCHAR* info) | |||
{ | { | |||
skipping to change at line 1117 | skipping to change at line 1173 | |||
if (!ck_space_for_numeric(info, end)) | if (!ck_space_for_numeric(info, end)) | |||
return 0; | return 0; | |||
*info++ = isc_spb_num_db; | *info++ = isc_spb_num_db; | |||
ADD_SPB_NUMERIC(info, num_dbs); | ADD_SPB_NUMERIC(info, num_dbs); | |||
// Move db names into the info buffer | // Move db names into the info buffer | |||
for (FB_SIZE_T i = 0; i < databases.getCount(); i ++) | for (FB_SIZE_T i = 0; i < databases.getCount(); i ++) | |||
{ | { | |||
if (!(info = INF_put_item(isc_spb_dbname, | if (!(info = INF_put_item(isc_spb_dbname, | |||
(USHORT) databases[i].length(), | (USHORT) databases[i].length(), | |||
(const UCHAR*) databases[i].c_str(), | databases[i].c_str(), | |||
info, end))) | info, end))) | |||
{ | { | |||
return 0; | return 0; | |||
} | } | |||
} | } | |||
if (info < end) | if (info < end) | |||
*info++ = isc_info_flag_end; | *info++ = isc_info_flag_end; | |||
} | } | |||
else | else | |||
skipping to change at line 1257 | skipping to change at line 1313 | |||
if (svc_flags & SVC_finished) | if (svc_flags & SVC_finished) | |||
ADD_SPB_NUMERIC(info, FALSE) | ADD_SPB_NUMERIC(info, FALSE) | |||
else | else | |||
ADD_SPB_NUMERIC(info, TRUE) | ADD_SPB_NUMERIC(info, TRUE) | |||
break; | break; | |||
case isc_info_svc_server_version: | case isc_info_svc_server_version: | |||
// The version of the server engine | // The version of the server engine | |||
{ // scope | { // scope | |||
static const UCHAR* pv = reinterpret_cast<const U | info = INF_put_item(item, static_cast<USHORT>(str | |||
CHAR*>(FB_VERSION); | len(FB_VERSION)), FB_VERSION, info, end); | |||
info = INF_put_item(item, static_cast<USHORT>(str | ||||
len(FB_VERSION)), pv, info, end); | ||||
if (!info) { | if (!info) { | |||
return 0; | return 0; | |||
} | } | |||
} // scope | } // scope | |||
break; | break; | |||
case isc_info_svc_implementation: | case isc_info_svc_implementation: | |||
// The server implementation - e.g. Firebird/sun4 | // The server implementation - e.g. Firebird/sun4 | |||
{ // scope | { // scope | |||
string buf2 = DbImplementation::current.implement ation(); | string buf2 = DbImplementation::current.implement ation(); | |||
info = INF_put_item(item, buf2.length(), | info = INF_put_item(item, buf2.length(), buf2.c_s | |||
reinterpr | tr(), info, end); | |||
et_cast<const UCHAR*>(buf2.c_str()), info, end); | ||||
if (!info) { | if (!info) { | |||
return 0; | return 0; | |||
} | } | |||
} // scope | } // scope | |||
break; | break; | |||
case isc_info_svc_stdin: | case isc_info_svc_stdin: | |||
// Check - is stdin data required for server | // Check - is stdin data required for server | |||
if (!ck_space_for_numeric(info, end)) | if (!ck_space_for_numeric(info, end)) | |||
{ | { | |||
skipping to change at line 1296 | skipping to change at line 1350 | |||
stdin_request_notification = info; | stdin_request_notification = info; | |||
} | } | |||
ADD_SPB_NUMERIC(info, 0); | ADD_SPB_NUMERIC(info, 0); | |||
break; | break; | |||
case isc_info_svc_user_dbpath: | case isc_info_svc_user_dbpath: | |||
if (svc_user_flag & SVC_user_dba) | if (svc_user_flag & SVC_user_dba) | |||
{ | { | |||
// The path to the user security database (securi ty2.fdb) | // The path to the user security database (securi ty2.fdb) | |||
char* pb = reinterpret_cast<char*>(buffer); | ||||
const RefPtr<const Config> defConf(Config::getDef aultConfig()); | const RefPtr<const Config> defConf(Config::getDef aultConfig()); | |||
strcpy(pb, defConf->getSecurityDatabase()); | const char* secDb = defConf->getSecurityDatabase( ); | |||
if (!(info = INF_put_item(item, static_cast<USHOR T>(strlen(pb)), buffer, info, end))) | if (!(info = INF_put_item(item, static_cast<USHOR T>(strlen(secDb)), secDb, info, end))) | |||
{ | { | |||
return 0; | return 0; | |||
} | } | |||
} | } | |||
else | else | |||
need_admin_privs(status, "isc_info_svc_user_dbpat h"); | need_admin_privs(status, "isc_info_svc_user_dbpat h"); | |||
break; | break; | |||
case isc_info_svc_response: | case isc_info_svc_response: | |||
svc_resp_len = 0; | svc_resp_len = 0; | |||
skipping to change at line 1648 | skipping to change at line 1701 | |||
case isc_info_svc_get_env_lock: | case isc_info_svc_get_env_lock: | |||
iscPrefixLock(PathBuffer, "", false); | iscPrefixLock(PathBuffer, "", false); | |||
break; | break; | |||
case isc_info_svc_get_env_msg: | case isc_info_svc_get_env_msg: | |||
gds__prefix_msg(PathBuffer, ""); | gds__prefix_msg(PathBuffer, ""); | |||
} | } | |||
// Note: it is safe to use strlen to get a length of "buffer" | // Note: it is safe to use strlen to get a length of "buffer" | |||
// because gds_prefix[_lock|_msg] return a zero-t erminated | // because gds_prefix[_lock|_msg] return a zero-t erminated | |||
// string. | // string. | |||
const UCHAR* pb = reinterpret_cast<const UCHAR*>( | if (!(info = INF_put_item(item, static_cast<USHOR | |||
PathBuffer); | T>(strlen(PathBuffer)), PathBuffer, info, end))) | |||
if (!(info = INF_put_item(item, static_cast<USHOR | ||||
T>(strlen(PathBuffer)), pb, info, end))) | ||||
return; | return; | |||
} | } | |||
// Can not return error for service v.1 => simply ignore request | // Can not return error for service v.1 => simply ignore request | |||
// else | // else | |||
// need_admin_privs(status, "isc_info_svc_get_env"); | // need_admin_privs(status, "isc_info_svc_get_env"); | |||
break; | break; | |||
case isc_info_svc_dump_pool_info: | case isc_info_svc_dump_pool_info: | |||
{ | { | |||
char fname[MAXPATHLEN]; | char fname[MAXPATHLEN]; | |||
skipping to change at line 1748 | skipping to change at line 1800 | |||
if (!(info = INF_put_item(item, p - buffer, buffer, info, end))) | if (!(info = INF_put_item(item, p - buffer, buffer, info, end))) | |||
{ | { | |||
return; | return; | |||
} | } | |||
break; | break; | |||
case isc_info_svc_user_dbpath: | case isc_info_svc_user_dbpath: | |||
if (svc_user_flag & SVC_user_dba) | if (svc_user_flag & SVC_user_dba) | |||
{ | { | |||
// The path to the user security database (securi ty2.fdb) | // The path to the user security database (securi ty2.fdb) | |||
char* pb = reinterpret_cast<char*>(buffer); | ||||
const RefPtr<const Config> defConf(Config::getDef aultConfig()); | const RefPtr<const Config> defConf(Config::getDef aultConfig()); | |||
strcpy(pb, defConf->getSecurityDatabase()); | const char* secDb = defConf->getSecurityDatabase( ); | |||
if (!(info = INF_put_item(item, static_cast<USHOR T>(strlen(pb)), buffer, info, end))) | if (!(info = INF_put_item(item, static_cast<USHOR T>(strlen(secDb)), secDb, info, end))) | |||
{ | { | |||
return; | return; | |||
} | } | |||
} | } | |||
// Can not return error for service v.1 => simply ignore request | // Can not return error for service v.1 => simply ignore request | |||
// else | // else | |||
// need_admin_privs(status, "isc_info_svc_user_dbpat h"); | // need_admin_privs(status, "isc_info_svc_user_dbpat h"); | |||
break; | break; | |||
case isc_info_svc_response: | case isc_info_svc_response: | |||
skipping to change at line 1903 | skipping to change at line 1954 | |||
THREAD_ENTRY_DECLARE Service::run(THREAD_ENTRY_PARAM arg) | THREAD_ENTRY_DECLARE Service::run(THREAD_ENTRY_PARAM arg) | |||
{ | { | |||
int exit_code = -1; | int exit_code = -1; | |||
try | try | |||
{ | { | |||
Service* svc = (Service*)arg; | Service* svc = (Service*)arg; | |||
RefPtr<SvcMutex> ref(svc->svc_existence); | RefPtr<SvcMutex> ref(svc->svc_existence); | |||
exit_code = svc->svc_service_run->serv_thd(svc); | exit_code = svc->svc_service_run->serv_thd(svc); | |||
if (svc->svc_thread) | ||||
{ | ||||
threadCollect->add(svc->svc_thread); | ||||
svc->svc_thread = 0; | ||||
} | ||||
svc->started(); | svc->started(); | |||
svc->svc_sem_full.release(); | svc->svc_sem_full.release(); | |||
svc->finish(SVC_finished); | svc->finish(SVC_finished); | |||
} | } | |||
catch (const Exception& ex) | catch (const Exception& ex) | |||
{ | { | |||
// Not much we can do here | // Not much we can do here | |||
exit_code = -1; | exit_code = -1; | |||
iscLogException("Exception in Service::run():", ex); | iscLogException("Exception in Service::run():", ex); | |||
} | } | |||
skipping to change at line 2064 | skipping to change at line 2120 | |||
// The service block can be reused hence init a status vector. | // The service block can be reused hence init a status vector. | |||
initStatus(); | initStatus(); | |||
if (serv->serv_thd) | if (serv->serv_thd) | |||
{ | { | |||
svc_flags &= ~(SVC_evnt_fired | SVC_finished); | svc_flags &= ~(SVC_evnt_fired | SVC_finished); | |||
svc_stdout_head = svc_stdout_tail = 0; | svc_stdout_head = svc_stdout_tail = 0; | |||
Thread::start(run, this, THREAD_medium); | Thread::start(run, this, THREAD_medium, &svc_thread); | |||
// good time for housekeeping while new thread starts | ||||
threadCollect->houseKeeping(); | ||||
// Check for the service being detached. This will prevent the th read | // Check for the service being detached. This will prevent the th read | |||
// from waiting infinitely if the client goes away. | // from waiting infinitely if the client goes away. | |||
while (!(svc_flags & SVC_detached)) | while (!(svc_flags & SVC_detached)) | |||
{ | { | |||
// The semaphore will be released once the particular ser vice | // The semaphore will be released once the particular ser vice | |||
// has reached a point in which it can start to return | // has reached a point in which it can start to return | |||
// information to the client. This will allow isc_servic e_start | // information to the client. This will allow isc_servic e_start | |||
// to include in its status vector information about the service's | // to include in its status vector information about the service's | |||
// ability to start. | // ability to start. | |||
skipping to change at line 2187 | skipping to change at line 2246 | |||
{ | { | |||
// Break up the command line into individual arguments. | // Break up the command line into individual arguments. | |||
parseSwitches(); | parseSwitches(); | |||
if (svc_service && svc_service->serv_name) | if (svc_service && svc_service->serv_name) | |||
{ | { | |||
argv[0] = svc_service->serv_name; | argv[0] = svc_service->serv_name; | |||
} | } | |||
svc_service_run = service_run; | svc_service_run = service_run; | |||
Thread::start(run, this, THREAD_medium); | Thread::start(run, this, THREAD_medium, &svc_thread); | |||
} | } | |||
ULONG Service::add_one(ULONG i) | ULONG Service::add_one(ULONG i) | |||
{ | { | |||
return (i + 1) % SVC_STDOUT_BUFFER_SIZE; | return (i + 1) % SVC_STDOUT_BUFFER_SIZE; | |||
} | } | |||
ULONG Service::add_val(ULONG i, ULONG val) | ULONG Service::add_val(ULONG i, ULONG val) | |||
{ | { | |||
return (i + val) % SVC_STDOUT_BUFFER_SIZE; | return (i + val) % SVC_STDOUT_BUFFER_SIZE; | |||
End of changes. 19 change blocks. | ||||
25 lines changed or deleted | 86 lines changed or added |