/************************************************************************* * UrBackup - Client/Server backup system * Copyright (C) 2011 Martin Raiber * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . **************************************************************************/ #include "vld.h" #include #include #include #ifndef _WIN32 #include #endif #include "libfastcgi/fastcgi.hpp" #include "Interface/PluginMgr.h" #include "Interface/Thread.h" #include "Server.h" #include "Template.h" #include "stringtools.h" #include "defaults.h" #include "SessionMgr.h" #include "md5.h" #include "ServiceAcceptor.h" #include "LookupService.h" #include "FileSettingsReader.h" #include "DBSettingsReader.h" #include "StreamPipe.h" #include "ThreadPool.h" #include "file.h" #include "utf8/utf8.h" #include "MemoryPipe.h" #include "MemorySettingsReader.h" //#include "file_memory.h" #ifdef THREAD_BOOST #include #include #include #include "Mutex_boost.h" #include "Condition_boost.h" #else #ifdef _WIN32 #else #include #include "Mutex_lin.h" #include "Condition_lin.h" #endif #endif #ifdef _WIN32 # include # include "Helper_win32.h" #else # include # include # include # include # include #endif const size_t SEND_BLOCKSIZE=8192; CServer::CServer() { curr_thread_id=0; curr_pluginid=0; curr_postfilekey=0; loglevel=LL_INFO; logfile_a=false; log_mutex=createMutex(); action_mutex=createMutex(); requests_mutex=createMutex(); outputs_mutex=createMutex(); db_mutex=createMutex(); thread_mutex=createMutex(); plugin_mutex=createMutex(); rps_mutex=createMutex(); postfiles_mutex=createMutex(); param_mutex=createMutex(); } void CServer::setup(void) { CFileSettingsReader::setup(); CDatabase::initMutex(); sessmgr=new CSessionMgr(); threadpool=new CThreadPool(); } void CServer::destroyAllDatabases(void) { for(std::map > >::iterator i=databases.begin(); i!=databases.end();++i) { for( std::map::iterator j=i->second.second.begin();j!=i->second.second.end();++j) { delete j->second; } i->second.second.clear(); } } CServer::~CServer() { Log("deleting cached settings..."); CFileSettingsReader::cleanup(); Log("deleting stream services..."); //Delete extra Services for(size_t i=0;i >::iterator iter1=perthread_pluginparams.begin(); iter1!=perthread_pluginparams.end();++iter1) { std::map >::iterator iter2=perthread_plugins.find( iter1->first ); if( iter2!=perthread_plugins.end() ) { std::map *pmap=&iter2->second; for( std::map::iterator iter3=pmap->begin();iter3!=pmap->end();++iter3 ) { iter1->second.first->destroyPluginInstance( iter3->second ); } } } Log("Deleting threadsafe plugins..."); for(std::map::iterator iter1=threadsafe_plugins.begin();iter1!=threadsafe_plugins.end();++iter1) { iter1->second->Remove(); } Log("Deleting pluginmanagers..."); for(std::map::iterator iter=perthread_pluginmgrs.begin();iter!=perthread_pluginmgrs.end();++iter) { iter->second->Remove(); } for(std::map::iterator iter=threadsafe_pluginmgrs.begin();iter!=threadsafe_pluginmgrs.end();++iter) { iter->second->Remove(); } Log("Deleting actions..."); for(std::map< std::wstring, std::map >::iterator iter1=actions.begin();iter1!=actions.end();++iter1) { for(std::map::iterator iter2=iter1->second.begin();iter2!=iter1->second.end();++iter2) { iter2->second->Remove(); } } actions.clear(); Log("Deleting sessmgr..."); delete sessmgr; Log("Shutting down ThreadPool..."); threadpool->Shutdown(); delete threadpool; Log("destroying databases..."); //Destroy Databases destroyAllDatabases(); Log("unloading dlls..."); UnloadDLLs(); Log("Destroying mutexes"); destroy(log_mutex); destroy(action_mutex); destroy(requests_mutex); destroy(outputs_mutex); destroy(db_mutex); destroy(thread_mutex); destroy(plugin_mutex); destroy(rps_mutex); destroy(postfiles_mutex); destroy(param_mutex); CDatabase::destroyMutex(); std::cout << "Server cleanup done..." << std::endl; } void CServer::setServerParameters(const str_nmap &pServerParams) { IScopedLock lock(param_mutex); server_params=pServerParams; } std::string CServer::getServerParameter(const std::string &key) { return getServerParameter(key, ""); } std::string CServer::getServerParameter(const std::string &key, const std::string &def) { IScopedLock lock(param_mutex); str_nmap::iterator iter=server_params.find(key); if( iter!=server_params.end() ) { return iter->second; } else return def; } void CServer::setServerParameter(const std::string &key, const std::string &value) { IScopedLock lock(param_mutex); server_params[key]=value; } void CServer::Log( const std::string &pStr, int LogLevel) { if( loglevel <=LogLevel ) { IScopedLock lock(log_mutex); time_t rawtime; char buffer [100]; time ( &rawtime ); #ifdef _WIN32 struct tm timeinfo; localtime_s(&timeinfo, &rawtime); strftime (buffer,100,"%x %X: ",&timeinfo); #else struct tm *timeinfo; timeinfo = localtime ( &rawtime ); strftime (buffer,100,"%x %X: ",timeinfo); #endif if( LogLevel==LL_ERROR ) { std::cout << buffer << "ERROR: " << pStr << std::endl; if(logfile_a) logfile << buffer << "ERROR: " << pStr << std::endl; } else if( LogLevel==LL_WARNING ) { std::cout << buffer << "WARNING: " << pStr << std::endl; if(logfile_a) logfile<< buffer << "WARNING: " << pStr << std::endl; } else { std::cout << buffer << pStr << std::endl; if(logfile_a) logfile << buffer << pStr << std::endl; } if(logfile_a) logfile.flush(); } } void CServer::Log( const std::wstring &pStr, int LogLevel) { if( loglevel <=LogLevel ) { IScopedLock lock(log_mutex); time_t rawtime; char buffer [100]; time ( &rawtime ); #ifdef _WIN32 struct tm timeinfo; localtime_s(&timeinfo, &rawtime); strftime (buffer,100,"%x %X: ",&timeinfo); #else struct tm *timeinfo; timeinfo = localtime ( &rawtime ); strftime (buffer,100,"%x %X: ",timeinfo); #endif if( LogLevel==LL_ERROR ) { std::cout << buffer; std::wcout << L"ERROR: " << pStr << std::endl; if(logfile_a) logfile << buffer << "ERROR: " << ConvertToUTF8(pStr) << std::endl; } else if( LogLevel==LL_WARNING ) { std::cout << buffer; std::wcout << L"WARNING: " << pStr << std::endl; if(logfile_a) logfile << buffer << "WARNING: " << ConvertToUTF8(pStr) << std::endl; } else { std::cout << buffer; std::wcout << pStr << std::endl; if(logfile_a) logfile << buffer << ConvertToUTF8(pStr) << std::endl; } if(logfile_a) logfile.flush(); } } void CServer::setLogFile(const std::string &plf, std::string chown_user) { if(logfile_a) { logfile.close(); logfile_a=false; } logfile.open( plf.c_str(), std::ios::app | std::ios::out | std::ios::binary ); if(logfile.is_open() ) { #ifndef _WIN32 if(!chown_user.empty()) { char buf[1000]; passwd pwbuf; passwd *pw; int rc=getpwnam_r(chown_user.c_str(), &pwbuf, buf, 1000, &pw); if(pw!=NULL) { chown(plf.c_str(), pw->pw_uid, pw->pw_gid); } else { Server->Log("Unable to change logfile ownership", LL_ERROR); } } #endif logfile_a=true; } } void CServer::setLogLevel(int LogLevel) { IScopedLock lock(log_mutex); loglevel=LogLevel; } THREAD_ID CServer::Execute(const std::wstring &action, const std::wstring &context, str_map &GET, str_map &POST, str_nmap &PARAMS, IOutputStream *req) { IAction *action_ptr=NULL; { IScopedLock lock(action_mutex); std::map >::iterator iter1=actions.find( context ); if( iter1!=actions.end() ) { std::map::iterator iter2=iter1->second.find(action); if( iter2!=iter1->second.end() ) action_ptr=iter2->second; } } if( action_ptr!=NULL ) { THREAD_ID tid=getThreadID(); IOutputStream *current_req=NULL; { IScopedLock lock(requests_mutex); std::map::iterator iter=current_requests.find(tid); if( iter!=current_requests.end() ) { current_req=iter->second; iter->second=req; } else { current_requests.insert(std::pair(tid, req) ); } } { IScopedLock lock(outputs_mutex); current_outputs[tid]=std::pair(false, ""); } action_ptr->Execute( GET, POST, tid, PARAMS); ClearDatabases(tid); WriteRaw(tid, NULL, 0, false); if( current_req!=NULL ) { IScopedLock lock(requests_mutex); current_requests[tid]=current_req; } return tid; } return 0; } std::string CServer::Execute(const std::wstring &action, const std::wstring &context, str_map &GET, str_map &POST, str_nmap &PARAMS) { CStringOutputStream cos; Execute(action, context, GET, POST, PARAMS, &cos); return cos.getData(); } void CServer::AddAction(IAction *action) { IScopedLock lock(action_mutex); std::map *ptr=&actions[action_context]; ptr->insert( std::pair(action->getName(), action ) ); } bool CServer::RemoveAction(IAction *action) { IScopedLock lock(action_mutex); std::map >::iterator iter1=actions.find(action_context); if( iter1!=actions.end() ) { std::map::iterator iter2=iter1->second.find( action->getName() ); if( iter2!=iter1->second.end() ) { iter1->second.erase( iter2 ); return true; } } return false; } void CServer::setActionContext(std::wstring context) { action_context=context; } void CServer::resetActionContext(void) { action_context.clear(); } unsigned int CServer::getTimeSeconds(void) { #ifdef _WIN32 SYSTEMTIME st; GetSystemTime(&st); return (unsigned int)(unix_timestamp(&st)); #else timeval t; gettimeofday(&t,NULL); return (unsigned int)t.tv_sec; #endif } unsigned int CServer::getTimeMS(void) { #ifdef _WIN32 return GetTickCount(); #else //return (unsigned int)(((double)clock()/(double)CLOCKS_PER_SEC)*1000.0); /* boost::xtime xt; boost::xtime_get(&xt, boost::TIME_UTC); static boost::int_fast64_t start_t=xt.sec; xt.sec-=start_t; unsigned int t=xt.sec*1000+(unsigned int)((double)xt.nsec/1000000.0); return t;*/ timeval tp; gettimeofday(&tp, NULL); static long start_t=tp.tv_sec; tp.tv_sec-=start_t; return tp.tv_sec*1000+tp.tv_usec/1000; #endif } void CServer::WriteRaw(THREAD_ID tid, const char *buf, size_t bsize, bool cached) { if( cached==false ) { IOutputStream* req=NULL; { IScopedLock lock(requests_mutex); std::map::iterator iter=current_requests.find( tid ); if( iter!=current_requests.end() ) req=iter->second; } if( req!=NULL ) { { IScopedLock lock(outputs_mutex); std::pair *co=¤t_outputs[tid]; std::string *curr_output=&co->second; bool sent=co->first; if( sent==false && next(*curr_output,0,"Content-type: ")==false ) { curr_output->insert(0, "Content-type: "+DEFAULT_CONTENTTYPE+"\r\n\r\n"); co->first=true; } if(curr_output->size()write(*curr_output); } else { for(size_t i=0,size=curr_output->size();iwrite(&(*curr_output)[i], (std::min)(SEND_BLOCKSIZE, size-i) ); } } curr_output->clear(); } if( bsize>0 && bsizewrite(buf, bsize); } else if(bsize>0 ) { for(size_t i=0,size=bsize;iwrite(&buf[i], (std::min)(SEND_BLOCKSIZE, size-i) ); } } } else Log("Couldn't find THREAD_ID - cached=true", LL_ERROR); } else { if( bsize>0 ) { IScopedLock lock(outputs_mutex); std::map >::iterator iter=current_outputs.find( tid ); if( iter!=current_outputs.end() ) { iter->second.second.append(buf, bsize); } else { Log("Couldn't find THREAD_ID - cached=false", LL_ERROR); } } } } void CServer::Write(THREAD_ID tid, const std::string &str, bool cached) { WriteRaw(tid, str.c_str(), str.size(), cached); } bool CServer::UnloadDLLs(void) { UnloadDLLs2(); return true; } void CServer::ShutdownPlugins(void) { for(std::map::iterator iter=unload_functs.begin(); iter!=unload_functs.end();++iter) { if(iter->second!=NULL) iter->second(); } unload_functs.clear(); } bool CServer::UnloadDLL(const std::string &name) { std::map::iterator iter=unload_functs.find(name); if(iter!=unload_functs.end() ) { if( iter->second!=NULL ) { iter->second(); unload_functs.erase(iter); } return true; } return false; } void CServer::destroy(IObject *obj) { obj->Remove(); } ITemplate* CServer::createTemplate(std::string pFile) { return new CTemplate(pFile); } THREAD_ID CServer::getThreadID(void) { #ifdef THREAD_BOOST IScopedLock lock(thread_mutex); boost::thread::id ct=boost::this_thread::get_id(); std::map::iterator iter=threads.find(ct); if(iter!=threads.end() ) { return iter->second; } ++curr_thread_id; if( curr_thread_id>10000 ) curr_thread_id=0; threads.insert( std::pair( ct, curr_thread_id) ); return curr_thread_id; #else #ifdef _WIN32 #else IScopedLock lock(thread_mutex); pthread_t ct=pthread_self(); std::map::iterator iter=threads.find(ct); if(iter!=threads.end() ) { return iter->second; } ++curr_thread_id; if( curr_thread_id>100000 ) curr_thread_id=0; threads.insert( std::pair( ct, curr_thread_id) ); return curr_thread_id; #endif #endif //THREAD_BOOST } bool CServer::openDatabase(std::string pFile, DATABASE_ID pIdentifier) { IScopedLock lock(db_mutex); std::fstream c(pFile.c_str(), std::ios::in); if( c.is_open()==false ) return false; c.close(); std::map > >::iterator iter=databases.find(pIdentifier); if( iter!=databases.end() ) return false; std::map thread_map; std::pair > tpair(pFile, thread_map); databases.insert( std::pair > >(pIdentifier, tpair) ); return true; } IDatabase* CServer::getDatabase(THREAD_ID tid, DATABASE_ID pIdentifier) { IScopedLock lock(db_mutex); std::map > >::iterator database_iter=databases.find(pIdentifier); if( database_iter==databases.end() ) { Log("Database with identifier \""+nconvert((int)pIdentifier)+"\" couldn't be opened", LL_ERROR); return NULL; } std::map::iterator thread_iter=database_iter->second.second.find( tid ); if( thread_iter==database_iter->second.second.end() ) { CDatabase *db=new CDatabase; if(db->Open(database_iter->second.first)==false ) { Log("Database \""+database_iter->second.first+"\" couldn't be opened", LL_ERROR); return NULL; } database_iter->second.second.insert( std::pair< THREAD_ID, CDatabase* >( tid, db ) ); return db; } else { return thread_iter->second; } } void CServer::ClearDatabases(THREAD_ID tid) { IScopedLock lock(db_mutex); for(std::map > >::iterator i=databases.begin(); i!=databases.end();++i) { std::map::iterator iter=i->second.second.find(tid); if( iter!=i->second.second.end() ) { iter->second->destroyAllQueries(); } } } void CServer::setContentType(THREAD_ID tid, const std::string &str) { { IScopedLock lock(outputs_mutex); std::pair *co=¤t_outputs[tid]; std::string *curr_output=&co->second; if( curr_output->find("Content-type: ")==0 ) { *curr_output=strdelete("Content-type: "+getbetween("Content-type: ","\r\n\r\n", *curr_output)+"\r\n\r\n", *curr_output); } if(curr_output->find("\r\n\r\n")!=std::string::npos ) { curr_output->insert(0, "Content-type: "+str+"\r\n"); } else { curr_output->insert(0, "Content-type: "+str+"\r\n\r\n"); } co->first=true; } } void CServer::addHeader(THREAD_ID tid, const std::string &str) { { IScopedLock lock(outputs_mutex); std::pair *co=¤t_outputs[tid]; std::string *curr_output=&co->second; std::string tadd=str; if( curr_output->find("\r\n\r\n")!=std::string::npos ) { tadd+="\r\n"; } else { tadd+="\r\n\r\n"; } curr_output->insert(0, tadd); co->first=true; } } ISessionMgr *CServer::getSessionMgr(void) { return sessmgr; } std::string CServer::GenerateHexMD5(const std::string &input) { MD5 md((unsigned char*)input.c_str() ); char *p=md.hex_digest(); std::string ret=p; delete []p; return ret; } std::string CServer::GenerateBinaryMD5(const std::string &input) { MD5 md((unsigned char*)input.c_str() ); unsigned char *p=md.raw_digest(); std::string ret; ret.resize(16); for(size_t i=0;i<16;++i) ret[i]=p[i]; delete []p; return ret; } std::string CServer::GenerateHexMD5(const std::wstring &input) { unsigned int *tmp=new unsigned int[input.size()]; for(size_t i=0,l=input.size();icreateThread(acc); stream_services.push_back( acc ); } IPipe* CServer::ConnectStream(std::string pServer, unsigned short pPort, unsigned int pTimeoutms) { sockaddr_in server; LookupBlocking(pServer, &server.sin_addr); server.sin_port=htons(pPort); server.sin_family=AF_INET; SOCKET s=socket(AF_INET, SOCK_STREAM, 0); if(s==SOCKET_ERROR) { return NULL; } #ifdef _WIN32 u_long nonBlocking=1; ioctlsocket(s,FIONBIO,&nonBlocking); #else fcntl(s,F_SETFL,fcntl(s, F_GETFL, 0) | O_NONBLOCK); #endif int rc=connect(s, (sockaddr*)&server, sizeof(sockaddr_in) ); #ifndef _WIN32 if(rc==SOCKET_ERROR) { if(errno!=EINPROGRESS) { closesocket(s); Server->Log("errno !=EINPROGRESS. Connect failed...", LL_DEBUG); return NULL; } } else { return new CStreamPipe(s); } #else if(rc!=SOCKET_ERROR) { return new CStreamPipe(s); } #endif fd_set conn; FD_ZERO(&conn); FD_SET(s, &conn); timeval lon; lon.tv_sec=(long)(pTimeoutms/1000); lon.tv_usec=(long)(pTimeoutms%1000)*1000; rc=select((int)s+1,NULL,&conn,NULL,&lon); if( rc>0 && FD_ISSET(s, &conn) ) { int err; socklen_t len=sizeof(int); rc=getsockopt(s, SOL_SOCKET, SO_ERROR, (char*)&err, &len); if(rc<0) { closesocket(s); Server->Log("Error getting socket status.", LL_ERROR); return NULL; } if(err) { closesocket(s); Server->Log("Socket has error: "+nconvert(err), LL_INFO); return NULL; } else { #ifdef _WIN32 int window_size=512*1024; setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *) &window_size, sizeof(window_size)); setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *) &window_size, sizeof(window_size)); #endif return new CStreamPipe(s); } } else { return NULL; } } void CServer::DisconnectStream(IPipe *pipe) { CStreamPipe *sp=(CStreamPipe*)pipe; SOCKET s=sp->getSocket(); closesocket(s); } bool CServer::RegisterPluginPerThreadModel(IPluginMgr *pPluginMgr, std::string pName) { IScopedLock lock(plugin_mutex); std::map::iterator iter=perthread_pluginmgrs.find( pName ); if( iter!= perthread_pluginmgrs.end() ) return false; perthread_pluginmgrs.insert( std::pair( pName, pPluginMgr ) ); return true; } bool CServer::RegisterPluginThreadsafeModel(IPluginMgr *pPluginMgr, std::string pName) { IScopedLock lock(plugin_mutex); std::map::iterator iter=threadsafe_pluginmgrs.find( pName ); if( iter!= threadsafe_pluginmgrs.end() ) return false; threadsafe_pluginmgrs.insert( std::pair( pName, pPluginMgr ) ); return true; } PLUGIN_ID CServer::StartPlugin(std::string pName, str_map ¶ms) { IScopedLock lock(plugin_mutex); { std::map::iterator iter=perthread_pluginmgrs.find( pName ); if( iter!=perthread_pluginmgrs.end() ) { ++curr_pluginid; std::pair tmp(iter->second, params); perthread_pluginparams.insert( std::pair >(curr_pluginid, tmp) ); return curr_pluginid; } } { std::map::iterator iter1=threadsafe_pluginmgrs.find( pName ); if( iter1!=threadsafe_pluginmgrs.end() ) { ++curr_pluginid; IPlugin *plugin=iter1->second->createPluginInstance( params ); threadsafe_plugins.insert( std::pair( curr_pluginid, plugin) ); return curr_pluginid; } } return ILLEGAL_PLUGIN_ID; } bool CServer::RestartPlugin(PLUGIN_ID pIdentifier) { IScopedLock lock(plugin_mutex); { std::map >::iterator iter1=perthread_plugins.find( pIdentifier ); if( iter1!=perthread_plugins.end() ) { bool ret=true; for( std::map::iterator iter2=iter1->second.begin();iter2!=iter1->second.end();++iter2) { bool b=iter2->second->Reload(); if( b==false ) ret=false; } return ret; } } { std::map::iterator iter1=threadsafe_plugins.find( pIdentifier ); if( iter1!=threadsafe_plugins.end() ) { return iter1->second->Reload(); } } return false; } IPlugin* CServer::getPlugin(THREAD_ID tid, PLUGIN_ID pIdentifier) { IScopedLock lock(plugin_mutex); { std::map::iterator iter1=threadsafe_plugins.find( pIdentifier ); if( iter1!=threadsafe_plugins.end() ) { return iter1->second; } } { std::map >::iterator iter1=perthread_pluginparams.find( pIdentifier ); if( iter1!= perthread_pluginparams.end() ) { std::map *pmap=&perthread_plugins[pIdentifier]; std::map::iterator iter2=pmap->find(tid); if( iter2==pmap->end() ) { IPlugin* newplugin=iter1->second.first->createPluginInstance( iter1->second.second); pmap->insert( std::pair( tid, newplugin) ); newplugin->Reset(); return newplugin; } else { iter2->second->Reset(); return iter2->second; } } } return NULL; } IMutex* CServer::createMutex(void) { return new CMutex; } IPipe *CServer::createMemoryPipe(void) { return new CMemoryPipe; } #ifdef THREAD_BOOST #else #ifndef _WIN32 void *thread_helper_f(void * t) { IThread *tmp=(IThread*)t; (*tmp)(); } #endif #endif //THREAD_BOOST void CServer::createThread(IThread *thread) { #ifdef THREAD_BOOST boost::thread tr(boost::ref(*thread)); tr.yield(); #else #ifdef _WIN32 #else pthread_t t; pthread_create(&t, NULL, &thread_helper_f, (void*)thread); #endif #endif //THREAD_BOOST } IThreadPool *CServer::getThreadPool(void) { return threadpool; } ISettingsReader* CServer::createFileSettingsReader(std::string pFile) { return new CFileSettingsReader(pFile); } ISettingsReader* CServer::createDBSettingsReader(THREAD_ID tid, DATABASE_ID pIdentifier, const std::string &pTable, const std::string &pSQL) { return new CDBSettingsReader(tid, pIdentifier, pTable, pSQL); } ISettingsReader* CServer::createDBSettingsReader(IDatabase *db, const std::string &pTable, const std::string &pSQL) { return new CDBSettingsReader(db, pTable, pSQL); } ISettingsReader* CServer::createMemorySettingsReader(const std::string &pData) { return new CMemorySettingsReader(pData); } void CServer::wait(unsigned int ms) { #ifdef _WIN32 Sleep(ms); #else usleep(ms*1000); #endif } unsigned int CServer::getNumRequests(void) { IScopedLock lock(rps_mutex); unsigned int ret=num_requests; num_requests=0; return ret; } void CServer::addRequest(void) { IScopedLock lock(rps_mutex); ++num_requests; } IFile* CServer::openFile(std::string pFilename, int pMode) { return openFile(widen(pFilename), pMode); } IFile* CServer::openFile(std::wstring pFilename, int pMode) { File *file=new File; if(!file->Open(pFilename, pMode) ) { delete file; return NULL; } return file; } IFile* CServer::openTemporaryFile(void) { File *file=new File; if(!file->OpenTemporaryFile(tmpdir) ) { Server->Log("Error creating temporary file", LL_ERROR); delete file; return NULL; } return file; } IFile* CServer::openMemoryFile(void) { //return new CMemoryFile(); return openTemporaryFile(); } bool CServer::deleteFile(std::string pFilename) { return DeleteFileInt(pFilename); } bool CServer::deleteFile(std::wstring pFilename) { return DeleteFileInt(pFilename); } std::string CServer::ConvertToUTF8(const std::wstring &input) { std::string ret; try { if(sizeof(wchar_t)==2 ) utf8::utf16to8(input.begin(), input.end(), back_inserter(ret)); else utf8::utf32to8(input.begin(), input.end(), back_inserter(ret)); } catch(...){} return ret; } std::wstring CServer::ConvertToUnicode(const std::string &input) { std::wstring ret; try { if(sizeof(wchar_t)==2) utf8::utf8to16(input.begin(), input.end(), back_inserter(ret)); else utf8::utf8to32(input.begin(), input.end(), back_inserter(ret)); } catch(...){} return ret; } std::string CServer::ConvertToUTF16(const std::wstring &input) { std::string ret; try { if(sizeof(wchar_t)==2) { ret.resize(input.size()*2); memcpy(&ret[0], &input[0], input.size()*2); } else { std::string utf8=ConvertToUTF8(input); std::vector tmp; utf8::utf8to16(utf8.begin(), utf8.end(), back_inserter(tmp) ); ret.resize(tmp.size()*2); memcpy(&ret[0], &tmp[0], tmp.size()*2); } } catch(...){} return ret; } std::string CServer::ConvertToUTF32(const std::wstring &input) { std::string ret; try { if(sizeof(wchar_t)==4) { ret.resize(input.size()*4); memcpy(&ret[0], &input[0], input.size()*4); } else { std::string utf8=ConvertToUTF8(input); std::vector tmp; utf8::utf8to32(utf8.begin(), utf8.end(), back_inserter(tmp) ); ret.resize(tmp.size()*4); memcpy(&ret[0], &tmp[0], tmp.size()*4); } } catch(...){} return ret; } std::wstring CServer::ConvertFromUTF16(const std::string &input) { std::wstring ret; try { if(sizeof(wchar_t)==2) { ret.resize(input.size()/2); memcpy(&ret[0], &input[0], input.size()); } else { if(input.empty()) { return L""; } else { std::string tmp; utf8::utf16to8((utf8::uint16_t*)&input[0], (utf8::uint16_t*)(&input[input.size()-1]+1), back_inserter(tmp)); ret=ConvertToUnicode(tmp); } } } catch(...){} return ret; } std::wstring CServer::ConvertFromUTF32(const std::string &input) { std::wstring ret; try { if(sizeof(wchar_t)==4) { ret.resize(input.size()/4); memcpy(&ret[0], &input[0], input.size()); } else { if(input.empty()) { return L""; } else { std::string tmp; utf8::utf32to8((utf8::uint32_t*)&input[0], (utf8::uint32_t*)(&input[input.size()-1]+1), back_inserter(tmp)); ret=ConvertToUnicode(tmp); } } } catch(...){} return ret; } ICondition* CServer::createCondition(void) { return new CCondition(); } void CServer::addPostFile(POSTFILE_KEY pfkey, const std::string &name, const SPostfile &pf) { IScopedLock lock(postfiles_mutex); postfiles[pfkey][name]=pf; } SPostfile CServer::getPostFile(POSTFILE_KEY pfkey, const std::string &name) { IScopedLock lock(postfiles_mutex); std::map >::iterator iter1=postfiles.find(pfkey); if(iter1!=postfiles.end()) { std::map::iterator iter2=iter1->second.find(name); if(iter2!=iter1->second.end() ) { return iter2->second; } } return SPostfile(); } void CServer::clearPostFiles(POSTFILE_KEY pfkey) { IScopedLock lock(postfiles_mutex); std::map >::iterator iter1=postfiles.find(pfkey); if(iter1!=postfiles.end()) { for(std::map::iterator iter2=iter1->second.begin();iter2!=iter1->second.end();++iter2) { destroy(iter2->second.file); } postfiles.erase(iter1); } } POSTFILE_KEY CServer::getPostFileKey() { IScopedLock lock(postfiles_mutex); return curr_postfilekey++; } std::wstring CServer::getServerWorkingDir(void) { return workingdir; } void CServer::setServerWorkingDir(const std::wstring &wdir) { workingdir=wdir; } void CServer::setTemporaryDirectory(const std::wstring &dir) { tmpdir=dir; }