Branch data Line data Source code
1 : : // Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
2 : : //
3 : : // Permission to use, copy, modify, and/or distribute this software for any
4 : : // purpose with or without fee is hereby granted, provided that the above
5 : : // copyright notice and this permission notice appear in all copies.
6 : : //
7 : : // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
8 : : // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
9 : : // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
10 : : // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
11 : : // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
12 : : // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
13 : : // PERFORMANCE OF THIS SOFTWARE.
14 : :
15 : : #ifndef __IO_ASIO_SOCKET_H
16 : : #define __IO_ASIO_SOCKET_H 1
17 : :
18 : : // IMPORTANT NOTE: only very few ASIO headers files can be included in
19 : : // this file. In particular, asio.hpp should never be included here.
20 : : // See the description of the namespace below.
21 : : #include <unistd.h> // for some network system calls
22 : :
23 : : #include <functional>
24 : : #include <string>
25 : :
26 : : #include <exceptions/exceptions.h>
27 : : #include <coroutine.h>
28 : :
29 : : #include <util/buffer.h>
30 : :
31 : : #include <asiolink/io_error.h>
32 : : #include <asiolink/io_socket.h>
33 : :
34 : : namespace isc {
35 : : namespace asiolink {
36 : :
37 : : /// \brief Socket not open
38 : : ///
39 : : /// Thrown on an attempt to do read/write to a socket that is not open.
40 : 0 : class SocketNotOpen : public IOError {
41 : : public:
42 : : SocketNotOpen(const char* file, size_t line, const char* what) :
43 [ # # ][ # # ]: 0 : IOError(file, line, what) {}
44 : : };
45 : :
46 : : /// \brief Error setting socket options
47 : : ///
48 : : /// Thrown if attempt to change socket options fails.
49 : 0 : class SocketSetError : public IOError {
50 : : public:
51 : : SocketSetError(const char* file, size_t line, const char* what) :
52 : : IOError(file, line, what) {}
53 : : };
54 : :
55 : : /// \brief Buffer overflow
56 : : ///
57 : : /// Thrown if an attempt is made to receive into an area beyond the end of
58 : : /// the receive data buffer.
59 : 0 : class BufferOverflow : public IOError {
60 : : public:
61 : : BufferOverflow(const char* file, size_t line, const char* what) :
62 [ # # ]: 0 : IOError(file, line, what) {}
63 : : };
64 : :
65 : : /// Forward declaration of an IOEndpoint
66 : : class IOEndpoint;
67 : :
68 : :
69 : : /// \brief I/O Socket with asynchronous operations
70 : : ///
71 : : /// This class is a wrapper for the ASIO socket classes such as
72 : : /// \c ip::tcp::socket and \c ip::udp::socket.
73 : : ///
74 : : /// This is the basic IOSocket with additional operations - open, send, receive
75 : : /// and close. Depending on how the asiolink code develops, it may be a
76 : : /// temporary class: its main use is to add the template parameter needed for
77 : : /// the derived classes UDPSocket and TCPSocket but without changing the
78 : : /// signature of the more basic IOSocket class.
79 : : ///
80 : : /// We may revisit this decision when we generalize the wrapper and more
81 : : /// modules use it. Also, at that point we may define a separate (visible)
82 : : /// derived class for testing purposes rather than providing factory methods
83 : : /// (i.e., getDummy variants below).
84 : : ///
85 : : /// \param C Template parameter identifying type of the callback object.
86 : :
87 : : template <typename C>
88 : : class IOAsioSocket : public IOSocket {
89 : : ///
90 : : /// \name Constructors and Destructor
91 : : ///
92 : : /// Note: The copy constructor and the assignment operator are
93 : : /// intentionally defined as private, making this class non-copyable.
94 : : //@{
95 : : private:
96 : : IOAsioSocket(const IOAsioSocket<C>& source);
97 : : IOAsioSocket& operator=(const IOAsioSocket<C>& source);
98 : : protected:
99 : : /// \brief The default constructor.
100 : : ///
101 : : /// This is intentionally defined as \c protected as this base class
102 : : /// should never be instantiated (except as part of a derived class).
103 : 212 : IOAsioSocket() {}
104 : : public:
105 : : /// The destructor.
106 : 0 : virtual ~IOAsioSocket() {}
107 : : //@}
108 : :
109 : : /// \brief Return the "native" representation of the socket.
110 : : ///
111 : : /// In practice, this is the file descriptor of the socket for UNIX-like
112 : : /// systems so the current implementation simply uses \c int as the type of
113 : : /// the return value. We may have to need revisit this decision later.
114 : : ///
115 : : /// In general, the application should avoid using this method; it
116 : : /// essentially discloses an implementation specific "handle" that can
117 : : /// change the internal state of the socket (consider what would happen if
118 : : /// the application closes it, for example). But we sometimes need to
119 : : /// perform very low-level operations that requires the native
120 : : /// representation. Passing the file descriptor to a different process is
121 : : /// one example. This method is provided as a necessary evil for such
122 : : /// limited purposes.
123 : : ///
124 : : /// This method never throws an exception.
125 : : ///
126 : : /// \return The native representation of the socket. This is the socket
127 : : /// file descriptor for UNIX-like systems.
128 : : virtual int getNative() const = 0;
129 : :
130 : : /// \brief Return the transport protocol of the socket.
131 : : ///
132 : : /// Currently, it returns \c IPPROTO_UDP for UDP sockets, and
133 : : /// \c IPPROTO_TCP for TCP sockets.
134 : : ///
135 : : /// This method never throws an exception.
136 : : ///
137 : : /// \return \c IPPROTO_UDP for UDP sockets, \c IPPROTO_TCP for TCP sockets
138 : : virtual int getProtocol() const = 0;
139 : :
140 : : /// \brief Is Open() synchronous?
141 : : ///
142 : : /// On a TCP socket, an "open" operation is a call to the socket's "open()"
143 : : /// method followed by a connection to the remote system: it is an
144 : : /// asynchronous operation. On a UDP socket, it is just a call to "open()"
145 : : /// and completes synchronously.
146 : : ///
147 : : /// For TCP, signalling of the completion of the operation is done by
148 : : /// by calling the callback function in the normal way. This could be done
149 : : /// for UDP (by posting en event on the event queue); however, that will
150 : : /// incur additional overhead in the most common case. So we give the
151 : : /// caller the choice for calling this open() method synchronously or
152 : : /// asynchronously.
153 : : ///
154 : : /// Owing to the way that the stackless coroutines are implemented, we need
155 : : /// to know _before_ executing the "open" function whether or not it is
156 : : /// asynchronous. So this method is called to provide that information.
157 : : ///
158 : : /// (The reason there is a need to know is because the call to open() passes
159 : : /// in the state of the coroutine at the time the call is made. On an
160 : : /// asynchronous I/O, we need to set the state to point to the statement
161 : : /// after the call to open() _before_ we pass the corouine to the open()
162 : : /// call. Unfortunately, the macros that set the state of the coroutine
163 : : /// also yield control - which we don't want to do if the open is
164 : : /// synchronous. Hence we need to know before we make the call to open()
165 : : /// whether that call will complete asynchronously.)
166 : : virtual bool isOpenSynchronous() const = 0;
167 : :
168 : : /// \brief Open AsioSocket
169 : : ///
170 : : /// Opens the socket for asynchronous I/O. The open will complete
171 : : /// synchronously on UCP or asynchronously on TCP (in which case a callback
172 : : /// will be queued).
173 : : ///
174 : : /// \param endpoint Pointer to the endpoint object. This is ignored for
175 : : /// a UDP socket (the target is specified in the send call), but
176 : : /// should be of type TCPEndpoint for a TCP connection.
177 : : /// \param callback I/O Completion callback, called when the operation has
178 : : /// completed, but only if the operation was asynchronous. (It is
179 : : /// ignored on a UDP socket.)
180 : : virtual void open(const IOEndpoint* endpoint, C& callback) = 0;
181 : :
182 : : /// \brief Send Asynchronously
183 : : ///
184 : : /// This corresponds to async_send_to() for UDP sockets and async_send()
185 : : /// for TCP. In both cases an endpoint argument is supplied indicating the
186 : : /// target of the send - this is ignored for TCP.
187 : : ///
188 : : /// \param data Data to send
189 : : /// \param length Length of data to send
190 : : /// \param endpoint Target of the send
191 : : /// \param callback Callback object.
192 : : virtual void asyncSend(const void* data, size_t length,
193 : : const IOEndpoint* endpoint, C& callback) = 0;
194 : :
195 : : /// \brief Receive Asynchronously
196 : : ///
197 : : /// This corresponds to async_receive_from() for UDP sockets and
198 : : /// async_receive() for TCP. In both cases, an endpoint argument is
199 : : /// supplied to receive the source of the communication. For TCP it will
200 : : /// be filled in with details of the connection.
201 : : ///
202 : : /// \param data Buffer to receive incoming message
203 : : /// \param length Length of the data buffer
204 : : /// \param offset Offset into buffer where data is to be put. Although the
205 : : /// offset could be implied by adjusting "data" and "length"
206 : : /// appropriately, using this argument allows data to be specified as
207 : : /// "const void*" - the overhead of converting it to a pointer to a
208 : : /// set of bytes is hidden away here.
209 : : /// \param endpoint Source of the communication
210 : : /// \param callback Callback object
211 : : virtual void asyncReceive(void* data, size_t length, size_t offset,
212 : : IOEndpoint* endpoint, C& callback) = 0;
213 : :
214 : : /// \brief Processes received data
215 : : ///
216 : : /// In the IOFetch code, data is received into a staging buffer before being
217 : : /// copied into the target buffer. (This is because (a) we don't know how
218 : : /// much data we will be receiving, so don't know how to size the output
219 : : /// buffer and (b) TCP data is preceded by a two-byte count field that needs
220 : : /// to be discarded before being returned to the user.)
221 : : ///
222 : : /// An additional consideration is that TCP data is not received in one
223 : : /// I/O - it may take a number of I/Os - each receiving any non-zero number
224 : : /// of bytes - to read the entire message.
225 : : ///
226 : : /// So the IOFetch code has to loop until it determines that all the data
227 : : /// has been read. This is where this method comes in. It has several
228 : : /// functions:
229 : : ///
230 : : /// - It checks if the received data is complete.
231 : : /// - If data is not complete, decides if the next set of data is to go into
232 : : /// the start of the staging buffer or at some offset into it. (This
233 : : /// simplifies the case we could have in a TCP receive where the two-byte
234 : : /// count field is received in one-byte chunks: we put off interpreting
235 : : /// the count until we have all of it. The alternative - copying the
236 : : /// data to the output buffer and interpreting the count from there -
237 : : /// would require moving the data in the output buffer by two bytes before
238 : : /// returning it to the caller.)
239 : : /// - Copies data from the staging buffer into the output buffer.
240 : : ///
241 : : /// This functionality mainly applies to TCP receives. For UDP, all the
242 : : /// data is received in one I/O, so this just copies the data into the
243 : : /// output buffer.
244 : : ///
245 : : /// \param staging Pointer to the start of the staging buffer.
246 : : /// \param length Amount of data in the staging buffer.
247 : : /// \param cumulative Amount of data received before the staging buffer is
248 : : /// processed (this includes the TCP count field if appropriate).
249 : : /// The value should be set to zero before the receive loop is
250 : : /// entered, and it will be updated by this method as required.
251 : : /// \param offset Offset into the staging buffer where the next read should
252 : : /// put the received data. It should be set to zero before the first
253 : : /// call and may be updated by this method.
254 : : /// \param expected Expected amount of data to be received. This is
255 : : /// really the TCP count field and is set to that value when enough
256 : : /// of a TCP message is received. It should be initialized to -1
257 : : /// before the first read is executed.
258 : : /// \param outbuff Output buffer. Data in the staging buffer may be copied
259 : : /// to this output buffer in the call.
260 : : ///
261 : : /// \return true if the receive is complete, false if another receive is
262 : : /// needed. This is always true for UDP, but for TCP involves
263 : : /// checking the amount of data received so far against the amount
264 : : /// expected (as indicated by the two-byte count field). If this
265 : : /// method returns false, another read should be queued and data
266 : : /// should be read into the staging buffer at offset given by the
267 : : /// "offset" parameter.
268 : : virtual bool processReceivedData(const void* staging, size_t length,
269 : : size_t& cumulative, size_t& offset,
270 : : size_t& expected,
271 : : isc::util::OutputBufferPtr& outbuff) = 0;
272 : :
273 : : /// \brief Cancel I/O On AsioSocket
274 : : virtual void cancel() = 0;
275 : :
276 : : /// \brief Close socket
277 : : virtual void close() = 0;
278 : : };
279 : :
280 : :
281 : : #include "io_socket.h"
282 : :
283 : : /// \brief The \c DummyAsioSocket class is a concrete derived class of
284 : : /// \c IOAsioSocket that is not associated with any real socket.
285 : : ///
286 : : /// This main purpose of this class is tests, where it may be desirable to
287 : : /// instantiate an \c IOAsioSocket object without involving system resource
288 : : /// allocation such as real network sockets.
289 : : ///
290 : : /// \param C Template parameter identifying type of the callback object.
291 : :
292 : : template <typename C>
293 : : class DummyAsioSocket : public IOAsioSocket<C> {
294 : : private:
295 : : DummyAsioSocket(const DummyAsioSocket<C>& source);
296 : : DummyAsioSocket& operator=(const DummyAsioSocket<C>& source);
297 : : public:
298 : : /// \brief Constructor from the protocol number.
299 : : ///
300 : : /// The protocol must validly identify a standard network protocol.
301 : : /// For example, to specify TCP \c protocol must be \c IPPROTO_TCP.
302 : : ///
303 : : /// \param protocol The network protocol number for the socket.
304 : : DummyAsioSocket(const int protocol) : protocol_(protocol) {}
305 : :
306 : : /// \brief A dummy derived method of \c IOAsioSocket::getNative().
307 : : ///
308 : : /// \return Always returns -1 as the object is not associated with a real
309 : : /// (native) socket.
310 : : virtual int getNative() const { return (-1); }
311 : :
312 : : /// \brief A dummy derived method of \c IOAsioSocket::getProtocol().
313 : : ///
314 : : /// \return Protocol socket was created with
315 : : virtual int getProtocol() const { return (protocol_); }
316 : :
317 : :
318 : : /// \brief Is socket opening synchronous?
319 : : ///
320 : : /// \return true - it is for this class.
321 : : bool isOpenSynchronous() const {
322 : : return true;
323 : : }
324 : :
325 : : /// \brief Open AsioSocket
326 : : ///
327 : : /// A call that is a no-op on UDP sockets, this opens a connection to the
328 : : /// system identified by the given endpoint.
329 : : /// The endpoint and callback are unused.
330 : : ///
331 : : /// \return false indicating that the operation completed synchronously.
332 : : virtual bool open(const IOEndpoint*, C&) {
333 : : return (false);
334 : : }
335 : :
336 : : /// \brief Send Asynchronously
337 : : ///
338 : : /// Must be supplied as it is abstract in the base class.
339 : : /// This is unused.
340 : : virtual void asyncSend(const void*, size_t, const IOEndpoint*, C&) {
341 : : }
342 : :
343 : : /// \brief Receive Asynchronously
344 : : ///
345 : : /// Must be supplied as it is abstract in the base class.
346 : : /// The parameters are unused.
347 : : virtual void asyncReceive(void* data, size_t, size_t, IOEndpoint*, C&) {
348 : : }
349 : :
350 : : /// \brief Checks if the data received is complete.
351 : : ///
352 : : /// \param staging Unused
353 : : /// \param length Unused
354 : : /// \param cumulative Unused
355 : : /// \param offset Unused.
356 : : /// \param expected Unused.
357 : : /// \param outbuff Unused.
358 : : ///
359 : : /// \return Always true
360 : : virtual bool receiveComplete(const void* staging, size_t length,
361 : : size_t& cumulative, size_t& offset,
362 : : size_t& expected,
363 : : isc::util::OutputBufferPtr& outbuff)
364 : : {
365 : : return (true);
366 : : }
367 : :
368 : :
369 : : /// \brief Cancel I/O On AsioSocket
370 : : ///
371 : : /// Must be supplied as it is abstract in the base class.
372 : : virtual void cancel() {
373 : : }
374 : :
375 : : /// \brief Close socket
376 : : ///
377 : : /// Must be supplied as it is abstract in the base class.
378 : : virtual void close() {
379 : : }
380 : :
381 : : private:
382 : : const int protocol_;
383 : : };
384 : :
385 : : } // namespace asiolink
386 : : } // namespace isc
387 : :
388 : : #endif // __IO_ASIO_SOCKET_H
|