1 // libTorrent - BitTorrent library
2 // Copyright (C) 2005-2011, Jari Sundell
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 //
18 // In addition, as a special exception, the copyright holders give
19 // permission to link the code of portions of this program with the
20 // OpenSSL library under certain conditions as described in each
21 // individual source file, and distribute linked combinations
22 // including the two.
23 //
24 // You must obey the GNU General Public License in all respects for
25 // all of the code used other than OpenSSL. If you modify file(s)
26 // with this exception, you may extend this exception to your version
27 // of the file(s), but you are not obligated to do so. If you do not
28 // wish to do so, delete this exception statement from your version.
29 // If you delete this exception statement from all source files in the
30 // program, then also delete it here.
31 //
32 // Contact: Jari Sundell <jaris@ifi.uio.no>
33 //
34 // Skomakerveien 33
35 // 3185 Skoppum, NORWAY
36
37 #include "config.h"
38
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <sys/ioctl.h>
42 #include <sys/types.h>
43 #include <sys/socket.h>
44 #include <arpa/inet.h>
45 #include <net/if.h>
46 #include <netinet/in.h>
47 #include <netinet/in_systm.h>
48 #include <netinet/ip.h>
49 #include <rak/socket_address.h>
50
51 #include <torrent/exceptions.h>
52 #include "socket_fd.h"
53
54 namespace utils {
55
56 inline void
check_valid() const57 SocketFd::check_valid() const {
58 if (!is_valid())
59 throw torrent::internal_error("SocketFd function called on an invalid fd.");
60 }
61
62 bool
set_nonblock()63 SocketFd::set_nonblock() {
64 check_valid();
65
66 return fcntl(m_fd, F_SETFL, O_NONBLOCK) == 0;
67 }
68
69 bool
set_priority(priority_type p)70 SocketFd::set_priority(priority_type p) {
71 check_valid();
72 int opt = p;
73
74 if (m_ipv6_socket)
75 return setsockopt(m_fd, IPPROTO_IPV6, IPV6_TCLASS, &opt, sizeof(opt)) == 0;
76 else
77 return setsockopt(m_fd, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)) == 0;
78 }
79
80 bool
set_reuse_address(bool state)81 SocketFd::set_reuse_address(bool state) {
82 check_valid();
83 int opt = state;
84
85 return setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == 0;
86 }
87
88 bool
set_dont_route(bool state)89 SocketFd::set_dont_route(bool state) {
90 check_valid();
91 int opt = state;
92
93 return setsockopt(m_fd, SOL_SOCKET, SO_DONTROUTE, &opt, sizeof(opt)) == 0;
94 }
95
96 // bool
97 // SocketFd::set_bind_to_device(const char* device) {
98 // check_valid();
99 // struct ifreq ifr;
100 // strlcpy(ifr.ifr_name, device, IFNAMSIZ);
101
102 // return setsockopt(m_fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) == 0;
103 // }
104
105 bool
set_send_buffer_size(uint32_t s)106 SocketFd::set_send_buffer_size(uint32_t s) {
107 check_valid();
108 int opt = s;
109
110 return setsockopt(m_fd, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) == 0;
111 }
112
113 bool
set_receive_buffer_size(uint32_t s)114 SocketFd::set_receive_buffer_size(uint32_t s) {
115 check_valid();
116 int opt = s;
117
118 return setsockopt(m_fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) == 0;
119 }
120
121 int
get_error() const122 SocketFd::get_error() const {
123 check_valid();
124
125 int err;
126 socklen_t length = sizeof(err);
127
128 if (getsockopt(m_fd, SOL_SOCKET, SO_ERROR, &err, &length) == -1)
129 throw torrent::internal_error("SocketFd::get_error() could not get error");
130
131 return err;
132 }
133
134 bool
open_stream()135 SocketFd::open_stream() {
136 m_fd = socket(rak::socket_address::pf_inet6, SOCK_STREAM, IPPROTO_TCP);
137
138 if (m_fd == -1) {
139 m_ipv6_socket = false;
140 return (m_fd = socket(rak::socket_address::pf_inet, SOCK_STREAM, IPPROTO_TCP)) != -1;
141 }
142
143 m_ipv6_socket = true;
144
145 int zero = 0;
146 return setsockopt(m_fd, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero)) != -1;
147 }
148
149 bool
open_datagram()150 SocketFd::open_datagram() {
151 m_fd = socket(rak::socket_address::pf_inet6, SOCK_DGRAM, 0);
152 if (m_fd == -1) {
153 m_ipv6_socket = false;
154 return (m_fd = socket(rak::socket_address::pf_inet, SOCK_DGRAM, 0)) != -1;
155 }
156 m_ipv6_socket = true;
157
158 int zero = 0;
159 return setsockopt(m_fd, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero)) != -1;
160 }
161
162 bool
open_local()163 SocketFd::open_local() {
164 return (m_fd = socket(rak::socket_address::pf_local, SOCK_STREAM, 0)) != -1;
165 }
166
167 void
close()168 SocketFd::close() {
169 if (::close(m_fd) && errno == EBADF)
170 throw torrent::internal_error("SocketFd::close() called on an invalid file descriptor");
171 }
172
173 bool
bind(const rak::socket_address & sa)174 SocketFd::bind(const rak::socket_address& sa) {
175 check_valid();
176
177 if (m_ipv6_socket && sa.family() == rak::socket_address::pf_inet) {
178 rak::socket_address_inet6 sa_mapped = sa.sa_inet()->to_mapped_address();
179 return !::bind(m_fd, sa_mapped.c_sockaddr(), sizeof(sa_mapped));
180 }
181
182 return !::bind(m_fd, sa.c_sockaddr(), sa.length());
183 }
184
185 bool
bind(const rak::socket_address & sa,unsigned int length)186 SocketFd::bind(const rak::socket_address& sa, unsigned int length) {
187 check_valid();
188
189 if (m_ipv6_socket && sa.family() == rak::socket_address::pf_inet) {
190 rak::socket_address_inet6 sa_mapped = sa.sa_inet()->to_mapped_address();
191 return !::bind(m_fd, sa_mapped.c_sockaddr(), sizeof(sa_mapped));
192 }
193
194 return !::bind(m_fd, sa.c_sockaddr(), length);
195 }
196
197 bool
connect(const rak::socket_address & sa)198 SocketFd::connect(const rak::socket_address& sa) {
199 check_valid();
200
201 if (m_ipv6_socket && sa.family() == rak::socket_address::pf_inet) {
202 rak::socket_address_inet6 sa_mapped = sa.sa_inet()->to_mapped_address();
203 return !::connect(m_fd, sa_mapped.c_sockaddr(), sizeof(sa_mapped)) || errno == EINPROGRESS;
204 }
205
206 return !::connect(m_fd, sa.c_sockaddr(), sa.length()) || errno == EINPROGRESS;
207 }
208
209 bool
getsockname(rak::socket_address * sa)210 SocketFd::getsockname(rak::socket_address *sa) {
211 check_valid();
212
213 socklen_t len = sizeof(rak::socket_address);
214 if (::getsockname(m_fd, sa->c_sockaddr(), &len)) {
215 return false;
216 }
217
218 if (m_ipv6_socket && sa->family() == rak::socket_address::af_inet6) {
219 *sa = sa->sa_inet6()->normalize_address();
220 }
221
222 return true;
223 }
224
225 bool
listen(int size)226 SocketFd::listen(int size) {
227 check_valid();
228
229 return !::listen(m_fd, size);
230 }
231
232 SocketFd
accept(rak::socket_address * sa)233 SocketFd::accept(rak::socket_address* sa) {
234 check_valid();
235 socklen_t len = sizeof(rak::socket_address);
236
237 if (sa == NULL) {
238 return SocketFd(::accept(m_fd, NULL, &len));
239 }
240 int fd = ::accept(m_fd, sa->c_sockaddr(), &len);
241 if (fd != -1 && m_ipv6_socket && sa->family() == rak::socket_address::af_inet6) {
242 *sa = sa->sa_inet6()->normalize_address();
243 }
244 return SocketFd(fd);
245 }
246
247 // unsigned int
248 // SocketFd::get_read_queue_size() const {
249 // unsigned int v;
250
251 // if (!is_valid() || ioctl(m_fd, SIOCINQ, &v) < 0)
252 // throw internal_error("SocketFd::get_read_queue_size() could not be performed");
253
254 // return v;
255 // }
256
257 // unsigned int
258 // SocketFd::get_write_queue_size() const {
259 // unsigned int v;
260
261 // if (!is_valid() || ioctl(m_fd, SIOCOUTQ, &v) < 0)
262 // throw internal_error("SocketFd::get_write_queue_size() could not be performed");
263
264 // return v;
265 // }
266
267 }
268