- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

gsocket.cpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2001-2013 Graeme Walker <graeme_walker@users.sourceforge.net>
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 // ===
17 //
18 // gsocket.cpp
19 //
20
21 #include "gdef.h"
22 #include "gnet.h"
23 #include "gtest.h"
24 #include "gsleep.h"
25 #include "gassert.h"
26 #include "gsocket.h"
27 #include "gcleanup.h"
28 #include "gmemory.h"
29 #include "gdebug.h"
30
31 GNet::Socket::Socket( int domain , int type , int protocol ) :
32 m_reason( 0 )
33 {
34 m_socket = Descriptor( ::socket( domain , type , protocol ) ) ;
35 if( valid() )
36 {
37 prepare() ;
38 }
39 else
40 {
41 m_reason = reason() ;
42 G_DEBUG( "GNet::Socket::open: cannot open a socket (" << m_reason << ")" ) ;
43 }
44 }
45
46 GNet::Socket::Socket( Descriptor s ) :
47 m_reason(0) ,
48 m_socket(s)
49 {
50 prepare() ;
51 }
52
53 void GNet::Socket::prepare()
54 {
55 G::Cleanup::init() ; // ignore SIGPIPE
56 if( ! setNonBlock() )
57 {
58 m_reason = reason() ;
59 doClose() ;
60 G_ASSERT( !valid() ) ;
61 G_WARNING( "GNet::Socket::open: cannot make socket non-blocking (" << m_reason << ")" ) ;
62 }
63 }
64
65 GNet::Socket::~Socket()
66 {
67 try
68 {
69 drop() ;
70 }
71 catch(...) // dtor
72 {
73 }
74
75 try
76 {
77 if( valid() ) doClose() ;
78 G_ASSERT( !valid() ) ;
79 }
80 catch(...) // dtor
81 {
82 }
83 }
84
85 void GNet::Socket::drop()
86 {
87 dropReadHandler() ;
88 dropWriteHandler() ;
89 dropExceptionHandler() ;
90 }
91
92 bool GNet::Socket::valid() const
93 {
94 return valid( m_socket ) ;
95 }
96
97 bool GNet::Socket::bind( const Address & local_address )
98 {
99 if( !valid() )
100 return false ;
101
102 // optionally allow immediate re-use -- may cause problems
103 setReuse() ;
104
105 G_DEBUG( "Socket::bind: binding " << local_address.displayString() << " on fd " << m_socket ) ;
106
107 int rc = ::bind( m_socket.fd(), local_address.address() , local_address.length() ) ;
108 if( error(rc) )
109 {
110 m_reason = reason() ;
111 return false ;
112 }
113
114 const bool debug = true ;
115 if( debug )
116 {
117 std::pair<bool,Address> pair = getLocalAddress() ;
118 if( ! pair.first )
119 {
120 G_WARNING( "GNet::Socket::bind: cannot get bound address" ) ;
121 return false ;
122 }
123
124 G_DEBUG( "GNet::Socket::bind: bound " << pair.second.displayString() << " on fd " << m_socket ) ;
125 }
126
127 return true ;
128 }
129
130 bool GNet::Socket::connect( const Address & address , bool *done )
131 {
132 if( !valid() )
133 return false;
134
135 G_DEBUG( "GNet::Socket::connect: connecting to " << address.displayString() ) ;
136 int rc = ::connect( m_socket.fd(), address.address(), address.length() ) ;
137 if( error(rc) )
138 {
139 m_reason = reason() ;
140
141 if( G::Test::enabled( "slow-connect" ) )
142 sleep( 1 ) ;
143
144 if( eInProgress() )
145 {
146 G_DEBUG( "GNet::Socket::connect: connection in progress" ) ;
147 if( done != NULL ) *done = false ;
148 return true ;
149 }
150
151 G_DEBUG( "GNet::Socket::connect: synchronous connect failure: " << m_reason ) ;
152 return false;
153 }
154
155 if( done != NULL ) *done = true ;
156 return true;
157 }
158
159 GNet::Socket::ssize_type GNet::Socket::write( const char * buf , size_type len )
160 {
161 if( static_cast<ssize_type>(len) < 0 )
162 G_WARNING( "GNet::Socket::write: too big" ) ; // EMSGSIZE from ::send() ?
163
164 ssize_type nsent = ::send( m_socket.fd() , buf , len , 0 ) ;
165
166 if( sizeError(nsent) ) // if -1
167 {
168 m_reason = reason() ;
169 G_DEBUG( "GNet::Socket::write: write error " << m_reason ) ;
170 return -1 ;
171 }
172 else if( nsent < 0 || static_cast<size_type>(nsent) < len )
173 {
174 m_reason = reason() ;
175 }
176 return nsent;
177 }
178
179 void GNet::Socket::setNoLinger()
180 {
181 struct linger options ;
182 options.l_onoff = 0 ;
183 options.l_linger = 0 ;
184 socklen_t sizeof_options = sizeof(options) ;
185 G_IGNORE_RETURN(int) ::setsockopt( m_socket.fd() , SOL_SOCKET ,
186 SO_LINGER , reinterpret_cast<char*>(&options) , sizeof_options ) ;
187 }
188
189 void GNet::Socket::setKeepAlive()
190 {
191 int keep_alive = 1 ;
192 G_IGNORE_RETURN(int) ::setsockopt( m_socket.fd() , SOL_SOCKET ,
193 SO_KEEPALIVE , reinterpret_cast<char*>(&keep_alive) , sizeof(keep_alive) ) ;
194 }
195
196 void GNet::Socket::setReuse()
197 {
198 int on = 1 ;
199 G_IGNORE_RETURN(int) ::setsockopt( m_socket.fd() , SOL_SOCKET ,
200 SO_REUSEADDR , reinterpret_cast<char*>(&on) , sizeof(on) ) ;
201 }
202
203 bool GNet::Socket::listen( int backlog )
204 {
205 int rc = ::listen( m_socket.fd() , backlog ) ;
206 if( error(rc) )
207 {
208 m_reason = reason() ;
209 return false ;
210 }
211 return true ;
212 }
213
214 std::pair<bool,GNet::Address> GNet::Socket::getAddress( bool local ) const
215 {
216 std::pair<bool,Address> error_pair( false , Address::invalidAddress() ) ;
217
218 if( !valid() )
219 return error_pair ;
220
221 AddressStorage address_storage ;
222 int rc =
223 local ?
224 ::getsockname( m_socket.fd() , address_storage.p1() , address_storage.p2() ) :
225 ::getpeername( m_socket.fd() , address_storage.p1() , address_storage.p2() ) ;
226
227 if( error(rc) )
228 {
229 const_cast<Socket*>(this)->m_reason = reason() ;
230 return error_pair ;
231 }
232
233 return std::pair<bool,Address>( true , Address(address_storage) ) ;
234 }
235
236 std::pair<bool,GNet::Address> GNet::Socket::getLocalAddress() const
237 {
238 return getAddress( true ) ;
239 }
240
241 std::pair<bool,GNet::Address> GNet::Socket::getPeerAddress() const
242 {
243 return getAddress( false ) ;
244 }
245
246 bool GNet::Socket::hasPeer() const
247 {
248 return getPeerAddress().first ;
249 }
250
251 void GNet::Socket::addReadHandler( EventHandler & handler )
252 {
253 G_ASSERT( valid() ) ;
254 G_DEBUG( "GNet::Socket::addReadHandler: fd " << m_socket ) ;
255 EventLoop::instance().addRead( m_socket , handler ) ;
256 }
257
258 void GNet::Socket::dropReadHandler()
259 {
260 EventLoop::instance().dropRead( m_socket ) ;
261 }
262
263 void GNet::Socket::addWriteHandler( EventHandler & handler )
264 {
265 G_ASSERT( valid() ) ;
266 G_DEBUG( "GNet::Socket::addWriteHandler: fd " << m_socket ) ;
267 EventLoop::instance().addWrite( m_socket , handler ) ;
268 }
269
270 void GNet::Socket::addExceptionHandler( EventHandler & handler )
271 {
272 G_ASSERT( valid() ) ;
273 G_DEBUG( "GNet::Socket::addExceptionHandler: fd " << m_socket ) ;
274 EventLoop::instance().addException( m_socket , handler ) ;
275 }
276
277 void GNet::Socket::dropWriteHandler()
278 {
279 EventLoop::instance().dropWrite( m_socket ) ;
280 }
281
282 void GNet::Socket::dropExceptionHandler()
283 {
284 EventLoop::instance().dropException( m_socket ) ;
285 }
286
287 std::string GNet::Socket::asString() const
288 {
289 std::ostringstream ss ;
290 ss << m_socket ;
291 return ss.str() ;
292 }
293
294 std::string GNet::Socket::reasonString() const
295 {
296 std::ostringstream ss ;
297 ss << m_reason ;
298 return ss.str() ;
299 }
300
301 void GNet::Socket::shutdown( bool for_writing )
302 {
303 ::shutdown( m_socket.fd() , for_writing ? 1 : 0 ) ;
304 }
305
306 int GNet::Socket::fd( Credentials ) const
307 {
308 return static_cast<int>( m_socket.fd() ) ;
309 }
310
311 //==
312
313 GNet::StreamSocket::StreamSocket() :
314 Socket( Address::defaultDomain() , SOCK_STREAM , 0 )
315 {
316 setNoLinger() ;
317 setKeepAlive() ;
318 }
319
320 GNet::StreamSocket::StreamSocket( const Address & address_hint ) :
321 Socket( address_hint.domain() , SOCK_STREAM , 0 )
322 {
323 setNoLinger() ;
324 setKeepAlive() ;
325 }
326
327 GNet::StreamSocket::StreamSocket( Descriptor s ) :
328 Socket( s )
329 {
330 }
331
332 GNet::StreamSocket::~StreamSocket()
333 {
334 }
335
336 GNet::Socket::ssize_type GNet::StreamSocket::read( char * buf , size_type len )
337 {
338 if( len == 0 ) return 0 ;
339 G_ASSERT( valid() ) ;
340 ssize_type nread = ::recv( m_socket.fd() , buf , len , 0 ) ;
341 if( sizeError(nread) )
342 {
343 m_reason = reason() ;
344 G_DEBUG( "GNet::StreamSocket::read: fd " << m_socket << ": read error " << m_reason ) ;
345 return -1 ;
346 }
347 if( nread == 0 )
348 {
349 G_DEBUG( "GNet::StreamSocket::read: fd " << m_socket << ": read zero bytes" ) ;
350 }
351 return nread ;
352 }
353
354 GNet::AcceptPair GNet::StreamSocket::accept()
355 {
356 AcceptPair pair( NULL , Address::invalidAddress() ) ;
357
358 sockaddr addr ;
359 socklen_t addr_length = sizeof(addr) ;
360 Descriptor new_socket( ::accept( m_socket.fd() , &addr, &addr_length ) ) ;
361 if( valid(new_socket) )
362 {
363 pair.second = Address( &addr , addr_length ) ;
364 G_DEBUG( "GNet::StreamSocket::accept: " << pair.second.displayString() ) ;
365 pair.first <<= new StreamSocket(new_socket) ;
366 pair.first.get()->setNoLinger() ;
367 }
368 else
369 {
370 m_reason = reason() ;
371 G_DEBUG( "GNet::StreamSocket::accept: failure" ) ;
372 }
373 return pair ;
374 }
375
376 //==
377
378 GNet::DatagramSocket::DatagramSocket() :
379 Socket( Address::defaultDomain() , SOCK_DGRAM , 0 )
380 {
381 }
382
383 GNet::DatagramSocket::DatagramSocket( const Address & address_hint ) :
384 Socket( address_hint.domain() , SOCK_DGRAM , 0 )
385 {
386 }
387
388 GNet::DatagramSocket::~DatagramSocket()
389 {
390 }
391
392 void GNet::DatagramSocket::disconnect()
393 {
394 int rc = ::connect( m_socket.fd() , 0 , 0 ) ;
395 if( error(rc) )
396 m_reason = reason() ;
397 }
398
399 GNet::Socket::ssize_type GNet::DatagramSocket::read( void *buf , size_type len , Address & src_address )
400 {
401 sockaddr sender ;
402 socklen_t sender_len = sizeof(sender) ;
403 ssize_type nread = ::recvfrom( m_socket.fd() , reinterpret_cast<char*>(buf) , len , 0 , &sender , &sender_len ) ;
404 if( sizeError(nread) )
405 {
406 m_reason = reason() ;
407 return -1 ;
408 }
409
410 src_address = Address( &sender , sender_len ) ;
411 return nread ;
412 }
413
414 GNet::Socket::ssize_type GNet::DatagramSocket::write( const char *buf , size_type len , const Address &dst )
415 {
416 G_DEBUG( "GNet::DatagramSocket::write: sending " << len << " bytes to " << dst.displayString() ) ;
417
418 ssize_type nsent = ::sendto( m_socket.fd() , buf, len, 0, dst.address(), dst.length() ) ;
419 if( nsent < 0 )
420 {
421 m_reason = reason() ;
422 G_DEBUG( "GNet::DatagramSocket::write: write error " << m_reason ) ;
423 return -1 ;
424 }
425 return nsent ;
426 }
427
GNet::DatagramSocket::write
ssize_type write(const char *buffer, size_type len, const Address &dst)
Sends a datagram to the given address.
Definition: gsocket.cpp:414
GNet::Socket::reason
static int reason()
Definition: gsocket_unix.cpp:56
gsleep.h
GNet::DatagramSocket::DatagramSocket
DatagramSocket()
Default constructor.
Definition: gsocket.cpp:378
GNet::Socket::listen
bool listen(int backlog=1)
Starts the socket listening on the bound address for incoming connections or incoming datagrams...
Definition: gsocket.cpp:203
GNet::Socket::getLocalAddress
std::pair< bool, Address > getLocalAddress() const
Retrieves local address of the socket.
Definition: gsocket.cpp:236
GNet::EventLoop::addWrite
virtual void addWrite(Descriptor fd, EventHandler &handler)=0
Adds the given event source descriptor and associated handler to the write list.
GNet::Socket::dropReadHandler
void dropReadHandler()
Reverses addReadHandler().
Definition: gsocket.cpp:258
GNet::Socket::addExceptionHandler
void addExceptionHandler(EventHandler &handler)
Adds this socket to the event source list so that the given handler receives exception events...
Definition: gsocket.cpp:270
GNet::Socket::connect
bool connect(const Address &addr, bool *done=NULL)
Initiates a connection to (or association with) the given address.
Definition: gsocket.cpp:130
GNet::Socket::write
virtual ssize_type write(const char *buf, size_type len)
Sends data.
Definition: gsocket.cpp:159
GNet::Socket::addWriteHandler
void addWriteHandler(EventHandler &handler)
Adds this socket to the event source list so that the given handler receives write events when flow c...
Definition: gsocket.cpp:263
GNet::DatagramSocket::~DatagramSocket
virtual ~DatagramSocket()
Destructor.
Definition: gsocket.cpp:388
GNet::Socket::getAddress
std::pair< bool, Address > getAddress(bool) const
Definition: gsocket.cpp:214
GNet::AddressStorage
A helper class for calling getsockname() and getpeername() and hiding the definition of sockaddr_stor...
Definition: gaddress.h:225
GNet::Address
The Address class encapsulates an IP transport address.
Definition: gaddress.h:48
GNet::Socket
The Socket class encapsulates a non-blocking Unix socket file descriptor or a Windows 'SOCKET' handle...
Definition: gsocket.h:60
GNet::AddressStorage::p2
socklen_t * p2()
Returns the length pointer for getsockname()/getpeername() to write into.
Definition: gaddress_ipv4.cpp:659
GNet::Socket::addReadHandler
void addReadHandler(EventHandler &handler)
Adds this socket to the event source list so that the given handler receives read events...
Definition: gsocket.cpp:251
GNet::AddressStorage::p1
sockaddr * p1()
Returns the sockaddr pointer for getsockname()/getpeername() to write into.
Definition: gaddress_ipv4.cpp:654
GNet::EventLoop::dropRead
virtual void dropRead(Descriptor fd)=0
Removes the given event source descriptor from the list of read sources.
GNet::Address::invalidAddress
static Address invalidAddress()
Returns an invalid address.
Definition: gaddress_ipv4.cpp:458
GNet::StreamSocket::~StreamSocket
virtual ~StreamSocket()
Destructor.
Definition: gsocket.cpp:332
GNet::Socket::m_reason
int m_reason
Definition: gsocket.h:230
GNet::Descriptor
A network file descriptor.
Definition: gdescriptor.h:37
gtest.h
GNet::Address::address
const sockaddr * address() const
Returns the sockaddr address.
Definition: gaddress_ipv4.cpp:601
GNet::StreamSocket::StreamSocket
StreamSocket()
Default constructor. Check with valid().
Definition: gsocket.cpp:313
GNet::Socket::bind
bool bind(const Address &address)
Binds the socket with an INADDR_ANY network address and the port number taken from the given address...
Definition: gsocket.cpp:97
gcleanup.h
GNet::Socket::fd
int fd(Credentials) const
Returns the socket descriptor as an integer.
Definition: gsocket.cpp:306
GNet::Socket::dropExceptionHandler
void dropExceptionHandler()
Reverses addExceptionHandler().
Definition: gsocket.cpp:282
GNet::EventLoop::dropException
virtual void dropException(Descriptor fd)=0
Removes the given event source descriptor from the list of exception sources.
GNet::Socket::dropWriteHandler
void dropWriteHandler()
Reverses addWriteHandler().
Definition: gsocket.cpp:277
GNet::Socket::reasonString
std::string reasonString() const
Returns the failure reason as a string.
Definition: gsocket.cpp:294
GNet::DatagramSocket::disconnect
void disconnect()
Releases the association between two datagram endpoints reversing the effect of the previous Socket::...
Definition: gsocket.cpp:392
GNet::Socket::getPeerAddress
std::pair< bool, Address > getPeerAddress() const
Retrieves address of socket's peer.
Definition: gsocket.cpp:241
GNet::StreamSocket
A derivation of Socket for a stream socket.
Definition: gsocket.h:270
GNet::EventLoop::addRead
virtual void addRead(Descriptor fd, EventHandler &handler)=0
Adds the given event source descriptor and associated handler to the read list.
G_ASSERT
#define G_ASSERT(test)
Definition: gassert.h:30
GNet::Address::displayString
std::string displayString(bool with_port=true, bool with_scope_id=false) const
Returns a string which represents the address for debugging and diagnostics purposes.
Definition: gaddress_ipv4.cpp:581
GNet::Socket::size_type
size_t size_type
Definition: gsocket.h:63
gassert.h
GNet::AcceptPair::first
first_type first
Definition: gsocket.h:252
GNet::DatagramSocket::read
ssize_type read(void *buffer, size_type len, Address &src)
Reads a datagram and returns the sender's address by reference.
Definition: gsocket.cpp:399
G::Test::enabled
static bool enabled()
Returns true if test features are enabled.
Definition: gtest.cpp:46
GNet::Address::length
socklen_t length() const
Returns the size of the sockaddr address.
Definition: gaddress_ipv4.cpp:606
GNet::Socket::~Socket
virtual ~Socket()
Destructor.
Definition: gsocket.cpp:65
GNet::Socket::Socket
Socket(int domain, int type, int protocol)
Constructor used by derived classes.
Definition: gsocket.cpp:31
GNet::EventLoop::addException
virtual void addException(Descriptor fd, EventHandler &handler)=0
Adds the given event source descriptor and associated handler to the exception list.
GNet::AcceptPair
A class which is used to return a new()ed socket to calling code, together with associated informatio...
Definition: gsocket.h:246
GNet::EventHandler
A base class for classes that handle asynchronous socket events.
Definition: geventhandler.h:54
GNet::Socket::setReuse
void setReuse()
Definition: gsocket.cpp:196
GNet::Socket::hasPeer
bool hasPeer() const
Returns true if the socket has a valid peer.
Definition: gsocket.cpp:246
GNet::StreamSocket::read
ssize_type read(char *buffer, size_type buffer_length)
Reads data from the socket stream.
Definition: gsocket.cpp:336
G_DEBUG
#define G_DEBUG(expr)
Definition: glog.h:95
gsocket.h
GNet::AcceptPair::second
second_type second
Definition: gsocket.h:253
G::Cleanup::init
static void init()
An optional early-initialisation function.
Definition: gcleanup_unix.cpp:73
GNet::Socket::setNoLinger
void setNoLinger()
Definition: gsocket.cpp:179
GNet::Socket::valid
bool valid() const
Returns true if the socket handle is valid (open).
Definition: gsocket.cpp:92
GNet::Socket::setKeepAlive
void setKeepAlive()
Definition: gsocket.cpp:189
GNet::Socket::Credentials
A credentials class that allows SocketProtocol to call Socket::fd().
Definition: gsocket.h:66
GNet::Socket::shutdown
void shutdown(bool for_writing=true)
Shuts the socket for writing (or reading).
Definition: gsocket.cpp:301
GNet::Socket::m_socket
Descriptor m_socket
Definition: gsocket.h:231
GNet::StreamSocket::accept
AcceptPair accept()
Accepts an incoming connection, returning a new()ed socket and the peer address.
Definition: gsocket.cpp:354
gmemory.h
GNet::Socket::ssize_type
ssize_t ssize_type
Definition: gsocket.h:64
GNet::EventLoop::dropWrite
virtual void dropWrite(Descriptor fd)=0
Removes the given event source descriptor from the list of write sources.
GNet::EventLoop::instance
static EventLoop & instance()
Returns a reference to an instance of the class, if any.
Definition: geventloop.cpp:43
GNet::Socket::prepare
void prepare()
Definition: gsocket.cpp:53
GNet::Socket::asString
std::string asString() const
Returns the socket handle as a string.
Definition: gsocket.cpp:287
G_WARNING
#define G_WARNING(expr)
Definition: glog.h:107
gdebug.h