|
a/src/utils/netcon.h |
|
b/src/utils/netcon.h |
|
... |
|
... |
14 |
* You should have received a copy of the GNU General Public License
|
14 |
* You should have received a copy of the GNU General Public License
|
15 |
* along with this program; if not, write to the
|
15 |
* along with this program; if not, write to the
|
16 |
* Free Software Foundation, Inc.,
|
16 |
* Free Software Foundation, Inc.,
|
17 |
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
17 |
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
18 |
*/
|
18 |
*/
|
|
|
19 |
#include <sys/time.h>
|
|
|
20 |
#include <map>
|
19 |
#include "refcntr.h"
|
21 |
#include "refcntr.h"
|
|
|
22 |
|
|
|
23 |
using std::map;
|
20 |
|
24 |
|
21 |
/// A set of classes to manage client-server communication over a
|
25 |
/// A set of classes to manage client-server communication over a
|
22 |
/// connection-oriented network, or a pipe.
|
26 |
/// connection-oriented network, or a pipe.
|
23 |
///
|
27 |
///
|
24 |
/// The listening/connection-accepting code currently only uses
|
28 |
/// The listening/connection-accepting code currently only uses
|
|
... |
|
... |
32 |
/// descriptor)
|
36 |
/// descriptor)
|
33 |
|
37 |
|
34 |
/// Base class for all network endpoints:
|
38 |
/// Base class for all network endpoints:
|
35 |
class Netcon;
|
39 |
class Netcon;
|
36 |
typedef RefCntr<Netcon> NetconP;
|
40 |
typedef RefCntr<Netcon> NetconP;
|
|
|
41 |
class SelectLoop;
|
37 |
|
42 |
|
38 |
class Netcon {
|
43 |
class Netcon {
|
39 |
public:
|
44 |
public:
|
40 |
enum Event {NETCONPOLL_READ = 0x1, NETCONPOLL_WRITE=0x2};
|
45 |
enum Event {NETCONPOLL_READ = 0x1, NETCONPOLL_WRITE=0x2};
|
41 |
Netcon()
|
46 |
Netcon()
|
42 |
: m_peer(0), m_fd(-1), m_ownfd(true), m_didtimo(0), m_wantedEvents(0)
|
47 |
: m_peer(0), m_fd(-1), m_ownfd(true), m_didtimo(0), m_wantedEvents(0),
|
|
|
48 |
m_loop(0)
|
43 |
{}
|
49 |
{}
|
44 |
virtual ~Netcon();
|
50 |
virtual ~Netcon();
|
45 |
/// Remember whom we're talking to. We let external code do this because
|
51 |
/// Remember whom we're talking to. We let external code do this because
|
46 |
/// the application may have a non-dns method to find the peer name.
|
52 |
/// the application may have a non-dns method to find the peer name.
|
47 |
virtual void setpeer(const char *hostname);
|
53 |
virtual void setpeer(const char *hostname);
|
|
... |
|
... |
73 |
/// Add events to current set
|
79 |
/// Add events to current set
|
74 |
int addselevents(int evs) {return m_wantedEvents |= evs;}
|
80 |
int addselevents(int evs) {return m_wantedEvents |= evs;}
|
75 |
/// Clear events from current set
|
81 |
/// Clear events from current set
|
76 |
int clearselevents(int evs) {return m_wantedEvents &= ~evs;}
|
82 |
int clearselevents(int evs) {return m_wantedEvents &= ~evs;}
|
77 |
|
83 |
|
|
|
84 |
friend class SelectLoop;
|
|
|
85 |
SelectLoop *getloop() {return m_loop;}
|
|
|
86 |
|
78 |
/// Utility function for a simplified select() interface: check one fd
|
87 |
/// Utility function for a simplified select() interface: check one fd
|
79 |
/// for reading or writing, for a specified maximum number of seconds.
|
88 |
/// for reading or writing, for a specified maximum number of seconds.
|
80 |
static int select1(int fd, int secs, int writing = 0);
|
89 |
static int select1(int fd, int secs, int writing = 0);
|
81 |
|
90 |
|
|
|
91 |
protected:
|
|
|
92 |
char *m_peer; // Name of the connected host
|
|
|
93 |
int m_fd;
|
|
|
94 |
bool m_ownfd;
|
|
|
95 |
int m_didtimo;
|
|
|
96 |
// Used when part of the selectloop map.
|
|
|
97 |
short m_wantedEvents;
|
|
|
98 |
SelectLoop *m_loop;
|
|
|
99 |
// Method called by the selectloop when something can be done with a netcon
|
|
|
100 |
virtual int cando(Netcon::Event reason) = 0;
|
|
|
101 |
// Called when added to loop
|
|
|
102 |
virtual void setloop(SelectLoop *loop) {m_loop = loop;}
|
|
|
103 |
};
|
|
|
104 |
|
|
|
105 |
|
82 |
/// The selectloop interface is used to implement parallel servers.
|
106 |
/// The selectloop interface is used to implement parallel servers.
|
83 |
/// All the interface is static (independant of any given object).
|
107 |
// The select loop mechanism allows several netcons to be used for io
|
|
|
108 |
// in a program without blocking as long as there is data to be read
|
|
|
109 |
// or written. In a multithread program which is also using select, it
|
|
|
110 |
// would typically make sense to have one SelectLoop active per
|
|
|
111 |
// thread.
|
|
|
112 |
class SelectLoop {
|
|
|
113 |
public:
|
|
|
114 |
SelectLoop()
|
|
|
115 |
: m_selectloopDoReturn(false), m_selectloopReturnValue(0),
|
|
|
116 |
m_placetostart(0),
|
|
|
117 |
m_periodichandler(0), m_periodicparam(0), m_periodicmillis(0)
|
|
|
118 |
{}
|
84 |
|
119 |
|
85 |
/// Loop waiting for events on the connections and call the
|
120 |
/// Loop waiting for events on the connections and call the
|
86 |
/// cando() method on the object when something happens (this will in
|
121 |
/// cando() method on the object when something happens (this will in
|
87 |
/// turn typically call the app callback set on the netcon). Possibly
|
122 |
/// turn typically call the app callback set on the netcon). Possibly
|
88 |
/// call the periodic handler (if set) at regular intervals.
|
123 |
/// call the periodic handler (if set) at regular intervals.
|
89 |
/// @return -1 for error. 0 if no descriptors left for i/o. 1 for periodic
|
124 |
/// @return -1 for error. 0 if no descriptors left for i/o. 1 for periodic
|
90 |
/// timeout (should call back in after processing)
|
125 |
/// timeout (should call back in after processing)
|
91 |
static int selectloop();
|
126 |
int doLoop();
|
|
|
127 |
|
92 |
/// Call from data handler: make selectloop return the param value
|
128 |
/// Call from data handler: make selectloop return the param value
|
93 |
static void selectloopReturn(int value)
|
129 |
void loopReturn(int value)
|
94 |
{
|
130 |
{
|
95 |
o_selectloopDoReturn = true;
|
131 |
m_selectloopDoReturn = true;
|
96 |
o_selectloopReturnValue = value;
|
132 |
m_selectloopReturnValue = value;
|
97 |
}
|
133 |
}
|
98 |
/// Add a connection to be monitored (this will usually be called
|
134 |
/// Add a connection to be monitored (this will usually be called
|
99 |
/// from the server's listen connection's accept callback)
|
135 |
/// from the server's listen connection's accept callback)
|
100 |
static int addselcon(NetconP con, int);
|
136 |
int addselcon(NetconP con, int events);
|
101 |
/// Remove a connection from the monitored set. Note that this is
|
137 |
/// Remove a connection from the monitored set. This is
|
102 |
/// automatically called from the Netcon destructor, and when EOF is
|
138 |
/// automatically called when EOF is detected on a connection.
|
103 |
/// detected on a connection.
|
|
|
104 |
static int remselcon(NetconP con);
|
139 |
int remselcon(NetconP con);
|
105 |
|
140 |
|
106 |
/// Set a function to be called periodically, or a time before return.
|
141 |
/// Set a function to be called periodically, or a time before return.
|
107 |
/// @param handler the function to be called.
|
142 |
/// @param handler the function to be called.
|
108 |
/// - if it is 0, selectloop() will return after ms mS (and can be called
|
143 |
/// - if it is 0, selectloop() will return after ms mS (and can be called
|
109 |
/// again
|
144 |
/// again
|
110 |
/// - if it is not 0, it will be called at ms mS intervals. If its return
|
145 |
/// - if it is not 0, it will be called at ms mS intervals. If its return
|
111 |
/// value is <= 0, selectloop will return.
|
146 |
/// value is <= 0, selectloop will return.
|
112 |
/// @param clp client data to be passed to handler at every call.
|
147 |
/// @param clp client data to be passed to handler at every call.
|
113 |
/// @param ms milliseconds interval between handler calls or
|
148 |
/// @param ms milliseconds interval between handler calls or
|
114 |
/// before return. Set to 0 for no periodic handler.
|
149 |
/// before return. Set to 0 for no periodic handler.
|
115 |
static void setperiodichandler(int (*handler)(void *), void *clp, int ms);
|
150 |
void setperiodichandler(int (*handler)(void *), void *clp, int ms);
|
116 |
|
151 |
|
117 |
protected:
|
152 |
private:
|
|
|
153 |
// Set by client callback to tell selectloop to return.
|
118 |
static bool o_selectloopDoReturn;
|
154 |
bool m_selectloopDoReturn;
|
119 |
static int o_selectloopReturnValue;
|
155 |
int m_selectloopReturnValue;
|
120 |
char *m_peer; // Name of the connected host
|
156 |
int m_placetostart;
|
121 |
int m_fd;
|
|
|
122 |
bool m_ownfd;
|
|
|
123 |
int m_didtimo;
|
|
|
124 |
// Used when part of the selectloop map.
|
|
|
125 |
short m_wantedEvents;
|
|
|
126 |
// Method called by the selectloop when something can be done with a netcon
|
|
|
127 |
virtual int cando(Netcon::Event reason) = 0;
|
|
|
128 |
};
|
|
|
129 |
|
157 |
|
|
|
158 |
// Map of NetconP indexed by fd
|
|
|
159 |
map<int, NetconP> m_polldata;
|
|
|
160 |
|
|
|
161 |
// The last time we did the periodic thing. Initialized by setperiodic()
|
|
|
162 |
struct timeval m_lasthdlcall;
|
|
|
163 |
// The call back function and its parameter
|
|
|
164 |
int (*m_periodichandler)(void *);
|
|
|
165 |
void *m_periodicparam;
|
|
|
166 |
// The periodic interval
|
|
|
167 |
int m_periodicmillis;
|
|
|
168 |
void periodictimeout(struct timeval *tv);
|
|
|
169 |
int maybecallperiodic();
|
|
|
170 |
};
|
130 |
|
171 |
|
131 |
///////////////////////
|
172 |
///////////////////////
|
132 |
class NetconData;
|
173 |
class NetconData;
|
133 |
|
174 |
|
134 |
/// Class for the application callback routine (when in
|
175 |
/// Class for the application callback routine (when in selectloop).
|
|
|
176 |
///
|
|
|
177 |
/// This is set by the app on the NetconData by calling
|
|
|
178 |
/// setcallback(). It is then called from the NetconData's cando()
|
|
|
179 |
/// routine, itself called by selectloop.
|
|
|
180 |
///
|
135 |
/// selectloop). It would be nicer to override cando() in a subclass
|
181 |
/// It would be nicer to override cando() in a subclass instead of
|
136 |
/// instead of setting a callback, but this can't be done conveniently
|
182 |
/// setting a callback, but this can't be done conveniently because
|
137 |
/// because accept() always creates a base NetconData (another way
|
183 |
/// accept() always creates a base NetconData (another approach would
|
138 |
/// would be to pass a factory function function to the listener, to create
|
184 |
/// be to pass a factory function to the listener, to create
|
139 |
/// NetconData derivatives).
|
185 |
/// NetconData derived classes).
|
140 |
class NetconWorker {
|
186 |
class NetconWorker {
|
141 |
public:
|
187 |
public:
|
142 |
virtual ~NetconWorker() {}
|
188 |
virtual ~NetconWorker() {}
|
143 |
// NetconP holds a NetconData oeuf corse
|
|
|
144 |
virtual int data(NetconData *con, Netcon::Event reason) = 0;
|
189 |
virtual int data(NetconData *con, Netcon::Event reason) = 0;
|
145 |
};
|
190 |
};
|
146 |
|
191 |
|
147 |
/// Base class for connections that actually transfer data. T
|
192 |
/// Base class for connections that actually transfer data. T
|
148 |
class NetconData : public Netcon {
|
193 |
class NetconData : public Netcon {
|
|
... |
|
... |
183 |
char *m_buf; // Buffer. Only used when doing getline()s
|
228 |
char *m_buf; // Buffer. Only used when doing getline()s
|
184 |
char *m_bufbase; // Pointer to current 1st byte of useful data
|
229 |
char *m_bufbase; // Pointer to current 1st byte of useful data
|
185 |
int m_bufbytes; // Bytes of data.
|
230 |
int m_bufbytes; // Bytes of data.
|
186 |
int m_bufsize; // Total buffer size
|
231 |
int m_bufsize; // Total buffer size
|
187 |
RefCntr<NetconWorker> m_user;
|
232 |
RefCntr<NetconWorker> m_user;
|
188 |
virtual int cando(Netcon::Event reason);
|
233 |
virtual int cando(Netcon::Event reason); // Selectloop slot
|
189 |
};
|
234 |
};
|
190 |
|
235 |
|
191 |
/// Network endpoint, client side.
|
236 |
/// Network endpoint, client side.
|
192 |
class NetconCli : public NetconData {
|
237 |
class NetconCli : public NetconData {
|
193 |
public:
|
238 |
public:
|