Line data Source code
1 :
2 : /* Copyright (c) 2005-2014, Stefan Eilemann <eile@equalizergraphics.com>
3 : * 2012-2014, Daniel Nachbaur <danielnachbaur@gmail.com>
4 : *
5 : * This file is part of Collage <https://github.com/Eyescale/Collage>
6 : *
7 : * This library is free software; you can redistribute it and/or modify it under
8 : * the terms of the GNU Lesser General Public License version 2.1 as published
9 : * by the Free Software Foundation.
10 : *
11 : * This library is distributed in the hope that it will be useful, but WITHOUT
12 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
14 : * details.
15 : *
16 : * You should have received a copy of the GNU Lesser General Public License
17 : * along with this library; if not, write to the Free Software Foundation, Inc.,
18 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 : */
20 :
21 : #ifndef CO_CONNECTION_H
22 : #define CO_CONNECTION_H
23 :
24 : #include <co/api.h>
25 : #include <co/types.h>
26 :
27 : #include <lunchbox/bitOperation.h> // used inline
28 : #include <lunchbox/referenced.h> // base class
29 : #include <boost/noncopyable.hpp> // base class
30 :
31 : #include <sys/types.h>
32 : #include <string.h>
33 : #include <vector>
34 :
35 : namespace co
36 : {
37 : namespace detail { class Connection; }
38 :
39 : /**
40 : * An interface definition for communication between hosts.
41 : *
42 : * Connections are stream-oriented communication lines. The parameters of a
43 : * Connection are described in a ConnectionDescription, which is used in
44 : * create(), listen() and connect(). A Connection has a Connection::State, which
45 : * changes when calling listen(), connect() or close(), or whenever the
46 : * underlying connection is closed by the operating system.
47 : *
48 : * The Connection class defines the interface for connections, various derived
49 : * classes implement it for the low-level communication protocols, e.g.,
50 : * SocketConnection for TCP/IP or RSPConnection for UDP-based reliable
51 : * multicast. An implementation may not implement all the functionality defined
52 : * in this interface.
53 : *
54 : * The Connection is used reference-counted throughout the Collage API.
55 : */
56 : class Connection : public lunchbox::Referenced, public boost::noncopyable
57 : {
58 : public:
59 : enum State //! The current state of the Connection @version 1.0
60 : {
61 : STATE_CLOSED, //!< Closed, initial state
62 : STATE_CONNECTING, //!< A connect() or listen() is in progress
63 : STATE_CONNECTED, //!< The connection has been connected and is open
64 : STATE_LISTENING, //!< The connection is listening for connects
65 : STATE_CLOSING //!< A close() is in progress
66 : };
67 :
68 : /**
69 : * Create a new connection.
70 : *
71 : * This factory method creates a new concrete connection for the requested
72 : * type. The description is set on the created Connection.
73 : *
74 : * @param desc the connection parameters.
75 : * @return the connection.
76 : * @version 1.0
77 : */
78 : CO_API static ConnectionPtr create( ConnectionDescriptionPtr desc );
79 :
80 : /** @name Data Access */
81 : //@{
82 : /** @return the State of this connection. @version 1.0 */
83 : CO_API State getState() const;
84 :
85 : /** @return true if the connection is closed. @version 1.0 */
86 1141 : bool isClosed() const { return getState() == STATE_CLOSED; }
87 :
88 : /** @return true if the connection is about to close. @version 1.0 */
89 6 : bool isClosing() const { return getState() == STATE_CLOSING; }
90 :
91 : /** @return true if the connection is connected. @version 1.0 */
92 2940399 : bool isConnected() const { return getState() == STATE_CONNECTED; }
93 :
94 : /** @return true if the connection is listening. @version 1.0 */
95 307014 : bool isListening() const { return getState() == STATE_LISTENING; }
96 :
97 : /** @return true if this is a multicast connection. @version 1.0 */
98 : CO_API bool isMulticast() const;
99 :
100 : /** @return the description for this connection. @version 1.0 */
101 : CO_API ConstConnectionDescriptionPtr getDescription() const;
102 :
103 : /** @internal */
104 : bool operator == ( const Connection& rhs ) const;
105 : //@}
106 :
107 : /** @name Connection State Changes */
108 : //@{
109 : /**
110 : * Connect to the remote peer.
111 : *
112 : * The ConnectionDescription of this connection is used to identify the
113 : * peer's parameters.
114 : *
115 : * @return true if the connection was successfully connected, false
116 : * if not.
117 : * @version 1.0
118 : */
119 0 : virtual bool connect() { return false; }
120 :
121 : /**
122 : * Put the connection into the listening state.
123 : *
124 : * The ConnectionDescription of this connection is used to identify the
125 : * listening parameters.
126 : *
127 : * @return true if the connection is listening for new incoming
128 : * connections, false if not.
129 : * @version 1.0
130 : */
131 0 : virtual bool listen() { return false; }
132 :
133 : /** Close a connected or listening connection. @version 1.0 */
134 0 : virtual void close() {}
135 : //@}
136 :
137 : /** @internal @name Listener Interface */
138 : //@{
139 : /** @internal Add a listener for connection state changes. */
140 : void addListener( ConnectionListener* listener );
141 :
142 : /** @internal Remove a listener for connection state changes. */
143 : void removeListener( ConnectionListener* listener );
144 : //@}
145 :
146 : /** @name Asynchronous accept */
147 : //@{
148 : /**
149 : * Start an accept operation.
150 : *
151 : * This method returns immediately. The Notifier will signal a new
152 : * connection request, upon which acceptSync() should be used to finish the
153 : * accept operation. Only one accept operation might be outstanding, that
154 : * is, acceptSync() has to be called before the next acceptNB().
155 : *
156 : * @sa acceptSync()
157 : * @version 1.0
158 : */
159 0 : virtual void acceptNB() { LBUNIMPLEMENTED; }
160 :
161 : /**
162 : * Complete an accept operation.
163 : *
164 : * @return the new connection, 0 on error.
165 : * @version 1.0
166 : */
167 0 : virtual ConnectionPtr acceptSync() { LBUNIMPLEMENTED; return 0; }
168 : //@}
169 :
170 : /** @name Asynchronous read */
171 : //@{
172 : /**
173 : * Start a read operation on the connection.
174 : *
175 : * This function returns immediately. The Notifier will signal data
176 : * availability, upon which recvSync() should be used to finish the
177 : * operation. The data will be appended to the given buffer. Only one read
178 : * operation might be outstanding, that is, readSync() has to be called
179 : * before the next readNB().
180 : *
181 : * @param buffer the buffer receiving the data.
182 : * @param bytes the number of bytes to read.
183 : * @sa recvSync()
184 : * @version 1.0
185 : */
186 : CO_API void recvNB( BufferPtr buffer, const uint64_t bytes );
187 :
188 : /**
189 : * Finish reading data from the connection.
190 : *
191 : * This function may block even if data availability was signaled, i.e.,
192 : * when only a part of the data requested has been received. The received
193 : * data is appended to the buffer, at most the number of bytes given to
194 : * recvNB(). This method uses readNB() and readSync() to fill a buffer,
195 : * potentially by using multiple reads.
196 : *
197 : * @param buffer return value, the buffer passed to recvNB().
198 : * @param block internal workaround parameter, do not use unless you
199 : * know exactly why.
200 : * @return true if all requested data has been read, false otherwise.
201 : * @version 1.0
202 : */
203 : CO_API bool recvSync( BufferPtr& buffer, const bool block = true );
204 :
205 : BufferPtr resetRecvData(); //!< @internal
206 : //@}
207 :
208 : /** @name Synchronous write to the connection */
209 : //@{
210 : /**
211 : * Send data using the connection.
212 : *
213 : * A send may be performed using multiple write() operations. For
214 : * thread-safe sending from multiple threads it is therefore crucial to
215 : * protect the send() operation internally. If the connection is not already
216 : * locked externally, it will use an internal mutex.
217 : *
218 : * @param buffer the buffer containing the message.
219 : * @param bytes the number of bytes to send.
220 : * @param isLocked true if the connection is locked externally.
221 : * @return true if all data has been read, false if not.
222 : * @sa lockSend(), unlockSend()
223 : * @version 1.0
224 : */
225 : CO_API bool send( const void* buffer, const uint64_t bytes,
226 : const bool isLocked = false );
227 :
228 : /** Lock the connection, no other thread can send data. @version 1.0 */
229 : CO_API void lockSend() const;
230 :
231 : /** Unlock the connection. @version 1.0 */
232 : CO_API void unlockSend() const;
233 :
234 : /** @internal Finish all pending send operations. */
235 0 : virtual void finish() {}
236 : //@}
237 :
238 : /**
239 : * The Notifier used by the ConnectionSet to detect readiness of a
240 : * Connection.
241 : */
242 : #ifdef _WIN32
243 : typedef void* Notifier;
244 : #else
245 : typedef int Notifier;
246 : #endif
247 : /** @return the notifier signaling events. @version 1.0 */
248 : virtual Notifier getNotifier() const = 0;
249 :
250 : protected:
251 : /** Construct a new connection. */
252 : Connection();
253 :
254 : /** Destruct this connection. */
255 : virtual ~Connection();
256 :
257 : /** @name Low-level IO methods */
258 : //@{
259 : enum ReadStatus //!< error codes for readSync()
260 : {
261 : READ_TIMEOUT = -2,
262 : READ_ERROR = -1
263 : // >= 0: nBytes read
264 : };
265 :
266 : /**
267 : * Start a read operation on the connection.
268 : *
269 : * This method is the low-level counterpart used by recvNB(), implemented by
270 : * the concrete connection.
271 : *
272 : * This function returns immediately. The operation's Notifier will
273 : * signal data availability, upon which readSync() is used to finish the
274 : * operation.
275 : *
276 : * @param buffer the buffer receiving the data.
277 : * @param bytes the number of bytes to read.
278 : * @sa readSync()
279 : */
280 : virtual void readNB( void* buffer, const uint64_t bytes ) = 0;
281 :
282 : /**
283 : * Finish reading data from the connection.
284 : *
285 : * This method is the low-level counterpart used by recvSync(), implemented
286 : * by the concrete connection. It may return with a partial read.
287 : *
288 : * @param buffer the buffer receiving the data.
289 : * @param bytes the number of bytes to read.
290 : * @param block internal WAR parameter, ignore it in the implementation
291 : * unless you know exactly why not.
292 : * @return the number of bytes read, or -1 upon error.
293 : */
294 : virtual int64_t readSync( void* buffer, const uint64_t bytes,
295 : const bool block ) = 0;
296 :
297 : /**
298 : * Write data to the connection.
299 : *
300 : * This method is the low-level counterpart used by send(), implemented by
301 : * the concrete connection. It may return with a partial write.
302 : *
303 : * @param buffer the buffer containing the message.
304 : * @param bytes the number of bytes to write.
305 : * @return the number of bytes written, or -1 upon error.
306 : */
307 : virtual int64_t write( const void* buffer, const uint64_t bytes ) = 0;
308 : //@}
309 :
310 : /** @internal @name State Changes */
311 : //@{
312 : /** @internal Set the connection parameter description. */
313 : CO_API void _setDescription( ConnectionDescriptionPtr description );
314 :
315 : CO_API void _setState( const State state ); //!< @internal
316 :
317 : /** @return the description for this connection. */
318 : CO_API ConnectionDescriptionPtr _getDescription();
319 : //@}
320 :
321 : private:
322 : detail::Connection* const _impl;
323 : };
324 :
325 : CO_API std::ostream& operator << ( std::ostream&, const Connection& );
326 : }
327 :
328 : namespace lunchbox
329 : {
330 0 : template<> inline void byteswap( co::Connection*& ) { /*NOP*/ }
331 : template<> inline void byteswap( co::ConnectionPtr& ) { /*NOP*/ }
332 : }
333 :
334 : #endif //CO_CONNECTION_H
|