adding missing includes; trivial fix - comparison with string literal. by
[centerim.git] / libicq2000 / src / socket.cpp
blobe8c27b9dad1b818de01405f8b1ef0d71f9db24be
1 /*
2 * TCPSocket class
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"
23 #include <algorithm>
24 #include <string.h>
26 #include "socket.h"
28 #include "buffer.h"
30 #ifdef HAVE_CONFIG_H
31 # include <config.h>
32 #endif
34 #ifdef MSG_NOSIGNAL
35 #define SEND_FLAGS MSG_NOSIGNAL
36 #else
37 #define SEND_FLAGS 0
38 #endif
40 using std::string;
41 using std::ostringstream;
42 using std::istringstream;
43 //using std::copy;
45 namespace ICQ2000
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;
54 if (!istr) return 0;
55 istr >> d4;
56 if (istr) return 0;
58 if (d1 == '.' && d2 == '.' && d3 == '.'
59 && b1 < 256 && b2 < 256 && b3 < 256 && b4 < 256) {
60 return (b1 << 24) | (b2 << 16) | (b3 << 8) | (b4 << 0);
61 } else {
62 return 0;
66 string IPtoString(unsigned int ip) {
67 ostringstream ostr;
68 ostr << (ip >> 24) << "."
69 << ((ip >> 16) & 0xff) << "."
70 << ((ip >> 8) & 0xff) << "."
71 << (ip & 0xff);
72 return ostr.str();
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 );
89 fcntlSetup();
92 TCPSocket::~TCPSocket() {
93 Disconnect();
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;
106 fcntlSetup();
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 );
123 m_state = CONNECTED;
126 void TCPSocket::FinishNonBlockingConnect() {
127 // this should be called for non blocking connects
128 // after the socket is writeable
129 int so_error;
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");
138 // success
139 socklen_t localLen = sizeof(struct sockaddr_in);
140 getsockname( m_socketDescriptor, (struct sockaddr *)&localAddr, &localLen );
142 m_state = CONNECTED;
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) {
164 blocking = b;
165 fcntlSetup();
168 bool TCPSocket::isBlocking() const {
169 return blocking;
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");
183 int ret;
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);
192 if (ret == -1) {
193 m_state = NOT_CONNECTED;
194 close(m_socketDescriptor);
195 m_socketDescriptor_valid = false;
196 free(data);
197 throw SocketException("Sending on socket");
200 sent += ret;
202 free(data);
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);
212 if (ret <= 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) );
223 b.Pack(buffer,ret);
224 return true;
227 void TCPSocket::setBindHost(const char *host) {
228 memset(&localAddr, 0, sizeof(localAddr));
229 if(strlen(host)) {
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");
276 } else {
277 return *((unsigned long *)(hostEnt->h_addr));
282 * TCPServer class
284 TCPServer::TCPServer()
285 : m_socketDescriptor_valid(false)
288 TCPServer::~TCPServer() {
289 Disconnect();
292 void TCPServer::StartServer() {
293 StartServer(0, 0);
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;
306 bool bound = false;
307 if (lower && upper) {
308 unsigned short port;
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 ) {
313 bound = true;
314 break;
320 if (!bound) {
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() {
343 int newsockfd;
344 socklen_t remoteLen;
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,
352 &remoteLen );
353 if (newsockfd < 0) {
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));
376 if(strlen(host)) {
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();