~ubuntu-branches/ubuntu/maverick/libtorrent-rasterbar/maverick

« back to all changes in this revision

Viewing changes to include/libtorrent/asio/detail/resolver_service.hpp

  • Committer: Bazaar Package Importer
  • Author(s): Christophe Sauthier
  • Date: 2010-08-10 12:59:37 UTC
  • mfrom: (1.3.7 upstream)
  • Revision ID: james.westby@ubuntu.com-20100810125937-jbcmmf17y8yo9hgz
Tags: 0.15.0-0ubuntu1
* New upstream version.
* debian/patches/100_fix_html_docs.patch: refreshed.
* debian/control: bump up standards-version to 3.9.1 (no changes).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
//
2
 
// resolver_service.hpp
3
 
// ~~~~~~~~~~~~~~~~~~~~
4
 
//
5
 
// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6
 
//
7
 
// Distributed under the Boost Software License, Version 1.0. (See accompanying
8
 
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9
 
//
10
 
 
11
 
#ifndef ASIO_DETAIL_RESOLVER_SERVICE_HPP
12
 
#define ASIO_DETAIL_RESOLVER_SERVICE_HPP
13
 
 
14
 
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15
 
# pragma once
16
 
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
 
 
18
 
#include "asio/detail/push_options.hpp"
19
 
 
20
 
#include "asio/detail/push_options.hpp"
21
 
#include <cstring>
22
 
#include <boost/scoped_ptr.hpp>
23
 
#include <boost/shared_ptr.hpp>
24
 
#include <boost/weak_ptr.hpp>
25
 
#include "asio/detail/pop_options.hpp"
26
 
 
27
 
#include "asio/error.hpp"
28
 
#include "asio/io_service.hpp"
29
 
#include "asio/detail/bind_handler.hpp"
30
 
#include "asio/detail/mutex.hpp"
31
 
#include "asio/detail/noncopyable.hpp"
32
 
#include "asio/detail/service_base.hpp"
33
 
#include "asio/detail/socket_ops.hpp"
34
 
#include "asio/detail/socket_types.hpp"
35
 
#include "asio/detail/thread.hpp"
36
 
 
37
 
namespace asio {
38
 
namespace detail {
39
 
 
40
 
template <typename Protocol>
41
 
class resolver_service
42
 
  : public asio::detail::service_base<resolver_service<Protocol> >
43
 
{
44
 
private:
45
 
  // Helper class to perform exception-safe cleanup of addrinfo objects.
46
 
  class auto_addrinfo
47
 
    : private asio::detail::noncopyable
48
 
  {
49
 
  public:
50
 
    explicit auto_addrinfo(asio::detail::addrinfo_type* ai)
51
 
      : ai_(ai)
52
 
    {
53
 
    }
54
 
 
55
 
    ~auto_addrinfo()
56
 
    {
57
 
      if (ai_)
58
 
        socket_ops::freeaddrinfo(ai_);
59
 
    }
60
 
 
61
 
    operator asio::detail::addrinfo_type*()
62
 
    {
63
 
      return ai_;
64
 
    }
65
 
 
66
 
  private:
67
 
    asio::detail::addrinfo_type* ai_;
68
 
  };
69
 
 
70
 
public:
71
 
  // The implementation type of the resolver. The shared pointer is used as a
72
 
  // cancellation token to indicate to the background thread that the operation
73
 
  // has been cancelled.
74
 
  typedef boost::shared_ptr<void> implementation_type;
75
 
  struct noop_deleter { void operator()(void*) {} };
76
 
 
77
 
  // The endpoint type.
78
 
  typedef typename Protocol::endpoint endpoint_type;
79
 
 
80
 
  // The query type.
81
 
  typedef typename Protocol::resolver_query query_type;
82
 
 
83
 
  // The iterator type.
84
 
  typedef typename Protocol::resolver_iterator iterator_type;
85
 
 
86
 
  // Constructor.
87
 
  resolver_service(asio::io_service& io_service)
88
 
    : asio::detail::service_base<
89
 
        resolver_service<Protocol> >(io_service),
90
 
      mutex_(),
91
 
      work_io_service_(new asio::io_service),
92
 
      work_(new asio::io_service::work(*work_io_service_)),
93
 
      work_thread_(0)
94
 
  {
95
 
  }
96
 
 
97
 
  // Destructor.
98
 
  ~resolver_service()
99
 
  {
100
 
    shutdown_service();
101
 
  }
102
 
 
103
 
  // Destroy all user-defined handler objects owned by the service.
104
 
  void shutdown_service()
105
 
  {
106
 
    work_.reset();
107
 
    if (work_io_service_)
108
 
    {
109
 
      work_io_service_->stop();
110
 
      if (work_thread_)
111
 
      {
112
 
        work_thread_->join();
113
 
        work_thread_.reset();
114
 
      }
115
 
      work_io_service_.reset();
116
 
    }
117
 
  }
118
 
 
119
 
  // Construct a new resolver implementation.
120
 
  void construct(implementation_type& impl)
121
 
  {
122
 
    impl.reset(static_cast<void*>(0), noop_deleter());
123
 
  }
124
 
 
125
 
  // Destroy a resolver implementation.
126
 
  void destroy(implementation_type&)
127
 
  {
128
 
  }
129
 
 
130
 
  // Cancel pending asynchronous operations.
131
 
  void cancel(implementation_type& impl)
132
 
  {
133
 
    impl.reset(static_cast<void*>(0), noop_deleter());
134
 
  }
135
 
 
136
 
  // Resolve a query to a list of entries.
137
 
  iterator_type resolve(implementation_type&, const query_type& query,
138
 
      asio::error_code& ec)
139
 
  {
140
 
    asio::detail::addrinfo_type* address_info = 0;
141
 
    std::string host_name = query.host_name();
142
 
    std::string service_name = query.service_name();
143
 
    asio::detail::addrinfo_type hints = query.hints();
144
 
 
145
 
    socket_ops::getaddrinfo(host_name.length() ? host_name.c_str() : 0,
146
 
        service_name.c_str(), &hints, &address_info, ec);
147
 
    auto_addrinfo auto_address_info(address_info);
148
 
 
149
 
    if (ec)
150
 
      return iterator_type();
151
 
 
152
 
    return iterator_type::create(address_info, host_name, service_name);
153
 
  }
154
 
 
155
 
  template <typename Handler>
156
 
  class resolve_query_handler
157
 
  {
158
 
  public:
159
 
    resolve_query_handler(implementation_type impl, const query_type& query,
160
 
        asio::io_service& io_service, Handler handler)
161
 
      : impl_(impl),
162
 
        query_(query),
163
 
        io_service_(io_service),
164
 
        work_(io_service),
165
 
        handler_(handler)
166
 
    {
167
 
    }
168
 
 
169
 
    void operator()()
170
 
    {
171
 
      // Check if the operation has been cancelled.
172
 
      if (impl_.expired())
173
 
      {
174
 
        iterator_type iterator;
175
 
        io_service_.post(asio::detail::bind_handler(handler_,
176
 
              asio::error::operation_aborted, iterator));
177
 
        return;
178
 
      }
179
 
 
180
 
      // Perform the blocking host resolution operation.
181
 
      asio::detail::addrinfo_type* address_info = 0;
182
 
      std::string host_name = query_.host_name();
183
 
      std::string service_name = query_.service_name();
184
 
      asio::detail::addrinfo_type hints = query_.hints();
185
 
      asio::error_code ec;
186
 
      socket_ops::getaddrinfo(host_name.length() ? host_name.c_str() : 0,
187
 
          service_name.c_str(), &hints, &address_info, ec);
188
 
      auto_addrinfo auto_address_info(address_info);
189
 
 
190
 
      // Invoke the handler and pass the result.
191
 
      iterator_type iterator;
192
 
      if (!ec)
193
 
        iterator = iterator_type::create(address_info, host_name, service_name);
194
 
      io_service_.post(asio::detail::bind_handler(
195
 
            handler_, ec, iterator));
196
 
    }
197
 
 
198
 
  private:
199
 
    boost::weak_ptr<void> impl_;
200
 
    query_type query_;
201
 
    asio::io_service& io_service_;
202
 
    asio::io_service::work work_;
203
 
    Handler handler_;
204
 
  };
205
 
 
206
 
  // Asynchronously resolve a query to a list of entries.
207
 
  template <typename Handler>
208
 
  void async_resolve(implementation_type& impl, const query_type& query,
209
 
      Handler handler)
210
 
  {
211
 
    if (work_io_service_)
212
 
    {
213
 
      start_work_thread();
214
 
      work_io_service_->post(
215
 
          resolve_query_handler<Handler>(
216
 
            impl, query, this->get_io_service(), handler));
217
 
    }
218
 
  }
219
 
 
220
 
  // Resolve an endpoint to a list of entries.
221
 
  iterator_type resolve(implementation_type&,
222
 
      const endpoint_type& endpoint, asio::error_code& ec)
223
 
  {
224
 
    // First try resolving with the service name. If that fails try resolving
225
 
    // but allow the service to be returned as a number.
226
 
    char host_name[NI_MAXHOST];
227
 
    char service_name[NI_MAXSERV];
228
 
    int flags = endpoint.protocol().type() == SOCK_DGRAM ? NI_DGRAM : 0;
229
 
    socket_ops::getnameinfo(endpoint.data(), endpoint.size(),
230
 
        host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec);
231
 
    if (ec)
232
 
    {
233
 
      flags |= NI_NUMERICSERV;
234
 
      socket_ops::getnameinfo(endpoint.data(), endpoint.size(),
235
 
          host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec);
236
 
    }
237
 
 
238
 
    if (ec)
239
 
      return iterator_type();
240
 
 
241
 
    return iterator_type::create(endpoint, host_name, service_name);
242
 
  }
243
 
 
244
 
  template <typename Handler>
245
 
  class resolve_endpoint_handler
246
 
  {
247
 
  public:
248
 
    resolve_endpoint_handler(implementation_type impl,
249
 
        const endpoint_type& endpoint, asio::io_service& io_service,
250
 
        Handler handler)
251
 
      : impl_(impl),
252
 
        endpoint_(endpoint),
253
 
        io_service_(io_service),
254
 
        work_(io_service),
255
 
        handler_(handler)
256
 
    {
257
 
    }
258
 
 
259
 
    void operator()()
260
 
    {
261
 
      // Check if the operation has been cancelled.
262
 
      if (impl_.expired())
263
 
      {
264
 
        iterator_type iterator;
265
 
        io_service_.post(asio::detail::bind_handler(handler_,
266
 
              asio::error::operation_aborted, iterator));
267
 
        return;
268
 
      }
269
 
 
270
 
 
271
 
      // First try resolving with the service name. If that fails try resolving
272
 
      // but allow the service to be returned as a number.
273
 
      char host_name[NI_MAXHOST];
274
 
      char service_name[NI_MAXSERV];
275
 
      int flags = endpoint_.protocol().type() == SOCK_DGRAM ? NI_DGRAM : 0;
276
 
      asio::error_code ec;
277
 
      socket_ops::getnameinfo(endpoint_.data(), endpoint_.size(),
278
 
          host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec);
279
 
      if (ec)
280
 
      {
281
 
        flags |= NI_NUMERICSERV;
282
 
        socket_ops::getnameinfo(endpoint_.data(), endpoint_.size(),
283
 
            host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec);
284
 
      }
285
 
 
286
 
      // Invoke the handler and pass the result.
287
 
      iterator_type iterator;
288
 
      if (!ec)
289
 
        iterator = iterator_type::create(endpoint_, host_name, service_name);
290
 
      io_service_.post(asio::detail::bind_handler(
291
 
            handler_, ec, iterator));
292
 
    }
293
 
 
294
 
  private:
295
 
    boost::weak_ptr<void> impl_;
296
 
    endpoint_type endpoint_;
297
 
    asio::io_service& io_service_;
298
 
    asio::io_service::work work_;
299
 
    Handler handler_;
300
 
  };
301
 
 
302
 
  // Asynchronously resolve an endpoint to a list of entries.
303
 
  template <typename Handler>
304
 
  void async_resolve(implementation_type& impl, const endpoint_type& endpoint,
305
 
      Handler handler)
306
 
  {
307
 
    if (work_io_service_)
308
 
    {
309
 
      start_work_thread();
310
 
      work_io_service_->post(
311
 
          resolve_endpoint_handler<Handler>(
312
 
            impl, endpoint, this->get_io_service(), handler));
313
 
    }
314
 
  }
315
 
 
316
 
private:
317
 
  // Helper class to run the work io_service in a thread.
318
 
  class work_io_service_runner
319
 
  {
320
 
  public:
321
 
    work_io_service_runner(asio::io_service& io_service)
322
 
      : io_service_(io_service) {}
323
 
    void operator()() { io_service_.run(); }
324
 
  private:
325
 
    asio::io_service& io_service_;
326
 
  };
327
 
 
328
 
  // Start the work thread if it's not already running.
329
 
  void start_work_thread()
330
 
  {
331
 
    asio::detail::mutex::scoped_lock lock(mutex_);
332
 
    if (work_thread_ == 0)
333
 
    {
334
 
      work_thread_.reset(new asio::detail::thread(
335
 
            work_io_service_runner(*work_io_service_)));
336
 
    }
337
 
  }
338
 
 
339
 
  // Mutex to protect access to internal data.
340
 
  asio::detail::mutex mutex_;
341
 
 
342
 
  // Private io_service used for performing asynchronous host resolution.
343
 
  boost::scoped_ptr<asio::io_service> work_io_service_;
344
 
 
345
 
  // Work for the private io_service to perform.
346
 
  boost::scoped_ptr<asio::io_service::work> work_;
347
 
 
348
 
  // Thread used for running the work io_service's run loop.
349
 
  boost::scoped_ptr<asio::detail::thread> work_thread_;
350
 
};
351
 
 
352
 
} // namespace detail
353
 
} // namespace asio
354
 
 
355
 
#include "asio/detail/pop_options.hpp"
356
 
 
357
 
#endif // ASIO_DETAIL_RESOLVER_SERVICE_HPP