//****************************************************************************** // RCF - Remote Call Framework // Copyright (c) 2005 - 2007. All rights reserved. // Consult your license for conditions of use. // Developed by Jarl Lindrud. // Contact: jlindrud@hotmail.com . //****************************************************************************** #ifndef INCLUDE_RCF_RCFSERVER_HPP #define INCLUDE_RCF_RCFSERVER_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace RCF { class I_ServerTransport; class StubEntry; class I_Service; class I_Session; class RcfSession; class I_Endpoint; class I_StubEntryLookupProvider; class I_FilterFactoryLookupProvider; class I_RcfClient; typedef boost::shared_ptr ServerTransportPtr; typedef boost::shared_ptr ProactorPtr; typedef boost::shared_ptr StubEntryPtr; typedef boost::shared_ptr ServicePtr; typedef boost::shared_ptr RcfSessionPtr; typedef boost::shared_ptr StubEntryLookupProviderPtr; typedef boost::shared_ptr FilterFactoryLookupProviderPtr; typedef boost::shared_ptr RcfClientPtr; #if defined(_MSC_VER) && _MSC_VER < 1310 template struct BindDirect { typedef char (&yes_type)[1]; typedef char (&no_type)[2]; template static yes_type dummyfunc(std::auto_ptr *); template static yes_type dummyfunc(boost::shared_ptr *); template static yes_type dummyfunc(boost::weak_ptr *); static no_type dummyfunc(...); typedef boost::mpl::bool_< sizeof(no_type) == sizeof(dummyfunc( (T *) 0)) > type; }; #else template struct BindDirect { typedef boost::mpl::true_ type; }; template struct BindDirect< std::auto_ptr > { typedef boost::mpl::false_ type; }; template struct BindDirect< boost::shared_ptr > { typedef boost::mpl::false_ type; }; template struct BindDirect< boost::weak_ptr > { typedef boost::mpl::false_ type; }; #endif #define RCF_SERVER_BINDING_SECTION_1_1(i1, T, arg) \ template \ bool bind_impl_1(i1*, T t, const std::string &name_, arg*) #define RCF_SERVER_BINDING_SECTION_1_2(i1, i2, T, arg) \ template \ bool bind_impl_2(i1*, i2 *, T t, const std::string &name_, arg*) #define RCF_SERVER_BINDING_SECTION_1_3(i1, i2, i3, T, arg) \ template \ bool bind_impl_3(i1*, i2*, i3*, T t, const std::string &name_, arg*) #define RCF_SERVER_BINDING_SECTION_1_4(i1, i2, i3, i4, T, arg) \ template \ bool bind_impl_4(i1*, i2*, i3*, i4*, T t, const std::string &name_, arg*) #define RCF_SERVER_BINDING_SECTION_2(/*T, */DerefT) \ { \ const std::string &name = (name_ == "") ? \ I1::getInterfaceName() : \ name_; \ \ boost::shared_ptr< I_Deref > derefPtr( \ new DerefT(t) ); \ \ RcfClientPtr rcfClientPtr = createServerStub( \ (I1 *) 0, \ (ImplementationT *) 0, \ derefPtr); \ #define RCF_SERVER_BINDING_SECTION_2_(/*T, */DerefT) \ { \ const std::string &name = (name_ == "") ? \ I1::getInterfaceName() : \ name_; \ \ boost::shared_ptr< I_Deref > derefPtr( \ new DerefT(t) ); \ \ RcfClientPtr rcfClientPtr = createServerStub( \ (I1 *) 0, \ (ImplementationT *) 0, \ derefPtr); \ #define RCF_SERVER_BINDING_SECTION_3(I_n) \ { \ RcfClientPtr mergeePtr = createServerStub( \ (I_n *) 0, \ (ImplementationT *) 0, \ derefPtr); \ \ rcfClientPtr->getServerStub().merge(mergeePtr); \ } #define RCF_SERVER_BINDING_SECTION_4 \ return bindShared(name, rcfClientPtr); \ } \ /// Server class, supporting pluggable transports and services. class RcfServer : public virtual I_SessionManager, boost::noncopyable { public: //************************************* // public interface /// Default constructor. RcfServer(); /// Constructor. /// \param endpoint Represents endpoint location of the server. Determines which server transport will be created and used. RcfServer(const I_Endpoint &endpoint); /// Constructor. /// \param servicePtr Service to load, typically a server transport. RcfServer(const ServicePtr &servicePtr); /// Constructor. /// \param serverTransportPtr Server transport to load. RcfServer(const ServerTransportPtr &serverTransportPtr); /// Constructor. /// \param serverTransports Vector of services to load. RcfServer(std::vector services); /// Constructor. /// \param serverTransports Vector of server transport services to load. RcfServer(std::vector serverTransports); /// Destructor. ~RcfServer(); /// Starts the server, by starting all services, including transports. /// Synchronized: yes, idempotent: yes. /// \param spawnThreads Indicates whether any server threads should be spawned. void start(bool spawnThreads = true); typedef boost::function0 JoinFunctor; /// Adds a join functor to the server, to be called when stopping the server. /// \param joinFunctor Join functor. void addJoinFunctor(const JoinFunctor &joinFunctor); /// Starts the server, by taking over the current thread. All server tasks will be run sequentially in the calling thread. /// Synchronized: no, idempotent: no. void startInThisThread(); /// Starts the server, by taking over the current thread. All server tasks will be run sequentially in the calling thread. /// Synchronized: no, idempotent: no. /// \param joinFunctor Functor to call in order to join this thread. void startInThisThread(const JoinFunctor &joinFunctor); /// Stops the server. Optionally waits until all server threads have terminated. /// Synchronized: yes, idempotent: yes /// \param wait True to wait for server threads to terminate, false to return immediately. void stop(bool wait = true); /// Cycles all services, including transports. May or may not result in the dispatching of a client request. /// \param timeoutMs Maximum waiting time, in milliseconds, for any blocking operations. /// \return boolean value indicating if the server is being stopped. bool cycle(int timeoutMs = 0); /// Cycles the server's thread-specific session queue. /// \param timeoutMs Maximum waiting time, in milliseconds, for any blocking operations. /// \param stopFlag Reference to boolean value that, when set, indicates that all server threads should terminate as soon as possible. void cycleSessions(int timeoutMs, const volatile bool &stopFlag); /// Opens all services, including transports. void open(); /// Closes all services, including transports. void close(); /// Returns a reference to the primary server transport. /// \return Reference to primary server transport. I_ServerTransport &getServerTransport(); /// Returns a reference to the primary server transport, as a service. /// \return Reference to primary server transport. I_Service &getServerTransportService(); /// Returns a shared pointer to the primary server transport. /// \return Shared pointer to primary server transport. ServerTransportPtr getServerTransportPtr(); /// Adds a service to the server. /// \param servicePtr Service to be added. E.g. ... /// \return true if service added successfully, false otherwise (probably because the service has already been added). bool addService(const ServicePtr &servicePtr); /// Removes a service from the server. /// \param servicePtr Service to be removed. /// \return true. bool removeService(const ServicePtr &servicePtr); /// Adds a server transport service to the server. /// \param serverTransportPtr Server transport to be added. E.g. ... /// \return true if server transport added successfully, false otherwise (probably because the server transport has already been added). bool addServerTransport(const ServerTransportPtr &serverTransportPtr); /// Removes a server transport service from the server. /// \param serverTransportPtr Server transport to be removed. /// \return true. bool removeServerTransport(const ServerTransportPtr &serverTransportPtr); typedef boost::function1 StartCallback; /// Sets the start callback, which is invoked by each worker thread when it starts. void setStartCallback(const StartCallback &startCallback); /* /// Sets the start callback, which is invoked by each worker thread when it starts. template void setStartCallback(void (T::*pfn)(RcfServer &), T &t) { // this function is implemented here (rather than in RcfServer.inl), because of borland c++ idiosyncracies setStartCallback( boost::bind(pfn, &t, _1) ); } */ private: void invokeStartCallback(); private: bool bindShared(const std::string &name, const RcfClientPtr &rcfClientPtr); //************************************* // async io transport interface private: SessionPtr createSession(); void onReadCompleted(const SessionPtr &sessionPtr); void onWriteCompleted(const SessionPtr &sessionPtr); void handleSession(const RcfSessionPtr &sessionPtr); void serializeSessionExceptionResponse(const RcfSessionPtr &sessionPtr); void sendSessionResponse(const RcfSessionPtr &sessionPtr, bool isException); void closeSession(const RcfSessionPtr &sessionPtr); //************************************* // transports, queues and threads private: //SessionQueue &getSessionQueue(const RcfSession &session); //typedef ThreadSpecificPtr::Val ThreadSpecificSessionQueuePtr; //ThreadSpecificSessionQueuePtr mThreadSpecificSessionQueuePtr; // eventually other specialized session queues... volatile bool mServerThreadsStopFlag; Mutex mOpenedMutex; bool mOpened; Mutex mStartedMutex; bool mStarted; public: /// Returns a value indicating whether or not all server threads should terminate their activities. bool getStopFlag() const; //************************************* // stub management private: ReadWriteMutex mStubMapMutex; typedef std::map StubMap; StubMap mStubMap; //************************************* // service management private: ReadWriteMutex mServicesMutex; std::vector mServices; std::vector mStubEntryLookupProviders; std::vector mFilterFactoryLookupProviders; std::vector mServerTransports; std::vector mJoinFunctors; void startService(const ServicePtr &servicePtr) const; void stopService(const ServicePtr &servicePtr, bool wait = true) const; FilterPtr createFilter(int filterId); private: // start callback StartCallback mStartCallback; // start functionality //Mutex mStartMutex; Platform::Threads::condition mStartEvent; // stop functionality //Mutex mStopMutex; Platform::Threads::condition mStopEvent; public: /// Waits for the server to be stopped. void waitForStopEvent(); /// Waits for the server to be started. void waitForStartEvent(); // TODO: get rid of this hack private: friend class MethodInvocationRequest; public: int getRcfRuntimeVersion(); void setRcfRuntimeVersion(int version); private: int mRcfRuntimeVersion; public: // binding infrastructure // following functions are defined inline for reasons of portability (vc6 in particular) // direct RCF_SERVER_BINDING_SECTION_1_1(I1, ImplementationT &, boost::mpl::true_) RCF_SERVER_BINDING_SECTION_2_(DerefObj) RCF_SERVER_BINDING_SECTION_4 RCF_SERVER_BINDING_SECTION_1_2(I1, I2, ImplementationT &, boost::mpl::true_) RCF_SERVER_BINDING_SECTION_2_(DerefObj) RCF_SERVER_BINDING_SECTION_3(I2) RCF_SERVER_BINDING_SECTION_4 RCF_SERVER_BINDING_SECTION_1_3(I1, I2, I3, ImplementationT &, boost::mpl::true_) RCF_SERVER_BINDING_SECTION_2_(DerefObj) RCF_SERVER_BINDING_SECTION_3(I2) RCF_SERVER_BINDING_SECTION_3(I3) RCF_SERVER_BINDING_SECTION_4 RCF_SERVER_BINDING_SECTION_1_4(I1, I2, I3, I4, ImplementationT &, boost::mpl::true_) RCF_SERVER_BINDING_SECTION_2_(DerefObj) RCF_SERVER_BINDING_SECTION_3(I2) RCF_SERVER_BINDING_SECTION_3(I3) RCF_SERVER_BINDING_SECTION_3(I4) RCF_SERVER_BINDING_SECTION_4 // indirect - shared_ptr RCF_SERVER_BINDING_SECTION_1_1(I1, boost::shared_ptr, boost::mpl::false_) RCF_SERVER_BINDING_SECTION_2(DerefSharedPtr) RCF_SERVER_BINDING_SECTION_4 RCF_SERVER_BINDING_SECTION_1_2(I1, I2, boost::shared_ptr, boost::mpl::false_) RCF_SERVER_BINDING_SECTION_2(DerefSharedPtr) RCF_SERVER_BINDING_SECTION_3(I2) RCF_SERVER_BINDING_SECTION_4 RCF_SERVER_BINDING_SECTION_1_3(I1, I2, I3, boost::shared_ptr, boost::mpl::false_) RCF_SERVER_BINDING_SECTION_2(DerefSharedPtr) RCF_SERVER_BINDING_SECTION_3(I2) RCF_SERVER_BINDING_SECTION_3(I3) RCF_SERVER_BINDING_SECTION_4 RCF_SERVER_BINDING_SECTION_1_4(I1, I2, I3, I4, boost::shared_ptr, boost::mpl::false_) RCF_SERVER_BINDING_SECTION_2(DerefSharedPtr) RCF_SERVER_BINDING_SECTION_3(I2) RCF_SERVER_BINDING_SECTION_3(I3) RCF_SERVER_BINDING_SECTION_3(I4) RCF_SERVER_BINDING_SECTION_4 // indirect - weak_ptr RCF_SERVER_BINDING_SECTION_1_1(I1, boost::weak_ptr, boost::mpl::false_) RCF_SERVER_BINDING_SECTION_2(DerefWeakPtr) RCF_SERVER_BINDING_SECTION_4 RCF_SERVER_BINDING_SECTION_1_2(I1, I2, boost::weak_ptr, boost::mpl::false_) RCF_SERVER_BINDING_SECTION_2(DerefWeakPtr) RCF_SERVER_BINDING_SECTION_3(I2) RCF_SERVER_BINDING_SECTION_4 RCF_SERVER_BINDING_SECTION_1_3(I1, I2, I3, boost::weak_ptr, boost::mpl::false_) RCF_SERVER_BINDING_SECTION_2(DerefWeakPtr) RCF_SERVER_BINDING_SECTION_3(I2) RCF_SERVER_BINDING_SECTION_3(I3) RCF_SERVER_BINDING_SECTION_4 RCF_SERVER_BINDING_SECTION_1_4(I1, I2, I3, I4, boost::weak_ptr, boost::mpl::false_) RCF_SERVER_BINDING_SECTION_2(DerefWeakPtr) RCF_SERVER_BINDING_SECTION_3(I2) RCF_SERVER_BINDING_SECTION_3(I3) RCF_SERVER_BINDING_SECTION_3(I4) RCF_SERVER_BINDING_SECTION_4 // indirect - auto_ptr RCF_SERVER_BINDING_SECTION_1_1(I1, const std::auto_ptr &, boost::mpl::false_) RCF_SERVER_BINDING_SECTION_2(DerefAutoPtr) RCF_SERVER_BINDING_SECTION_4 RCF_SERVER_BINDING_SECTION_1_2(I1, I2, const std::auto_ptr &, boost::mpl::false_) RCF_SERVER_BINDING_SECTION_2(DerefAutoPtr) RCF_SERVER_BINDING_SECTION_3(I2) RCF_SERVER_BINDING_SECTION_4 RCF_SERVER_BINDING_SECTION_1_3(I1, I2, I3, const std::auto_ptr &, boost::mpl::false_) RCF_SERVER_BINDING_SECTION_2(DerefAutoPtr) RCF_SERVER_BINDING_SECTION_3(I2) RCF_SERVER_BINDING_SECTION_3(I3) RCF_SERVER_BINDING_SECTION_4 RCF_SERVER_BINDING_SECTION_1_4(I1, I2, I3, I4, const std::auto_ptr &, boost::mpl::false_) RCF_SERVER_BINDING_SECTION_2(DerefAutoPtr) RCF_SERVER_BINDING_SECTION_3(I2) RCF_SERVER_BINDING_SECTION_3(I3) RCF_SERVER_BINDING_SECTION_3(I4) RCF_SERVER_BINDING_SECTION_4 #if !defined(_MSC_VER) || _MSC_VER > 1200 template bool bind(ImplementationT &t, const std::string &name = "") { typedef typename BindDirect::type type; return bind_impl_1((I1 *) NULL, t, name, (type *) NULL); } template bool bind(ImplementationT &t, const std::string &name = "") { typedef typename BindDirect::type type; return bind_impl_2((I1 *) NULL, (I2 *) NULL, t, name, (type *) NULL); } template bool bind(ImplementationT &t, const std::string &name = "") { typedef typename BindDirect::type type; return bind_impl_3((I1 *) NULL, (I2 *) NULL, (I3 *) NULL, t, name, (type *) NULL); } template bool bind(ImplementationT &t, const std::string &name = "") { typedef typename BindDirect::type type; return bind_impl_4((I1 *) NULL, (I2 *) NULL, (I3 *) NULL, (I4 *) NULL, t, name, (type *) NULL); } template bool bind(const ImplementationT &t, const std::string &name = "") { typedef typename BindDirect::type type; return bind_impl_1((I1 *) NULL, t, name, (type *) NULL); } template bool bind(const ImplementationT &t, const std::string &name = "") { typedef typename BindDirect::type type; return bind_impl_2((I1 *) NULL, (I2 *) NULL, t, name, (type *) NULL); } template bool bind(const ImplementationT &t, const std::string &name = "") { typedef typename BindDirect::type type; return bind_impl_3((I1 *) NULL, (I2 *) NULL, (I3 *) NULL, t, name, (type *) NULL); } template bool bind(const ImplementationT &t, const std::string &name = "") { typedef typename BindDirect::type type; return bind_impl_4((I1 *) NULL, (I2 *) NULL, (I3 *) NULL, (I4 *) NULL, t, name, (type *) NULL); } template bool unbind(const std::string &name = "") { return unbind((InterfaceT *) NULL, name); } #endif template bool bind(I1 *i1, ImplementationT &t, const std::string &name = "") { typedef typename BindDirect::type type; return bind_impl_1(i1, t, name, (type *) NULL); } template bool bind(I1 *i1, I2 *i2, ImplementationT &t, const std::string &name = "") { typedef typename BindDirect::type type; return bind_impl_2(i1, i2, t, name, (type *) NULL); } template bool bind(I1 *i1, I2 *i2, I3 *i3, ImplementationT &t, const std::string &name = "") { typedef typename BindDirect::type type; return bind_impl_3(i1, i2, i3, t, name, (type *) NULL); } template bool bind(I1 *i1, I2 *i2, I3 *i3, I4 *i4, ImplementationT &t, const std::string &name = "") { typedef typename BindDirect::type type; return bind_impl_4(i1, i2, i3, i4, t, name, (type *) NULL); } template bool unbind(InterfaceT * , const std::string &name_ = "") { const std::string &name = (name_ == "") ? getInterfaceName((InterfaceT *) NULL) : name_; WriteLock writeLock(mStubMapMutex); mStubMap[name].reset(); return true; } }; } // namespace RCF #include #endif // ! INCLUDE_RCF_RCFSERVER_HPP