summaryrefslogtreecommitdiff
path: root/src/tcpserversocket.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tcpserversocket.cpp')
-rw-r--r--src/tcpserversocket.cpp249
1 files changed, 249 insertions, 0 deletions
diff --git a/src/tcpserversocket.cpp b/src/tcpserversocket.cpp
new file mode 100644
index 0000000..7d7f6e4
--- /dev/null
+++ b/src/tcpserversocket.cpp
@@ -0,0 +1,249 @@
1/*
2 * Copyright (C) 2007-2010 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef WIN32
9 #include <sys/socket.h>
10 #include <netinet/in.h>
11 #include <netdb.h>
12 #include <arpa/inet.h>
13#endif
14
15#include <time.h>
16#include <string.h>
17#include <stdio.h>
18#include <errno.h>
19#include <stdlib.h>
20#include <unistd.h>
21#include <sys/types.h>
22//#include <termios.h>
23#include <fcntl.h>
24#include "bu/tcpserversocket.h"
25
26#include "bu/config.h"
27
28namespace Bu { subExceptionDef( TcpServerSocketException ) }
29
30Bu::TcpServerSocket::TcpServerSocket( int nPort, int nPoolSize ) :
31 nPort( nPort )
32{
33#ifdef WIN32
34 Bu::Winsock2::getInstance();
35#endif
36
37 /* Create the socket and set it up to accept connections. */
38 struct sockaddr_in name;
39
40 /* Give the socket a name. */
41 name.sin_family = AF_INET;
42 name.sin_port = bu_htons( nPort );
43
44 // I think this specifies who we will accept connections from,
45 // a good thing to make configurable later on
46 name.sin_addr.s_addr = bu_htonl( INADDR_ANY );
47
48 startServer( name, nPoolSize );
49}
50
51Bu::TcpServerSocket::TcpServerSocket(const FString &sAddr,int nPort, int nPoolSize) :
52 nPort( nPort )
53{
54#ifdef WIN32
55 Bu::Winsock2::getInstance();
56#endif
57
58 /* Create the socket and set it up to accept connections. */
59 struct sockaddr_in name;
60
61 /* Give the socket a name. */
62 name.sin_family = AF_INET;
63
64 name.sin_port = bu_htons( nPort );
65
66#ifdef WIN32
67 name.sin_addr.s_addr = bu_inet_addr( sAddr.getStr() );
68#else
69 inet_aton( sAddr.getStr(), &name.sin_addr );
70#endif
71
72 startServer( name, nPoolSize );
73}
74
75Bu::TcpServerSocket::TcpServerSocket( int nServer, bool bInit, int nPoolSize ) :
76 nServer( nServer ),
77 nPort( 0 )
78{
79#ifdef WIN32
80 Bu::Winsock2::getInstance();
81#endif
82
83 if( bInit )
84 {
85 struct sockaddr name;
86 socklen_t namelen = sizeof(name);
87 getpeername( nServer, &name, &namelen );
88
89 initServer( *((sockaddr_in *)&name), nPoolSize );
90 }
91 else
92 {
93 FD_ZERO( &fdActive );
94 FD_SET( nServer, &fdActive );
95 }
96}
97
98Bu::TcpServerSocket::TcpServerSocket( const TcpServerSocket &rSrc )
99{
100#ifdef WIN32
101 Bu::Winsock2::getInstance();
102#endif
103
104 nServer = dup( rSrc.nServer );
105 nPort = rSrc.nPort;
106 FD_ZERO( &fdActive );
107 FD_SET( nServer, &fdActive );
108}
109
110Bu::TcpServerSocket::~TcpServerSocket()
111{
112 if( nServer > -1 )
113 ::close( nServer );
114}
115
116void Bu::TcpServerSocket::startServer( struct sockaddr_in &name, int nPoolSize )
117{
118 /* Create the socket. */
119 nServer = bu_socket( PF_INET, SOCK_STREAM, 0 );
120
121 if( nServer < 0 )
122 {
123 throw Bu::TcpServerSocketException("Couldn't create a listen socket.");
124 }
125
126 int opt = 1;
127 bu_setsockopt(
128 nServer,
129 SOL_SOCKET,
130 SO_REUSEADDR,
131 (char *)&opt,
132 sizeof( opt )
133 );
134
135 initServer( name, nPoolSize );
136}
137
138void Bu::TcpServerSocket::initServer( struct sockaddr_in &name, int nPoolSize )
139{
140 if( bu_bind( nServer, (struct sockaddr *) &name, sizeof(name) ) < 0 )
141 {
142 throw Bu::TcpServerSocketException("Couldn't bind to the listen socket.");
143 }
144
145 if( bu_listen( nServer, nPoolSize ) < 0 )
146 {
147 throw Bu::TcpServerSocketException(
148 "Couldn't begin listening to the server socket."
149 );
150 }
151
152 FD_ZERO( &fdActive );
153 /* Initialize the set of active sockets. */
154 FD_SET( nServer, &fdActive );
155}
156
157int Bu::TcpServerSocket::getSocket()
158{
159 return nServer;
160}
161
162int Bu::TcpServerSocket::accept( int nTimeoutSec, int nTimeoutUSec )
163{
164 fd_set fdRead = fdActive;
165
166 struct timeval xT;
167
168 xT.tv_sec = nTimeoutSec;
169 xT.tv_usec = nTimeoutUSec;
170
171 if( TEMP_FAILURE_RETRY(
172 bu_select( nServer+1, &fdRead, NULL, NULL, &xT )) < 0 )
173 {
174 throw Bu::TcpServerSocketException(
175 "Error scanning for new connections: %s", strerror( errno )
176 );
177 }
178
179 if( FD_ISSET( nServer, &fdRead ) )
180 {
181 struct sockaddr_in clientname;
182 socklen_t size;
183 int nClient;
184
185 size = sizeof( clientname );
186#ifdef WIN32
187 nClient = bu_accept( nServer, (struct sockaddr *)&clientname, &size);
188#else /* not-WIN32 */
189#ifdef __CYGWIN__
190 nClient = ::accept( nServer, (struct sockaddr *)&clientname,
191 (int *)&size
192 );
193#else /* not-cygwin */
194#ifdef __APPLE__
195 nClient = ::accept( nServer, (struct sockaddr *)&clientname, (socklen_t*)&size );
196#else /* linux */
197 nClient = ::accept( nServer, (struct sockaddr *)&clientname, &size );
198#endif /* __APPLE__ */
199#endif /* __CYGWIN__ */
200#endif /* WIN32 */
201 if( nClient < 0 )
202 {
203 throw Bu::TcpServerSocketException(
204 "Error accepting a new connection: %s", strerror( errno )
205 );
206 }
207
208#ifndef WIN32
209 char tmpa[20];
210 inet_ntop( AF_INET, (void *)&clientname.sin_addr, tmpa, 20 );
211 //"New connection from host %s, port %hd.",
212 // tmpa, ntohs (clientname.sin_port) );
213#endif
214
215 {
216#ifndef WIN32
217 int flags;
218 flags = fcntl( nClient, F_GETFL, 0 );
219 flags |= O_NONBLOCK;
220 if( fcntl( nClient, F_SETFL, flags ) < 0)
221 {
222 throw Bu::TcpServerSocketException(
223 "Error setting option on client socket: %s",
224 strerror( errno )
225 );
226 }
227#else
228 //-------------------------
229 // Set the socket I/O mode: In this case FIONBIO
230 // enables or disables the blocking mode for the
231 // socket based on the numerical value of iMode.
232 // If iMode = 0, blocking is enabled;
233 // If iMode != 0, non-blocking mode is enabled.
234 u_long iMode = 1;
235 bu_ioctlsocket(nClient, FIONBIO, &iMode);
236#endif
237 }
238
239 return nClient;
240 }
241
242 return -1;
243}
244
245int Bu::TcpServerSocket::getPort()
246{
247 return nPort;
248}
249