1 #include "video/tcp.hpp"
7 void deleter_fn(void* f
)
12 socket_address::socket_address(const std::string
& spec
)
14 throw std::runtime_error("TCP/IP support not compiled in");
17 socket_address
socket_address::next()
21 std::ostream
& socket_address::connect()
23 throw std::runtime_error("TCP/IP support not compiled in");
26 bool socket_address::supported()
32 #include <boost/iostreams/categories.hpp>
33 #include <boost/iostreams/copy.hpp>
34 #include <boost/iostreams/stream.hpp>
35 #include <boost/iostreams/stream_buffer.hpp>
36 #include <boost/iostreams/filter/symmetric.hpp>
37 #include <boost/iostreams/filter/zlib.hpp>
38 #include <boost/iostreams/filtering_stream.hpp>
39 #include <boost/iostreams/device/back_inserter.hpp>
41 #if defined(_WIN32) || defined(_WIN64)
42 //Why the fuck does windows have nonstandard socket API???
43 #define _WIN32_WINNT 0x0501
46 struct sockaddr_un
{ int sun_family
; char sun_path
[108]; };
48 #include <sys/socket.h>
52 #include <sys/types.h>
59 typedef char char_type
;
60 typedef struct : public boost::iostreams::sink_tag
, boost::iostreams::closable_tag
{} category
;
61 socket_output(int _fd
)
72 std::streamsize
write(const char* s
, std::streamsize n
)
78 ssize_t r
= ::send(fd
, s
, n
, 0);
82 } else if(errno
== EPIPE
) {
83 std::cerr
<< "The other end of socket went away" << std::endl
;
89 std::cerr
<< "Socket write error: " << strerror(err
) << std::endl
;
101 void deleter_fn(void* f
)
103 delete reinterpret_cast<boost::iostreams::stream
<socket_output
>*>(f
);
107 socket_address::socket_address(const std::string
& name
)
109 struct addrinfo hints
;
110 struct addrinfo
* ainfo
;
112 std::string node
, service
, tmp
= name
;
114 struct sockaddr_un uaddr
;
115 if(name
[0] == '/' || name
[0] == '@') {
116 //Fake a unix-domain.
117 if(name
.length() >= sizeof(sockaddr_un
) - offsetof(sockaddr_un
, sun_path
) - 1)
118 throw std::runtime_error("Path too long for filesystem socket");
119 size_t namelen
= offsetof(struct sockaddr_un
, sun_path
) + name
.length();
120 uaddr
.sun_family
= AF_UNIX
;
121 strcpy(uaddr
.sun_path
, name
.c_str());
123 uaddr
.sun_path
[0] = 0; //Mark as abstract namespace socket.
125 socktype
= SOCK_STREAM
;
127 memory
.resize((name
[0] == '@') ? namelen
: sizeof(sockaddr_un
));
128 memcpy(&memory
[0], &uaddr
, memory
.size());
131 //Split into address and port.
132 s
= tmp
.find_last_of(":");
133 if(s
>= tmp
.length())
134 throw std::runtime_error("Port number has to be specified");
135 node
= tmp
.substr(0, s
);
136 service
= tmp
.substr(s
+ 1);
138 memset(&hints
, 0, sizeof(hints
));
139 hints
.ai_family
= AF_UNSPEC
;
140 hints
.ai_socktype
= SOCK_STREAM
;
142 hints
.ai_flags
= AI_V4MAPPED
;
145 hints
.ai_flags
= AI_ADDRCONFIG
;
147 r
= getaddrinfo(node
.c_str(), service
.c_str(), &hints
, &ainfo
);
149 throw std::runtime_error(std::string("getaddrinfo: ") + gai_strerror(r
));
150 family
= ainfo
->ai_family
;
151 socktype
= ainfo
->ai_socktype
;
152 protocol
= ainfo
->ai_protocol
;
154 memory
.resize(ainfo
->ai_addrlen
);
155 memcpy(&memory
[0], ainfo
->ai_addr
, ainfo
->ai_addrlen
);
163 socket_address
socket_address::next()
165 std::vector
<char> newaddr
= memory
;
166 struct sockaddr
* addr
= reinterpret_cast<struct sockaddr
*>(&newaddr
[0]);
167 socklen_t addrlen
= memory
.size();
168 switch(addr
->sa_family
) {
169 case AF_INET
: { //IPv4
170 struct sockaddr_in
* _addr
= (struct sockaddr_in
*)addr
;
171 _addr
->sin_port
= htons(htons(_addr
->sin_port
) + 1);
174 case AF_INET6
: { //IPv6
175 struct sockaddr_in6
* _addr
= (struct sockaddr_in6
*)addr
;
176 _addr
->sin6_port
= htons(htons(_addr
->sin6_port
) + 1);
179 case AF_UNIX
: { //Unix domain sockets.
180 struct sockaddr_un
* _addr
= (struct sockaddr_un
*)addr
;
181 const char* b1
= (char*)_addr
;
182 const char* b2
= (char*)&_addr
->sun_path
;
183 size_t maxpath
= addrlen
- (b2
- b1
);
184 for(size_t i
= 0; i
< maxpath
; i
++)
185 if(i
&& !_addr
->sun_path
[i
]) {
190 throw std::runtime_error("Eh, empty unix domain socket path?");
191 _addr
->sun_path
[maxpath
- 1]++;
195 throw std::runtime_error("This address family is not supported, sorry.");
197 socket_address
n(family
, socktype
, protocol
);
202 std::ostream
& socket_address::connect()
204 int a
= socket(family
, socktype
, protocol
);
207 throw std::runtime_error(std::string("socket: ") + strerror(err
));
210 struct sockaddr
* addr
= reinterpret_cast<struct sockaddr
*>(&memory
[0]);
211 socklen_t addrlen
= memory
.size();
212 #if defined(_WIN32) || defined(_WIN64)
213 r
= ::connect(a
, addr
, addrlen
) ? -1 : 0;
215 r
= ::connect(a
, addr
, addrlen
);
220 throw std::runtime_error(std::string("connect: ") + strerror(err
));
223 return *new boost::iostreams::stream
<socket_output
>(a
);
230 bool socket_address::supported()
237 deleter_fn_t
socket_address::deleter()
243 socket_address::socket_address(int f
, int st
, int p
)