| /* |
| * Copyright (c) 2022 René Beckmann |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| /** @file mqtt_sn_transport_udp.c |
| * |
| * @brief MQTT-SN UDP transport. |
| */ |
| |
| #include <errno.h> |
| |
| #include <zephyr/net/mqtt_sn.h> |
| #include <zephyr/net/net_ip.h> |
| #include <zephyr/net/socket.h> |
| |
| #ifdef CONFIG_ARCH_POSIX |
| #include <fcntl.h> |
| #else |
| #include <zephyr/posix/fcntl.h> |
| #endif |
| |
| #include <zephyr/logging/log.h> |
| LOG_MODULE_DECLARE(net_mqtt_sn, CONFIG_MQTT_SN_LOG_LEVEL); |
| |
| static char *get_ip_str(const struct sockaddr *sa, char *s, size_t maxlen) |
| { |
| switch (sa->sa_family) { |
| case AF_INET: |
| inet_ntop(AF_INET, &(((struct sockaddr_in *)sa)->sin_addr), s, maxlen); |
| break; |
| |
| case AF_INET6: |
| inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)sa)->sin6_addr), s, maxlen); |
| break; |
| |
| default: |
| strncpy(s, "Unknown AF", maxlen); |
| break; |
| } |
| |
| return s; |
| } |
| |
| static int tp_udp_init(struct mqtt_sn_transport *transport) |
| { |
| struct mqtt_sn_transport_udp *udp = UDP_TRANSPORT(transport); |
| int err; |
| |
| udp->sock = zsock_socket(udp->gwaddr.sa_family, SOCK_DGRAM, 0); |
| if (udp->sock < 0) { |
| return errno; |
| } |
| |
| LOG_DBG("Socket %d", udp->sock); |
| |
| #ifdef LOG_DBG |
| char ip[30], *out; |
| |
| out = get_ip_str((struct sockaddr *)&udp->gwaddr, ip, sizeof(ip)); |
| if (out != NULL) { |
| LOG_DBG("Connecting to IP %s:%u", out, |
| ((struct sockaddr_in *)&udp->gwaddr)->sin_port); |
| } |
| #endif |
| |
| err = zsock_connect(udp->sock, (struct sockaddr *)&udp->gwaddr, udp->gwaddrlen); |
| if (err < 0) { |
| return errno; |
| } |
| |
| return 0; |
| } |
| |
| static void tp_udp_deinit(struct mqtt_sn_transport *transport) |
| { |
| struct mqtt_sn_transport_udp *udp = UDP_TRANSPORT(transport); |
| |
| zsock_close(udp->sock); |
| } |
| |
| static int tp_udp_msg_send(struct mqtt_sn_client *client, void *buf, size_t sz) |
| { |
| struct mqtt_sn_transport_udp *udp = UDP_TRANSPORT(client->transport); |
| int rc; |
| |
| LOG_HEXDUMP_DBG(buf, sz, "Sending UDP packet"); |
| |
| rc = zsock_send(udp->sock, buf, sz, 0); |
| if (rc < 0) { |
| return -errno; |
| } |
| |
| if (rc != sz) { |
| return -EIO; |
| } |
| |
| return 0; |
| } |
| |
| static ssize_t tp_udp_recv(struct mqtt_sn_client *client, void *buffer, size_t length) |
| { |
| struct mqtt_sn_transport_udp *udp = UDP_TRANSPORT(client->transport); |
| int rc; |
| |
| rc = zsock_recv(udp->sock, buffer, length, 0); |
| LOG_DBG("recv %d", rc); |
| if (rc < 0) { |
| return -errno; |
| } |
| |
| LOG_HEXDUMP_DBG(buffer, rc, "recv"); |
| |
| return rc; |
| } |
| |
| static int tp_udp_poll(struct mqtt_sn_client *client) |
| { |
| struct mqtt_sn_transport_udp *udp = UDP_TRANSPORT(client->transport); |
| int rc; |
| |
| struct zsock_pollfd pollfd = { |
| .fd = udp->sock, |
| .events = ZSOCK_POLLIN, |
| }; |
| |
| rc = zsock_poll(&pollfd, 1, 0); |
| if (rc < 1) { |
| return rc; |
| } |
| |
| LOG_DBG("revents %d", pollfd.revents & ZSOCK_POLLIN); |
| |
| return pollfd.revents & ZSOCK_POLLIN; |
| } |
| |
| int mqtt_sn_transport_udp_init(struct mqtt_sn_transport_udp *udp, struct sockaddr *gwaddr, |
| socklen_t addrlen) |
| { |
| if (!udp || !gwaddr || !addrlen) { |
| return -EINVAL; |
| } |
| |
| memset(udp, 0, sizeof(*udp)); |
| |
| udp->tp = (struct mqtt_sn_transport){.init = tp_udp_init, |
| .deinit = tp_udp_deinit, |
| .msg_send = tp_udp_msg_send, |
| .poll = tp_udp_poll, |
| .recv = tp_udp_recv}; |
| |
| udp->sock = 0; |
| |
| memcpy(&udp->gwaddr, gwaddr, addrlen); |
| udp->gwaddrlen = addrlen; |
| |
| return 0; |
| } |