/* * Starts a blocking and never-returning loop dispatching CoAP requests. * * When using gnrc, make sure the calling thread has an initialized msg queue. */ void microcoap_server_loop(void) { static const sock_udp_ep_t local = { .family = AF_INET6, .port = COAP_SERVER_PORT }; sock_udp_ep_t remote; sock_udp_t sock; int rc = sock_udp_create(&sock, &local, NULL, 0); while (1) { DEBUG("Waiting for incoming UDP packet...\n"); rc = sock_udp_recv(&sock, (char *)_udp_buf, sizeof(_udp_buf), SOCK_NO_TIMEOUT, &remote); if (rc < 0) { DEBUG("Error in sock_udp_recv(). rc=%u\n", rc); continue; } size_t n = rc; coap_packet_t pkt; DEBUG("Received packet: "); coap_dump(_udp_buf, n, true); DEBUG("\n"); /* parse UDP packet to CoAP */ if (0 != (rc = coap_parse(&pkt, _udp_buf, n))) { DEBUG("Bad packet rc=%d\n", rc); } else { coap_packet_t rsppkt; DEBUG("content:\n"); coap_dumpPacket(&pkt); /* handle CoAP request */ coap_handle_req(&scratch_buf, &pkt, &rsppkt); /* build reply */ size_t rsplen = sizeof(_udp_buf); if ((rc = coap_build(_udp_buf, &rsplen, &rsppkt)) != 0) { DEBUG("coap_build failed rc=%d\n", rc); } else { DEBUG("Sending packet: "); coap_dump(_udp_buf, rsplen, true); DEBUG("\n"); DEBUG("content:\n"); coap_dumpPacket(&rsppkt); /* send reply via UDP */ rc = sock_udp_send(&sock, _udp_buf, rsplen, &remote); if (rc < 0) { DEBUG("Error sending CoAP reply via udp; %u\n", rc); } } } } }
static void on_pingreq(sock_udp_ep_t *remote) { /* @todo respond with a PINGRESP only if the PINGREQ came from the * connected gateway -> see spec v1.2, section 6.11 */ uint8_t buf[2] = { 2, PINGRESP }; sock_udp_send(&sock, &buf, 2, remote); }
static int syncsend(uint8_t resp, size_t len, bool unlock) { int res = EMCUTE_TIMEOUT; waiton = resp; timer.arg = (void *)sched_active_thread; /* clear flags, in case the timer was triggered last time right before the * remove was called */ thread_flags_clear(TFLAGS_ANY); for (unsigned retries = 0; retries <= EMCUTE_N_RETRY; retries++) { DEBUG("[emcute] syncsend: sending round %i\n", retries); sock_udp_send(&sock, tbuf, len, &gateway); xtimer_set(&timer, (EMCUTE_T_RETRY * US_PER_SEC)); thread_flags_t flags = thread_flags_wait_any(TFLAGS_ANY); if (flags & TFLAGS_RESP) { DEBUG("[emcute] syncsend: got response [%i]\n", result); xtimer_remove(&timer); res = result; break; } } /* cleanup sync state */ waiton = 0xff; if (unlock) { mutex_unlock(&txlock); } return res; }
static void send_ping(void) { if (gateway.port != 0) { uint8_t buf[2] = { 2, PINGREQ }; sock_udp_send(&sock, &buf, 2, &gateway); } }
/** * @brief Request prefix from uhcp server * * Never returns. * Calls @c uhcp_handle_prefix() when a prefix or prefix change is received. * * @param[in] iface interface to request prefix on */ void uhcp_client(uhcp_iface_t iface) { sock_udp_t sock; sock_udp_ep_t local = { .family=AF_INET6, .port=UHCP_PORT, .netif=iface }; sock_udp_ep_t req_target = { .family=AF_INET6, .port=UHCP_PORT, .netif=iface }; sock_udp_ep_t remote; inet_pton(AF_INET6, "ff15::abcd", req_target.addr.ipv6); /* prepare UHCP header */ uhcp_req_t req; uhcp_hdr_set(&req.hdr, UHCP_REQ); req.prefix_len = 64; /* create listening socket */ int res = sock_udp_create(&sock, &local, NULL, 0); uint8_t buf[sizeof(uhcp_push_t) + 16]; while(1) { puts("uhcp_client(): sending REQ..."); sock_udp_send(&sock, &req, sizeof(uhcp_req_t), &req_target); res = sock_udp_recv(&sock, buf, sizeof(buf), 10U*US_PER_SEC, &remote); if (res > 0) { uhcp_handle_udp(buf, res, remote.addr.ipv6, remote.port, iface); xtimer_sleep(60); } else { puts("uhcp_client(): no reply received"); } } }
static int udp_send(char *addr_str, char *port_str, char *data, unsigned int num, unsigned int delay) { sock_udp_ep_t dst = SOCK_IPV6_EP_ANY; uint8_t byte_data[SHELL_DEFAULT_BUFSIZE / 2]; size_t data_len; /* parse destination address */ if (ipv6_addr_from_str((ipv6_addr_t *)&dst.addr.ipv6, addr_str) == NULL) { puts("Error: unable to parse destination address"); return 1; } /* parse port */ dst.port = atoi(port_str); data_len = hex2ints(byte_data, data); for (unsigned int i = 0; i < num; i++) { sock_udp_t *sock = NULL; if (server_running) { sock = &server_sock; } if (sock_udp_send(sock, byte_data, data_len, &dst) < 0) { puts("could not send"); } else { printf("Success: send %u byte over UDP to [%s]:%" PRIu16 "\n", (unsigned)data_len, addr_str, dst.port); } xtimer_usleep(delay); } return 0; }
/* Listen for an incoming CoAP message. */ static void _listen(sock_udp_t *sock) { coap_pkt_t pdu; uint8_t buf[GCOAP_PDU_BUF_SIZE]; sock_udp_ep_t remote; gcoap_request_memo_t *memo = NULL; uint8_t open_reqs = gcoap_op_state(); ssize_t res = sock_udp_recv(sock, buf, sizeof(buf), open_reqs > 0 ? GCOAP_RECV_TIMEOUT : SOCK_NO_TIMEOUT, &remote); if (res <= 0) { #if ENABLE_DEBUG if (res < 0 && res != -ETIMEDOUT) { DEBUG("gcoap: udp recv failure: %d\n", res); } #endif return; } res = coap_parse(&pdu, buf, res); if (res < 0) { DEBUG("gcoap: parse failure: %d\n", res); /* If a response, can't clear memo, but it will timeout later. */ return; } if (pdu.hdr->code == COAP_CODE_EMPTY) { DEBUG("gcoap: empty messages not handled yet\n"); return; /* incoming request */ } else if (coap_get_code_class(&pdu) == COAP_CLASS_REQ) { if (coap_get_type(&pdu) == COAP_TYPE_NON || coap_get_type(&pdu) == COAP_TYPE_CON) { size_t pdu_len = _handle_req(&pdu, buf, sizeof(buf), &remote); if (pdu_len > 0) { sock_udp_send(sock, buf, pdu_len, &remote); } } else { DEBUG("gcoap: illegal request type: %u\n", coap_get_type(&pdu)); return; } } /* incoming response */ else { _find_req_memo(&memo, &pdu, &remote); if (memo) { xtimer_remove(&memo->response_timer); memo->state = GCOAP_MEMO_RESP; memo->resp_handler(memo->state, &pdu, &remote); memo->state = GCOAP_MEMO_UNUSED; } } }
ssize_t nanocoap_request(coap_pkt_t *pkt, sock_udp_ep_t *local, sock_udp_ep_t *remote, size_t len) { ssize_t res; size_t pdu_len = (pkt->payload - (uint8_t *)pkt->hdr) + pkt->payload_len; uint8_t *buf = (uint8_t*)pkt->hdr; sock_udp_t sock; if (!remote->port) { remote->port = COAP_PORT; } res = sock_udp_create(&sock, local, remote, 0); if (res < 0) { return res; } /* TODO: timeout random between between ACK_TIMEOUT and (ACK_TIMEOUT * * ACK_RANDOM_FACTOR) */ uint32_t timeout = COAP_ACK_TIMEOUT * US_PER_SEC; unsigned tries_left = COAP_MAX_RETRANSMIT + 1; /* add 1 for initial transmit */ while (tries_left) { res = sock_udp_send(&sock, buf, pdu_len, NULL); if (res <= 0) { DEBUG("nanocoap: error sending coap request, %d\n", (int)res); break; } res = sock_udp_recv(&sock, buf, len, timeout, NULL); if (res <= 0) { if (res == -ETIMEDOUT) { DEBUG("nanocoap: timeout\n"); timeout *= 2; tries_left--; if (!tries_left) { DEBUG("nanocoap: maximum retries reached\n"); } continue; } DEBUG("nanocoap: error receiving coap response, %d\n", (int)res); break; } else { if (coap_parse(pkt, (uint8_t *)buf, res) < 0) { DEBUG("nanocoap: error parsing packet\n"); res = -EBADMSG; } break; } } sock_udp_close(&sock); return res; }
static void on_publish(size_t len, size_t pos) { /* make sure packet length is valid - if not, drop packet silently */ if (len < (pos + 6)) { return; } emcute_sub_t *sub; uint16_t tid = byteorder_lebuftohs(&rbuf[pos + 2]); /* allocate a response packet */ uint8_t buf[7] = { 7, PUBACK, 0, 0, 0, 0, ACCEPT }; /* and populate message ID and topic ID fields */ memcpy(&buf[2], &rbuf[pos + 2], 4); /* return error code in case we don't support/understand active flags. So * far we only understand QoS 1... */ if (rbuf[pos + 1] & ~(EMCUTE_QOS_1 | EMCUTE_TIT_SHORT)) { buf[6] = REJ_NOTSUP; sock_udp_send(&sock, &buf, 7, &gateway); return; } /* find the registered topic */ for (sub = subs; sub && (sub->topic.id != tid); sub = sub->next) {} if (sub == NULL) { buf[6] = REJ_INVTID; sock_udp_send(&sock, &buf, 7, &gateway); DEBUG("[emcute] on pub: no subscription found\n"); } else { if (rbuf[pos + 1] & EMCUTE_QOS_1) { sock_udp_send(&sock, &buf, 7, &gateway); } DEBUG("[emcute] on pub: got %i bytes of data\n", (int)(len - pos - 6)); size_t dat_len = (len - pos - 6); void *dat = (dat_len > 0) ? &rbuf[pos + 6] : NULL; sub->cb(&sub->topic, dat, dat_len); } }
int sntp_sync(sock_udp_ep_t *server, uint32_t timeout) { int result; mutex_lock(&_sntp_mutex); if ((result = sock_udp_create(&_sntp_sock, NULL, server, 0)) < 0) { DEBUG("Error creating UDP sock\n"); mutex_unlock(&_sntp_mutex); return result; } memset(&_sntp_packet, 0, sizeof(_sntp_packet)); ntp_packet_set_vn(&_sntp_packet); ntp_packet_set_mode(&_sntp_packet, NTP_MODE_CLIENT); if ((result = (int)sock_udp_send(&_sntp_sock, &_sntp_packet, sizeof(_sntp_packet), NULL)) < 0) { DEBUG("Error sending message\n"); sock_udp_close(&_sntp_sock); mutex_unlock(&_sntp_mutex); return result; } if ((result = (int)sock_udp_recv(&_sntp_sock, &_sntp_packet, sizeof(_sntp_packet), timeout, NULL)) < 0) { DEBUG("Error receiving message\n"); sock_udp_close(&_sntp_sock); mutex_unlock(&_sntp_mutex); return result; } sock_udp_close(&_sntp_sock); _sntp_offset = (byteorder_ntohl(_sntp_packet.transmit.seconds) * US_PER_SEC) + ((byteorder_ntohl(_sntp_packet.transmit.fraction) * 232) / 1000000) - xtimer_now64(); mutex_unlock(&_sntp_mutex); return 0; }
int emcute_pub(emcute_topic_t *topic, const void *data, size_t len, unsigned flags) { int res = EMCUTE_OK; assert((topic->id != 0) && data && (len > 0) && !(flags & ~PUB_FLAGS)); if (gateway.port == 0) { return EMCUTE_NOGW; } if (len >= (EMCUTE_BUFSIZE - 9)) { return EMCUTE_OVERFLOW; } if (flags & EMCUTE_QOS_2) { return EMCUTE_NOTSUP; } mutex_lock(&txlock); size_t pos = set_len(tbuf, (len + 6)); len += (pos + 6); tbuf[pos++] = PUBLISH; tbuf[pos++] = flags; byteorder_htolebufs(&tbuf[pos], topic->id); pos += 2; byteorder_htolebufs(&tbuf[pos], id_next); waitonid = id_next++; pos += 2; memcpy(&tbuf[pos], data, len); if (flags & EMCUTE_QOS_1) { res = syncsend(PUBACK, len, true); } else { sock_udp_send(&sock, tbuf, len, &gateway); mutex_unlock(&txlock); } return res; }
int nanocoap_server(sock_udp_ep_t *local, uint8_t *buf, size_t bufsize) { sock_udp_t sock; sock_udp_ep_t remote; if (!local->port) { local->port = COAP_PORT; } ssize_t res = sock_udp_create(&sock, local, NULL, 0); if (res != 0) { return -1; } while (1) { res = sock_udp_recv(&sock, buf, bufsize, -1, &remote); if (res < 0) { DEBUG("error receiving UDP packet %d\n", (int)res); } else if (res > 0) { coap_pkt_t pkt; if (coap_parse(&pkt, (uint8_t *)buf, res) < 0) { DEBUG("error parsing packet\n"); continue; } if ((res = coap_handle_req(&pkt, buf, bufsize)) > 0) { res = sock_udp_send(&sock, buf, res, &remote); } else { DEBUG("error handling request %d\n", (int)res); } } } return 0; }
/* Listen for an incoming CoAP message. */ static void _listen(sock_udp_t *sock) { coap_pkt_t pdu; uint8_t buf[GCOAP_PDU_BUF_SIZE]; sock_udp_ep_t remote; gcoap_request_memo_t *memo = NULL; uint8_t open_reqs = gcoap_op_state(); /* We expect a -EINTR response here when unlimited waiting (SOCK_NO_TIMEOUT) * is interrupted when sending a message in gcoap_req_send2(). While a * request is outstanding, sock_udp_recv() is called here with limited * waiting so the request's timeout can be handled in a timely manner in * _event_loop(). */ ssize_t res = sock_udp_recv(sock, buf, sizeof(buf), open_reqs > 0 ? GCOAP_RECV_TIMEOUT : SOCK_NO_TIMEOUT, &remote); if (res <= 0) { #if ENABLE_DEBUG if (res < 0 && res != -ETIMEDOUT) { DEBUG("gcoap: udp recv failure: %d\n", res); } #endif return; } res = coap_parse(&pdu, buf, res); if (res < 0) { DEBUG("gcoap: parse failure: %d\n", (int)res); /* If a response, can't clear memo, but it will timeout later. */ return; } if (pdu.hdr->code == COAP_CODE_EMPTY) { DEBUG("gcoap: empty messages not handled yet\n"); return; } /* validate class and type for incoming */ switch (coap_get_code_class(&pdu)) { /* incoming request */ case COAP_CLASS_REQ: if (coap_get_type(&pdu) == COAP_TYPE_NON || coap_get_type(&pdu) == COAP_TYPE_CON) { size_t pdu_len = _handle_req(&pdu, buf, sizeof(buf), &remote); if (pdu_len > 0) { ssize_t bytes = sock_udp_send(sock, buf, pdu_len, &remote); if (bytes <= 0) { DEBUG("gcoap: send response failed: %d\n", (int)bytes); } } } else { DEBUG("gcoap: illegal request type: %u\n", coap_get_type(&pdu)); } break; /* incoming response */ case COAP_CLASS_SUCCESS: case COAP_CLASS_CLIENT_FAILURE: case COAP_CLASS_SERVER_FAILURE: _find_req_memo(&memo, &pdu, &remote); if (memo) { switch (coap_get_type(&pdu)) { case COAP_TYPE_NON: case COAP_TYPE_ACK: xtimer_remove(&memo->response_timer); memo->state = GCOAP_MEMO_RESP; if (memo->resp_handler) { memo->resp_handler(memo->state, &pdu, &remote); } if (memo->send_limit >= 0) { /* if confirmable */ *memo->msg.data.pdu_buf = 0; /* clear resend PDU buffer */ } memo->state = GCOAP_MEMO_UNUSED; break; case COAP_TYPE_CON: DEBUG("gcoap: separate CON response not handled yet\n"); break; default: DEBUG("gcoap: illegal response type: %u\n", coap_get_type(&pdu)); break; } } else { DEBUG("gcoap: msg not found for ID: %u\n", coap_get_id(&pdu)); } break; default: DEBUG("gcoap: illegal code class: %u\n", coap_get_code_class(&pdu)); } }
/* Event/Message loop for gcoap _pid thread. */ static void *_event_loop(void *arg) { msg_t msg_rcvd; (void)arg; msg_init_queue(_msg_queue, GCOAP_MSG_QUEUE_SIZE); sock_udp_ep_t local; memset(&local, 0, sizeof(sock_udp_ep_t)); local.family = AF_INET6; local.netif = SOCK_ADDR_ANY_NETIF; local.port = GCOAP_PORT; int res = sock_udp_create(&_sock, &local, NULL, 0); if (res < 0) { DEBUG("gcoap: cannot create sock: %d\n", res); return 0; } while(1) { res = msg_try_receive(&msg_rcvd); if (res > 0) { switch (msg_rcvd.type) { case GCOAP_MSG_TYPE_TIMEOUT: { gcoap_request_memo_t *memo = (gcoap_request_memo_t *)msg_rcvd.content.ptr; /* no retries remaining */ if ((memo->send_limit == GCOAP_SEND_LIMIT_NON) || (memo->send_limit == 0)) { _expire_request(memo); } /* reduce retries remaining, double timeout and resend */ else { memo->send_limit--; unsigned i = COAP_MAX_RETRANSMIT - memo->send_limit; uint32_t timeout = ((uint32_t)COAP_ACK_TIMEOUT << i) * US_PER_SEC; uint32_t variance = ((uint32_t)COAP_ACK_VARIANCE << i) * US_PER_SEC; timeout = random_uint32_range(timeout, timeout + variance); ssize_t bytes = sock_udp_send(&_sock, memo->msg.data.pdu_buf, memo->msg.data.pdu_len, &memo->remote_ep); if (bytes > 0) { xtimer_set_msg(&memo->response_timer, timeout, &memo->timeout_msg, _pid); } else { DEBUG("gcoap: sock resend failed: %d\n", (int)bytes); _expire_request(memo); } } break; } default: break; } } _listen(&_sock); } return 0; }