]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - include/inspsocket.h
Merge pull request #92 from Robby-/insp20-headers
[user/henk/code/inspircd.git] / include / inspsocket.h
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
5  *   Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net>
6  *   Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
7  *   Copyright (C) 2006-2007 Craig Edwards <craigedwards@brainbox.cc>
8  *   Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.com>
9  *
10  * This file is part of InspIRCd.  InspIRCd is free software: you can
11  * redistribute it and/or modify it under the terms of the GNU General Public
12  * License as published by the Free Software Foundation, version 2.
13  *
14  * This program is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
17  * details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  */
22
23
24 #ifndef INSPSOCKET_H
25 #define INSPSOCKET_H
26
27 #include "timer.h"
28
29 /**
30  * States which a socket may be in
31  */
32 enum BufferedSocketState
33 {
34         /** Socket disconnected */
35         I_DISCONNECTED,
36         /** Socket connecting */
37         I_CONNECTING,
38         /** Socket fully connected */
39         I_CONNECTED,
40         /** Socket has an error */
41         I_ERROR
42 };
43
44 /**
45  * Error types which a socket may exhibit
46  */
47 enum BufferedSocketError
48 {
49         /** No error */
50         I_ERR_NONE,
51         /** Socket was closed by peer */
52         I_ERR_DISCONNECT,
53         /** Socket connect timed out */
54         I_ERR_TIMEOUT,
55         /** Socket could not be created */
56         I_ERR_SOCKET,
57         /** Socket could not connect (refused) */
58         I_ERR_CONNECT,
59         /** Socket could not bind to local port/ip */
60         I_ERR_BIND,
61         /** Socket could not write data */
62         I_ERR_WRITE,
63         /** No more file descriptors left to create socket! */
64         I_ERR_NOMOREFDS,
65         /** Some other error */
66         I_ERR_OTHER
67 };
68
69 /* Required forward declarations */
70 class BufferedSocket;
71
72 /** Used to time out socket connections
73  */
74 class CoreExport SocketTimeout : public Timer
75 {
76  private:
77         /** BufferedSocket the class is attached to
78          */
79         BufferedSocket* sock;
80
81         /** File descriptor of class this is attached to
82          */
83         int sfd;
84
85  public:
86         /** Create a socket timeout class
87          * @param fd File descriptor of BufferedSocket
88          * @pram Instance server instance to attach to
89          * @param thesock BufferedSocket to attach to
90          * @param secs_from_now Seconds from now to time out
91          * @param now The current time
92          */
93         SocketTimeout(int fd, BufferedSocket* thesock, long secs_from_now, time_t now) : Timer(secs_from_now, now), sock(thesock), sfd(fd) { }
94
95         /** Handle tick event
96          */
97         virtual void Tick(time_t now);
98 };
99
100 /**
101  * StreamSocket is a class that wraps a TCP socket and handles send
102  * and receive queues, including passing them to IO hooks
103  */
104 class CoreExport StreamSocket : public EventHandler
105 {
106         /** Module that handles raw I/O for this socket, or NULL */
107         reference<Module> IOHook;
108         /** Private send queue. Note that individual strings may be shared
109          */
110         std::deque<std::string> sendq;
111         /** Length, in bytes, of the sendq */
112         size_t sendq_len;
113         /** Error - if nonempty, the socket is dead, and this is the reason. */
114         std::string error;
115  protected:
116         std::string recvq;
117  public:
118         StreamSocket() : sendq_len(0) {}
119         inline Module* GetIOHook();
120         inline void AddIOHook(Module* m);
121         inline void DelIOHook();
122         /** Handle event from socket engine.
123          * This will call OnDataReady if there is *new* data in recvq
124          */
125         virtual void HandleEvent(EventType et, int errornum = 0);
126         /** Dispatched from HandleEvent */
127         virtual void DoRead();
128         /** Dispatched from HandleEvent */
129         virtual void DoWrite();
130
131         /** Sets the error message for this socket. Once set, the socket is dead. */
132         void SetError(const std::string& err) { if (error.empty()) error = err; }
133
134         /** Gets the error message for this socket. */
135         const std::string& getError() const { return error; }
136
137         /** Called when new data is present in recvq */
138         virtual void OnDataReady() = 0;
139         /** Called when the socket gets an error from socket engine or IO hook */
140         virtual void OnError(BufferedSocketError e) = 0;
141
142         /** Send the given data out the socket, either now or when writes unblock
143          */
144         void WriteData(const std::string& data);
145         /** Convenience function: read a line from the socket
146          * @param line The line read
147          * @param delim The line delimiter
148          * @return true if a line was read
149          */
150         bool GetNextLine(std::string& line, char delim = '\n');
151         /** Useful for implementing sendq exceeded */
152         inline const size_t getSendQSize() const { return sendq_len; }
153
154         /**
155          * Close the socket, remove from socket engine, etc
156          */
157         virtual void Close();
158         /** This ensures that close is called prior to destructor */
159         virtual CullResult cull();
160 };
161 /**
162  * BufferedSocket is an extendable socket class which modules
163  * can use for TCP socket support. It is fully integrated
164  * into InspIRCds socket loop and attaches its sockets to
165  * the core's instance of the SocketEngine class, meaning
166  * that all use is fully asynchronous.
167  *
168  * To use BufferedSocket, you must inherit a class from it.
169  */
170 class CoreExport BufferedSocket : public StreamSocket
171 {
172  public:
173         /** Timeout object or NULL
174          */
175         SocketTimeout* Timeout;
176
177         /**
178          * The state for this socket, either
179          * listening, connecting, connected
180          * or error.
181          */
182         BufferedSocketState state;
183
184         BufferedSocket();
185         /**
186          * This constructor is used to associate
187          * an existing connecting with an BufferedSocket
188          * class. The given file descriptor must be
189          * valid, and when initialized, the BufferedSocket
190          * will be placed in CONNECTED state.
191          */
192         BufferedSocket(int newfd);
193
194         /** Begin connection to the given address
195          * This will create a socket, register with socket engine, and start the asynchronous
196          * connection process. If an error is detected at this point (such as out of file descriptors),
197          * OnError will be called; otherwise, the state will become CONNECTING.
198          * @param dest Address to connect to
199          * @param bind Address to bind to (if NULL, no bind will be done)
200          * @param timeout Time to wait for connection
201          */
202         void DoConnect(const std::string &ipaddr, int aport, unsigned long maxtime, const std::string &connectbindip);
203
204         /** This method is called when an outbound connection on your socket is
205          * completed.
206          */
207         virtual void OnConnected();
208
209         /** When there is data waiting to be read on a socket, the OnDataReady()
210          * method is called.
211          */
212         virtual void OnDataReady() = 0;
213
214         /**
215          * When an outbound connection fails, and the attempt times out, you
216          * will receive this event.  The method will trigger once maxtime
217          * seconds are reached (as given in the constructor) just before the
218          * socket's descriptor is closed.  A failed DNS lookup may cause this
219          * event if the DNS server is not responding, as well as a failed
220          * connect() call, because DNS lookups are nonblocking as implemented by
221          * this class.
222          */
223         virtual void OnTimeout();
224
225         virtual ~BufferedSocket();
226  protected:
227         virtual void DoWrite();
228         BufferedSocketError BeginConnect(const irc::sockets::sockaddrs& dest, const irc::sockets::sockaddrs& bind, unsigned long timeout);
229         BufferedSocketError BeginConnect(const std::string &ipaddr, int aport, unsigned long maxtime, const std::string &connectbindip);
230 };
231
232 #include "modules.h"
233
234 inline Module* StreamSocket::GetIOHook() { return IOHook; }
235 inline void StreamSocket::AddIOHook(Module* m) { IOHook = m; }
236 inline void StreamSocket::DelIOHook() { IOHook = NULL; }
237 #endif