00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifndef MANAGER_HPP
00023 #define MANAGER_HPP
00024
00025 #include <map>
00026 #include <string>
00027 #include <queue>
00028 #include <algorithm>
00029 #include <cstring>
00030
00031 #include <boost/bind.hpp>
00032 #include <boost/shared_ptr.hpp>
00033 #include <boost/thread.hpp>
00034 #include <boost/thread/shared_mutex.hpp>
00035
00036 #include <signal.h>
00037 #include <pthread.h>
00038
00039 #include <fastcgi++/exceptions.hpp>
00040 #include <fastcgi++/protocol.hpp>
00041 #include <fastcgi++/transceiver.hpp>
00042
00044 namespace Fastcgipp
00045 {
00047
00057 template<typename T>
00058 class Manager
00059 {
00060 public:
00062
00071 Manager(int fd=0): transceiver(fd, boost::bind(&Manager::push, boost::ref(*this), _1, _2)), asleep(false), terminateBool(false), stopBool(false) { setupSignals(); instance=this; }
00072
00073 ~Manager() { instance=0; }
00074
00076
00083 void handler();
00084
00086
00101 void push(Protocol::FullId id, Message message);
00102
00104
00113 void stop();
00114
00115
00117
00124 void setupSignals();
00125 private:
00127 Transceiver transceiver;
00128
00130
00134 class Tasks: public std::queue<Protocol::FullId>, public boost::mutex {};
00136
00139 Tasks tasks;
00140
00142
00146 class Requests: public std::map<Protocol::FullId, boost::shared_ptr<T> >, public boost::shared_mutex {};
00148
00152 Requests requests;
00153
00155 std::queue<Message> messages;
00156
00158
00166 inline void localHandler(Protocol::FullId id);
00167
00169 bool asleep;
00171 boost::mutex sleepMutex;
00173
00177 pthread_t threadId;
00178
00180
00183 bool stopBool;
00185 boost::mutex stopMutex;
00187
00190 bool terminateBool;
00192 boost::mutex terminateMutex;
00193
00195 static void signalHandler(int signum);
00197 static Manager<T>* instance;
00199
00207 inline void terminate();
00208 };
00209 }
00210
00211 template<class T>
00212 Fastcgipp::Manager<T>* Fastcgipp::Manager<T>::instance=0;
00213
00214 template<class T>
00215 void Fastcgipp::Manager<T>::terminate()
00216 {
00217 boost::lock_guard<boost::mutex> lock(terminateMutex);
00218 terminateBool=true;
00219 }
00220
00221 template<class T>
00222 void Fastcgipp::Manager<T>::stop()
00223 {
00224 boost::lock_guard<boost::mutex> lock(stopMutex);
00225 stopBool=true;
00226 }
00227
00228 template<class T>
00229 void Fastcgipp::Manager<T>::signalHandler(int signum)
00230 {
00231 switch(signum)
00232 {
00233 case SIGUSR1:
00234 {
00235 if(instance) instance->terminate();
00236 break;
00237 }
00238 case SIGTERM:
00239 {
00240 if(instance) instance->stop();
00241 break;
00242 }
00243 }
00244 }
00245
00246 template<class T>
00247 void Fastcgipp::Manager<T>::setupSignals()
00248 {
00249 struct sigaction sigAction;
00250 sigAction.sa_handler=Fastcgipp::Manager<T>::signalHandler;
00251
00252 sigaction(SIGPIPE, &sigAction, NULL);
00253 sigaction(SIGUSR2, &sigAction, NULL);
00254 sigaction(SIGUSR1, &sigAction, NULL);
00255 sigaction(SIGTERM, &sigAction, NULL);
00256 }
00257
00258 template<class T>
00259 void Fastcgipp::Manager<T>::push(Protocol::FullId id, Message message)
00260 {
00261 using namespace std;
00262 using namespace Protocol;
00263 using namespace boost;
00264
00265 if(id.fcgiId)
00266 {
00267 upgrade_lock<shared_mutex> reqLock(requests);
00268 typename Requests::iterator it(requests.find(id));
00269 if(it!=requests.end())
00270 {
00271 lock_guard<mutex> mesLock(it->second->messages);
00272 it->second->messages.push(message);
00273 lock_guard<mutex> tasksLock(tasks);
00274 tasks.push(id);
00275 }
00276 else if(!message.type)
00277 {
00278 Header& header=*(Header*)message.data.get();
00279 if(header.getType()==BEGIN_REQUEST)
00280 {
00281 BeginRequest& body=*(BeginRequest*)(message.data.get()+sizeof(Header));
00282 upgrade_to_unique_lock<shared_mutex> lock(reqLock);
00283 boost::shared_ptr<T>& request = requests[id];
00284 request.reset(new T);
00285 request->set(id, transceiver, body.getRole(), !body.getKeepConn(), boost::bind(&Manager::push, boost::ref(*this), id, _1));
00286 }
00287 else
00288 return;
00289 }
00290 }
00291 else
00292 {
00293 messages.push(message);
00294 tasks.push(id);
00295 }
00296
00297 lock_guard<mutex> sleepLock(sleepMutex);
00298 if(asleep)
00299 pthread_kill(threadId, SIGUSR2);
00300 }
00301
00302 template<class T>
00303 void Fastcgipp::Manager<T>::handler()
00304 {
00305 using namespace std;
00306 using namespace boost;
00307
00308 threadId=pthread_self();
00309
00310 while(1)
00311 {{
00312 {
00313 lock_guard<mutex> stopLock(stopMutex);
00314 if(stopBool)
00315 {
00316 stopBool=false;
00317 return;
00318 }
00319 }
00320
00321 bool sleep=transceiver.handler();
00322
00323 {
00324 lock_guard<mutex> terminateLock(terminateMutex);
00325 if(terminateBool)
00326 {
00327 shared_lock<shared_mutex> requestsLock(requests);
00328 if(requests.empty() && sleep)
00329 {
00330 terminateBool=false;
00331 return;
00332 }
00333 }
00334 }
00335
00336 unique_lock<mutex> tasksLock(tasks);
00337
00338 sigset_t sigSet;
00339 sigemptyset(&sigSet);
00340 sigaddset(&sigSet, SIGUSR2);
00341 unique_lock<mutex> sleepLock(sleepMutex);
00342 sigprocmask(SIG_BLOCK, &sigSet, NULL);
00343
00344 if(tasks.empty())
00345 {
00346 tasksLock.unlock();
00347
00348 asleep=true;
00349 sleepLock.unlock();
00350
00351 if(sleep) transceiver.sleep();
00352
00353 sleepLock.lock();
00354 asleep=false;
00355 sigprocmask(SIG_UNBLOCK, &sigSet, NULL);
00356 sleepLock.unlock();
00357
00358 continue;
00359 }
00360
00361 sigprocmask(SIG_UNBLOCK, &sigSet, NULL);
00362 sleepLock.unlock();
00363
00364 Protocol::FullId id=tasks.front();
00365 tasks.pop();
00366 tasksLock.unlock();
00367
00368 if(id.fcgiId==0)
00369 localHandler(id);
00370 else
00371 {
00372 upgrade_lock<shared_mutex> reqReadLock(requests);
00373 typename map<Protocol::FullId, boost::shared_ptr<T> >::iterator it(requests.find(id));
00374 if(it!=requests.end() && it->second->handler())
00375 {
00376 upgrade_to_unique_lock<shared_mutex> reqWriteLock(reqReadLock);
00377 requests.erase(it);
00378 }
00379 }
00380 }}
00381 }
00382
00383 template<class T>
00384 void Fastcgipp::Manager<T>::localHandler(Protocol::FullId id)
00385 {
00386 using namespace std;
00387 using namespace Protocol;
00388 Message message(messages.front());
00389 messages.pop();
00390
00391 if(!message.type)
00392 {
00393 const Header& header=*(Header*)message.data.get();
00394 switch(header.getType())
00395 {
00396 case GET_VALUES:
00397 {
00398 size_t nameSize;
00399 size_t valueSize;
00400 const char* name;
00401 const char* value;
00402 processParamHeader(message.data.get()+sizeof(Header), name, nameSize, value, valueSize);
00403 if(nameSize==14 && !memcmp(name, "FCGI_MAX_CONNS", 14))
00404 {
00405 Block buffer(transceiver.requestWrite(sizeof(maxConnsReply)));
00406 memcpy(buffer.data, (const char*)&maxConnsReply, sizeof(maxConnsReply));
00407 transceiver.secureWrite(sizeof(maxConnsReply), id, false);
00408 }
00409 else if(nameSize==13 && !memcmp(name, "FCGI_MAX_REQS", 13))
00410 {
00411 Block buffer(transceiver.requestWrite(sizeof(maxReqsReply)));
00412 memcpy(buffer.data, (const char*)&maxReqsReply, sizeof(maxReqsReply));
00413 transceiver.secureWrite(sizeof(maxReqsReply), id, false);
00414 }
00415 else if(nameSize==15 && !memcmp(name, "FCGI_MPXS_CONNS", 15))
00416 {
00417 Block buffer(transceiver.requestWrite(sizeof(mpxsConnsReply)));
00418 memcpy(buffer.data, (const char*)&mpxsConnsReply, sizeof(mpxsConnsReply));
00419 transceiver.secureWrite(sizeof(mpxsConnsReply), id, false);
00420 }
00421
00422 break;
00423 }
00424
00425 default:
00426 {
00427 Block buffer(transceiver.requestWrite(sizeof(Header)+sizeof(UnknownType)));
00428
00429 Header& sendHeader=*(Header*)buffer.data;
00430 sendHeader.setVersion(version);
00431 sendHeader.setType(UNKNOWN_TYPE);
00432 sendHeader.setRequestId(0);
00433 sendHeader.setContentLength(sizeof(UnknownType));
00434 sendHeader.setPaddingLength(0);
00435
00436 UnknownType& sendBody=*(UnknownType*)(buffer.data+sizeof(Header));
00437 sendBody.setType(header.getType());
00438
00439 transceiver.secureWrite(sizeof(Header)+sizeof(UnknownType), id, false);
00440
00441 break;
00442 }
00443 }
00444 }
00445 else
00446 throw Exceptions::FastcgiException("Invalid message type received in Fastcgipp::Manager<T>::localHandler");
00447 }
00448
00449 #endif