Exemple #1
0
/*
 * 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);
                }
            }
        }
    }
}
Exemple #2
0
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);
}
Exemple #3
0
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;
}
Exemple #4
0
static void send_ping(void)
{
    if (gateway.port != 0) {
        uint8_t buf[2] = { 2, PINGREQ };
        sock_udp_send(&sock, &buf, 2, &gateway);
    }
}
Exemple #5
0
/**
 * @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");
        }
    }
}
Exemple #6
0
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;
}
Exemple #7
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;
        }
    }
}
Exemple #8
0
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;
}
Exemple #9
0
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);
    }
}
Exemple #10
0
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;
}
Exemple #11
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;
}
Exemple #12
0
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;
}
Exemple #13
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));
    }
}
Exemple #14
0
/* 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;
}