void Casan::send_discover (Msg &out) { char tmpstr [CASAN_BUF_LEN] ; l2addr *dest ; DBGLN1 (F ("Sending Discover")) ; out.reset () ; out.set_id (curid_++) ; out.set_type (COAP_TYPE_NON) ; out.set_code (COAP_CODE_POST) ; mk_ctl_msg (out) ; snprintf (tmpstr, sizeof tmpstr, CASAN_DISCOVER_SLAVEID, slaveid_) ; option o1 (option::MO_Uri_Query, tmpstr, strlen (tmpstr)) ; out.push_option (o1) ; snprintf (tmpstr, sizeof tmpstr, CASAN_DISCOVER_MTU, (long int) defmtu_) ; option o2 (option::MO_Uri_Query, tmpstr, strlen (tmpstr)) ; out.push_option (o2) ; dest = (master_ != NULL) ? master_ : l2_->bcastaddr () ; out.send (*dest) ; }
void Casan::check_observed_resources (Msg &out) { Resource *res ; reslist *rl ; for (rl = reslist_ ; rl != NULL ; rl = rl->next) { res = rl->res ; if (res->check_trigger ()) { DBG1 (F (B_BLUE "Observed resource '")) ; DBG1 (rl->res->name ()) ; DBG1 (F ("' triggered" C_RESET)) ; DBGLN0 () ; out.reset () ; out.set_type (COAP_TYPE_ACK) ; out.set_token (res->get_token ()) ; out.set_id (curid_++) ; out.set_code (COAP_CODE_OK) ; option obs (option::MO_Observe, res->next_serial ()) ; out.push_option (obs) ; request_resource (NULL, &out, res) ; out.send (*master_) ; } } }
void Casan::mk_ctl_msg (Msg &out) { int i ; for (i = 0 ; i < NTAB (casan_namespace) ; i++) { option path (option::MO_Uri_Path, (void *) casan_namespace [i].path, casan_namespace [i].len) ; out.push_option (path) ; } }
void Casan::loop () { Msg in (l2_) ; Msg out (l2_) ; l2net::l2_recv_t ret ; uint8_t oldstatus ; long int hlid ; l2addr *srcaddr ; int mtu ; // mtu announced by master in assoc msg oldstatus = status_ ; // keep old value for debug display sync_time (curtime) ; // get current time retrans_.loop (*l2_, curtime) ; // check needed retransmissions srcaddr = NULL ; ret = in.recv () ; // get received message if (ret == l2net::RECV_OK) srcaddr = l2_->get_src () ; // get a new address switch (status_) { case SL_COLDSTART : send_discover (out) ; twait_.init (curtime) ; status_ = SL_WAITING_UNKNOWN ; break ; case SL_WAITING_UNKNOWN : if (ret == l2net::RECV_OK) { retrans_.check_msg_received (in) ; if (is_ctl_msg (in)) { if (is_hello (in, hlid)) { DBGLN1 (F ("Received a CTL HELLO msg")) ; change_master (hlid, -1) ; // don't change mtu twait_.init (curtime) ; status_ = SL_WAITING_KNOWN ; } else if (is_assoc (in, sttl_, mtu)) { DBGLN1 (F ("Received a CTL ASSOC msg")) ; change_master (-1, mtu) ; // "unknown" hlid send_assoc_answer (in, out) ; trenew_.init (curtime, sttl_) ; status_ = SL_RUNNING ; } else DBGLN1 (F (RED ("Unkwnon CTL"))) ; } } if (status_ == SL_WAITING_UNKNOWN && twait_.next (curtime)) send_discover (out) ; break ; case SL_WAITING_KNOWN : if (ret == l2net::RECV_OK) { retrans_.check_msg_received (in) ; if (is_ctl_msg (in)) { if (is_hello (in, hlid)) { DBGLN1 (F ("Received a CTL HELLO msg")) ; change_master (hlid, -1) ; // don't change mtu } else if (is_assoc (in, sttl_, mtu)) { DBGLN1 (F ("Received a CTL ASSOC msg")) ; change_master (-1, mtu) ; // unknown hlid send_assoc_answer (in, out) ; trenew_.init (curtime, sttl_) ; status_ = SL_RUNNING ; } else DBGLN1 (F (RED ("Unkwnon CTL"))) ; } } if (status_ == SL_WAITING_KNOWN) { if (twait_.expired (curtime)) { reset_master () ; // master_ is no longer known send_discover (out) ; twait_.init (curtime) ; // reset timer status_ = SL_WAITING_UNKNOWN ; } else if (twait_.next (curtime)) { send_discover (out) ; } } break ; case SL_RUNNING : case SL_RENEW : if (ret == l2net::RECV_OK) { retrans_.check_msg_received (in) ; if (is_ctl_msg (in)) { if (is_hello (in, hlid)) { DBGLN1 (F ("Received a CTL HELLO msg")) ; if (! same_master (srcaddr) || hlid != hlid_) { int oldhlid = hlid_ ; change_master (hlid, 0) ; // reset mtu if (oldhlid != -1) { twait_.init (curtime) ; status_ = SL_WAITING_KNOWN ; } } } else if (is_assoc (in, sttl_, mtu)) { DBGLN1 (F ("Received a CTL ASSOC msg")) ; if (same_master (srcaddr)) { negociate_mtu (mtu) ; send_assoc_answer (in, out) ; trenew_.init (curtime, sttl_) ; status_ = SL_RUNNING ; } } else DBGLN1 (F (RED ("Unkwnon CTL"))) ; } else // request for a normal resource { // deduplicate () ; process_request (in, out) ; out.send (*master_) ; } } else if (ret == l2net::RECV_TRUNCATED) { DBGLN1 (F (RED ("Request too large"))) ; out.set_type (COAP_TYPE_ACK) ; out.set_id (in.get_id ()) ; out.set_token (in.get_token ()) ; option o (option::MO_Size1, l2_->mtu ()) ; out.push_option (o) ; out.set_code (COAP_CODE_TOO_LARGE) ; out.send (*master_) ; } check_observed_resources (out) ; if (status_ == SL_RUNNING && trenew_.renew (curtime)) { send_discover (out) ; status_ = SL_RENEW ; } if (status_ == SL_RENEW && trenew_.next (curtime)) { send_discover (out) ; } if (status_ == SL_RENEW && trenew_.expired (curtime)) { reset_master () ; // master_ is no longer known send_discover (out) ; twait_.init (curtime) ; // reset timer status_ = SL_WAITING_UNKNOWN ; } break ; default : DBGLN1 (F ("Error : casan status not known")) ; DBGLN1 (status_) ; break ; } if (oldstatus != status_) { DBG1 (F ("Status: " C_GREEN)) ; print_status (oldstatus) ; DBG1 (F (C_RESET " -> " C_GREEN)) ; print_status (status_) ; DBGLN1 (F (C_RESET)) ; } if (srcaddr != NULL) delete srcaddr ; }
void Casan::process_request (Msg &in, Msg &out) { option *o ; bool rfound = false ; // resource found in.reset_next_option () ; for (o = in.next_option () ; o != NULL ; o = in.next_option ()) { if (o->optcode () == option::MO_Uri_Path) { // request for all resources if (o->optlen () == (int) (sizeof CASAN_RESOURCES_ALL - 1) && memcmp (o->optval ((int *) 0), CASAN_RESOURCES_ALL, sizeof CASAN_RESOURCES_ALL - 1) == 0) { rfound = true ; out.set_type (COAP_TYPE_ACK) ; out.set_id (in.get_id ()) ; out.set_token (in.get_token ()) ; out.set_code (COAP_CODE_OK) ; (void) get_well_known (out) ; } else { Resource *res ; // we benefit from the added '\0' at the end of an option res = get_resource ((char *) o->optval ((int *) 0)) ; if (res != NULL) { option *obs ; uint32_t obsval ; rfound = true ; obs = in.search_option (option::MO_Observe) ; if (obs != NULL) obsval = obs->optval () ; if (obs != NULL && obsval == 0) res->observed (true, &in) ; else res->observed (false, NULL) ; out.set_type (COAP_TYPE_ACK) ; out.set_id (in.get_id ()) ; out.set_token (in.get_token ()) ; if (obs != NULL && obsval == 0) { option robs (option::MO_Observe, res->next_serial ()) ; out.push_option (robs) ; } request_resource (&in, &out, res) ; } } break ; } } if (! rfound) { out.set_type (COAP_TYPE_ACK) ; out.set_id (in.get_id ()) ; out.set_token (in.get_token ()) ; out.set_code (COAP_CODE_NOT_FOUND) ; } }