aboutsummaryrefslogtreecommitdiff
path: root/src/serversocket.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/serversocket.cpp')
-rw-r--r--src/serversocket.cpp148
1 files changed, 148 insertions, 0 deletions
diff --git a/src/serversocket.cpp b/src/serversocket.cpp
new file mode 100644
index 0000000..c53c80d
--- /dev/null
+++ b/src/serversocket.cpp
@@ -0,0 +1,148 @@
1#include <time.h>
2#include <string.h>
3#include <stdio.h>
4#include <errno.h>
5#include <stdlib.h>
6#include <unistd.h>
7#include <sys/types.h>
8#include <sys/socket.h>
9#include <termios.h>
10#include <netinet/in.h>
11#include <netdb.h>
12#include <arpa/inet.h>
13#include <fcntl.h>
14#include "serversocket.h"
15#include "exceptions.h"
16
17Bu::ServerSocket::ServerSocket( int nPort, int nPoolSize ) :
18 nPort( nPort )
19{
20 /* Create the socket and set it up to accept connections. */
21 struct sockaddr_in name;
22
23 /* Give the socket a name. */
24 name.sin_family = AF_INET;
25 name.sin_port = htons( nPort );
26
27 // I think this specifies who we will accept connections from,
28 // a good thing to make configurable later on
29 name.sin_addr.s_addr = htonl( INADDR_ANY );
30
31 startServer( name, nPoolSize );
32}
33
34Bu::ServerSocket::ServerSocket(const FString &sAddr,int nPort, int nPoolSize) :
35 nPort( nPort )
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 = htons( nPort );
43
44 inet_aton( sAddr.getStr(), &name.sin_addr );
45
46 startServer( name, nPoolSize );
47}
48
49Bu::ServerSocket::~ServerSocket()
50{
51}
52
53void Bu::ServerSocket::startServer( struct sockaddr_in &name, int nPoolSize )
54{
55 /* Create the socket. */
56 nServer = socket( PF_INET, SOCK_STREAM, 0 );
57 if( nServer < 0 )
58 {
59 throw Bu::SocketException("Couldn't create a listen socket.");
60 }
61
62 int opt = 1;
63 setsockopt(
64 nServer,
65 SOL_SOCKET,
66 SO_REUSEADDR,
67 (char *)&opt,
68 sizeof( opt )
69 );
70
71 if( bind( nServer, (struct sockaddr *) &name, sizeof(name) ) < 0 )
72 {
73 throw Bu::SocketException("Couldn't bind to the listen socket.");
74 }
75
76 if( listen( nServer, nPoolSize ) < 0 )
77 {
78 throw Bu::SocketException(
79 "Couldn't begin listening to the server socket."
80 );
81 }
82
83 FD_ZERO( &fdActive );
84 /* Initialize the set of active sockets. */
85 FD_SET( nServer, &fdActive );
86}
87
88int Bu::ServerSocket::accept( int nTimeoutSec, int nTimeoutUSec )
89{
90 fd_set fdRead = fdActive;
91
92 struct timeval xT;
93
94 xT.tv_sec = nTimeoutSec;
95 xT.tv_usec = nTimeoutUSec;
96
97 if( TEMP_FAILURE_RETRY(select( nServer+1, &fdRead, NULL, NULL, &xT )) < 0 )
98 {
99 throw SocketException(
100 "Error scanning for new connections: %s", strerror( errno )
101 );
102 }
103
104 if( FD_ISSET( nServer, &fdRead ) )
105 {
106 struct sockaddr_in clientname;
107 size_t size;
108 int nClient;
109
110 size = sizeof( clientname );
111#ifdef __CYGWIN__
112 nClient = ::accept( nServer, (struct sockaddr *)&clientname,
113 (int *)&size
114 );
115#else
116 nClient = ::accept( nServer, (struct sockaddr *)&clientname, &size );
117#endif
118 if( nClient < 0 )
119 {
120 throw SocketException(
121 "Error accepting a new connection: %s", strerror( errno )
122 );
123 }
124 char tmpa[20];
125 inet_ntop( AF_INET, (void *)&clientname.sin_addr, tmpa, 20 );
126 //"New connection from host %s, port %hd.",
127 // tmpa, ntohs (clientname.sin_port) );
128
129 {
130 int flags;
131
132 flags = fcntl( nClient, F_GETFL, 0 );
133 flags |= O_NONBLOCK;
134 if( fcntl( nClient, F_SETFL, flags ) < 0)
135 {
136 throw SocketException(
137 "Error setting option on client socket: %s",
138 strerror( errno )
139 );
140 }
141 }
142
143 return nClient;
144 }
145
146 return -1;
147}
148