1 /* +------------------------------------+
2 * | Inspire Internet Relay Chat Daemon |
3 * +------------------------------------+
5 * InspIRCd: (C) 2002-2008 InspIRCd Development Team
6 * See: http://www.inspircd.org/wiki/index.php/Credits
8 * This program is free but copyrighted software; see
9 * the file COPYING for details.
11 * ---------------------------------------------------
14 #ifndef __INSP_SOCKET_H__
15 #define __INSP_SOCKET_H__
20 * States which a socket may be in
22 enum BufferedSocketState
24 /** Socket disconnected */
26 /** Socket connecting */
28 /** Socket fully connected */
30 /** Socket listening for connections */
32 /** Socket has an error */
37 * Error types which a socket may exhibit
39 enum BufferedSocketError
41 /** Socket connect timed out */
43 /** Socket could not be created */
45 /** Socket could not connect (refused) */
47 /** Socket could not bind to local port/ip */
49 /** Socket could not reslve host (depreciated) */
51 /** Socket could not write data */
53 /** No more file descriptors left to create socket! */
57 /* Required forward declarations */
61 using irc::sockets::insp_sockaddr;
62 using irc::sockets::insp_inaddr;
63 using irc::sockets::insp_ntoa;
64 using irc::sockets::insp_aton;
66 /** Used to time out socket connections
68 class CoreExport SocketTimeout : public Timer
71 /** BufferedSocket the class is attached to
74 /** Server instance creating the timeout class
76 InspIRCd* ServerInstance;
77 /** File descriptor of class this is attached to
81 /** Create a socket timeout class
82 * @param fd File descriptor of BufferedSocket
83 * @pram Instance server instance to attach to
84 * @param thesock BufferedSocket to attach to
85 * @param secs_from_now Seconds from now to time out
86 * @param now The current time
88 SocketTimeout(int fd, InspIRCd* Instance, BufferedSocket* thesock, long secs_from_now, time_t now) : Timer(secs_from_now, now), sock(thesock), ServerInstance(Instance), sfd(fd) { };
91 virtual void Tick(time_t now);
95 * BufferedSocket is an extendable socket class which modules
96 * can use for TCP socket support. It is fully integrated
97 * into InspIRCds socket loop and attaches its sockets to
98 * the core's instance of the SocketEngine class, meaning
99 * that any sockets you create have the same power and
100 * abilities as a socket created by the core itself.
101 * To use BufferedSocket, you must inherit a class from it,
102 * and use the BufferedSocket constructors to establish connections
105 class CoreExport BufferedSocket : public EventHandler
115 * Is hooked by a module for low level IO
120 * Instance we were created by
125 * Timeout class or NULL
127 SocketTimeout* Timeout;
132 unsigned long timeout_val;
135 * Socket output buffer (binary safe)
137 std::deque<std::string> outbuffer;
140 * The hostname connected to
145 * The port connected to, or the port
146 * this socket is listening on
151 * The state for this socket, either
152 * listening, connecting, connected
155 BufferedSocketState state;
158 * This value is true if the
159 * socket has timed out.
164 * The IP address being connected
165 * to stored in string form for
166 * easy retrieval by accessors.
171 * Used by accept() to indicate the
172 * sizes of the sockaddr_in structures
176 /** Flushes the write buffer
178 bool FlushWriteBuffer();
180 /** Set the queue sizes
181 * This private method sets the operating system queue
182 * sizes for this socket to 65535 so that it can queue
183 * more information without application-level queueing
184 * which was required in older software.
186 void SetQueues(int nfd);
188 /** When the socket has been marked as closing, this flag
189 * will be set to true, then the next time the socket is
190 * examined, the socket is deleted and closed.
194 /** Set to true when we're waiting for a write event.
195 * If this is true and a write event comes in, we
196 * call the write instead of the read method.
198 bool WaitingForWriteEvent;
202 * @param ip IP to bind to
203 * @return True is the binding succeeded
205 bool BindAddr(const std::string &ip);
208 * The default constructor does nothing
209 * and should not be used.
211 BufferedSocket(InspIRCd* SI);
214 * This constructor is used to associate
215 * an existing connecting with an BufferedSocket
216 * class. The given file descriptor must be
217 * valid, and when initialized, the BufferedSocket
218 * will be set with the given IP address
219 * and placed in CONNECTED state.
221 BufferedSocket(InspIRCd* SI, int newfd, const char* ip);
224 * This constructor is used to create a new
225 * socket, either listening for connections, or an outbound connection to another host.
226 * Note that if you specify a hostname in the 'ipaddr' parameter, this class will not
227 * connect. You must resolve your hostnames before passing them to BufferedSocket. To do so,
228 * you should use the nonblocking class 'Resolver'.
229 * @param ipaddr The IP to connect to, or bind to
230 * @param port The port number to connect to, or bind to
231 * @param listening true to listen on the given host:port pair, or false to connect to them
232 * @param maxtime Number of seconds to wait, if connecting, before the connection times out and an OnTimeout() event is generated
233 * @param connectbindip When creating an outbound connection, the IP to bind the connection to. If not defined, the port is not bound.
234 * @return On exit, GetState() returns I_ERROR if an error occured, and errno can be used to read the socket error.
236 BufferedSocket(InspIRCd* SI, const std::string &ipaddr, int port, bool listening, unsigned long maxtime, const std::string &connectbindip = "");
239 * This method is called when an outbound
240 * connection on your socket is completed.
241 * @return false to abort the connection, true to continue
243 virtual bool OnConnected();
246 * This method is called when an error occurs.
247 * A closed socket in itself is not an error,
248 * however errors also generate close events.
249 * @param e The error type which occured
251 virtual void OnError(BufferedSocketError e);
254 * When an established connection is terminated,
255 * the OnDisconnect method is triggered.
257 virtual int OnDisconnect();
260 * When there is data waiting to be read on a
261 * socket, the OnDataReady() method is called.
262 * Within this method, you *MUST* call the Read()
263 * method to read any pending data. At its lowest
264 * level, this event is signalled by the core via
265 * the socket engine. If you return false from this
266 * function, the core removes your socket from its
267 * list and erases it from the socket engine, then
268 * calls BufferedSocket::Close() and deletes it.
269 * @return false to close the socket
271 virtual bool OnDataReady();
274 * When it is ok to write to the socket, and a
275 * write event was requested, this method is
276 * triggered. Within this method you should call
277 * write() or send() etc, to send data to the
278 * other end of the socket. Further write events
279 * will not be triggered unless you call WantWrite().
280 * @return false to close the socket
282 virtual bool OnWriteReady();
285 * When an outbound connection fails, and the
286 * attempt times out, you will receive this event.
287 * The method will trigger once maxtime seconds are
288 * reached (as given in the constructor) just
289 * before the socket's descriptor is closed.
290 * A failed DNS lookup may cause this event if
291 * the DNS server is not responding, as well as
292 * a failed connect() call, because DNS lookups are
293 * nonblocking as implemented by this class.
295 virtual void OnTimeout();
298 * Whenever close() is called, OnClose() will be
299 * called first. Please note that this means
300 * OnClose will be called alongside OnError(),
301 * OnTimeout(), and Close(), and also when
302 * cancelling a listening socket by calling
303 * the destructor indirectly.
305 virtual void OnClose();
308 * Reads all pending bytes from the socket
309 * into a char* array which can be up to
310 * 16 kilobytes in length.
312 virtual const char* Read();
315 * Returns the IP address associated with
316 * this connection, or an empty string if
317 * no IP address exists.
322 * Writes a std::string to the socket. No carriage
323 * returns or linefeeds are appended to the string.
324 * @param data The data to send
326 virtual void Write(const std::string &data);
329 * If your socket is a listening socket, when a new
330 * connection comes in on the socket this method will
331 * be called. Given the new file descriptor in the
332 * parameters, and the IP, it is recommended you copy
333 * them to a new instance of your socket class,
336 * MySocket* newsocket = new MySocket(newfd,ip);
338 * Once you have done this, you can then associate the
339 * new socket with the core using Server::AddSocket().
341 virtual int OnIncomingConnection(int newfd, char* ip);
344 * Changes the socket's state. The core uses this
345 * to change socket states, and you should not call
348 void SetState(BufferedSocketState s);
351 * Call this to receive the next write event
352 * that comes along for this fd to the OnWriteReady
358 * Returns the current socket state.
360 BufferedSocketState GetState();
363 * Only the core should call this function.
364 * When called, it is assumed the socket is ready
365 * to read data, and the method call routes the
366 * event to the various methods of BufferedSocket
367 * for you to handle. This can also cause the
368 * socket's state to change.
373 * This method returns the socket's file descriptor
374 * as assigned by the operating system, or -1
375 * if no descriptor has been assigned.
380 * This method causes the socket to close, and may
381 * also be triggered by other methods such as OnTimeout
384 virtual void Close();
387 * The destructor may implicitly call OnClose(), and
388 * will close() and shutdown() the file descriptor
389 * used for this socket.
391 virtual ~BufferedSocket();
394 * This method attempts to connect to a hostname.
395 * This only occurs on a non-listening socket. This
396 * method is asyncronous.
398 virtual bool DoConnect();
400 /** Handle event from EventHandler parent class
402 void HandleEvent(EventType et, int errornum = 0);
404 /** Returns true if this socket is readable