int conn_udp_sendto(const void *data, size_t len, const void *src, size_t src_len, const void *dst, size_t dst_len, int family, uint16_t sport, uint16_t dport) { int res; _send_cmd_t send_cmd; if (!send_registered) { if (evproc_regCallback(EVENT_TYPE_CONN_SEND, _output_callback) != E_SUCCESS) { return -EIO; } else { send_registered = true; } } mutex_init(&send_cmd.mutex); if ((len > (UIP_BUFSIZE - (UIP_LLH_LEN + UIP_IPUDPH_LEN))) || (len > UINT16_MAX)) { return -EMSGSIZE; } if ((dst_len > sizeof(ipv6_addr_t)) || (family != AF_INET6)) { return -EAFNOSUPPORT; } mutex_lock(&send_cmd.mutex); send_cmd.data = data; send_cmd.data_len = (uint16_t)len; if ((res = _reg_and_bind(&send_cmd.sock, NULL, NULL, sport)) < 0) { mutex_unlock(&send_cmd.mutex); return res; } udp_socket_connect(&send_cmd.sock, (uip_ipaddr_t *)dst, dport); /* can't fail at this point */ /* change to emb6 thread context */ if (evproc_putEvent(E_EVPROC_TAIL, EVENT_TYPE_CONN_SEND, &send_cmd) != E_SUCCESS) { udp_socket_close(&send_cmd.sock); mutex_unlock(&send_cmd.mutex); return -EIO; } /* block thread until data was send */ mutex_lock(&send_cmd.mutex); udp_socket_close(&send_cmd.sock); mutex_unlock(&send_cmd.mutex); return send_cmd.res; }
static int _reg_and_bind(struct udp_socket *c, void *ptr, udp_socket_input_callback_t cb, uint16_t port) { if (udp_socket_register(c, ptr, cb) < 0) { return -EMFILE; } if (udp_socket_bind(c, port) < 0) { udp_socket_close(c); return -EALREADY; } return 0; }
void sock_udp_close(sock_udp_t *sock) { assert(sock != NULL); if (sock->sock.input_callback != NULL) { while (atomic_fetch_sub(&sock->receivers, 1) > 0) { msg_t msg = { .type = _MSG_TYPE_CLOSE }; mbox_put(&sock->mbox, &msg); } mutex_lock(&sock->mutex); udp_socket_close(&sock->sock); sock->sock.input_callback = NULL; mutex_unlock(&sock->mutex); } }
void conn_udp_close(conn_udp_t *conn) { if (conn->sock.input_callback != NULL) { mutex_lock(&conn->mutex); if (conn->waiting_thread != KERNEL_PID_UNDEF) { msg_t msg; msg.type = _MSG_TYPE_CLOSE; msg.content.ptr = conn; mutex_unlock(&conn->mutex); msg_send(&msg, conn->waiting_thread); mutex_lock(&conn->mutex); } udp_socket_close(&conn->sock); conn->sock.input_callback = NULL; mutex_unlock(&conn->mutex); } }
static int _reg(struct udp_socket *c, void *ptr, udp_socket_input_callback_t cb, const sock_udp_ep_t *local, const sock_udp_ep_t *remote) { if (((local != NULL) && (local->family != AF_INET6)) || ((remote != NULL) && (remote->family != AF_INET6))) { return -EAFNOSUPPORT; } if (udp_socket_register(c, ptr, cb) < 0) { return -ENOMEM; } if (local != NULL) { if (udp_socket_bind(c, local->port) < 0) { udp_socket_close(c); return -EADDRINUSE; } } if (remote != NULL) { /* check of return value not necessary, since neither c nor * c->udp_conn is NULL (only error case) at this point */ udp_socket_connect(c, (uip_ipaddr_t *)&remote->addr, remote->port); } return 0; }
int sock_udp_send(sock_udp_t *sock, const void *data, size_t len, const sock_udp_ep_t *remote) { struct udp_socket tmp; _send_cmd_t send_cmd = { .block = MUTEX_INIT, .remote = remote, .data = data, .len = len }; assert((sock != NULL) || (remote != NULL)); assert((len == 0) || (data != NULL)); /* (len != 0) => (data != NULL) */ /* we want the send in the uip thread (which udp_socket_send does not offer) * so we need to do it manually */ if (!send_registered) { if (evproc_regCallback(EVENT_TYPE_SOCK_SEND, _output_callback) != E_SUCCESS) { return -ENOMEM; } else { send_registered = true; } } if ((len > (UIP_BUFSIZE - (UIP_LLH_LEN + UIP_IPUDPH_LEN))) || (len > UINT16_MAX)) { return -ENOMEM; } if (remote != NULL) { if (remote->family != AF_INET6) { return -EAFNOSUPPORT; } if (remote->port == 0) { return -EINVAL; } send_cmd.remote = remote; } else if (sock->sock.udp_conn->rport == 0) { return -ENOTCONN; } /* cppcheck-supress nullPointerRedundantCheck * remote == NULL implies that sock != NULL (see assert at start of * function) * that's why it is okay in the if-statement above to check * sock->... without checking (sock != NULL) first => this check afterwards * isn't redundant */ if (sock == NULL) { int res; if ((res = _reg(&tmp, NULL, NULL, NULL, NULL)) < 0) { return res; } send_cmd.sock = &tmp; } else { send_cmd.sock = &sock->sock; } mutex_lock(&send_cmd.block); /* change to emb6 thread context */ if (evproc_putEvent(E_EVPROC_TAIL, EVENT_TYPE_SOCK_SEND, &send_cmd) == E_SUCCESS) { /* block thread until data was sent */ mutex_lock(&send_cmd.block); } else { /* most likely error: event queue was full */ send_cmd.res = -ENOMEM; } if (send_cmd.sock == &tmp) { udp_socket_close(&tmp); } mutex_unlock(&send_cmd.block); return send_cmd.res; }