media/mtransport/test/stunserver.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=2 et sw=2 tw=80: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     5  * You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 // Original author: ekr@rtfm.com
     9 /*
    10 Original code from nICEr and nrappkit.
    12 nICEr copyright:
    14 Copyright (c) 2007, Adobe Systems, Incorporated
    15 All rights reserved.
    17 Redistribution and use in source and binary forms, with or without
    18 modification, are permitted provided that the following conditions are
    19 met:
    21 * Redistributions of source code must retain the above copyright
    22   notice, this list of conditions and the following disclaimer.
    24 * Redistributions in binary form must reproduce the above copyright
    25   notice, this list of conditions and the following disclaimer in the
    26   documentation and/or other materials provided with the distribution.
    28 * Neither the name of Adobe Systems, Network Resonance nor the names of its
    29   contributors may be used to endorse or promote products derived from
    30   this software without specific prior written permission.
    32 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    33 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    34 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    35 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    36 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    37 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    38 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    39 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    40 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    41 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    42 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    45 nrappkit copyright:
    47    Copyright (C) 2001-2003, Network Resonance, Inc.
    48    Copyright (C) 2006, Network Resonance, Inc.
    49    All Rights Reserved
    51    Redistribution and use in source and binary forms, with or without
    52    modification, are permitted provided that the following conditions
    53    are met:
    55    1. Redistributions of source code must retain the above copyright
    56       notice, this list of conditions and the following disclaimer.
    57    2. Redistributions in binary form must reproduce the above copyright
    58       notice, this list of conditions and the following disclaimer in the
    59       documentation and/or other materials provided with the distribution.
    60    3. Neither the name of Network Resonance, Inc. nor the name of any
    61       contributors to this software may be used to endorse or promote
    62       products derived from this software without specific prior written
    63       permission.
    65    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
    66    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    67    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    68    ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
    69    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    70    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    71    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    72    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    73    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    74    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    75    POSSIBILITY OF SUCH DAMAGE.
    78    ekr@rtfm.com  Thu Dec 20 20:14:49 2001
    79 */
    80 #include "logging.h"
    81 #include "mozilla/Scoped.h"
    82 #include "databuffer.h"
    84 extern "C" {
    85 #include "nr_api.h"
    86 #include "async_wait.h"
    87 #include "async_timer.h"
    88 #include "nr_socket.h"
    89 #include "nr_socket_local.h"
    90 #include "transport_addr.h"
    91 #include "addrs.h"
    92 #include "local_addr.h"
    93 #include "stun_util.h"
    94 #include "registry.h"
    95 }
    97 #include "stunserver.h"
    99 #include <string>
   101 MOZ_MTLOG_MODULE("stunserver");
   103 namespace mozilla {
   105 // Wrapper nr_socket which allows us to lie to the stun server about the
   106 // IP address.
   107 struct nr_socket_wrapped {
   108   nr_socket *sock_;
   109   nr_transport_addr addr_;
   110 };
   112 static int nr_socket_wrapped_destroy(void **objp) {
   113   if (!objp || !*objp)
   114     return 0;
   116   nr_socket_wrapped *wrapped = static_cast<nr_socket_wrapped *>(*objp);
   117   *objp = 0;
   119   delete wrapped;
   121   return 0;
   122 }
   124 static int nr_socket_wrapped_sendto(void *obj, const void *msg, size_t len, int flags,
   125     nr_transport_addr *addr) {
   126   nr_socket_wrapped *wrapped = static_cast<nr_socket_wrapped *>(obj);
   128   return nr_socket_sendto(wrapped->sock_, msg, len, flags, &wrapped->addr_);
   129 }
   131 static int nr_socket_wrapped_recvfrom(void *obj, void * restrict buf, size_t maxlen,
   132     size_t *len, int flags, nr_transport_addr *addr) {
   133   MOZ_CRASH();
   134 }
   136 static int nr_socket_wrapped_getfd(void *obj, NR_SOCKET *fd) {
   137   MOZ_CRASH();
   138 }
   140 static int nr_socket_wrapped_getaddr(void *obj, nr_transport_addr *addrp) {
   141   nr_socket_wrapped *wrapped = static_cast<nr_socket_wrapped *>(obj);
   143   return nr_socket_getaddr(wrapped->sock_, addrp);
   144 }
   146 static int nr_socket_wrapped_close(void *obj) {
   147   MOZ_CRASH();
   148 }
   150 static int nr_socket_wrapped_set_send_addr(nr_socket *sock, nr_transport_addr *addr) {
   151   nr_socket_wrapped *wrapped = static_cast<nr_socket_wrapped *>(sock->obj);
   153   return nr_transport_addr_copy(&wrapped->addr_, addr);
   154 }
   156 static nr_socket_vtbl nr_socket_wrapped_vtbl = {
   157   1,
   158   nr_socket_wrapped_destroy,
   159   nr_socket_wrapped_sendto,
   160   nr_socket_wrapped_recvfrom,
   161   nr_socket_wrapped_getfd,
   162   nr_socket_wrapped_getaddr,
   163   0,
   164   0,
   165   0,
   166   nr_socket_wrapped_close
   167 };
   169 int nr_socket_wrapped_create(nr_socket *inner, nr_socket **outp) {
   170   ScopedDeletePtr<nr_socket_wrapped> wrapped(new nr_socket_wrapped());
   172   wrapped->sock_ = inner;
   174   int r = nr_socket_create_int(wrapped.get(), &nr_socket_wrapped_vtbl, outp);
   175   if (r)
   176     return r;
   178   wrapped.forget();
   179   return 0;
   180 }
   183 // Instance static.
   184 // Note: Calling Create() at static init time is not going to be safe, since
   185 // we have no reason to expect this will be initted to a nullptr yet.
   186 TestStunServer* TestStunServer::instance;
   187 uint16_t TestStunServer::instance_port = 3478;
   189 TestStunServer::~TestStunServer() {
   190   // TODO(ekr@rtfm.com): Put this on the right thread.
   192   // Unhook callback from our listen socket.
   193   if (listen_sock_) {
   194     NR_SOCKET fd;
   195     if (!nr_socket_getfd(listen_sock_, &fd)) {
   196       NR_ASYNC_CANCEL(fd, NR_ASYNC_WAIT_READ);
   197     }
   198   }
   200   // Free up stun context and network resources
   201   nr_stun_server_ctx_destroy(&stun_server_);
   202   nr_socket_destroy(&listen_sock_);
   203   nr_socket_destroy(&send_sock_);
   205   // Make sure we aren't still waiting on a deferred response timer to pop
   206   if (timer_handle_)
   207     NR_async_timer_cancel(timer_handle_);
   209   delete response_addr_;
   210 }
   212 int TestStunServer::TryOpenListenSocket(nr_local_addr* addr, uint16_t port) {
   214     if (nr_transport_addr_set_port(&addr->addr, port)) {
   215       MOZ_MTLOG(ML_ERROR, "Couldn't set port");
   216       return R_INTERNAL;
   217     }
   219     if (nr_transport_addr_fmt_addr_string(&addr->addr)) {
   220       MOZ_MTLOG(ML_ERROR, "Couldn't re-set addr string");
   221       return R_INTERNAL;
   222     }
   224     if (nr_socket_local_create(&addr->addr, &listen_sock_)) {
   225       MOZ_MTLOG(ML_ERROR, "Couldn't create listen socket");
   226       return R_ALREADY;
   227     }
   229     return 0;
   230 }
   232 TestStunServer* TestStunServer::Create() {
   233   NR_reg_init(NR_REG_MODE_LOCAL);
   235   ScopedDeletePtr<TestStunServer> server(new TestStunServer());
   237   nr_local_addr addrs[100];
   238   int addr_ct;
   239   int r;
   241   r = nr_stun_find_local_addresses(addrs, 100, &addr_ct);
   242   if (r) {
   243     MOZ_MTLOG(ML_ERROR, "Couldn't retrieve addresses");
   244     return nullptr;
   245   }
   247   if (addr_ct < 1) {
   248     MOZ_MTLOG(ML_ERROR, "No local addresses");
   249     return nullptr;
   250   }
   252   NR_SOCKET fd;
   253   int tries = 10;
   254   while (tries--) {
   255     // Bind to the first address (arbitrarily) on configured port (default 3478)
   256     r = server->TryOpenListenSocket(&addrs[0], instance_port);
   257     // We interpret R_ALREADY to mean the addr is probably in use. Try another.
   258     // Otherwise, it either worked or it didn't, and we check below.
   259     if (r != R_ALREADY) {
   260       break;
   261     }
   262     ++instance_port;
   263   }
   265   if (r) {
   266     return nullptr;
   267   }
   269   r = nr_socket_getfd(server->listen_sock_, &fd);
   270   if (r) {
   271     MOZ_MTLOG(ML_ERROR, "Couldn't get fd");
   272     return nullptr;
   273   }
   275   r = nr_socket_wrapped_create(server->listen_sock_, &server->send_sock_);
   276   if (r) {
   277     MOZ_MTLOG(ML_ERROR, "Couldn't create send socket");
   278     return nullptr;
   279   }
   281   r = nr_stun_server_ctx_create(const_cast<char *>("Test STUN server"),
   282                                 server->send_sock_,
   283                                 &server->stun_server_);
   284   if (r) {
   285     MOZ_MTLOG(ML_ERROR, "Couldn't create STUN server");
   286     return nullptr;
   287   }
   289   // Cache the address and port.
   290   char addr_string[INET6_ADDRSTRLEN];
   291   r = nr_transport_addr_get_addrstring(&addrs[0].addr, addr_string,
   292                                        sizeof(addr_string));
   293   if (r) {
   294     MOZ_MTLOG(ML_ERROR, "Failed to convert listen addr to a string representation");
   295     return nullptr;
   296   }
   298   server->listen_addr_ = addr_string;
   299   server->listen_port_ = instance_port;
   301   NR_ASYNC_WAIT(fd, NR_ASYNC_WAIT_READ, &TestStunServer::readable_cb, server.get());
   303   return server.forget();
   304 }
   306 void TestStunServer::ConfigurePort(uint16_t port) {
   307   instance_port = port;
   308 }
   310 TestStunServer* TestStunServer::GetInstance() {
   311   if (!instance)
   312     instance = Create();
   314   MOZ_ASSERT(instance);
   315   return instance;
   316 }
   318 void TestStunServer::ShutdownInstance() {
   319   delete instance;
   321   instance = nullptr;
   322 }
   325 struct DeferredStunOperation {
   326   DeferredStunOperation(TestStunServer *server,
   327                         const char *data, size_t len,
   328                         nr_transport_addr *addr) :
   329       server_(server),
   330       buffer_(reinterpret_cast<const uint8_t *>(data), len) {
   331     nr_transport_addr_copy(&addr_, addr);
   332   }
   334   TestStunServer *server_;
   335   DataBuffer buffer_;
   336   nr_transport_addr addr_;
   337 };
   339 void TestStunServer::Process(const uint8_t *msg, size_t len, nr_transport_addr *addr) {
   340   // Set the wrapped address so that the response goes to the right place.
   341   nr_socket_wrapped_set_send_addr(send_sock_, addr);
   342   nr_stun_server_process_request(stun_server_, send_sock_,
   343                                  const_cast<char *>(reinterpret_cast<const char *>(msg)),
   344                                  len,
   345                                  response_addr_ ?
   346                                  response_addr_ : addr,
   347                                  NR_STUN_AUTH_RULE_OPTIONAL);
   348 }
   350 void TestStunServer::process_cb(NR_SOCKET s, int how, void *cb_arg) {
   351   DeferredStunOperation *op = static_cast<DeferredStunOperation *>(cb_arg);
   352   op->server_->timer_handle_ = nullptr;
   353   op->server_->Process(op->buffer_.data(), op->buffer_.len(), &op->addr_);
   355   delete op;
   356 }
   358 void TestStunServer::readable_cb(NR_SOCKET s, int how, void *cb_arg) {
   359   TestStunServer* server = static_cast<TestStunServer*>(cb_arg);
   361   char message[4096];
   362   size_t message_len;
   363   nr_transport_addr addr;
   365   int r = nr_socket_recvfrom(server->listen_sock_, message, sizeof(message),
   366     &message_len, 0, &addr);
   368   if (r) {
   369     MOZ_MTLOG(ML_ERROR, "Couldn't read STUN message");
   370     return;
   371   }
   373   MOZ_MTLOG(ML_DEBUG, "Received data of length " << message_len);
   375   // Re-arm.
   376   NR_ASYNC_WAIT(s, NR_ASYNC_WAIT_READ, &TestStunServer::readable_cb, server);
   379   // If we have initial dropping set, check at this point.
   380   std::string key(addr.as_string);
   382   if (server->received_ct_.count(key) == 0) {
   383     server->received_ct_[key] = 0;
   384   }
   386   ++server->received_ct_[key];
   388   if (!server->active_ || (server->received_ct_[key] <= server->initial_ct_)) {
   389     MOZ_MTLOG(ML_DEBUG, "Dropping message #"
   390               << server->received_ct_[key] << " from " << key);
   391     return;
   392   }
   394   if (server->delay_ms_) {
   395     NR_ASYNC_TIMER_SET(server->delay_ms_,
   396                        process_cb,
   397                        new DeferredStunOperation(
   398                            server,
   399                            message, message_len,
   400                            &addr),
   401                        &server->timer_handle_);
   402   } else {
   403     server->Process(reinterpret_cast<const uint8_t *>(message), message_len, &addr);
   404   }
   405 }
   407 void TestStunServer::SetActive(bool active) {
   408   active_ = active;
   409 }
   411 void TestStunServer::SetDelay(uint32_t delay_ms) {
   412   delay_ms_ = delay_ms;
   413 }
   415 void TestStunServer::SetDropInitialPackets(uint32_t count) {
   416   initial_ct_ = count;
   417 }
   419 nsresult TestStunServer::SetResponseAddr(nr_transport_addr *addr) {
   420   delete response_addr_;
   422   response_addr_ = new nr_transport_addr();
   424   int r = nr_transport_addr_copy(response_addr_, addr);
   425   if (r)
   426     return NS_ERROR_FAILURE;
   428   return NS_OK;
   429 }
   431 nsresult TestStunServer::SetResponseAddr(const std::string& addr,
   432                                          uint16_t port) {
   433   nr_transport_addr addr2;
   435   int r = nr_ip4_str_port_to_transport_addr(addr.c_str(),
   436                                             port, IPPROTO_UDP,
   437                                             &addr2);
   438   if (r)
   439     return NS_ERROR_FAILURE;
   441   return SetResponseAddr(&addr2);
   442 }
   444 void TestStunServer::Reset() {
   445   delay_ms_ = 0;
   446   if (timer_handle_) {
   447     NR_async_timer_cancel(timer_handle_);
   448     timer_handle_ = nullptr;
   449   }
   450   delete response_addr_;
   451   response_addr_ = nullptr;
   452 }
   454 }  // close namespace

mercurial