예제 #1
0
smcp_status_t
smcp_set_remote_sockaddr_from_host_and_port(const char* addr_str,uint16_t toport) {
	smcp_status_t ret;
	SMCP_NON_RECURSIVE smcp_sockaddr_t saddr;

	DEBUG_PRINTF("Outbound: Dest host [%s]:%d",addr_str,toport);

	// Check to see if this host is a group we know about.
	if (strcasecmp(addr_str, COAP_MULTICAST_STR_ALLDEVICES) == 0) {
		addr_str = SMCP_COAP_MULTICAST_ALLDEVICES_ADDR;
	}

	ret = smcp_plat_lookup_hostname(addr_str, &saddr);
	require_noerr(ret, bail);

	saddr.smcp_port = htons(toport);

	smcp_plat_set_remote_sockaddr(&saddr);


bail:
	return ret;
}
예제 #2
0
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;
}
예제 #3
0
ssize_t
sendtofrom(
	int fd,
	const void *data, size_t len, int flags,
	const struct sockaddr * saddr_to, socklen_t socklen_to,
	const struct sockaddr * saddr_from, socklen_t socklen_from
)
{
	ssize_t ret = -1;

	if (SMCP_IS_ADDR_MULTICAST(&((smcp_sockaddr_t*)saddr_from)->smcp_addr)) {
		saddr_from = NULL;
		socklen_from = 0;
	}

	if ((socklen_from == 0)
		|| (saddr_from == NULL)
		|| (saddr_from->sa_family != saddr_to->sa_family)
	) {
		ret = sendto(
			fd,
			data,
			len,
			0,
			(struct sockaddr *)saddr_to,
			socklen_to
		);
		check(ret>0);
	} else {
		struct iovec iov = { (void *)data, len };
		uint8_t cmbuf[CMSG_SPACE(sizeof (struct in6_pktinfo))];
		struct cmsghdr *scmsgp;
		struct msghdr msg = {
			.msg_name = (void*)saddr_to,
			.msg_namelen = socklen_to,
			.msg_iov = &iov,
			.msg_iovlen = 1,
			.msg_control = cmbuf,
			.msg_controllen = sizeof(cmbuf),
		};

#if defined(AF_INET6)
		if (saddr_to->sa_family == AF_INET6) {
			struct in6_pktinfo *pktinfo;
			scmsgp = CMSG_FIRSTHDR(&msg);
			scmsgp->cmsg_level = IPPROTO_IPV6;
			scmsgp->cmsg_type = IPV6_PKTINFO;
			scmsgp->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
			pktinfo = (struct in6_pktinfo *)(CMSG_DATA(scmsgp));

			pktinfo->ipi6_addr = ((struct sockaddr_in6*)saddr_from)->sin6_addr;
			pktinfo->ipi6_ifindex = ((struct sockaddr_in6*)saddr_from)->sin6_scope_id;
		} else
#endif

		if (saddr_to->sa_family == AF_INET) {
			struct in_pktinfo *pktinfo;
			scmsgp = CMSG_FIRSTHDR(&msg);
			scmsgp->cmsg_level = IPPROTO_IP;
			scmsgp->cmsg_type = IP_PKTINFO;
			scmsgp->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
			pktinfo = (struct in_pktinfo *)(CMSG_DATA(scmsgp));

			pktinfo->ipi_spec_dst = ((struct sockaddr_in*)saddr_to)->sin_addr;
			pktinfo->ipi_addr = ((struct sockaddr_in*)saddr_from)->sin_addr;
			pktinfo->ipi_ifindex = 0;
		}

		ret = sendmsg(fd, &msg, flags);

		check(ret > 0);
		check_string(ret >= 0, strerror(errno));
	}

	return ret;
}

smcp_status_t
smcp_plat_set_remote_hostname_and_port(const char* hostname, uint16_t port)
{
	smcp_status_t ret;
	SMCP_NON_RECURSIVE smcp_sockaddr_t saddr;

	DEBUG_PRINTF("Outbound: Dest host [%s]:%d",hostname,port);

#if SMCP_DTLS
	smcp_plat_ssl_set_remote_hostname(hostname);
#endif

	// Check to see if this host is a group we know about.
	if (strcasecmp(hostname, COAP_MULTICAST_STR_ALLDEVICES) == 0) {
		hostname = SMCP_COAP_MULTICAST_ALLDEVICES_ADDR;
	}

	ret = smcp_plat_lookup_hostname(hostname, &saddr, SMCP_LOOKUP_HOSTNAME_FLAG_DEFAULT);
	require_noerr(ret, bail);

	saddr.smcp_port = htons(port);

	smcp_plat_set_remote_sockaddr(&saddr);

bail:
	return ret;
}
예제 #4
-1
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;
}