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