Switch to unified view

a b/src/utils/netcon.h
1
#ifndef _NETCON_H_
2
#define _NETCON_H_
3
/* @(#$Id: netcon.h,v 1.11 2009-02-05 14:25:24 dockes Exp $  (C) 2002 Jean-Francois Dockes */
4
#include "refcntr.h"
5
6
/// A set of classes to manage client-server communication over a
7
/// connection-oriented network, or a pipe.
8
///
9
/// Currently only uses TCP. The classes include client-side and
10
/// server-side (accepting) endpoints, and server-side code to handle
11
/// a set of client connections in parallel.
12
/// 
13
/// The client data transfer class can also be used for
14
/// timeout-protected/asynchronous io using a given fd.
15
16
/// Base class for all network endpoints:
17
class Netcon;
18
typedef RefCntr<Netcon> NetconP;
19
20
class Netcon {
21
public:
22
    enum Event {NETCONPOLL_READ = 0x1, NETCONPOLL_WRITE=0x2};
23
    Netcon() 
24
  : m_peer(0), m_fd(-1), m_didtimo(0), m_wantedEvents(0)
25
    {}
26
    virtual ~Netcon();
27
    /// Remember whom we're talking to. We let external code do this because 
28
    /// the application may have a non-dns method to find the peer name.
29
    virtual void setpeer(const char *hostname);
30
    /// Retrieve the peer's hostname. Only works if it was set before !
31
    virtual const char *getpeer() {
32
  return m_peer ? (const char *)m_peer : "none";
33
    }
34
    /// Set or reset the TCP_NODELAY option. 
35
    virtual int settcpnodelay(int on = 1); 
36
    /// Did the last receive() call time out ? Resets the flag.
37
    virtual int timedout() {int s = m_didtimo; m_didtimo = 0; return s;}
38
    /// Return string version of last syscall error
39
    virtual char *sterror();
40
    /// Return the socket descriptor
41
    virtual int getfd() {return m_fd;}
42
    /// Close the current connection if it is open
43
    virtual void closeconn();
44
    /// Set/reset the non-blocking flag on the underlying fd. Returns
45
    /// prev state The default is that sockets are blocking except
46
    /// when added to the selectloop, or, transparently, to handle
47
    /// connection timeout issues.
48
    virtual int set_nonblock(int onoff);
49
50
    /// Decide what events the connection will be looking for
51
    /// (NETCONPOLL_READ, NETCONPOLL_WRITE)
52
    int setselevents(int evs) {return m_wantedEvents = evs;}
53
    /// Retrieve the connection's currently monitored set of events
54
    int getselevents() {return m_wantedEvents;}
55
    /// Add events to current set
56
    int addselevents(int evs) {return m_wantedEvents |= evs;}
57
    /// Clear events from current set
58
    int clearselevents(int evs) {return m_wantedEvents &= ~evs;}
59
60
    /// Utility function for a simplified select() interface: check one fd
61
    /// for reading or writing, for a specified maximum number of seconds.
62
    static int select1(int fd, int secs, int writing = 0);
63
    
64
    /// The selectloop interface is used to implement parallel servers. 
65
    /// All the interface is static (independant of any given object).
66
67
    /// Loop waiting for events on the connections and call the
68
    /// cando() method on the object where something happens (this will in 
69
    /// turn typically call the app callback set on the netcon). Possibly
70
    /// call the periodic handler (if set) at regular intervals.
71
    /// @return -1 for error. 0 if no descriptors left for i/o. 1 for periodic
72
    ///  timeout (should call back in after processing)
73
    static  int selectloop();
74
    /// Call from data handler: make selectloop return the param value
75
    static void selectloopReturn(int value) 
76
    {
77
  o_selectloopDoReturn = true;
78
  o_selectloopReturnValue = value;
79
    }
80
    /// Add a connection to be monitored (this will usually be called
81
    /// from the server's listen connection's accept callback)
82
    static  int addselcon(NetconP con, int);
83
    /// Remove a connection from the monitored set. Note that this is
84
    /// automatically called from the Netcon destructor, and when EOF is
85
    /// detected on a connection.
86
    static  int remselcon(NetconP con);
87
88
    /// Set a function to be called periodically, or a time before return.
89
    /// @param handler the function to be called. 
90
    ///  - if it is 0, selectloop() will return after ms mS (and can be called
91
    ///    again
92
    /// - if it is not 0, it will be called at ms mS intervals. If its return 
93
    ///   value is <= 0, selectloop will return. 
94
    /// @param clp client data to be passed to handler at every call.
95
    /// @param ms  milliseconds interval between handler calls or before return.
96
    ///   set ms to 0 for no periodic handler
97
    static  void setperiodichandler(int (*handler)(void *), void *clp, int ms);
98
99
protected:
100
    static bool o_selectloopDoReturn;
101
    static int  o_selectloopReturnValue;
102
    char *m_peer; // Name of the connected host
103
    int  m_fd;
104
    int m_didtimo;
105
    // Used when part of the selectloop map.
106
    short m_wantedEvents;
107
    // Method called by the selectloop when something can be done with a netcon
108
    virtual int cando(Netcon::Event reason) = 0;
109
};
110
111
112
///////////////////////
113
class NetconData;
114
115
/// Class for the application callback routine (when in
116
/// selectloop). It would be nicer to override cando() in a subclass
117
/// instead of setting a callback, but this can't be done conveniently
118
/// because accept() always creates a base NetconData (another way
119
/// would be to pass a factory function function to the listener, to create
120
/// NetconData derivatives).
121
class NetconWorker {
122
public:
123
    virtual ~NetconWorker() {}
124
    // NetconP holds a NetconData oeuf corse
125
    virtual int data(NetconData *con, Netcon::Event reason) = 0;
126
};
127
128
/// Base class for connections that actually transfer data.
129
class NetconData : public Netcon {
130
public:
131
    NetconData() : m_buf(0), m_bufbase(0), m_bufbytes(0), m_bufsize(0)
132
    {}
133
    virtual ~NetconData();
134
135
    /// Write data to the connection.
136
    /// @param buf the data buffer
137
    /// @param cnt the number of bytes we should try to send
138
    /// @param expedited send data in as 'expedited' data.
139
    /// @return the count of bytes actually transferred, -1 if an
140
    ///  error occurred.
141
    virtual int send(const char *buf, int cnt, int expedited = 0);
142
143
    /// Read from the connection
144
    /// @param buf the data buffer
145
    /// @param cnt the number of bytes we should try to read
146
    /// @param timeo maximum number of seconds we should be waiting for data.
147
    /// @return the count of bytes actually read. 0 for timeout (call
148
    ///        didtimo() to discriminate from EOF). -1 if an error occurred.
149
    virtual int receive(char *buf, int cnt, int timeo = -1);
150
    /// Loop on receive until cnt bytes are actually read or a timeout occurs
151
    virtual int doreceive(char *buf, int cnt, int timeo = -1);
152
    /// Check for data being available for reading
153
    virtual int readready();
154
    /// Check for data being available for writing
155
    virtual int writeready();
156
    /// Read a line of text on an ascii connection
157
    virtual int getline(char *buf, int cnt, int timeo = -1);
158
    /// Set handler to be called when the connection is placed in the
159
    /// selectloop and an event occurs.
160
    virtual void setcallback(RefCntr<NetconWorker> user) {m_user = user;}
161
162
private:
163
    char *m_buf;  // Buffer. Only used when doing getline()s
164
    char *m_bufbase;    // Pointer to current 1st byte of useful data
165
    int m_bufbytes;   // Bytes of data.
166
    int m_bufsize;    // Total buffer size
167
    RefCntr<NetconWorker> m_user;
168
    virtual int cando(Netcon::Event reason);
169
};
170
171
/// Network endpoint, client side.
172
class NetconCli : public NetconData { 
173
public:
174
    NetconCli(int silent = 0) {m_silentconnectfailure = silent;}
175
    /// Open connection to specified host and named service. 
176
    int openconn(const char *host, char *serv, int timeo = -1);
177
    /// Open connection to specified host and numeric port. port is in
178
    /// HOST byte order
179
    int openconn(const char *host, unsigned int port, int timeo = -1);
180
    /// Reuse existing fd. We DONT take ownership of the fd, and do no closin'
181
    /// EVEN on an explicit closeconn() (use getfd(), close, setconn(-1)).
182
    int setconn(int fd);
183
    /// Do not log message if openconn() fails.
184
    void setSilentFail(int onoff) {m_silentconnectfailure = onoff;}
185
private:
186
    int m_silentconnectfailure;   // No logging of connection failures if set
187
};
188
189
class NetconServCon;
190
#ifdef NETCON_ACCESSCONTROL
191
struct intarrayparam {
192
    int len;
193
    unsigned int *intarray;
194
};
195
#endif /* NETCON_ACCESSCONTROL */
196
197
/// Server listening end point.
198
///
199
/// if NETCON_ACCESSCONTROL is defined during compilation,
200
/// NetconServLis has primitive access control features: okaddrs holds
201
/// the host addresses for the hosts which we allow to connect to
202
/// us. okmasks holds the masks to be used for comparison.  okmasks
203
/// can be shorter than okaddrs, in which case we use the last entry
204
/// for all addrs beyond the masks array length. Both arrays are
205
/// retrieved from the configuration file when we create the endpoint
206
/// the key is either based on the service name (ex: cdpathdb_okaddrs,
207
/// cdpathdb_okmasks), or "default" if the service name is not found
208
/// (ex: default_okaddrs, default_okmasks)
209
class NetconServLis : public Netcon {
210
public:
211
    NetconServLis() {
212
#ifdef NETCON_ACCESSCONTROL
213
  permsinit = 0;
214
  okaddrs.len = okmasks.len = 0;
215
  okaddrs.intarray = okmasks.intarray = 0;
216
#endif /* NETCON_ACCESSCONTROL */
217
    }
218
    ~NetconServLis();
219
    /// Open named service.
220
    int openservice(char *serv, int backlog = 10);
221
    /// Open service by port number.
222
    int openservice(int port, int backlog = 10);
223
    /// Wait for incoming connection. Returned connected Netcon 
224
    NetconServCon *accept(int timeo = -1);
225
226
protected:
227
    /// This should be overriden in a derived class to handle incoming
228
    /// connections. It will usually call NetconServLis::accept(), and
229
    /// insert the new connection in the selectloop.
230
    virtual int cando(Netcon::Event reason);
231
232
private:
233
#ifdef NETCON_ACCESSCONTROL
234
    int permsinit;
235
    struct intarrayparam okaddrs;
236
    struct intarrayparam okmasks;
237
    int initperms(char *servicename);
238
    int initperms(int port);
239
    int checkperms(void *cli, int clilen);
240
#endif /* NETCON_ACCESSCONTROL */
241
};
242
243
/// Server-side accepted client connection. The only specific code
244
/// allows closing the listening endpoint in the child process (in the
245
/// case of a forking server)
246
class NetconServCon : public NetconData { 
247
public:
248
    NetconServCon(int newfd, Netcon* lis = 0) 
249
    { 
250
  m_liscon = lis;
251
  m_fd = newfd;
252
    }
253
    /// This is for forked servers that want to get rid of the main socket
254
    void closeLisCon() {
255
  if (m_liscon)
256
      m_liscon->closeconn();
257
    }
258
private:
259
    Netcon* m_liscon;
260
};
261
262
#endif /* _NETCON_H_ */