gloox  1.0.16
connectiontcpserver.cpp
1 /*
2  Copyright (c) 2004-2015 by Jakob Schröter <js@camaya.net>
3  This file is part of the gloox library. http://camaya.net/gloox
4 
5  This software is distributed under a license. The full license
6  agreement can be found in the file LICENSE in this distribution.
7  This software may not be copied, modified, sold or distributed
8  other than expressed in the named license agreement.
9 
10  This software is distributed without any warranty.
11 */
12 
13 
14 
15 #include "gloox.h"
16 
17 #include "config.h"
18 
19 #include "connectiontcpserver.h"
20 #include "connectiontcpclient.h"
21 #include "connectionhandler.h"
22 #include "dns.h"
23 #include "logsink.h"
24 #include "mutex.h"
25 #include "mutexguard.h"
26 #include "util.h"
27 
28 #ifdef __MINGW32__
29 # include <winsock.h>
30 #endif
31 
32 #if ( !defined( _WIN32 ) && !defined( _WIN32_WCE ) ) || defined( __SYMBIAN32__ )
33 # include <netinet/in.h>
34 # include <arpa/nameser.h>
35 # include <resolv.h>
36 # include <netdb.h>
37 # include <arpa/inet.h>
38 # include <sys/socket.h>
39 # include <sys/un.h>
40 # include <sys/select.h>
41 # include <unistd.h>
42 # include <errno.h>
43 #endif
44 
45 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
46 # include <winsock.h>
47 #elif defined( _WIN32_WCE )
48 # include <winsock2.h>
49 #endif
50 
51 #include <cstdlib>
52 #include <string>
53 
54 #ifndef _WIN32_WCE
55 # include <sys/types.h>
56 #endif
57 
58 // remove for 1.1
59 #ifndef INVALID_SOCKET
60 # define INVALID_SOCKET -1
61 #endif
62 
63 namespace gloox
64 {
65 
67  const std::string& ip, int port )
68  : ConnectionTCPBase( 0, logInstance, ip, port ),
69  m_connectionHandler( ch )
70  {
71  }
72 
74  {
75  }
76 
78  {
79  return new ConnectionTCPServer( m_connectionHandler, m_logInstance, m_server, m_port );
80  }
81 
82  // remove for 1.1
83  int ConnectionTCPServer::getSocket( int af, int socktype, int proto, const LogSink& logInstance )
84  {
85 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
86  SOCKET fd;
87 #else
88  int fd;
89 #endif
90  if( ( fd = ::socket( af, socktype, proto ) ) == INVALID_SOCKET )
91  {
92  std::string message = "getSocket( "
93  + util::int2string( af ) + ", "
94  + util::int2string( socktype ) + ", "
95  + util::int2string( proto )
96  + " ) failed. "
97 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
98  "WSAGetLastError: " + util::int2string( ::WSAGetLastError() );
99 #else
100  "errno: " + util::int2string( errno ) + ": " + strerror( errno );
101 #endif
102  logInstance.dbg( LogAreaClassDns, message );
103 
104 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
105  if( WSACleanup() != 0 )
106  {
107  logInstance.dbg( LogAreaClassDns, "WSACleanup() failed. WSAGetLastError: "
108  + util::int2string( ::WSAGetLastError() ) );
109  }
110 #endif
111 
112  return -ConnConnectionRefused;
113  }
114 
115 #ifdef HAVE_SETSOCKOPT
116  int timeout = 5000;
117  int reuseaddr = 1;
118  setsockopt( fd, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof( timeout ) );
119  setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, (char*)&reuseaddr, sizeof( reuseaddr ) );
120 #endif
121 
122  return (int)fd;
123  }
124 
126  {
127  util::MutexGuard mg( &m_sendMutex );
128 
129  if( m_socket >= 0 || m_state > StateDisconnected )
130  return ConnNoError;
131 
133 
134  if( m_socket < 0 )
135  m_socket = DNS::getSocket( m_logInstance );
136 
137  if( m_socket < 0 )
138  return ConnIoError;
139 
140 #ifdef HAVE_SETSOCKOPT
141  int buf = 0;
142 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
143  int bufbytes = sizeof( int );
144 #else
145  socklen_t bufbytes = sizeof( int );
146 #endif
147  if( ( getsockopt( m_socket, SOL_SOCKET, SO_RCVBUF, (char*)&buf, &bufbytes ) != -1 ) &&
148  ( m_bufsize > buf ) )
149  setsockopt( m_socket, SOL_SOCKET, SO_RCVBUF, (char*)&m_bufsize, sizeof( m_bufsize ) );
150 
151  if( ( getsockopt( m_socket, SOL_SOCKET, SO_SNDBUF, (char*)&buf, &bufbytes ) != -1 ) &&
152  ( m_bufsize > buf ) )
153  setsockopt( m_socket, SOL_SOCKET, SO_SNDBUF, (char*)&m_bufsize, sizeof( m_bufsize ) );
154 #endif
155 
156  int status = 0;
157  struct addrinfo hints;
158  struct addrinfo *res;
159 
160  memset( &hints, 0, sizeof hints );
161  hints.ai_family = AF_UNSPEC;
162  hints.ai_socktype = SOCK_STREAM;
163  hints.ai_flags = AI_PASSIVE;
164  status = getaddrinfo( m_server.c_str(), util::int2string( m_port ).c_str(), &hints, &res );
165  if( status != 0 )
166  {
167  std::string message = "getaddrinfo() for " + ( m_server.empty() ? std::string( "*" ) : m_server )
168  + " (" + util::int2string( m_port ) + ") failed. "
169 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
170  "WSAGetLastError: " + util::int2string( ::WSAGetLastError() );
171 #else
172  "errno: " + util::int2string( errno );
173 #endif
174  return ConnIoError;
175  }
176 
177  m_socket = ::socket( res->ai_family, res->ai_socktype, res->ai_protocol );
178 
179  if( bind( m_socket, res->ai_addr, res->ai_addrlen ) < 0 )
180  {
181  std::string message = "bind() to " + ( m_server.empty() ? std::string( "*" ) : m_server )
182  + " (" + /*inet_ntoa( local.sin_addr ) + ":" +*/ util::int2string( m_port ) + ") failed. "
183 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
184  "WSAGetLastError: " + util::int2string( ::WSAGetLastError() );
185 #else
186  "errno: " + util::int2string( errno );
187 #endif
188  m_logInstance.dbg( LogAreaClassConnectionTCPServer, message );
189 
190  return ConnIoError;
191  }
192 
193  if( listen( m_socket, 10 ) < 0 )
194  {
195  std::string message = "listen on " + ( m_server.empty() ? std::string( "*" ) : m_server )
196  + " (" + /*inet_ntoa( local.sin_addr ) +*/ ":" + util::int2string( m_port ) + ") failed. "
197 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
198  "WSAGetLastError: " + util::int2string( ::WSAGetLastError() );
199 #else
200  "errno: " + util::int2string( errno );
201 #endif
202  m_logInstance.dbg( LogAreaClassConnectionTCPServer, message );
203 
204  return ConnIoError;
205  }
206 
207  m_cancel = false;
208  return ConnNoError;
209  }
210 
212  {
213  m_recvMutex.lock();
214 
215  if( m_cancel || m_socket < 0 || !m_connectionHandler )
216  {
217  m_recvMutex.unlock();
218  return ConnNotConnected;
219  }
220 
221  if( !dataAvailable( timeout ) )
222  {
223  m_recvMutex.unlock();
224  return ConnNoError;
225  }
226 
227  struct sockaddr_storage they;
228  int addr_size = sizeof( struct sockaddr_storage );
229 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
230  int newfd = static_cast<int>( accept( static_cast<SOCKET>( m_socket ), (struct sockaddr_storage*)&they, &addr_size ) );
231 #else
232  int newfd = accept( m_socket, (struct sockaddr*)&they, (socklen_t*)&addr_size );
233 #endif
234 
235  m_recvMutex.unlock();
236 
237  char buffer[INET6_ADDRSTRLEN];
238  char portstr[NI_MAXSERV];
239  int err = getnameinfo( (struct sockaddr*)&they, addr_size, buffer, sizeof( buffer ),
240  portstr, sizeof( portstr ), NI_NUMERICHOST | NI_NUMERICSERV );
241  if( !err )
242  return ConnIoError;
243 
244  ConnectionTCPClient* conn = new ConnectionTCPClient( m_logInstance, buffer,
245  atoi( portstr ) );
246  conn->setSocket( newfd );
247  m_connectionHandler->handleIncomingConnection( this, conn );
248 
249  return ConnNoError;
250  }
251 
252 }
An abstract base class for a connection.
A simple implementation of a mutex guard.
Definition: mutexguard.h:31
ConnectionError
Definition: gloox.h:679
virtual ConnectionError recv(int timeout=-1)
virtual void handleIncomingConnection(ConnectionBase *server, ConnectionBase *connection)=0
This is an implementation of a simple TCP connection.
This is a base class for a simple TCP connection.
virtual ConnectionError connect()
This is an abstract base class to receive incoming connection attempts. Do not confuse this with Conn...
The namespace for the gloox library.
Definition: adhoc.cpp:27
virtual ConnectionBase * newInstance() const
void dbg(LogArea area, const std::string &message) const
Definition: logsink.h:66
ConnectionState m_state
static int getSocket(const LogSink &logInstance)
Definition: dns.cpp:334
ConnectionTCPServer(ConnectionHandler *ch, const LogSink &logInstance, const std::string &ip, int port)
void setSocket(int socket)
An implementation of log sink and source.
Definition: logsink.h:38