DTNTunnel.cc

Go to the documentation of this file.
00001 /*
00002  * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By
00003  * downloading, copying, installing or using the software you agree to
00004  * this license. If you do not agree to this license, do not download,
00005  * install, copy or use the software.
00006  * 
00007  * Intel Open Source License 
00008  * 
00009  * Copyright (c) 2004 Intel Corporation. All rights reserved. 
00010  * 
00011  * Redistribution and use in source and binary forms, with or without
00012  * modification, are permitted provided that the following conditions are
00013  * met:
00014  * 
00015  *   Redistributions of source code must retain the above copyright
00016  *   notice, this list of conditions and the following disclaimer.
00017  * 
00018  *   Redistributions in binary form must reproduce the above copyright
00019  *   notice, this list of conditions and the following disclaimer in the
00020  *   documentation and/or other materials provided with the distribution.
00021  * 
00022  *   Neither the name of the Intel Corporation nor the names of its
00023  *   contributors may be used to endorse or promote products derived from
00024  *   this software without specific prior written permission.
00025  *  
00026  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00027  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00028  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00029  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR
00030  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00031  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00032  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00033  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00034  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00035  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00036  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00037  */
00038 
00039 #include <stdio.h>
00040 #include <unistd.h>
00041 #include <errno.h>
00042 #include <strings.h>
00043 #include <stdlib.h>
00044 #include <sys/time.h>
00045 #include <time.h>
00046 #include <sys/socket.h>
00047 
00048 #include "dtn_api.h"
00049 #include "APIEndpointIDOpt.h"
00050 
00051 #include <oasys/util/Getopt.h>
00052 
00053 #include "DTNTunnel.h"
00054 #include "TCPTunnel.h"
00055 #include "UDPTunnel.h"
00056 
00057 namespace dtntunnel {
00058 
00059 template <>
00060 DTNTunnel* oasys::Singleton<DTNTunnel>::instance_ = 0;
00061 
00062 //----------------------------------------------------------------------
00063 DTNTunnel::DTNTunnel()
00064     : Logger("DTNTunnel", "/dtntunnel"),
00065       loglevelstr_(""),
00066       loglevel_(LOG_DEFAULT_THRESHOLD),
00067       logfile_("-"),
00068       send_lock_("/dtntunnel", oasys::Mutex::TYPE_RECURSIVE, true),
00069       listen_(false),
00070       expiration_(30),
00071       tcp_(false),
00072       udp_(false),
00073       local_addr_(INADDR_ANY),
00074       local_port_(0),
00075       remote_addr_(INADDR_NONE),
00076       remote_port_(0),
00077       max_size_(4096)
00078 {
00079     memset(&local_eid_, 0, sizeof(local_eid_));
00080     memset(&dest_eid_,  0, sizeof(dest_eid_));
00081 }
00082 
00083 //----------------------------------------------------------------------
00084 void
00085 DTNTunnel::get_options(int argc, char* argv[])
00086 {
00087     oasys::Getopt::addopt(
00088         new oasys::StringOpt('o', "output", &logfile_, "<output>",
00089                              "file name for error logging output "
00090                              "(- indicates stdout)"));
00091 
00092     oasys::Getopt::addopt(
00093         new oasys::StringOpt('l', NULL, &loglevelstr_, "<level>",
00094                              "default log level [debug|warn|info|crit]"));
00095 
00096     oasys::Getopt::addopt(
00097         new oasys::BoolOpt('L', "listen", &listen_,
00098                            "run in listen mode for incoming CONN bundles"));
00099     
00100     oasys::Getopt::addopt(
00101         new oasys::UIntOpt('e', "expiration", &expiration_, "<secs>",
00102                            "expiration time"));
00103     
00104     oasys::Getopt::addopt(
00105         new oasys::BoolOpt('t', "tcp", &tcp_,
00106                            "proxy for TCP connections"));
00107     
00108     oasys::Getopt::addopt(
00109         new oasys::BoolOpt('u', "udp", &udp_,
00110                            "proxy for UDP traffic"));
00111     
00112     bool dest_eid_set = false;
00113     oasys::Getopt::addopt(
00114         new dtn::APIEndpointIDOpt('d', "dest_eid", &dest_eid_, "<eid>",
00115                                   "destination endpoint id", &dest_eid_set));
00116     
00117     oasys::Getopt::addopt(
00118         new dtn::APIEndpointIDOpt("local_eid_override", &local_eid_, "<eid>",
00119                                   "local endpoint id"));
00120     
00121     oasys::Getopt::addopt(
00122         new oasys::InAddrOpt("laddr", &local_addr_, "<addr>",
00123                              "local address to listen on"));
00124     
00125     oasys::Getopt::addopt(
00126         new oasys::UInt16Opt("lport", &local_port_, "<port>",
00127                              "local port to listen on"));
00128     
00129     oasys::Getopt::addopt(
00130         new oasys::InAddrOpt("rhost", &remote_addr_, "<addr>",
00131                              "remote host/address to proxy for"));
00132     
00133     oasys::Getopt::addopt(
00134         new oasys::UInt16Opt("rport", &remote_port_, "<port>",
00135                              "remote port to proxy"));
00136     
00137     oasys::Getopt::addopt(
00138         new oasys::UIntOpt('z', "max_size", &max_size_, "<bytes>",
00139                            "maximum bundle size for stream transports (e.g. tcp)"));
00140     
00141     int remainder = oasys::Getopt::getopt(argv[0], argc, argv);
00142     if (remainder != argc) {
00143         fprintf(stderr, "invalid argument '%s'\n", argv[remainder]);
00144  usage:
00145         oasys::Getopt::usage(argv[0]);
00146         exit(1);
00147     }
00148     
00149 #define CHECK_OPT(_condition, _err) \
00150     if ((_condition)) { \
00151         fprintf(stderr, "error: " _err "\n"); \
00152         goto usage; \
00153     }
00154     
00155     //
00156     // TODO?:  couldn't we use these in listen mode to over-ride
00157     // what is provided at the sender? -kfall.  Also: mcast for udp?
00158     //
00159     if (listen_) {
00160         CHECK_OPT(dest_eid_set, "setting destination eid is "
00161                   "meaningless in listen mode");
00162         CHECK_OPT((tcp_ != false) || (udp_ != false), "setting tcp or udp is "
00163                   "meaningless in listen mode");
00164         CHECK_OPT(local_port_  != 0,  "setting local port is "
00165                   "meaningless in listen mode");
00166         CHECK_OPT(remote_addr_ != INADDR_NONE, "setting remote host is "
00167                   "meaningless in listen mode");
00168         CHECK_OPT(remote_port_ != 0,  "setting remote port is "
00169                   "meaningless in listen mode");
00170     } else {
00171         CHECK_OPT(!dest_eid_set, "must set destination eid "
00172                   "or be in listen mode");
00173         CHECK_OPT((tcp_ == false) && (udp_ == false),
00174                   "must set either tcp or udp mode");
00175         CHECK_OPT((tcp_ != false) && (udp_ != false),
00176                   "cannot set both tcp and udp mode");
00177         CHECK_OPT(local_addr_  == INADDR_NONE, "local addr is invalid");
00178         CHECK_OPT(local_port_  == 0,  "must set local port");
00179         CHECK_OPT(remote_addr_ == INADDR_NONE, "must set remote host");
00180         CHECK_OPT(remote_port_ == 0,  "must set remote port");
00181     }
00182     
00183 #undef CHECK_OPT
00184 }
00185 
00186 //----------------------------------------------------------------------
00187 void
00188 DTNTunnel::init_log()
00189 {
00190     // Parse the debugging level argument
00191     if (loglevelstr_.length() == 0) 
00192     {
00193         loglevel_ = oasys::LOG_NOTICE;
00194     }
00195     else 
00196     {
00197         loglevel_ = oasys::str2level(loglevelstr_.c_str());
00198         if (loglevel_ == oasys::LOG_INVALID) 
00199         {
00200             fprintf(stderr, "invalid level value '%s' for -l option, "
00201                     "expected debug | info | warning | error | crit\n",
00202                     loglevelstr_.c_str());
00203             exit(1);
00204         }
00205     }
00206     oasys::Log::init(logfile_.c_str(), loglevel_, "", "~/.dtndebug");
00207 }
00208 
00209 //----------------------------------------------------------------------
00210 void
00211 DTNTunnel::init_tunnel()
00212 {
00213     tcptunnel_ = new TCPTunnel();
00214     udptunnel_ = new UDPTunnel();
00215 
00216     if (!listen_) {
00217         if (tcp_) {
00218             tcptunnel_->add_listener(local_addr_, local_port_,
00219                                      remote_addr_, remote_port_);
00220         } else if (udp_) {
00221             udptunnel_->add_listener(local_addr_, local_port_,
00222                                      remote_addr_, remote_port_);
00223         }
00224     }
00225 }
00226 
00227 //----------------------------------------------------------------------
00228 void
00229 DTNTunnel::init_registration()
00230 {
00231     int err = dtn_open(&recv_handle_);
00232     if (err != DTN_SUCCESS) {
00233         log_crit("can't open recv handle to daemon: %s",
00234                  dtn_strerror(err));
00235         exit(1);
00236     }
00237     
00238     err = dtn_open(&send_handle_);
00239     if (err != DTN_SUCCESS) {
00240         log_crit("can't open send handle to daemon: %s",
00241                  dtn_strerror(err));
00242         exit(1);
00243     }
00244 
00245     if (local_eid_.uri[0] == '\0') {
00246         err = dtn_build_local_eid(recv_handle_, &local_eid_, "dtntunnel");
00247         if (err != DTN_SUCCESS) {
00248             log_crit("can't build local eid: %s",
00249                      dtn_strerror(dtn_errno(recv_handle_)));
00250             exit(1);
00251         }
00252     }
00253 
00254     log_debug("using local endpoint id %s", local_eid_.uri);
00255 
00256     u_int32_t regid;
00257     err = dtn_find_registration(recv_handle_, &local_eid_, &regid);
00258     if (err == 0) {
00259         log_notice("found existing registration id %d, calling dtn_bind",
00260                    regid);
00261         
00262         err = dtn_bind(recv_handle_, regid);
00263         if (err != 0) {
00264             log_crit("error in dtn_bind: %s", 
00265                      dtn_strerror(dtn_errno(recv_handle_)));
00266             exit(1);
00267         }
00268     } else if (dtn_errno(recv_handle_) == DTN_ENOTFOUND) {
00269         dtn_reg_info_t reginfo;
00270         memset(&reginfo, 0, sizeof(reginfo));
00271         dtn_copy_eid(&reginfo.endpoint, &local_eid_);
00272         reginfo.failure_action = DTN_REG_DEFER;
00273         reginfo.expiration     = 60 * 60 * 24; // 1 day
00274 
00275         err = dtn_register(recv_handle_, &reginfo, &regid);
00276         if (err != 0) {
00277             log_crit("error in dtn_register: %s",
00278                      dtn_strerror(dtn_errno(recv_handle_)));
00279             exit(1);
00280         }
00281     } else {
00282         log_crit("error in dtn_find_registration: %s",
00283                  dtn_strerror(dtn_errno(recv_handle_)));
00284         exit(1);
00285     }
00286 }
00287 
00288 //----------------------------------------------------------------------
00289 int
00290 DTNTunnel::send_bundle(dtn::APIBundle* bundle, dtn_endpoint_id_t* dest_eid)
00291 {
00292     // lock to coordinate access to the send_handle_ from multiple
00293     // client threads
00294     oasys::ScopeLock l(&send_lock_, "DTNTunnel::send_bundle");
00295     
00296     dtn_bundle_spec_t spec;
00297     memset(&spec, 0, sizeof(spec));
00298     dtn_copy_eid(&spec.source, &local_eid_);
00299     dtn_copy_eid(&spec.dest,   dest_eid);
00300     spec.priority   = COS_NORMAL;
00301     spec.dopts      = DOPTS_NONE;
00302     spec.expiration = expiration_;
00303 
00304     dtn_bundle_payload_t payload;
00305     memset(&payload, 0, sizeof(payload));
00306 
00307     int err = dtn_set_payload(&payload,
00308                               DTN_PAYLOAD_MEM,
00309                               bundle->payload_.buf(),
00310                               bundle->payload_.len());
00311     if (err != 0) {
00312         log_err("error setting payload: %s",
00313                 dtn_strerror(dtn_errno(recv_handle_)));
00314         return err;
00315     }
00316     
00317     dtn_bundle_id_t bundle_id;
00318     memset(&bundle_id, 0, sizeof(bundle_id));
00319 
00320     err = dtn_send(send_handle_, &spec, &payload, &bundle_id);
00321     if (err != 0) {
00322         log_err("error sending bundle: %s",
00323                 dtn_strerror(dtn_errno(recv_handle_)));
00324         return err;
00325     }
00326 
00327     log_info("sent %zu byte bundle", bundle->payload_.len());
00328 
00329     return DTN_SUCCESS;
00330 }
00331 
00332 //----------------------------------------------------------------------
00333 int
00334 DTNTunnel::handle_bundle(dtn_bundle_spec_t* spec,
00335                          dtn_bundle_payload_t* payload)
00336 {
00337     dtn::APIBundle* b = new dtn::APIBundle();
00338     b->spec_ = *spec;
00339     ASSERT(payload->location == DTN_PAYLOAD_MEM);
00340 
00341     int len = payload->dtn_bundle_payload_t_u.buf.buf_len;
00342 
00343     if (len < (int)sizeof(BundleHeader)) {
00344         log_err("too short bundle: len %d < sizeof bundle header", len);
00345         delete b;
00346         return -1;
00347     }
00348     
00349     char* dst = b->payload_.buf(len);
00350     memcpy(dst, payload->dtn_bundle_payload_t_u.buf.buf_val, len);
00351     b->payload_.set_len(len);
00352     
00353     BundleHeader* hdr = (BundleHeader*)dst;
00354     
00355     switch (hdr->protocol_) {
00356     case IPPROTO_UDP: udptunnel_->handle_bundle(b); break;
00357     case IPPROTO_TCP: tcptunnel_->handle_bundle(b); break;
00358     default:
00359         log_err("unknown protocol %d in %d byte tunnel bundle",
00360                 hdr->protocol_, len);
00361         delete b;
00362         return -1;
00363     }
00364 
00365     return 0;
00366 }
00367 
00368 //----------------------------------------------------------------------
00369 int
00370 DTNTunnel::main(int argc, char* argv[])
00371 {
00372     get_options(argc, argv);
00373     init_log();
00374     log_notice("DTNTunnel starting up...");
00375 
00376     init_tunnel();
00377     init_registration();
00378 
00379     log_debug("DTNTunnel starting receive loop...");
00380     
00381     while (1) {
00382         dtn_bundle_spec_t    spec;
00383         dtn_bundle_payload_t payload;
00384 
00385         memset(&spec,    0, sizeof(spec));
00386         memset(&payload, 0, sizeof(payload));
00387     
00388         log_debug("calling dtn_recv...");
00389         int err = dtn_recv(recv_handle_, &spec, DTN_PAYLOAD_MEM, &payload,
00390                            DTN_TIMEOUT_INF);
00391         if (err != 0) {
00392             log_err("error in dtn_recv: %s",
00393                     dtn_strerror(dtn_errno(recv_handle_)));
00394             break;
00395         }
00396 
00397         log_info("got %d byte bundle",
00398                  payload.dtn_bundle_payload_t_u.buf.buf_len);
00399 
00400         handle_bundle(&spec, &payload);
00401 
00402         dtn_free_payload(&payload);
00403     }
00404 
00405     dtn_close(recv_handle_);
00406     dtn_close(send_handle_);
00407     
00408     return 0;
00409 }
00410 
00411 } // namespace dtntunnel
00412 
00413 int
00414 main(int argc, char** argv)
00415 {
00416     dtntunnel::DTNTunnel::create();
00417     dtntunnel::DTNTunnel::instance()->main(argc, argv);
00418 }

Generated on Fri Dec 22 14:47:58 2006 for DTN Reference Implementation by  doxygen 1.5.1