~ubuntu-branches/ubuntu/intrepid/miro/intrepid

« back to all changes in this revision

Viewing changes to portable/libtorrent/src/broadcast_socket.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Christopher James Halse Rogers
  • Date: 2008-02-09 13:37:10 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20080209133710-9rs90q6gckvp1b6i
Tags: 1.1.2-0ubuntu1
New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 
 
3
Copyright (c) 2007, Arvid Norberg
 
4
All rights reserved.
 
5
 
 
6
Redistribution and use in source and binary forms, with or without
 
7
modification, are permitted provided that the following conditions
 
8
are met:
 
9
 
 
10
    * Redistributions of source code must retain the above copyright
 
11
      notice, this list of conditions and the following disclaimer.
 
12
    * Redistributions in binary form must reproduce the above copyright
 
13
      notice, this list of conditions and the following disclaimer in
 
14
      the documentation and/or other materials provided with the distribution.
 
15
    * Neither the name of the author nor the names of its
 
16
      contributors may be used to endorse or promote products derived
 
17
      from this software without specific prior written permission.
 
18
 
 
19
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 
20
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
21
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
22
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 
23
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 
24
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 
25
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 
26
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 
27
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 
28
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 
29
POSSIBILITY OF SUCH DAMAGE.
 
30
 
 
31
*/
 
32
 
 
33
#include <asio/ip/host_name.hpp>
 
34
#include <asio/ip/multicast.hpp>
 
35
#include <boost/bind.hpp>
 
36
 
 
37
#include "libtorrent/socket.hpp"
 
38
#include "libtorrent/enum_net.hpp"
 
39
#include "libtorrent/broadcast_socket.hpp"
 
40
#include "libtorrent/assert.hpp"
 
41
 
 
42
namespace libtorrent
 
43
{
 
44
        bool is_local(address const& a)
 
45
        {
 
46
                if (a.is_v6()) return a.to_v6().is_link_local();
 
47
                address_v4 a4 = a.to_v4();
 
48
                unsigned long ip = a4.to_ulong();
 
49
                return ((ip & 0xff000000) == 0x0a000000
 
50
                        || (ip & 0xfff00000) == 0xac100000
 
51
                        || (ip & 0xffff0000) == 0xc0a80000);
 
52
        }
 
53
 
 
54
        bool is_loopback(address const& addr)
 
55
        {
 
56
                if (addr.is_v4())
 
57
                  return addr.to_v4() == address_v4::loopback();
 
58
                else
 
59
                        return addr.to_v6() == address_v6::loopback();
 
60
        }
 
61
 
 
62
        bool is_multicast(address const& addr)
 
63
        {
 
64
                if (addr.is_v4())
 
65
                        return addr.to_v4().is_multicast();
 
66
                else
 
67
                        return addr.to_v6().is_multicast();
 
68
        }
 
69
 
 
70
        bool is_any(address const& addr)
 
71
        {
 
72
                if (addr.is_v4())
 
73
                        return addr.to_v4() == address_v4::any();
 
74
                else
 
75
                        return addr.to_v6() == address_v6::any();
 
76
        }
 
77
 
 
78
        address guess_local_address(asio::io_service& ios)
 
79
        {
 
80
                // make a best guess of the interface we're using and its IP
 
81
                asio::error_code ec;
 
82
                std::vector<address> const& interfaces = enum_net_interfaces(ios, ec);
 
83
                address ret = address_v4::any();
 
84
                for (std::vector<address>::const_iterator i = interfaces.begin()
 
85
                        , end(interfaces.end()); i != end; ++i)
 
86
                {
 
87
                        address const& a = *i;
 
88
                        if (is_loopback(a)
 
89
                                || is_multicast(a)
 
90
                                || is_any(a)) continue;
 
91
 
 
92
                        // prefer a v4 address, but return a v6 if
 
93
                        // there are no v4
 
94
                        if (a.is_v4()) return a;
 
95
 
 
96
                        if (ret != address_v4::any())
 
97
                                ret = a;
 
98
                }
 
99
                return ret;
 
100
        }
 
101
 
 
102
        broadcast_socket::broadcast_socket(asio::io_service& ios
 
103
                , udp::endpoint const& multicast_endpoint
 
104
                , receive_handler_t const& handler
 
105
                , bool loopback)
 
106
                : m_multicast_endpoint(multicast_endpoint)
 
107
                , m_on_receive(handler)
 
108
        {
 
109
                TORRENT_ASSERT(is_multicast(m_multicast_endpoint.address()));
 
110
 
 
111
                using namespace asio::ip::multicast;
 
112
        
 
113
                asio::error_code ec;
 
114
                std::vector<address> interfaces = enum_net_interfaces(ios, ec);
 
115
 
 
116
                for (std::vector<address>::const_iterator i = interfaces.begin()
 
117
                        , end(interfaces.end()); i != end; ++i)
 
118
                {
 
119
                        // only broadcast to IPv4 addresses that are not local
 
120
                        if (!is_local(*i)) continue;
 
121
                        // only multicast on compatible networks
 
122
                        if (i->is_v4() != multicast_endpoint.address().is_v4()) continue;
 
123
                        // ignore any loopback interface
 
124
                        if (is_loopback(*i)) continue;
 
125
 
 
126
                        boost::shared_ptr<datagram_socket> s(new datagram_socket(ios));
 
127
                        if (i->is_v4())
 
128
                        {
 
129
                                s->open(udp::v4(), ec);
 
130
                                if (ec) continue;
 
131
                                s->set_option(datagram_socket::reuse_address(true), ec);
 
132
                                if (ec) continue;
 
133
                                s->bind(udp::endpoint(address_v4::any(), multicast_endpoint.port()), ec);
 
134
                                if (ec) continue;
 
135
                                s->set_option(join_group(multicast_endpoint.address()), ec);
 
136
                                if (ec) continue;
 
137
                                s->set_option(outbound_interface(i->to_v4()), ec);
 
138
                                if (ec) continue;
 
139
                        }
 
140
                        else
 
141
                        {
 
142
                                s->open(udp::v6(), ec);
 
143
                                if (ec) continue;
 
144
                                s->set_option(datagram_socket::reuse_address(true), ec);
 
145
                                if (ec) continue;
 
146
                                s->bind(udp::endpoint(address_v6::any(), multicast_endpoint.port()), ec);
 
147
                                if (ec) continue;
 
148
                                s->set_option(join_group(multicast_endpoint.address()), ec);
 
149
                                if (ec) continue;
 
150
//                              s->set_option(outbound_interface(i->to_v6()), ec);
 
151
//                              if (ec) continue;
 
152
                        }
 
153
                        s->set_option(hops(255), ec);
 
154
                        if (ec) continue;
 
155
                        s->set_option(enable_loopback(loopback), ec);
 
156
                        if (ec) continue;
 
157
                        m_sockets.push_back(socket_entry(s));
 
158
                        socket_entry& se = m_sockets.back();
 
159
                        s->async_receive_from(asio::buffer(se.buffer, sizeof(se.buffer))
 
160
                                , se.remote, bind(&broadcast_socket::on_receive, this, &se, _1, _2));
 
161
#ifndef NDEBUG
 
162
//                      std::cerr << "broadcast socket [ if: " << i->to_v4().to_string()
 
163
//                              << " group: " << multicast_endpoint.address() << " ]" << std::endl;
 
164
#endif
 
165
                }
 
166
        }
 
167
 
 
168
        void broadcast_socket::send(char const* buffer, int size, asio::error_code& ec)
 
169
        {
 
170
                for (std::list<socket_entry>::iterator i = m_sockets.begin()
 
171
                        , end(m_sockets.end()); i != end; ++i)
 
172
                {
 
173
                        asio::error_code e;
 
174
                        i->socket->send_to(asio::buffer(buffer, size), m_multicast_endpoint, 0, e);
 
175
#ifndef NDEBUG
 
176
//                      std::cerr << " sending on " << i->socket->local_endpoint().address().to_string() << std::endl;
 
177
#endif
 
178
                        if (e) ec = e;
 
179
                }
 
180
        }
 
181
 
 
182
        void broadcast_socket::on_receive(socket_entry* s, asio::error_code const& ec
 
183
                , std::size_t bytes_transferred)
 
184
        {
 
185
                if (ec || bytes_transferred == 0) return;
 
186
                m_on_receive(s->remote, s->buffer, bytes_transferred);
 
187
                s->socket->async_receive_from(asio::buffer(s->buffer, sizeof(s->buffer))
 
188
                        , s->remote, bind(&broadcast_socket::on_receive, this, s, _1, _2));
 
189
        }
 
190
 
 
191
        void broadcast_socket::close()
 
192
        {
 
193
                for (std::list<socket_entry>::iterator i = m_sockets.begin()
 
194
                        , end(m_sockets.end()); i != end; ++i)
 
195
                {
 
196
                        i->socket->close();
 
197
                }
 
198
        }
 
199
}
 
200
 
 
201