1 /*
2 * Copyright (c) 2022 René Beckmann
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /** @file mqtt_sn_transport_udp.c
8 *
9 * @brief MQTT-SN UDP transport.
10 */
11
12 #include <errno.h>
13
14 #include <zephyr/net/mqtt_sn.h>
15 #include <zephyr/net/net_ip.h>
16 #include <zephyr/net/socket.h>
17
18 #ifdef CONFIG_ARCH_POSIX
19 #include <fcntl.h>
20 #else
21 #include <zephyr/posix/fcntl.h>
22 #endif
23
24 #include <zephyr/logging/log.h>
25 LOG_MODULE_DECLARE(net_mqtt_sn, CONFIG_MQTT_SN_LOG_LEVEL);
26
get_ip_str(const struct sockaddr * sa,char * s,size_t maxlen)27 static char *get_ip_str(const struct sockaddr *sa, char *s, size_t maxlen)
28 {
29 switch (sa->sa_family) {
30 case AF_INET:
31 inet_ntop(AF_INET, &(((struct sockaddr_in *)sa)->sin_addr), s, maxlen);
32 break;
33
34 case AF_INET6:
35 inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)sa)->sin6_addr), s, maxlen);
36 break;
37
38 default:
39 strncpy(s, "Unknown AF", maxlen);
40 break;
41 }
42
43 return s;
44 }
45
tp_udp_init(struct mqtt_sn_transport * transport)46 static int tp_udp_init(struct mqtt_sn_transport *transport)
47 {
48 struct mqtt_sn_transport_udp *udp = UDP_TRANSPORT(transport);
49 int err;
50
51 udp->sock = zsock_socket(udp->gwaddr.sa_family, SOCK_DGRAM, 0);
52 if (udp->sock < 0) {
53 return errno;
54 }
55
56 LOG_DBG("Socket %d", udp->sock);
57
58 #ifdef LOG_DBG
59 char ip[30], *out;
60
61 out = get_ip_str((struct sockaddr *)&udp->gwaddr, ip, sizeof(ip));
62 if (out != NULL) {
63 LOG_DBG("Connecting to IP %s:%u", out,
64 ntohs(((struct sockaddr_in *)&udp->gwaddr)->sin_port));
65 }
66 #endif
67
68 err = zsock_connect(udp->sock, (struct sockaddr *)&udp->gwaddr, udp->gwaddrlen);
69 if (err < 0) {
70 return errno;
71 }
72
73 return 0;
74 }
75
tp_udp_deinit(struct mqtt_sn_transport * transport)76 static void tp_udp_deinit(struct mqtt_sn_transport *transport)
77 {
78 struct mqtt_sn_transport_udp *udp = UDP_TRANSPORT(transport);
79
80 zsock_close(udp->sock);
81 }
82
tp_udp_msg_send(struct mqtt_sn_client * client,void * buf,size_t sz)83 static int tp_udp_msg_send(struct mqtt_sn_client *client, void *buf, size_t sz)
84 {
85 struct mqtt_sn_transport_udp *udp = UDP_TRANSPORT(client->transport);
86 int rc;
87
88 LOG_HEXDUMP_DBG(buf, sz, "Sending UDP packet");
89
90 rc = zsock_send(udp->sock, buf, sz, 0);
91 if (rc < 0) {
92 return -errno;
93 }
94
95 if (rc != sz) {
96 return -EIO;
97 }
98
99 return 0;
100 }
101
tp_udp_recv(struct mqtt_sn_client * client,void * buffer,size_t length)102 static ssize_t tp_udp_recv(struct mqtt_sn_client *client, void *buffer, size_t length)
103 {
104 struct mqtt_sn_transport_udp *udp = UDP_TRANSPORT(client->transport);
105 int rc;
106
107 rc = zsock_recv(udp->sock, buffer, length, 0);
108 LOG_DBG("recv %d", rc);
109 if (rc < 0) {
110 return -errno;
111 }
112
113 LOG_HEXDUMP_DBG(buffer, rc, "recv");
114
115 return rc;
116 }
117
tp_udp_poll(struct mqtt_sn_client * client)118 static int tp_udp_poll(struct mqtt_sn_client *client)
119 {
120 struct mqtt_sn_transport_udp *udp = UDP_TRANSPORT(client->transport);
121 int rc;
122
123 struct zsock_pollfd pollfd = {
124 .fd = udp->sock,
125 .events = ZSOCK_POLLIN,
126 };
127
128 rc = zsock_poll(&pollfd, 1, 0);
129 if (rc < 1) {
130 return rc;
131 }
132
133 LOG_DBG("revents %d", pollfd.revents & ZSOCK_POLLIN);
134
135 return pollfd.revents & ZSOCK_POLLIN;
136 }
137
mqtt_sn_transport_udp_init(struct mqtt_sn_transport_udp * udp,struct sockaddr * gwaddr,socklen_t addrlen)138 int mqtt_sn_transport_udp_init(struct mqtt_sn_transport_udp *udp, struct sockaddr *gwaddr,
139 socklen_t addrlen)
140 {
141 if (!udp || !gwaddr || !addrlen) {
142 return -EINVAL;
143 }
144
145 memset(udp, 0, sizeof(*udp));
146
147 udp->tp = (struct mqtt_sn_transport){.init = tp_udp_init,
148 .deinit = tp_udp_deinit,
149 .msg_send = tp_udp_msg_send,
150 .poll = tp_udp_poll,
151 .recv = tp_udp_recv};
152
153 udp->sock = 0;
154
155 memcpy(&udp->gwaddr, gwaddr, addrlen);
156 udp->gwaddrlen = addrlen;
157
158 return 0;
159 }
160