NSIS-ka
A free C++ implementation of NSIS protocols

source: ntlp/branches/20090723-multicast/src/ntlp_statemodule_api.cpp @ 4570

Last change on this file since 4570 was 4570, checked in by stud-lenk, 8 years ago

Refined local address selection code.

This change fixes that, for multicast targets, GIST chooses the interface address directed to the standard gateway even if it is NOT an address GIST has been configured for in etc/gist-ka.conf. In this case GIST now prefers the source address specified by the NSLP APImsg, but only if it is an address configured in etc/gist-ka.conf.

  • Property svn:keywords set to Id HeadURL Rev
File size: 32.0 KB
Line 
1/// ----------------------------------------*- mode: C++; -*--
2/// @file ntlp_statemodule_api.cpp
3/// GIST state module - implements API interactions for GIST
4/// ----------------------------------------------------------
5/// $Id: ntlp_statemodule_api.cpp 4570 2009-10-18 13:34:45Z stud-lenk $
6/// $HeadURL: ntlp/branches/20090723-multicast/src/ntlp_statemodule_api.cpp $
7// ===========================================================
8//                     
9// Copyright (C) 2005-2007, all rights reserved by
10// - Institute of Telematics, Universitaet Karlsruhe (TH)
11//
12// More information and contact:
13// https://projekte.tm.uka.de/trac/NSIS
14//                     
15// This program is free software; you can redistribute it and/or modify
16// it under the terms of the GNU General Public License as published by
17// the Free Software Foundation; version 2 of the License
18//
19// This program is distributed in the hope that it will be useful,
20// but WITHOUT ANY WARRANTY; without even the implied warranty of
21// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22// GNU General Public License for more details.
23//
24// You should have received a copy of the GNU General Public License along
25// with this program; if not, write to the Free Software Foundation, Inc.,
26// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27//
28// ===========================================================
29/** @ingroup statemodule
30 * Statemodule
31 *
32 * This module implements API functions for GIST
33 *
34 * Messages from network are processed and routing state is managed.
35 *
36 */
37#include "ntlp_statemodule.h"
38#include <sstream>
39
40#include "gist_conf.h"
41#include "rfc5014_hack.h"
42
43namespace ntlp {
44
45/** @deftogroup gistapi GIST application programming interface interactions
46 *  @ingroup statemodule
47 *  @ingroup ntlp
48 * @{
49 */
50
51using namespace protlib;
52
53
54/**
55 * process API messages from NSLP modules or from APIWrapper module
56 * @param apimsg -- the messge to process
57 */
58void 
59Statemodule::process_api_msg(APIMsg* apimsg) 
60{
61  // Putting Message Source and NSLPID into nslptable
62  param.nslptable.save_address(apimsg->get_nslpid(), apimsg->get_source());
63
64  EVLog(param.name, color[blue] << "API call received: " << color[off] 
65        << apimsg->get_subtype_name() << " msg#" << apimsg->get_id() << " from NSLPID " << apimsg->get_nslpid() 
66      << " at API interface address " << param.nslptable.get_address(apimsg->get_nslpid()));
67
68   
69  // ===============================================
70  // Start Processing
71  // ===============================================
72 
73
74  switch (apimsg->get_subtype()) 
75  {
76    case APIMsg::Register: 
77    { // ================
78      EVLog(param.name, "NSLP registered with NSLPID " << apimsg->get_nslpid() << " at address " << apimsg->get_source());
79     
80      uint16 rao = apimsg->get_rao();
81     
82      param.rt.add_rao(apimsg->get_nslpid(), rao);
83      EVLog(param.name, "Registered RAO value " << rao << " for this NSLPID");
84     
85      bool found = false;
86      for (unsigned int i = 0; i < param.raovec.size(); i++) {
87        if (param.raovec[i] == rao) found = true;
88      }
89       
90      if (!found) param.raovec.push_back(apimsg->get_rao());
91       
92      ostringstream os;
93     
94      for (unsigned int i = 0; i < param.raovec.size(); i++) {
95        os << "|" << param.raovec[i];
96      }
97     
98      EVLog(param.name, "Now intercepting the following RAOs: " << os.str().c_str());
99     
100      break;
101    }
102
103
104    case APIMsg::SendMessage: 
105    { // ===================
106      tg_send_message(apimsg);
107      break;
108    }
109
110    case APIMsg::RecvMessageAnswer: 
111    { // =========================
112      tg_recv_message_answer(apimsg);
113      break;
114    }
115
116
117    case APIMsg::InvalidateRoutingState: 
118    { // ==============================
119      DLog(param.name, "InvalidateRoutingState received, carrying out the instructions");
120     
121      if (apimsg->get_status_change()==APIMsg::bad) 
122      {
123        DLog(param.name, "We are requested to put state to BAD, this means we put it to state DEAD");
124        param.rt.invalidate_routing_state(apimsg->get_mri()->copy(), apimsg->get_nslpid(), apimsg->get_status_change(), apimsg->get_urgency());
125      }
126       
127      if (apimsg->get_status_change()==APIMsg::tentative) 
128      {
129        DLog(param.name, "We are requested to put state to TENTATIVE, this means we put it to state REFRESH and carry out a Refresh, even if we are not requested via 'urgency' flag");
130        param.rt.invalidate_routing_state(apimsg->get_mri()->copy(), apimsg->get_nslpid(), apimsg->get_status_change(), apimsg->get_urgency());
131       
132      }
133
134      if ((apimsg->get_status_change()!=APIMsg::bad) && (apimsg->get_status_change()!=APIMsg::tentative)) {
135        WLog(param.name, "It is not foreseen that NSLP may set Routing State to something other than BAD or TENTATIVE - doing nothing");
136      }
137      break;
138    }
139     
140
141    case APIMsg::SetStateLifetime: 
142    { // =========================
143      DLog(param.name, "SetStateLifetime received, carrying out the instructions");
144     
145      param.rt.set_state_lifetime(apimsg->get_mri()->copy(), apimsg->get_nslpid(), apimsg->get_state_lifetime());
146      break;
147    }
148
149    default: 
150      {
151        ERRCLog(param.name, "API call unimplemented"); 
152      }
153    } // end switch
154   
155    delete apimsg;
156
157} // end process_api_message
158
159
160/**
161 * Deliver received data to NSLP instance
162 * @param peer -- the peer from which we received the data
163 * @param own_addr -- the IP address of the interface we received the data on
164 * @param pdu -- the pdu containing the data (may NOT be NULL)
165 * @param r_key -- the routing key (may be NULL)
166 * @param r_entry -- the routing entry itself (may be NULL)
167 */
168void
169Statemodule::deliver(const appladdress* peer, const appladdress* own_addr, const known_ntlp_pdu* pdu, const routingkey* r_key, const routingentry* r_entry) 
170{
171  APIMsg* msg = new APIMsg;
172
173  assert (pdu != NULL);
174
175  nslpdata* mydata = pdu->get_nslpdata();
176 
177  assert( pdu->get_mri() != NULL );
178  mri* mymr=pdu->get_mri()->copy();
179   
180  // get SII-Handle from PDU (from NLI info is present), if unavailable (GIST Data Message or Message in C-Mode) take it from entry
181
182  // check NLI information
183  nli* nlinfo=  pdu->get_nli();
184
185  uint32 sii_handle = nlinfo ? param.rt.get_sii_handle(nlinfo) : 0;
186
187  tx_attr_t myattr;
188   
189  if (r_entry) {
190          myattr.secure=r_entry->is_secure();
191          myattr.reliable=!(r_entry->is_dmode());
192
193          if (!sii_handle)
194          {
195                  sii_handle= r_entry->get_sii_handle();
196          }
197  } else {
198          // Initial Query/Initial Confirm, D-Mode, unsecure
199          myattr.secure=false;
200          myattr.reliable=false;
201  }
202
203  /*
204   * Check if this GIST node is the final hop for this flow. This is the
205   * case if either
206   *     1. this is a downstream message and we are the destination hop, or
207   *     2. this is an upstream message and we are the source hop
208   *
209   * We have to compare the relevant address with each of our own addresses,
210   * given in the configuration.
211   */
212  if ( mymr->get_downstream() )
213    myattr.final_hop = is_local_address(mymr->get_destaddress());
214  else
215    myattr.final_hop = is_local_address(mymr->get_sourceaddress());
216
217  DLog("statemodule", "GIST node is the final hop: " << myattr.final_hop);
218
219  nslpdata* senddata = NULL;
220
221  if (mydata) senddata = new nslpdata(*mydata);
222
223  uint8 ip_distance = 0;
224  uint8 ip_ttl = 0;
225
226  if (nlinfo) 
227  {
228    ip_ttl = nlinfo->get_ip_ttl();
229  } 
230  else 
231  {
232    if (r_entry && r_entry->get_peer_nli()) 
233            ip_ttl = r_entry->get_peer_nli()->get_ip_ttl();
234  }
235
236  if (nlinfo && peer->get_ip_ttl()) 
237  {
238    ip_distance = ip_ttl - peer->get_ip_ttl();
239  } 
240  else 
241  {
242    if (r_entry && peer->get_ip_ttl()) {
243            ip_distance = r_entry->get_peer_nli()->get_ip_ttl() - peer->get_ip_ttl();
244    }
245  }
246
247  msg->set_recvmessage(senddata, own_addr->copy(), pdu->get_nslpid(), new sessionid(*(pdu->get_sessionid())), mymr, false, sii_handle, myattr, ip_ttl, ip_distance, pdu->get_hops(), r_entry ? r_entry->get_incoming_if() : 0 );
248   
249  msg->send_to(param.nslptable.get_address(pdu->get_nslpid()));
250
251  DLog(param.name, "Message passed to NSLP instance at address "
252       << param.nslptable.get_address(pdu->get_nslpid()));
253}
254
255
256
257
258/**
259 * Deliver received data to NSLP instance and set adjacency check flag
260 * @param peer -- the peer from which we received the data
261 * @param own_addr -- the IP address of the interface we received the data on
262 * @param pdu -- the pdu containing the data (may NOT be NULL)
263 * @param r_entry -- the routing entry itself
264 */
265void
266Statemodule::deliver_adjacency_flag(const appladdress* peer, const appladdress* own_addr, const known_ntlp_pdu* pdu, const routingentry* r_entry) 
267{
268  APIMsg* msg = new APIMsg;
269
270  nslpdata* mydata = pdu->get_nslpdata();
271
272 
273  if( pdu->get_mri() == NULL )
274  {
275          // at this stage it is not possible that an MRI in the PDU is missing since it should have
276          // been checked twice, i.e., during parsing and in ntlp_statemodule_main
277          ERRCLog("statemodule","deliver_adjacency_flag(): PDU contains no MRI, which is required though. This should not happen and is an internal error.");
278          return;
279  }
280 
281  nattraversal* nattravobj= pdu->get_nattraversal(); 
282  mri* pdumri= pdu->get_mri()->copy();
283  // use MRI from NTO if present
284  mri* ntomri= nattravobj ? nattravobj->get_embedded_mri()->copy() : 0;
285       
286  tx_attr_t myattr;
287       
288  if (r_entry) {
289          myattr.secure= r_entry->is_secure();
290          myattr.reliable=!(r_entry->is_dmode());
291  } else {
292    // Initial Query/Initial Confirm, D-Mode, unsecure
293    myattr.secure= false;
294    myattr.reliable= false;
295  }
296
297  // check for final hop, same as in Statemodule::deliver()
298  // this must be done using the outer flow destination address
299  if ( pdumri->get_downstream() )
300    myattr.final_hop = is_local_address(pdumri->get_destaddress());
301  else
302    myattr.final_hop = is_local_address(pdumri->get_sourceaddress());
303
304  DLog("statemodule", "GIST node is the final hop: " << myattr.final_hop);
305
306  nslpdata* senddata = NULL;
307
308  if (mydata) senddata = new nslpdata(*mydata);
309
310  uint8 ip_distance = 0;
311  // if we can do distance calculation, DO IT!
312  if (peer->get_ip_ttl()) {
313    if (pdu->get_nli()) {
314      ip_distance = pdu->get_nli()->get_ip_ttl() - peer->get_ip_ttl();
315    }
316  }
317
318  // TODO: for MA setup only
319  msg->set_recvmessage(senddata, own_addr->copy(), 
320                       pdu->get_nslpid(), 
321                       pdu->get_sessionid()->copy(), 
322                       ntomri ? ntomri : pdumri,  // use MRI from NAT traversal object if present
323                       true, 0, myattr, 
324                       pdu->get_nli()->get_ip_ttl(), 
325                       ip_distance, 
326                       pdu->get_hops(), 
327                       r_entry ? r_entry->get_incoming_if() : 0 );
328   
329  msg->send_to(param.nslptable.get_address(pdu->get_nslpid()));
330
331  DLog(param.name, "Message passed to NSLP instance at address "<< param.nslptable.get_address(pdu->get_nslpid()));
332}
333
334
335/**
336 * Notify NSLP via NetworkNotification about Changes, store state in r_entry (esentially, give MRI, SII-Handle and state)
337 * @param r_key -- the routing key (may NOT be NULL)
338 * @param r_entry -- the routing entry itself (may NOT be NULL)
339 * @param status -- the Status to report to NSLP
340 * @param force -- force notification, even if the same status was rported before (used on rerouting events)
341 */
342void 
343Statemodule::networknotification(const routingkey* r_key, routingentry* r_entry, APIMsg::error_t status, bool force) {
344  if ((r_entry->get_errstate() != status) || force) 
345  {
346    // save the change
347    r_entry->set_errstate(status);
348       
349    mri* mymri = r_key->mr->copy();
350    APIMsg* msg = new APIMsg;
351       
352    sessionid* mysid = r_key->sid->copy();
353   
354    msg->set_source(message::qaddr_coordination);
355       
356    msg->set_networknotification(r_key->nslpid, mysid, mymri, status, r_entry->get_sii_handle());
357       
358    msg->send_to(param.nslptable.get_address(r_key->nslpid));
359       
360    EVLog(param.name, color[yellow] << "NetworkNotification passed to NSLP instance at address "<< param.nslptable.get_address(r_key->nslpid) << ": " << msg->get_error_str(status) << color[off]);
361  } else {
362    DLog(param.name, color[yellow] << "Routing State unchanged, no need to notify NSLP" << color[off]);
363  }
364}
365
366
367/**
368 * Notify NSLP via MessageStatus about Message Failures
369 * @param r_key -- the routing key (may NOT be NULL)
370 * @param r_entry -- the routing entry itself (may NOT be NULL)
371 * @param nslpmsghandle -- the Msg Handle of the message referred to
372 * @param status -- the status to report
373 */
374void 
375Statemodule::messagestatus(const routingkey* r_key, routingentry* r_entry, msghandle_t nslpmsghandle, APIMsg::error_t status) {
376 
377  APIMsg* msg = new APIMsg;
378
379  msg->set_source(message::qaddr_coordination);
380   
381  tx_attr_t txattr;
382  txattr.secure=r_entry->is_secure();
383  txattr.reliable=!r_entry->is_dmode();
384  txattr.final_hop = false; // meaningless in this context
385
386  sessionid *sid = NULL;
387  if ( r_key->sid != NULL )
388    sid = r_key->sid->copy(); // ApiMsg's destructor will delete it
389
390  msg->set_messagestatus(r_key->nslpid, sid, nslpmsghandle, txattr, status);
391
392  msg->send_to(param.nslptable.get_address(r_key->nslpid));
393   
394  EVLog(param.name, color[yellow] << "MessageStatus passed to NSLP instance at address "<< param.nslptable.get_address(r_key->nslpid) << ": " << msg->get_error_str(status) << color[yellow]);
395
396}
397
398
399/**
400 * SendMessage API Call processing, set up state or send via existing state a GIST Data
401 * @param apimsg -- the API message from caller containing all data we need
402 */
403void 
404Statemodule::tg_send_message(APIMsg* apimsg) 
405{
406  assert(apimsg != NULL);
407
408  if (!apimsg->get_mri()) 
409  {
410    ERRCLog(param.name, "SendMessage Call without given MRI");
411    return;
412  }
413
414  bool explicit_routed = false;
415
416  if (apimsg->get_sii_handle()) 
417  {
418    DLog("param.name", "Got an explicit routing request, using entry derived from SII-Handle");
419    explicit_routed = true;
420  }
421
422  transfer_t transtype;
423 
424  // if MRI contains IPv4 and IPv6 mix, we bail out and inform via LOG entry. This is the NSLP's fault and an error
425  hostaddress src = apimsg->get_mri()->get_sourceaddress();
426  hostaddress dst = apimsg->get_mri()->get_destaddress();
427
428  if (src.is_ipv6() != dst.is_ipv6()) 
429  {
430    ERRCLog(param.name, "MRI of API call contains mixed IPv4/IPv6 addresses, dropping");
431    delete apimsg;
432    return;
433  }
434   
435  // print some info
436  DLog(param.name, color[yellow] << "IP TTL: " << apimsg->get_ip_ttl() << " GHC: " << apimsg->get_ghc() << color[off]);
437   
438  // 1st step: Look for Routing State
439   
440  routingentry* r_entry=NULL;
441   
442  // create a new routingkey, this will in the end given to timermessage, a copy is stored in routingtable
443  routingkey* r_key=new routingkey();
444   
445  r_key->mr=(apimsg->get_mri())->copy();
446  r_key->sid=new sessionid(*(apimsg->get_sessionid()));
447  r_key->nslpid=apimsg->get_nslpid();
448   
449  //DLog(param.name, "Routing map key created from API Message for NSLPID " << r_key->nslpid);
450   
451  //r_key->mr->print(cout, 0, 0);
452  //r_key->sid->print(cout, 0, 0);
453   
454   
455  //=======================================================
456  // look up routing state and print a status dump of routing table
457  //=======================================================
458  param.rt.status();
459 
460  // try to do explicit routing and return
461  if (explicit_routed) 
462  {
463    DLog(param.name, "Explicit Routing requested");
464       
465    send_data_explicit(apimsg);
466       
467//    delete apimsg;
468    return;
469  } 
470     
471  DLog(param.name, "No explicit routing, try to look up the normal way");
472  // look up routing state in routing map. If there is none, r_entry remains NULL
473  r_entry=param.rt.lookup(r_key);
474
475  // 2nd step: Consider which type of transmit is needed for the message
476   
477  // look for nslp data payload size, decide initially between C- and D-Mode
478  if (!apimsg->get_data()) 
479  {
480    ERRCLog(param.name, "No Data Payload in SendMessage. We will not process this further");
481    delete apimsg;
482    if (r_entry)
483      param.rt.unlock(r_key);
484    return;
485  }
486
487  // look for GIST Hop Count
488  // Sec. 4.3.3.: GIST MUST reject messages for which the signalling application
489  // has specified a value of zero.
490  if (apimsg->get_ghc() == 0)
491  {
492    ERRCLog(param.name, "Not allowed to send messages with GIST Hop Count = 0. We will not process this further.");
493    delete apimsg;
494    if (r_entry)
495      param.rt.unlock(r_key);
496    return;
497  }
498
499  // check whether fragmentation is required
500  transtype= (apimsg->get_data()->get_size() > MAX_NSLP_PAYLOAD) ? tx_cmode : tx_dmode;
501   
502  // look if we were asked to transfer reliable -> C-Mode instead of DMode
503  if (apimsg->get_tx_attr().reliable) transtype=tx_cmode;
504   
505  // look if we were asked to transfer secure -> Secure C-Mode
506  if (apimsg->get_tx_attr().secure) transtype=tx_cmode_sec;
507   
508  // if we have no routing state we must change our attitude and consider transfer change based on that
509  if (!r_entry) 
510  {
511    // if we can transfer the data in D-Mode, we can transfer queryencapsulated, else we have to queue
512    // the data and set up C-Mode (sec/unsec) prior to be able to send it.
513    if (transtype==tx_dmode) 
514    { 
515      // Here we can send QueryEncapsulated and set up our local state in "awaiting response", as we use only D-Mode
516      DLog(param.name, "No Routing State - Sending Payload Query Encapsulated (in a QUERY), creating local routing state in 'qn_awaiting_response' mode");
517           
518      // create new routingentry (as a querier)
519      r_entry= new routingentry(false);
520      if (param.addresses.addr_is(src, AddressList::HomeAddr_P)) {
521        r_entry->set_local_src(src);
522      } else {
523        DLog(param.name, "APImsg source address: " << src << " (is HA: "
524                         << param.addresses.addr_is(src, AddressList::HAAddr_P) << ")");
525        uint32_t pref = IPV6_PREFER_SRC_COA;
526        hostaddress *laddr = param.addresses.get_src_addr(dst, &pref);
527        DLog(param.name, "Considering local address: " << *laddr << " (is HA: "
528                         << param.addresses.addr_is(*laddr, AddressList::HAAddr_P)  << ")");
529        if (param.addresses.addr_is(*laddr, AddressList::HAAddr_P)) {
530          laddr = param.addresses.get_first(AddressList::AltHAAddr_P, src.is_ipv4());
531          DLog(param.name, "Using alternative home agent address: " << *laddr);
532        } else {
533          if (! param.addresses.addr_is(*laddr, AddressList::ConfiguredAddr_P)) {
534            DLog(param.name, "Address " << *laddr << " is not configured for GIST");
535            if (param.addresses.addr_is(src, AddressList::ConfiguredAddr_P)) {
536              DLog(param.name, "but APImsg source address " << src << " is configured for GIST");
537              laddr = new netaddress(src);
538            }
539          }
540        }
541        DLog(param.name, "Selected local address: " << *laddr << " (is HA: "
542                         << param.addresses.addr_is(*laddr, AddressList::HAAddr_P)  << ")");
543        //cout << *laddr << endl;
544        r_entry->set_local_src(*laddr);
545        delete laddr;
546      }
547
548      apimsg->set_local_addr(r_entry->get_local_src()->copy());
549
550      // set it to qn_awaiting_response
551      r_entry->set_state(qn_awaiting_response);
552     
553      // save IP TTL for Query Repetitions (NSLP gives us the IP TTL value)
554      r_entry->set_ip_ttl(apimsg->get_ip_ttl());
555     
556      // save GIST Hop count for Query Repetitions (NSLP gives us the hop count value)
557      r_entry->set_gist_hop_count(apimsg->get_ghc());
558     
559      // set D-Mode unsecure (we set it here, so we remember it when processing response)
560      r_entry->set_dmode(true);
561      r_entry->set_secure(false);
562     
563      // set local default RS_Validity Time
564      r_entry->set_rs_validity_time(gconf.getpar<uint32>(gistconf_rs_validity_time));
565     
566      // initiate sending the Query
567      send_query(apimsg,r_key,r_entry);
568
569      // start NoResponse timer
570      starttimer(r_key, r_entry, noresponse, 0, r_entry->reset_retry_timeout());
571           
572      // add routing state
573      param.rt.add(r_key, r_entry);
574    } 
575    else 
576    { // Routing State Setup with Message Association
577      DLog(param.name, "No Routing State - 'Reliable' or 'Secure' requested, queueing data, initiating C-Mode setup, creating local routing state in 'qn_awaiting_response' mode");
578           
579      // create new routingentry (as querier)
580      r_entry= new routingentry(false);
581      if (param.addresses.addr_is(src, AddressList::HomeAddr_P)) {
582        r_entry->set_local_src(src);
583      } else {
584        uint32_t pref = IPV6_PREFER_SRC_COA;
585        hostaddress *laddr = param.addresses.get_src_addr(dst, &pref);
586        r_entry->set_local_src(*laddr);
587      }
588
589      apimsg->set_local_addr(r_entry->get_local_src()->copy());
590   
591      // set it to qn_awaiting_response
592      r_entry->set_state(qn_awaiting_response);
593           
594      // set C-Mode (we set it here, so we remember it when processing response)
595      r_entry->set_cmode();
596           
597      // save IP TTL for Query Repetitions (NSLP gives us the IP TTL value)
598      r_entry->set_ip_ttl(apimsg->get_ip_ttl());
599
600      // set security option in local state, so we choose a secure protocol if needed when processing response
601      r_entry->set_secure((transtype==tx_cmode) ? false : true);
602
603      // set local Default RS_Validity Time
604      r_entry->set_rs_validity_time(gconf.getpar<uint32>(gistconf_rs_validity_time));
605           
606      // send a Query requesting handshake, this will NOT transfer data payload!
607      send_query_handshake(apimsg, r_key, r_entry);
608               
609      // start NoResponse timer
610      starttimer(r_key, r_entry, noresponse, 0, r_entry->reset_retry_timeout());
611           
612      // Here we enqueue the data
613      enqueuedata(r_key, r_entry, apimsg->get_data(), apimsg->get_timeout(), apimsg->get_nslpmsghandle());
614           
615      // add routing state
616      param.rt.add(r_key, r_entry);
617    }
618  } // endif no routing state exists
619  else 
620  { // routing state exists already
621    // save GIST Hop count for Query Repetitions (NSLP gives us the hop count value)
622    r_entry->set_gist_hop_count(apimsg->get_ghc());
623       
624    // save IP TTL for any Messages sent on behalf of this SendMessage
625    r_entry->set_ip_ttl(apimsg->get_ip_ttl());
626
627    apimsg->set_local_addr(r_entry->get_local_src()->copy());
628       
629    switch (r_entry->get_state())
630    {
631      // there is a handshake in progress, we must queue the data
632      case rn_awaiting_confirm:
633      case qn_awaiting_response: 
634        {
635       
636          ERRCLog(param.name, "Routing State available - Handshake in progress, queueing data");
637          enqueuedata(r_key, r_entry, apimsg->get_data(), apimsg->get_timeout(), apimsg->get_nslpmsghandle());
638          break;
639        }
640
641        // Routing State is established. However we must decide if it suits our transfer requirements   
642      case qn_awaiting_refresh:
643      case rn_awaiting_refresh:
644      case rn_established:
645      case qn_established: 
646        {
647          mcast_peer_list_t::const_iterator mcast_peer_it = r_entry->get_multicast_peers()->begin();
648          const nli* peer_nli = r_entry->is_multicast_QNode() ? &mcast_peer_it->first : r_entry->get_peer_nli();
649          assert(peer_nli);
650          while (peer_nli) {
651          // if it is set up in D-Mode and MA re-use not requested
652          if (r_entry->is_dmode() && (r_entry->is_ma_reuse_requested(peer_nli) == false)) 
653          {
654            // if transfer type is dmode -> OK, send in D-MODE
655            if (transtype==tx_dmode) 
656            {
657              DLog(param.name, "Routing State set up in D-Mode, this suits, we send data Message in D-Mode");
658              send_data_dmode(apimsg->get_data(), r_key, r_entry, apimsg->get_nslpid(), peer_nli);
659            }
660                   
661            // if transfer type is something else -> New Handshake required
662            if (transtype!=tx_dmode) 
663            {
664              DLog(param.name, "Routing State set up in D-Mode, however, we need to use C-Mode, so we enqueue the data and prepare a new handshake.");
665                       
666              if (r_entry->get_state() == qn_established) 
667              {
668                DLog(param.name, color[red] << "Upgrading to C-Mode from Querier side" << color[off]);
669                           
670                if (apimsg->get_data()) 
671                {
672                  enqueuedata(r_key, r_entry, apimsg->get_data(), apimsg->get_timeout(), apimsg->get_nslpmsghandle());
673                  DLog(param.name, color[red] << "Enqueued data payload" << color[off]);       
674                }
675                           
676                r_entry->set_state(qn_awaiting_response);
677                r_entry->set_dmode(false);  // was !(apimsg->get_tx_attr().reliable); unreliabe but secure currently not supported
678                r_entry->set_secure(apimsg->get_tx_attr().secure);
679
680                // start NoResponse timer
681                starttimer(r_key, r_entry, noresponse, 0, r_entry->reset_retry_timeout());
682                           
683              } // if state established
684            }
685          } // endif D-Mode
686          else 
687          { // C-Mode or MA re-use desired
688
689            // if transfer type is dmode -> Transfer in C-Mode instead
690            if (transtype==tx_dmode) 
691            {
692              DLog(param.name, "Routing State set up in C-Mode, we use it however it was not required.");
693              send_data_cmode(apimsg->get_data(), r_key, r_entry, apimsg->get_nslpmsghandle(), peer_nli);
694            }
695                   
696            // if transfer type is cmode -> OK, send in C-Mode
697            if (transtype==tx_cmode) 
698            {
699              DLog(param.name, "Routing State set up in C-Mode, we use it as it was required.");
700              send_data_cmode(apimsg->get_data(), r_key, r_entry, apimsg->get_nslpmsghandle(), peer_nli);
701            }
702                   
703            // if set up cmode with security and transfer type is cmode_sec -> OK, send in C-Mode
704            if (r_entry->is_secure() && (transtype==tx_cmode_sec)) 
705            {
706              DLog(param.name, "Routing State set up in C-Mode with security, we use it.");
707              send_data_cmode(apimsg->get_data(), r_key, r_entry, apimsg->get_nslpmsghandle(), peer_nli);
708            }
709                   
710            // if set up cmode without security and transfer type is cmode_sec -> Bad, queue and re-initiate
711            if (!r_entry->is_secure() && (transtype==tx_cmode_sec)) 
712            {
713              DLog(param.name, "Routing State currently in C-Mode without security, queueing data and initiating secure C-Mode setup.");
714                   
715              if (apimsg->get_data()) 
716              {
717                enqueuedata(r_key, r_entry, apimsg->get_data(), apimsg->get_timeout(), apimsg->get_nslpmsghandle());
718                DLog(param.name, color[red] << "Enqueued data payload" << color[off]); 
719              }
720                           
721              r_entry->set_state(qn_awaiting_response);
722
723              r_entry->set_dmode(false); // unreliable but secure currently not supported
724              r_entry->set_secure(apimsg->get_tx_attr().secure);
725
726              // start NoResponse timer
727              starttimer(r_key, r_entry, noresponse, 0, r_entry->reset_retry_timeout());
728                       
729            } // endif set up cmode without security and transfer type is cmode_sec
730          } // endif C-Mode or MA re-use desired
731          if (r_entry->is_multicast_QNode()) {
732            // iterate to next NLI
733            mcast_peer_it++;
734            peer_nli = mcast_peer_it == r_entry->get_multicast_peers()->end() ? NULL : &mcast_peer_it->first;
735          } else { // terminate while-loop in unicast case
736            peer_nli = NULL;
737          }
738          } // while peer_nli
739          break;
740        } // end case
741               
742      case dead: 
743        {
744          DLog(param.name, "Encountered Request to send data for DEAD Routing State, this is possible via explicit routing, only D-Mode possible");
745               
746          send_data_dmode(apimsg->get_data(), r_key, r_entry, apimsg->get_nslpid());
747          break;
748        }
749               
750      default: 
751        { 
752                ERRCLog(param.name, "Routing State available - Invalid State " << r_entry->get_state());
753                break;
754        }               
755    } // end switch
756  } // end else routing state exists already
757  param.rt.unlock(r_key);
758}
759
760
761/**
762 * RecvMessageAnswer API Call: set up state backwards or relay the received message on behalf of NSLP
763 * @param apimsg -- the API message from caller containing all data we need
764 */
765void 
766Statemodule::tg_recv_message_answer(APIMsg* apimsg) 
767{
768  assert(apimsg != NULL);
769   
770  // Here we initiate backwards routing state (install state and send response)
771  // or we relay the message (not yet implemented)
772   
773  // 1st step: Look for Routing State
774   
775  routingentry* r_entry=NULL;
776   
777  // create a new routinkey
778  routingkey* r_key= new routingkey();
779  r_key->mr=  (apimsg->get_mri())->copy();
780  r_key->sid= new sessionid(*(apimsg->get_sessionid()));
781  r_key->nslpid= apimsg->get_nslpid();
782   
783  //=======================================================
784  // look up routing state and print a status dump of routing table
785  //=======================================================
786   
787  // we communicated via uninverted MRI with API client!
788  // but status is saved with inverted MRI!
789  r_key->mr->invertDirection();
790   
791  r_entry=param.rt.lookup(r_key);
792   
793  if (!r_entry) 
794  {
795    ERRCLog(param.name, "Cannot find routing state for RecvMessageAnswer. Ignoring API call.");
796    // apimsg will be deleted in calling method anyway
797    return;
798  }
799
800  // do something in case of Routing State in rn_querynslp
801  if (r_entry->get_state() == rn_querynslp) 
802  {
803    DLog(param.name, "State in RN_QUERYNSLP");
804       
805    // take the saved PDU, remove it from entry
806    known_ntlp_pdu* reqpdu = r_entry->deliver_tmppdu();
807       
808    if (!reqpdu) 
809      ERRCLog(param.name, "There should be a saved PDU but there isn't!");
810       
811    // take the saved Peer
812    appladdress* peer = r_entry->deliver_tmppeer();
813       
814    if (!peer) 
815      ERRCLog(param.name, "There should be a saved Peer address but there isn't!");
816       
817    // decide what to do
818    if (apimsg->get_directive() == APIMsg::directive_establish) 
819    {
820      // save data payload in entry, for repetitions of responses
821      if (apimsg->get_data()) 
822              r_entry->set_mod_data(apimsg->get_data());
823           
824      //##############################################################
825      // State setup
826      //##############################################################
827           
828      DLog(param.name, "Dispatching GIST Response");
829      send_response(reqpdu, r_key, r_entry, peer);
830           
831      // do we enforce late state installation?
832      if ( gconf.getpar<bool>(gistconf_latestate) )
833      {
834        DLog(param.name, "Late state installation configured, no state is saved");                 
835        param.rt.destroy_entry(r_key);
836
837        r_key= 0;
838        //param.rt.delete_entry(r_key);
839      } 
840      else 
841      {
842        DLog(param.name, "Immediate state installation configured, set up state");
843               
844        r_entry->set_rs_validity_time(gconf.getpar<uint32>(gistconf_rs_validity_time));
845       
846        // put in state "rn_established"
847        if ( gconf.getpar<bool>(gistconf_confirmrequired) == false ) 
848        {
849          DLog(param.name, "No full handshake is configured, state set up");
850                   
851          // install Routing State
852          if (!r_entry->is_dmode()) 
853          {
854            // install Routing State, note that add_ma will store the address as IPv6
855                  param.rt.add_ma(r_entry->get_peer_nli()->copy(), *peer, r_entry->get_ma_hold_time(), true);
856          }
857          networknotification(r_key, r_entry, APIMsg::route_changed_status_good, false);
858                   
859          r_entry->set_state(rn_established);
860          // Start Expire_RNode timer!
861          starttimer(r_key, r_entry, expire_rnode, 0, r_entry->get_rs_validity_time());
862                   
863          // set retry timeout back to default
864          r_entry->reset_retry_timeout();
865                   
866          // check and restart downstream Refresh_QNode timer if necessary
867          check_refresh_timer(r_key);
868        } 
869        else 
870        {
871          DLog(param.name, "Full handshake is configured, waiting for GIST Confirm");
872          r_entry->set_state(rn_awaiting_confirm);
873                   
874          starttimer(r_key, r_entry, noconfirm, 0, r_entry->reset_retry_timeout());
875        }
876      } //end if param.latestate (else)
877    } 
878    else 
879    {
880      //************************************************************
881      // Relay on NSLP's order
882      //************************************************************
883           
884      EVLog(param.name, "NSLP told us to relay only");
885           
886      nslpdata* mydata=apimsg->get_data();
887      if (mydata) 
888      {
889        DLog(param.name, "NSLP provided data for relaying");
890        reqpdu->set_data(mydata->copy());
891      }
892           
893      mri* mymri=reqpdu->get_mri();
894      nli* mynli=reqpdu->get_nli();
895           
896      // this cannot happen, if everything is all right
897      assert(mymri != NULL);
898      assert(mynli != NULL);
899           
900      appladdress* peer = mymri->determine_dest_address();
901      DLog(param.name, "Constructed target address for relaying");
902           
903      if (SignalingNTLP::is_local_addr(peer)) 
904      {
905        ERRCLog(param.name, "NSLP told us to relay, but we are the end");
906        ERRCLog(param.name, "Sending Error Message is redundant, as we would send it to ourself.");
907        // apimsg will be deleted in calling method anyway
908       
909        if (r_entry)
910          param.rt.unlock(r_key);
911        delete apimsg;
912        return;
913      }
914
915      peer->set_ip_ttl(mynli->get_ip_ttl());
916      DLog(param.name, "Set IP TTL of target address to the one in the original NLI");
917           
918      peer->set_rao(param.rt.get_rao(r_key->nslpid));
919      DLog(param.name, "Set RAO value to the one of the NSLP (we know it for sure)");
920
921      // send it to signaling
922      SignalingMsgNTLP* sigmsg = new SignalingMsgNTLP;
923      sigmsg->set_local_addr(r_entry->get_local_src()->copy());
924      sigmsg->set_req(peer, reqpdu);
925      sigmsg->send_or_delete();
926     
927      param.rt.destroy_entry(r_key);
928
929      DLog(param.name, "Message sent to signaling for Relaying");
930      if (r_key) delete r_key;
931      r_key= 0;
932    }
933  } // end if state==rn_querynslp
934   
935  if (r_key) param.rt.unlock(r_key);
936}
937
938//@}
939
940} // end namespace ntlp
Note: See TracBrowser for help on using the repository browser.