gloox  1.0.28
connectiontcpserver.cpp
1 /*
2  Copyright (c) 2004-2023 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 <winsock2.h>
30 # include <ws2tcpip.h>
31 #endif
32 
33 #if ( !defined( _WIN32 ) && !defined( _WIN32_WCE ) ) || defined( __SYMBIAN32__ )
34 # include <netinet/in.h>
35 # include <arpa/nameser.h>
36 # include <resolv.h>
37 # include <netdb.h>
38 # include <arpa/inet.h>
39 # include <string.h>
40 # include <sys/socket.h>
41 # include <sys/un.h>
42 # include <sys/select.h>
43 # include <unistd.h>
44 # include <errno.h>
45 #endif
46 
47 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
48 # include <winsock2.h>
49 # include <ws2tcpip.h>
50 #elif defined( _WIN32_WCE )
51 # include <winsock2.h>
52 #endif
53 
54 #include <cstdlib>
55 #include <string>
56 
57 #ifndef _WIN32_WCE
58 # include <sys/types.h>
59 #endif
60 
61 // remove for 1.1
62 #ifndef INVALID_SOCKET
63 # define INVALID_SOCKET -1
64 #endif
65 
66 namespace gloox
67 {
68 
70  const std::string& ip, int port )
71  : ConnectionTCPBase( 0, logInstance, ip, port ),
72  m_connectionHandler( ch )
73  {
74  }
75 
77  {
78  }
79 
81  {
82  return new ConnectionTCPServer( m_connectionHandler, m_logInstance, m_server, m_port );
83  }
84 
86  {
87  util::MutexGuard mg( &m_sendMutex );
88 
89  if( m_socket >= 0 || m_state > StateDisconnected )
90  return ConnNoError;
91 
93 
94  if( m_socket < 0 )
95  m_socket = DNS::getSocket( m_logInstance );
96 
97  if( m_socket < 0 )
98  return ConnIoError;
99 
100 #ifdef HAVE_SETSOCKOPT
101  int buf = 0;
102 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
103  int bufbytes = sizeof( int );
104 #else
105  socklen_t bufbytes = sizeof( int );
106 #endif
107  if( ( getsockopt( m_socket, SOL_SOCKET, SO_RCVBUF, reinterpret_cast<char*>( &buf ), &bufbytes ) != -1 ) && ( m_bufsize > buf ) )
108  setsockopt( m_socket, SOL_SOCKET, SO_RCVBUF, reinterpret_cast<const char*>( &m_bufsize ), sizeof( m_bufsize ) );
109 
110  if( ( getsockopt( m_socket, SOL_SOCKET, SO_SNDBUF, reinterpret_cast<char*>( &buf ), &bufbytes ) != -1 ) && ( m_bufsize > buf ) )
111  setsockopt( m_socket, SOL_SOCKET, SO_SNDBUF, reinterpret_cast<const char*>( &m_bufsize ), sizeof( m_bufsize ) );
112 #endif
113 
114  int status = 0;
115  int err = 0;
116  struct addrinfo hints;
117  struct addrinfo *res;
118 
119  memset( &hints, 0, sizeof hints );
120  hints.ai_family = AF_UNSPEC;
121  hints.ai_socktype = SOCK_STREAM;
122  hints.ai_flags = AI_PASSIVE;
123  status = getaddrinfo( m_server.empty() ? 0 : m_server.c_str(), util::int2string( m_port ).c_str(), &hints, &res );
124  if( status != 0 )
125  {
126  err = errno;
127  std::string message = "getaddrinfo() for " + ( m_server.empty() ? std::string( "*" ) : m_server )
128  + " (" + util::int2string( m_port ) + ") failed. "
129 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
130  "WSAGetLastError: " + util::int2string( ::WSAGetLastError() );
131 #else
132  + strerror( err ) + " (errno: " + util::int2string( err ) + ")";
133 #endif
134  m_logInstance.dbg( LogAreaClassConnectionTCPServer, message );
135 
136  DNS::closeSocket( m_socket, m_logInstance );
137  return ConnIoError;
138  }
139 
140  if( bind( m_socket, res->ai_addr, res->ai_addrlen ) < 0 )
141  {
142  err = errno;
143  std::string message = "bind() to " + ( m_server.empty() ? std::string( "*" ) : m_server )
144  + " (" + /*inet_ntoa( local.sin_addr ) + ":" +*/ util::int2string( m_port ) + ") failed. "
145 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
146  "WSAGetLastError: " + util::int2string( ::WSAGetLastError() );
147 #else
148  + strerror( err ) + " (errno: " + util::int2string( err ) + ")";
149 #endif
150  m_logInstance.dbg( LogAreaClassConnectionTCPServer, message );
151 
152  DNS::closeSocket( m_socket, m_logInstance );
153  return ConnIoError;
154  }
155 
156  if( listen( m_socket, 10 ) < 0 )
157  {
158  err = errno;
159  std::string message = "listen() on " + ( m_server.empty() ? std::string( "*" ) : m_server )
160  + " (" + /*inet_ntoa( local.sin_addr ) +*/ ":" + util::int2string( m_port ) + ") failed. "
161 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
162  "WSAGetLastError: " + util::int2string( ::WSAGetLastError() );
163 #else
164  + strerror( err ) + " (errno: " + util::int2string( err ) + ")";
165 #endif
166  m_logInstance.dbg( LogAreaClassConnectionTCPServer, message );
167 
168  DNS::closeSocket( m_socket, m_logInstance );
169  return ConnIoError;
170  }
171 
172  m_cancel = false;
173  return ConnNoError;
174  }
175 
177  {
178  m_recvMutex.lock();
179 
180  if( m_cancel || m_socket < 0 || !m_connectionHandler )
181  {
182  m_recvMutex.unlock();
183  return ConnNotConnected;
184  }
185 
186  if( !dataAvailable( timeout ) )
187  {
188  m_recvMutex.unlock();
189  return ConnNoError;
190  }
191 
192  struct sockaddr_storage they;
193  int addr_size = sizeof( struct sockaddr_storage );
194 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
195  int newfd = static_cast<int>( accept( static_cast<SOCKET>( m_socket ), reinterpret_cast<struct sockaddr*>( &they ), &addr_size ) );
196 #else
197  int newfd = accept( m_socket, reinterpret_cast<struct sockaddr*>( &they ), reinterpret_cast<socklen_t*>( &addr_size ) );
198 #endif
199 
200  m_recvMutex.unlock();
201 
202  char buffer[INET6_ADDRSTRLEN];
203  char portstr[NI_MAXSERV];
204  int err = getnameinfo( reinterpret_cast<struct sockaddr*>( &they ), addr_size, buffer, sizeof( buffer ),
205  portstr, sizeof( portstr ), NI_NUMERICHOST | NI_NUMERICSERV );
206  if( err )
207  return ConnIoError;
208 
209  ConnectionTCPClient* conn = new ConnectionTCPClient( m_logInstance, buffer,
210  atoi( portstr ) );
211  conn->setSocket( newfd );
212  m_connectionHandler->handleIncomingConnection( this, conn );
213 
214  return ConnNoError;
215  }
216 
217 }
An abstract base class for a connection.
ConnectionState m_state
This is an abstract base class to receive incoming connection attempts. Do not confuse this with Conn...
virtual void handleIncomingConnection(ConnectionBase *server, ConnectionBase *connection)=0
This is a base class for a simple TCP connection.
This is an implementation of a simple TCP connection.
ConnectionTCPServer(ConnectionHandler *ch, const LogSink &logInstance, const std::string &ip, int port)
virtual ConnectionError recv(int timeout=-1)
virtual ConnectionBase * newInstance() const
virtual ConnectionError connect()
static int getSocket(const LogSink &logInstance)
Definition: dns.cpp:339
static void closeSocket(int fd, const LogSink &logInstance)
Definition: dns.cpp:518
An implementation of log sink and source.
Definition: logsink.h:39
void dbg(LogArea area, const std::string &message) const
Definition: logsink.h:66
A simple implementation of a mutex guard.
Definition: mutexguard.h:32
The namespace for the gloox library.
Definition: adhoc.cpp:28
ConnectionError
Definition: gloox.h:684
@ ConnNotConnected
Definition: gloox.h:715
@ ConnNoError
Definition: gloox.h:685
@ ConnIoError
Definition: gloox.h:696
@ LogAreaClassConnectionTCPServer
Definition: gloox.h:1063
@ StateDisconnected
Definition: gloox.h:642
@ StateConnecting
Definition: gloox.h:643