1 // Socket.cpp - an IOChannel for sockets
3 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Free Software
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 3 of the License, or
9 // (at your option) any later version.
11 // This program 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
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <sys/times.h>
24 #include <arpa/inet.h>
26 #include <netinet/in.h>
27 #include <netinet/tcp.h>
30 #include <boost/cstdint.hpp>
33 #include <boost/lexical_cast.hpp>
38 #include "GnashAlgorithm.h"
53 Socket::connected() const
55 if (_connected
) return true;
56 if (!_socket
) return false;
62 while (retries
-- > 0) {
65 FD_SET(_socket
, &fdset
);
70 const int ret
= select(_socket
+ 1, NULL
, &fdset
, NULL
, &tval
);
73 if (ret
== 0) continue;
76 boost::uint32_t val
= 0;
77 socklen_t len
= sizeof(val
);
78 if (::getsockopt(_socket
, SOL_SOCKET
, SO_ERROR
, &val
, &len
) < 0) {
92 // If interrupted by a system call, try again
94 const int err
= errno
;
96 log_debug(_("Socket interrupted by a system call"));
100 log_error(_("XMLSocket: The socket was never available"));
112 if (_socket
) ::close(_socket
);
121 Socket::connect(const std::string
& hostname
, boost::uint16_t port
)
124 // We use _socket here because connected() or _connected might not
125 // be true if a connection attempt is underway but not completed.
127 log_error("Connection attempt while already connected");
131 // If _socket is 0, either there has been no connection, or close() has
132 // been called. There must not be an error in either case.
135 if (hostname
.empty()) return false;
137 struct sockaddr_in addr
;
138 std::memset(&addr
, 0, sizeof(addr
));
139 addr
.sin_family
= AF_INET
;
141 addr
.sin_addr
.s_addr
= ::inet_addr(hostname
.c_str());
142 if (addr
.sin_addr
.s_addr
== INADDR_NONE
) {
143 struct hostent
* host
= ::gethostbyname(hostname
.c_str());
144 if (!host
|| !host
->h_addr
) {
147 addr
.sin_addr
= *reinterpret_cast<in_addr
*>(host
->h_addr
);
150 addr
.sin_port
= htons(port
);
152 _socket
= ::socket(AF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
155 const int err
= errno
;
156 log_debug("Socket creation failed: %s", std::strerror(err
));
162 const int flag
= ::fcntl(_socket
, F_GETFL
, 0);
163 ::fcntl(_socket
, F_SETFL
, flag
| O_NONBLOCK
);
165 const struct sockaddr
* a
= reinterpret_cast<struct sockaddr
*>(&addr
);
167 // Attempt connection
168 if (::connect(_socket
, a
, sizeof(struct sockaddr
)) < 0) {
169 const int err
= errno
;
170 if (err
!= EINPROGRESS
) {
171 log_error("Failed to connect socket: %s", std::strerror(err
));
177 // Magic timeout number. Use rcfile ?
178 struct timeval tv
= { 120, 0 };
180 if (::setsockopt(_socket
, SOL_SOCKET
, SO_RCVTIMEO
,
181 reinterpret_cast<unsigned char*>(&tv
), sizeof(tv
))) {
182 log_error("Setting socket timeout failed");
185 const boost::int32_t on
= 1;
186 ::setsockopt(_socket
, IPPROTO_TCP
, TCP_NODELAY
, &on
, sizeof(on
));
196 // Read position is always _pos + _size wrapped.
197 const size_t cacheSize
= arraySize(_cache
);
198 size_t start
= (_pos
+ _size
) % cacheSize
;
200 // Try to fill the whole remaining buffer.
201 const size_t completeRead
= cacheSize
- _size
;
203 // End is start + read size, wrapped.
204 size_t end
= (start
+ completeRead
) % cacheSize
;
205 if (end
== 0) end
= cacheSize
;
207 boost::uint8_t* startpos
= _cache
+ start
;
211 // The end pos is either the end of the cache or the first
213 boost::uint8_t* endpos
= _cache
+ ((startpos
< _cache
+ _pos
) ?
216 const int thisRead
= endpos
- startpos
;
217 assert(thisRead
>= 0);
219 const int bytesRead
= ::recv(_socket
, startpos
, thisRead
, 0);
221 if (bytesRead
== -1) {
223 const int err
= errno
;
224 if (err
== EWOULDBLOCK
|| err
== EAGAIN
) {
225 // Nothing to read. Carry on.
228 log_error("Socket receive error %s", std::strerror(err
));
235 // If there weren't enough bytes, that's it.
236 if (bytesRead
< thisRead
) break;
238 // If we wrote up to the end of the cache, try writing more to the
246 // Do a single read and report how many bytes were read.
248 Socket::read(void* dst
, std::streamsize num
)
251 if (num
< 0) return 0;
253 if (_size
< num
&& !_error
) {
257 if (_size
< num
) return 0;
258 return readNonBlocking(dst
, num
);
263 Socket::readNonBlocking(void* dst
, std::streamsize num
)
267 boost::uint8_t* ptr
= static_cast<boost::uint8_t*>(dst
);
269 if (!_size
&& !_error
) {
273 size_t cacheSize
= arraySize(_cache
);
275 // First read from pos to end
277 // Maximum bytes available to read.
278 const size_t canRead
= std::min
<size_t>(_size
, num
);
280 size_t toRead
= canRead
;
282 // Space to the end (for the first read).
283 const int thisRead
= std::min
<size_t>(canRead
, cacheSize
- _pos
);
285 std::copy(_cache
+ _pos
, _cache
+ _pos
+ thisRead
, ptr
);
291 std::copy(_cache
, _cache
+ toRead
, ptr
+ thisRead
);
297 return canRead
- toRead
;
301 Socket::write(const void* src
, std::streamsize num
)
308 const boost::uint8_t* buf
= static_cast<const boost::uint8_t*>(src
);
310 while (toWrite
> 0) {
311 bytesSent
= ::send(_socket
, buf
, toWrite
, 0);
313 const int err
= errno
;
314 log_error("Socket send error %s", std::strerror(err
));
319 if (!bytesSent
) break;
320 toWrite
-= bytesSent
;
323 return num
- toWrite
;
329 log_error("tell() called for Socket");
330 return static_cast<std::streamsize
>(-1);
334 Socket::seek(std::streampos
)
336 log_error("seek() called for Socket");
343 log_error("go_to_end() called for Socket");
349 log_error("eof() called for Socket");