smcp_status_t smcp_plat_process(smcp_t self) { SMCP_EMBEDDED_SELF_HOOK; if (!uip_udpconnection()) { goto bail; } if (uip_udp_conn != smcp_plat_get_udp_conn(smcp)) { goto bail; } if(uip_newdata()) { memcpy(&self->plat.sockaddr_remote.smcp_addr,&UIP_IP_BUF->srcipaddr,sizeof(smcp_addr_t)); self->plat.sockaddr_remote.smcp_port = UIP_UDP_BUF->srcport; memcpy(&self->plat.sockaddr_local.smcp_addr,&UIP_IP_BUF->destipaddr,sizeof(smcp_addr_t)); self->plat.sockaddr_local.smcp_port = UIP_UDP_BUF->destport; smcp_plat_set_session_type(SMCP_SESSION_TYPE_UDP); smcp_inbound_packet_process(smcp, uip_appdata, uip_datalen(), 0); } else if(uip_poll()) { smcp_set_current_instance(self); smcp_handle_timers(self); } bail: smcp_set_current_instance(NULL); self->is_responding = false; return 0; }
void smcp_handle_timers(smcp_t self) { SMCP_EMBEDDED_SELF_HOOK; smcp_set_current_instance(self); if (self->timers && (smcp_plat_timestamp_to_cms(self->timers->fire_date) <= 0) ) { SMCP_NON_RECURSIVE smcp_timer_t timer; SMCP_NON_RECURSIVE smcp_timer_callback_t callback; SMCP_NON_RECURSIVE void* context; timer = self->timers; callback = timer->callback; context = timer->context; DEBUG_PRINTF("Timer:%p(CTX=%p): Firing...",timer,timer->context); timer->cancel = NULL; smcp_invalidate_timer(self, timer); if (callback) { callback(self, context); } } #if SMCP_DEBUG_TIMERS smcp_dump_all_timers(self); #endif }
smcp_status_t smcp_outbound_begin( smcp_t self, coap_code_t code, coap_transaction_type_t tt ) { SMCP_EMBEDDED_SELF_HOOK; #if !SMCP_EMBEDDED if(!self) self = smcp_get_current_instance(); #endif check(!smcp_get_current_instance() || smcp_get_current_instance()==self); smcp_set_current_instance(self); #if SMCP_USE_BSD_SOCKETS self->outbound.packet = (struct coap_header_s*)self->outbound.packet_bytes; #elif CONTIKI uip_udp_conn = self->udp_conn; self->outbound.packet = (struct coap_header_s*)&uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN]; if(self->outbound.packet==self->inbound.packet) { self->outbound.packet = (struct coap_header_s*)&uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN + self->inbound.packet_len + 1]; } #else #warning WRITEME! #endif self->outbound.packet->tt = tt; self->outbound.packet->msg_id = self->outbound.next_tid; self->outbound.packet->code = code; self->outbound.packet->version = COAP_VERSION; // Set the token. if( self->is_processing_message && self->inbound.packet->token_len && code && tt != COAP_TRANS_TYPE_RESET ) { self->outbound.packet->token_len = self->inbound.packet->token_len; memcpy(self->outbound.packet->token,self->inbound.packet->token,self->outbound.packet->token_len); } else if(code && code<COAP_RESULT_100 && self->current_transaction) { // For sending a request. self->outbound.packet->token_len = sizeof(self->current_transaction->token); memcpy(self->outbound.packet->token,(void*)&self->current_transaction->token,self->outbound.packet->token_len); } else { self->outbound.packet->token_len = 0; } self->outbound.last_option_key = 0; self->outbound.content_ptr = (char*)self->outbound.packet->token + self->outbound.packet->token_len; *self->outbound.content_ptr++ = 0xFF; // Add end-of-options marker self->outbound.content_len = 0; self->force_current_outbound_code = false; self->is_responding = false; #if SMCP_USE_BSD_SOCKETS self->outbound.socklen = 0; #elif defined(CONTIKI) // Writeme! #endif return SMCP_STATUS_OK; }
smcp_status_t smcp_outbound_begin( smcp_t self, coap_code_t code, coap_transaction_type_t tt ) { smcp_status_t ret = SMCP_STATUS_FAILURE; SMCP_EMBEDDED_SELF_HOOK; check(!smcp_get_current_instance() || smcp_get_current_instance()==self); smcp_set_current_instance(self); #if SMCP_USE_CASCADE_COUNT require_action(self->cascade_count != 1, bail, ret = SMCP_STATUS_CASCADE_LOOP); #endif if (!self->is_processing_message) { smcp_plat_set_remote_sockaddr(NULL); smcp_plat_set_local_sockaddr(NULL); } self->outbound.max_packet_len = SMCP_MAX_PACKET_LENGTH; require_noerr((ret=smcp_plat_outbound_start(self,(uint8_t**)&self->outbound.packet,&self->outbound.max_packet_len)), bail); assert(NULL != self->outbound.packet); self->outbound.packet->tt = tt; self->outbound.packet->msg_id = self->outbound.next_tid; self->outbound.packet->code = code; self->outbound.packet->version = COAP_VERSION; // Set the token. if ( self->is_processing_message && self->inbound.packet != NULL && self->inbound.packet->token_len != 0 && code != COAP_CODE_EMPTY ) { self->outbound.packet->token_len = self->inbound.packet->token_len; memcpy(self->outbound.packet->token,self->inbound.packet->token,self->outbound.packet->token_len); } else if (code && (code < COAP_RESULT_100) && self->current_transaction) { // For sending a request. self->outbound.packet->token_len = sizeof(self->current_transaction->token); memcpy(self->outbound.packet->token,(void*)&self->current_transaction->token,self->outbound.packet->token_len); } else { self->outbound.packet->token_len = 0; } self->outbound.last_option_key = 0; self->outbound.content_ptr = (char*)self->outbound.packet->token + self->outbound.packet->token_len; *self->outbound.content_ptr++ = 0xFF; // start-of-content marker self->outbound.content_len = 0; self->force_current_outbound_code = false; self->is_responding = false; ret = SMCP_STATUS_OK; bail: return ret; }
smcp_status_t smcp_plat_process( smcp_t self ) { SMCP_EMBEDDED_SELF_HOOK; smcp_status_t ret = 0; int tmp; struct pollfd polls[4]; int poll_count; poll_count = smcp_plat_update_pollfds(self, polls, sizeof(polls)/sizeof(polls[0])); if (poll_count > (int)(sizeof(polls)/sizeof(*polls))) { poll_count = sizeof(polls)/sizeof(*polls); } errno = 0; tmp = poll(polls, poll_count, 0); // Ensure that poll did not fail with an error. require_action_string( errno == 0, bail, ret = SMCP_STATUS_ERRNO, strerror(errno) ); if(tmp > 0) { for (tmp = 0; tmp < poll_count; tmp++) { if (!polls[tmp].revents) { continue; } else { char packet[SMCP_MAX_PACKET_LENGTH+1]; smcp_sockaddr_t remote_saddr = {}; smcp_sockaddr_t local_saddr = {}; ssize_t packet_len = 0; char cmbuf[0x100]; struct iovec iov = { packet, SMCP_MAX_PACKET_LENGTH }; struct msghdr msg = { .msg_name = &remote_saddr, .msg_namelen = sizeof(remote_saddr), .msg_iov = &iov, .msg_iovlen = 1, .msg_control = cmbuf, .msg_controllen = sizeof(cmbuf), }; struct cmsghdr *cmsg; packet_len = recvmsg(polls[tmp].fd, &msg, 0); require_action(packet_len > 0, bail, ret = SMCP_STATUS_ERRNO); packet[packet_len] = 0; for ( cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg) ) { if (cmsg->cmsg_level != SMCP_IPPROTO || cmsg->cmsg_type != SMCP_PKTINFO ) { continue; } // Preinitialize some of the fields. local_saddr = remote_saddr; #if SMCP_BSD_SOCKETS_NET_FAMILY==AF_INET6 struct in6_pktinfo *pi = (struct in6_pktinfo *)CMSG_DATA(cmsg); local_saddr.smcp_addr = pi->ipi6_addr; local_saddr.sin6_scope_id = pi->ipi6_ifindex; #elif SMCP_BSD_SOCKETS_NET_FAMILY==AF_INET struct in_pktinfo *pi = (struct in_pktinfo *)CMSG_DATA(cmsg); local_saddr.smcp_addr = pi->ipi_addr; #endif local_saddr.smcp_port = htons(get_port_for_fd(polls[tmp].fd)); self->plat.pktinfo = *pi; } smcp_set_current_instance(self); smcp_plat_set_remote_sockaddr(&remote_saddr); smcp_plat_set_local_sockaddr(&local_saddr); if (self->plat.fd_udp == polls[tmp].fd) { smcp_plat_set_session_type(SMCP_SESSION_TYPE_UDP); ret = smcp_inbound_packet_process(self, packet, (coap_size_t)packet_len, 0); require_noerr(ret, bail); #if SMCP_DTLS } else if (self->plat.fd_dtls == polls[tmp].fd) { smcp_plat_set_session_type(SMCP_SESSION_TYPE_DTLS); smcp_plat_ssl_inbound_packet_process( self, packet, (coap_size_t)packet_len ); #endif } } } } smcp_handle_timers(self); bail: smcp_set_current_instance(NULL); self->is_responding = false; return ret; } smcp_status_t smcp_plat_lookup_hostname(const char* hostname, smcp_sockaddr_t* saddr, int flags) { smcp_status_t ret; struct addrinfo hint = { .ai_flags = AI_ADDRCONFIG, .ai_family = AF_UNSPEC, }; struct addrinfo *results = NULL; struct addrinfo *iter = NULL; #if SMCP_BSD_SOCKETS_NET_FAMILY != AF_INET6 hint.ai_family = SMCP_BSD_SOCKETS_NET_FAMILY; #endif if ((flags & (SMCP_LOOKUP_HOSTNAME_FLAG_IPV4_ONLY|SMCP_LOOKUP_HOSTNAME_FLAG_IPV6_ONLY)) == (SMCP_LOOKUP_HOSTNAME_FLAG_IPV4_ONLY|SMCP_LOOKUP_HOSTNAME_FLAG_IPV6_ONLY)) { ret = SMCP_STATUS_INVALID_ARGUMENT; goto bail; } else if ((flags & SMCP_LOOKUP_HOSTNAME_FLAG_IPV4_ONLY) == SMCP_LOOKUP_HOSTNAME_FLAG_IPV4_ONLY) { hint.ai_family = AF_INET; } else if ((flags & SMCP_LOOKUP_HOSTNAME_FLAG_IPV6_ONLY) == SMCP_LOOKUP_HOSTNAME_FLAG_IPV6_ONLY) { hint.ai_family = AF_INET6; } memset(saddr, 0, sizeof(*saddr)); saddr->___smcp_family = SMCP_BSD_SOCKETS_NET_FAMILY; #if SOCKADDR_HAS_LENGTH_FIELD saddr->___smcp_len = sizeof(*saddr); #endif int error = getaddrinfo(hostname, NULL, &hint, &results); #if SMCP_BSD_SOCKETS_NET_FAMILY==AF_INET6 if(error && (inet_addr(hostname) != INADDR_NONE)) { char addr_v4mapped_str[8 + strlen(hostname)]; hint.ai_family = AF_INET6; hint.ai_flags = AI_ALL | AI_V4MAPPED, strcpy(addr_v4mapped_str,"::ffff:"); strcat(addr_v4mapped_str,hostname); error = getaddrinfo(addr_v4mapped_str, NULL, &hint, &results ); } #endif if (EAI_AGAIN == error) { ret = SMCP_STATUS_WAIT_FOR_DNS; goto bail; } #ifdef TM_EWOULDBLOCK if (TM_EWOULDBLOCK == error) { ret = SMCP_STATUS_WAIT_FOR_DNS; goto bail; } #endif require_action_string( !error, bail, ret = SMCP_STATUS_HOST_LOOKUP_FAILURE, gai_strerror(error) ); // Move to the first recognized result for(iter = results;iter && (iter->ai_family!=AF_INET6 && iter->ai_family!=AF_INET);iter=iter->ai_next); require_action( iter, bail, ret = SMCP_STATUS_HOST_LOOKUP_FAILURE ); #if SMCP_BSD_SOCKETS_NET_FAMILY==AF_INET6 if(iter->ai_family == AF_INET) { struct sockaddr_in *v4addr = (void*)iter->ai_addr; saddr->sin6_addr.s6_addr[10] = 0xFF; saddr->sin6_addr.s6_addr[11] = 0xFF; memcpy(&saddr->sin6_addr.s6_addr[12], &v4addr->sin_addr.s_addr, 4); } else #endif if(iter->ai_family == SMCP_BSD_SOCKETS_NET_FAMILY) { memcpy(saddr, iter->ai_addr, iter->ai_addrlen); } if(SMCP_IS_ADDR_MULTICAST(&saddr->smcp_addr)) { smcp_t const self = smcp_get_current_instance(); check(self->outbound.packet->tt != COAP_TRANS_TYPE_CONFIRMABLE); if(self->outbound.packet->tt == COAP_TRANS_TYPE_CONFIRMABLE) { self->outbound.packet->tt = COAP_TRANS_TYPE_NONCONFIRMABLE; } } ret = SMCP_STATUS_OK; bail: if(results) freeaddrinfo(results); return ret; }