1 /*
2    Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License, version 2.0,
6    as published by the Free Software Foundation.
7 
8    This program is also distributed with certain software (including
9    but not limited to OpenSSL) that is licensed under separate terms,
10    as designated in a particular file or component or in included license
11    documentation.  The authors of MySQL hereby grant you an additional
12    permission to link the program and your derivative works with the
13    separately licensed software that they have included with MySQL.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License, version 2.0, for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
23 */
24 
25 #ifndef SOCKET_SERVER_HPP
26 #define SOCKET_SERVER_HPP
27 
28 #include <NdbTCP.h>
29 #include <NdbMutex.h>
30 #include <NdbThread.h>
31 #include <Vector.hpp>
32 
33 extern "C" void* sessionThread_C(void*);
34 extern "C" void* socketServerThread_C(void*);
35 
36 /**
37  *  Socket Server
38  */
39 class SocketServer {
40 public:
41   /**
42    * A Session
43    */
44   class Session {
45   public:
~Session()46     virtual ~Session() {}
runSession()47     virtual void runSession(){}
stopSession()48     virtual void stopSession(){ m_stop = true; }
49   protected:
50     friend class SocketServer;
51     friend void* sessionThread_C(void*);
Session(NDB_SOCKET_TYPE sock)52     Session(NDB_SOCKET_TYPE sock) :
53       m_stop(false),
54       m_socket(sock),
55       m_refCount(0),
56       m_thread_stopped(false)
57       {
58 	DBUG_ENTER("SocketServer::Session");
59 	DBUG_PRINT("enter",("NDB_SOCKET: " MY_SOCKET_FORMAT,
60                             MY_SOCKET_FORMAT_VALUE(m_socket)));
61 	DBUG_VOID_RETURN;
62       }
63     bool m_stop;    // Has the session been ordered to stop?
64     NDB_SOCKET_TYPE m_socket;
65     unsigned m_refCount;
66   private:
67     bool m_thread_stopped; // Has the session thread stopped?
68   };
69 
70   /**
71    * A service i.e. a session factory
72    */
73   class Service {
74   public:
Service()75     Service() {}
~Service()76     virtual ~Service(){}
77 
78     /**
79      * Returned Session will be ran in own thread
80      *
81      * To manage threads self, just return NULL
82      */
83     virtual Session * newSession(NDB_SOCKET_TYPE theSock) = 0;
stopSessions()84     virtual void stopSessions(){}
85   };
86 
87   /**
88    * Constructor / Destructor
89    */
90   SocketServer(unsigned maxSessions = ~(unsigned)0);
91   ~SocketServer();
92 
93   /**
94    * Setup socket and bind it
95    *  then  close the socket
96    * Returns true if succeding in binding
97    */
98   static bool tryBind(unsigned short port, const char * intface = 0);
99 
100   /**
101    * Setup socket
102    *   bind & listen
103    * Returns false if no success
104    */
105   bool setup(Service *, unsigned short *port, const char * pinterface = 0);
106 
107   /**
108    * start/stop the server
109    */
110   struct NdbThread* startServer();
111   void stopServer();
112 
113   /**
114    * stop sessions
115    *
116    * Note: Implies previous stopServer
117    *
118    * wait, wait until all sessions has stopped if true
119    * wait_timeout - wait, but abort wait after this
120    *                time(in milliseconds)
121    *                0 = infinite
122    *
123    * returns false if wait was abandoned
124    *
125    */
126   bool stopSessions(bool wait = false, unsigned wait_timeout = 0);
127 
128   void foreachSession(void (*f)(Session*, void*), void *data);
129   void checkSessions();
130 
131 private:
132   struct SessionInstance {
133     Service * m_service;
134     Session * m_session;
135     NdbThread * m_thread;
136   };
137   struct ServiceInstance {
138     Service * m_service;
139     NDB_SOCKET_TYPE m_socket;
140   };
141   NdbLockable m_session_mutex;
142   Vector<SessionInstance> m_sessions;
143   MutexVector<ServiceInstance> m_services;
144   ndb_socket_poller m_services_poller;
145   unsigned m_maxSessions;
146 
147   bool doAccept();
148   void checkSessionsImpl();
149   void startSession(SessionInstance &);
150 
151   /**
152    * Note, this thread is only used when running interactive
153    *
154    */
155   bool m_stopThread;
156   struct NdbThread * m_thread;
157   NdbLockable m_threadLock;
158   void doRun();
159   friend void* socketServerThread_C(void*);
160   friend void* sessionThread_C(void*);
161 };
162 
163 #endif
164