/* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. 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, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SOCKET_SERVER_HPP #define SOCKET_SERVER_HPP #include #include #include #include extern "C" void* sessionThread_C(void*); extern "C" void* socketServerThread_C(void*); /** * Socket Server */ class SocketServer { public: /** * A Session */ class Session { public: virtual ~Session() {} virtual void runSession(){} virtual void stopSession(){ m_stop = true; } protected: friend class SocketServer; friend void* sessionThread_C(void*); Session(NDB_SOCKET_TYPE sock) : m_stop(false), m_socket(sock), m_refCount(0), m_thread_stopped(false) { DBUG_ENTER("SocketServer::Session"); DBUG_PRINT("enter",("NDB_SOCKET: " MY_SOCKET_FORMAT, MY_SOCKET_FORMAT_VALUE(m_socket))); DBUG_VOID_RETURN; } bool m_stop; // Has the session been ordered to stop? NDB_SOCKET_TYPE m_socket; unsigned m_refCount; private: bool m_thread_stopped; // Has the session thread stopped? }; /** * A service i.e. a session factory */ class Service { public: Service() {} virtual ~Service(){} /** * Returned Session will be ran in own thread * * To manage threads self, just return NULL */ virtual Session * newSession(NDB_SOCKET_TYPE theSock) = 0; virtual void stopSessions(){} }; /** * Constructor / Destructor */ SocketServer(unsigned maxSessions = ~(unsigned)0); ~SocketServer(); /** * Setup socket and bind it * then close the socket * Returns true if succeding in binding */ static bool tryBind(unsigned short port, const char * intface = 0); /** * Setup socket * bind & listen * Returns false if no success */ bool setup(Service *, unsigned short *port, const char * pinterface = 0); /** * start/stop the server */ struct NdbThread* startServer(); void stopServer(); /** * stop sessions * * Note: Implies previous stopServer * * wait, wait until all sessions has stopped if true * wait_timeout - wait, but abort wait after this * time(in milliseconds) * 0 = infinite * * returns false if wait was abandoned * */ bool stopSessions(bool wait = false, unsigned wait_timeout = 0); void foreachSession(void (*f)(Session*, void*), void *data); void checkSessions(); private: struct SessionInstance { Service * m_service; Session * m_session; NdbThread * m_thread; }; struct ServiceInstance { Service * m_service; NDB_SOCKET_TYPE m_socket; }; NdbLockable m_session_mutex; Vector m_sessions; MutexVector m_services; ndb_socket_poller m_services_poller; unsigned m_maxSessions; bool doAccept(); void checkSessionsImpl(); void startSession(SessionInstance &); /** * Note, this thread is only used when running interactive * */ bool m_stopThread; struct NdbThread * m_thread; NdbLockable m_threadLock; void doRun(); friend void* socketServerThread_C(void*); friend void* sessionThread_C(void*); }; #endif