4 * Copyright (C) 2001 Barnaby Gray <barnaby@beedesign.co.uk>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "sstream_fix.h"
35 #define SEND_FLAGS MSG_NOSIGNAL
41 using std::ostringstream
;
42 using std::istringstream
;
48 // StringtoIP and IPtoString both work on host order ip address expressed as unsigned int's
49 unsigned int StringtoIP(const string
& s
) {
50 istringstream
istr(s
);
51 unsigned char d1
,d2
,d3
,d4
;
52 unsigned int b1
,b2
,b3
,b4
;
53 istr
>> b1
>> d1
>> b2
>> d2
>> b3
>> d3
>> b4
;
58 if (d1
== '.' && d2
== '.' && d3
== '.'
59 && b1
< 256 && b2
< 256 && b3
< 256 && b4
< 256) {
60 return (b1
<< 24) | (b2
<< 16) | (b3
<< 8) | (b4
<< 0);
66 string
IPtoString(unsigned int ip
) {
68 ostr
<< (ip
>> 24) << "."
69 << ((ip
>> 16) & 0xff) << "."
70 << ((ip
>> 8) & 0xff) << "."
75 TCPSocket::TCPSocket()
76 : m_socketDescriptor(-1), m_socketDescriptor_valid(false),
77 blocking(false), m_state(NOT_CONNECTED
)
79 memset(&remoteAddr
, 0, sizeof(remoteAddr
));
82 TCPSocket::TCPSocket( int fd
, struct sockaddr_in addr
)
83 : m_socketDescriptor(fd
), m_socketDescriptor_valid(true), remoteAddr(addr
),
84 blocking(false), m_state(CONNECTED
)
86 socklen_t localLen
= sizeof(struct sockaddr_in
);
87 getsockname( m_socketDescriptor
, (struct sockaddr
*)&localAddr
, &localLen
);
92 TCPSocket::~TCPSocket() {
96 extern "C" int cw_connect(int sockfd
, const struct sockaddr
*serv_addr
, int addrlen
, int ssl
);
98 void TCPSocket::Connect() {
99 if (m_state
!= NOT_CONNECTED
) throw SocketException("Already connected");
101 m_socketDescriptor
= socket(AF_INET
,SOCK_STREAM
,0);
102 if (m_socketDescriptor
== -1) throw SocketException("Couldn't create socket");
103 m_socketDescriptor_valid
= true;
104 remoteAddr
.sin_family
= AF_INET
;
108 if (cw_connect(m_socketDescriptor
,(struct sockaddr
*)&remoteAddr
,sizeof(struct sockaddr
), 0) == -1) {
109 if (errno
== EINPROGRESS
) {
110 m_state
= NONBLOCKING_CONNECT
;
111 return; // non-blocking connect
114 // m_state will still be NOT_CONNECTED
115 close(m_socketDescriptor
);
116 m_socketDescriptor_valid
= false;
117 throw SocketException("Couldn't connect socket");
120 socklen_t localLen
= sizeof(struct sockaddr_in
);
121 getsockname( m_socketDescriptor
, (struct sockaddr
*)&localAddr
, &localLen
);
126 void TCPSocket::FinishNonBlockingConnect() {
127 // this should be called for non blocking connects
128 // after the socket is writeable
130 socklen_t optlen
= sizeof(so_error
);
131 if (getsockopt(m_socketDescriptor
, SOL_SOCKET
, SO_ERROR
, (char *) &so_error
, &optlen
) == -1 || so_error
!= 0) {
132 m_state
= NOT_CONNECTED
;
133 close(m_socketDescriptor
);
134 m_socketDescriptor_valid
= false;
135 throw SocketException("Couldn't connect socket");
139 socklen_t localLen
= sizeof(struct sockaddr_in
);
140 getsockname( m_socketDescriptor
, (struct sockaddr
*)&localAddr
, &localLen
);
145 void TCPSocket::Disconnect() {
147 if (m_socketDescriptor_valid
) {
148 close(m_socketDescriptor
);
149 m_socketDescriptor_valid
= false;
152 m_state
= NOT_CONNECTED
;
155 int TCPSocket::getSocketHandle() { return m_socketDescriptor
; }
157 TCPSocket::State
TCPSocket::getState() const { return m_state
; }
159 bool TCPSocket::connected() {
160 return (m_state
== CONNECTED
);
163 void TCPSocket::setBlocking(bool b
) {
168 bool TCPSocket::isBlocking() const {
172 void TCPSocket::fcntlSetup() {
173 if (m_socketDescriptor_valid
) {
174 int f
= fcntl(m_socketDescriptor
, F_GETFL
);
175 if (blocking
) fcntl(m_socketDescriptor
, F_SETFL
, f
& ~O_NONBLOCK
);
176 else fcntl(m_socketDescriptor
, F_SETFL
, f
| O_NONBLOCK
);
180 void TCPSocket::Send(Buffer
& b
) {
181 if (!connected()) throw SocketException("Not connected");
184 unsigned int sent
= 0;
186 unsigned char *data
= (unsigned char *) malloc(b
.size());
187 copy( b
.begin(), b
.end(), data
);
189 while (sent
< b
.size())
191 ret
= send(m_socketDescriptor
, (char *) (data
+ sent
), b
.size() - sent
, SEND_FLAGS
);
193 m_state
= NOT_CONNECTED
;
194 close(m_socketDescriptor
);
195 m_socketDescriptor_valid
= false;
197 throw SocketException("Sending on socket");
205 bool TCPSocket::Recv(Buffer
& b
) {
206 if (!connected()) throw SocketException("Not connected");
208 unsigned char buffer
[max_receive_size
];
210 int ret
= recv(m_socketDescriptor
, (char *) buffer
, max_receive_size
, 0);
213 if (ret
== -1 && (errno
== EAGAIN
|| errno
== EWOULDBLOCK
)) return false;
215 m_state
= NOT_CONNECTED
;
216 close(m_socketDescriptor
);
217 m_socketDescriptor_valid
= false;
219 if (ret
== 0) throw SocketException( "Other end closed connection" );
220 else throw SocketException( strerror(errno
) );
227 void TCPSocket::setBindHost(const char *host
) {
228 memset(&localAddr
, 0, sizeof(localAddr
));
230 localAddr
.sin_addr
.s_addr
= gethostname(host
);
231 localAddr
.sin_port
= 0;
235 void TCPSocket::setRemoteHost(const char *host
) {
236 remoteAddr
.sin_addr
.s_addr
= gethostname(host
);
239 void TCPSocket::setRemotePort(unsigned short port
) {
240 remoteAddr
.sin_port
= htons(port
);
243 void TCPSocket::setRemoteIP(unsigned int ip
) {
244 remoteAddr
.sin_addr
.s_addr
= htonl(ip
);
247 unsigned short TCPSocket::getRemotePort() const {
248 return ntohs( remoteAddr
.sin_port
);
251 unsigned int TCPSocket::getRemoteIP() const {
252 return ntohl( remoteAddr
.sin_addr
.s_addr
);
255 unsigned short TCPSocket::getLocalPort() const {
256 return ntohs( localAddr
.sin_port
);
259 unsigned int TCPSocket::getLocalIP() const {
260 return ntohl( localAddr
.sin_addr
.s_addr
);
264 // returns ip address of host in network byte order
266 unsigned long TCPSocket::gethostname(const char *hostname
) {
268 unsigned int ip
= htonl( StringtoIP(hostname
) );
269 if (ip
!= 0) return ip
;
272 // try and resolve hostname
273 struct hostent
*hostEnt
;
274 if ((hostEnt
= gethostbyname(hostname
)) == NULL
|| hostEnt
->h_addrtype
!= AF_INET
) {
275 throw SocketException("DNS lookup failed");
277 return *((unsigned long *)(hostEnt
->h_addr
));
284 TCPServer::TCPServer()
285 : m_socketDescriptor_valid(false)
288 TCPServer::~TCPServer() {
292 void TCPServer::StartServer() {
296 void TCPServer::StartServer(unsigned short lower
, unsigned short upper
) {
297 if (m_socketDescriptor_valid
) throw SocketException("Already listening");
299 m_socketDescriptor
= socket( AF_INET
, SOCK_STREAM
, 0 );
300 if (m_socketDescriptor
< 0) throw SocketException("Couldn't create socket");
301 m_socketDescriptor_valid
= true;
303 localAddr
.sin_family
= AF_INET
;
304 localAddr
.sin_addr
.s_addr
= INADDR_ANY
;
307 if (lower
&& upper
) {
309 // attempt to bind to a port within the range
310 for (port
=lower
;port
<=upper
;port
++) {
311 localAddr
.sin_port
= htons(port
);
312 if ( bind( m_socketDescriptor
,(struct sockaddr
*)&localAddr
,sizeof(struct sockaddr
) ) >= 0 ) {
321 // bind to a random port
322 localAddr
.sin_port
= 0;
323 if ( bind( m_socketDescriptor
,(struct sockaddr
*)&localAddr
,sizeof(struct sockaddr
) ) < 0 )
324 throw SocketException("Couldn't bind socket");
327 listen( m_socketDescriptor
, 5 );
328 // queue size of 5 should be sufficient
330 socklen_t localLen
= sizeof(struct sockaddr_in
);
331 getsockname( m_socketDescriptor
, (struct sockaddr
*)&localAddr
, &localLen
);
334 unsigned short TCPServer::getPort() const {
335 return ntohs( localAddr
.sin_port
);
338 unsigned int TCPServer::getIP() const {
339 return ntohl( localAddr
.sin_addr
.s_addr
);
342 TCPSocket
* TCPServer::Accept() {
345 struct sockaddr_in remoteAddr
;
347 if (!m_socketDescriptor_valid
) throw SocketException("Not connected");
349 remoteLen
= sizeof(remoteAddr
);
350 newsockfd
= accept( m_socketDescriptor
,
351 (struct sockaddr
*) &remoteAddr
,
354 close(m_socketDescriptor
);
355 m_socketDescriptor_valid
= false;
356 throw SocketException("Error on accept");
359 return new TCPSocket( newsockfd
, remoteAddr
);
362 int TCPServer::getSocketHandle() { return m_socketDescriptor
; }
364 void TCPServer::Disconnect() {
365 if (m_socketDescriptor_valid
) {
366 close(m_socketDescriptor
);
367 m_socketDescriptor
= 0;
368 m_socketDescriptor_valid
= false;
372 bool TCPServer::isStarted() const { return m_socketDescriptor_valid
; }
374 void TCPServer::setBindHost(const char *host
) {
375 memset(&localAddr
, 0, sizeof(localAddr
));
377 localAddr
.sin_addr
.s_addr
= TCPSocket::gethostname(host
);
378 localAddr
.sin_port
= 0;
383 * SocketException class
385 SocketException::SocketException(const string
& text
) : m_errortext(text
) { }
387 const char* SocketException::what() const throw() {
388 return m_errortext
.c_str();