1 /*
2  * Copyright (c) 2018 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /** @file mqtt_transport_socket_tcp.h
8  *
9  * @brief Internal functions to handle transport over TCP socket.
10  */
11 
12 #include <zephyr/logging/log.h>
13 LOG_MODULE_REGISTER(net_mqtt_sock_tcp, CONFIG_MQTT_LOG_LEVEL);
14 
15 #include <errno.h>
16 #include <zephyr/net/socket.h>
17 #include <zephyr/net/mqtt.h>
18 
19 #include "mqtt_os.h"
20 
mqtt_client_tcp_connect(struct mqtt_client * client)21 int mqtt_client_tcp_connect(struct mqtt_client *client)
22 {
23 	const struct sockaddr *broker = client->broker;
24 	int ret;
25 
26 	client->transport.tcp.sock = zsock_socket(broker->sa_family, SOCK_STREAM,
27 						  IPPROTO_TCP);
28 	if (client->transport.tcp.sock < 0) {
29 		return -errno;
30 	}
31 
32 	NET_DBG("Created socket %d", client->transport.tcp.sock);
33 
34 	if (client->transport.if_name != NULL) {
35 		struct ifreq ifname = { 0 };
36 
37 		strncpy(ifname.ifr_name, client->transport.if_name,
38 			sizeof(ifname.ifr_name) - 1);
39 
40 		ret = zsock_setsockopt(client->transport.tcp.sock, SOL_SOCKET,
41 				       SO_BINDTODEVICE, &ifname,
42 				       sizeof(struct ifreq));
43 		if (ret < 0) {
44 			NET_ERR("Failed to bind ot interface %s error (%d)",
45 				ifname.ifr_name, -errno);
46 			goto error;
47 		}
48 
49 		NET_DBG("Bound to interface %s", ifname.ifr_name);
50 	}
51 
52 #if defined(CONFIG_SOCKS)
53 	if (client->transport.proxy.addrlen != 0) {
54 		ret = setsockopt(client->transport.tcp.sock,
55 				 SOL_SOCKET, SO_SOCKS5,
56 				 &client->transport.proxy.addr,
57 				 client->transport.proxy.addrlen);
58 		if (ret < 0) {
59 			goto error;
60 		}
61 	}
62 #endif
63 
64 	size_t peer_addr_size = sizeof(struct sockaddr_in6);
65 
66 	if (broker->sa_family == AF_INET) {
67 		peer_addr_size = sizeof(struct sockaddr_in);
68 	}
69 
70 	ret = zsock_connect(client->transport.tcp.sock, client->broker,
71 			    peer_addr_size);
72 	if (ret < 0) {
73 		goto error;
74 	}
75 
76 	NET_DBG("Connect completed");
77 	return 0;
78 
79 error:
80 	(void)zsock_close(client->transport.tcp.sock);
81 	return -errno;
82 }
83 
mqtt_client_tcp_write(struct mqtt_client * client,const uint8_t * data,uint32_t datalen)84 int mqtt_client_tcp_write(struct mqtt_client *client, const uint8_t *data,
85 			  uint32_t datalen)
86 {
87 	uint32_t offset = 0U;
88 	int ret;
89 
90 	while (offset < datalen) {
91 		ret = zsock_send(client->transport.tcp.sock, data + offset,
92 				 datalen - offset, 0);
93 		if (ret < 0) {
94 			return -errno;
95 		}
96 
97 		offset += ret;
98 	}
99 
100 	return 0;
101 }
102 
mqtt_client_tcp_write_msg(struct mqtt_client * client,const struct msghdr * message)103 int mqtt_client_tcp_write_msg(struct mqtt_client *client,
104 			      const struct msghdr *message)
105 
106 {
107 	int ret, i;
108 	size_t offset = 0;
109 	size_t total_len = 0;
110 
111 	for (i = 0; i < message->msg_iovlen; i++) {
112 		total_len += message->msg_iov[i].iov_len;
113 	}
114 
115 	while (offset < total_len) {
116 		ret = zsock_sendmsg(client->transport.tcp.sock, message, 0);
117 		if (ret < 0) {
118 			return -errno;
119 		}
120 
121 		offset += ret;
122 		if (offset >= total_len) {
123 			break;
124 		}
125 
126 		/* Update msghdr for the next iteration. */
127 		for (i = 0; i < message->msg_iovlen; i++) {
128 			if (ret < message->msg_iov[i].iov_len) {
129 				message->msg_iov[i].iov_len -= ret;
130 				message->msg_iov[i].iov_base =
131 					(uint8_t *)message->msg_iov[i].iov_base + ret;
132 				break;
133 			}
134 
135 			ret -= message->msg_iov[i].iov_len;
136 			message->msg_iov[i].iov_len = 0;
137 		}
138 	}
139 
140 	return 0;
141 }
142 
mqtt_client_tcp_read(struct mqtt_client * client,uint8_t * data,uint32_t buflen,bool shall_block)143 int mqtt_client_tcp_read(struct mqtt_client *client, uint8_t *data, uint32_t buflen,
144 			 bool shall_block)
145 {
146 	int flags = 0;
147 	int ret;
148 
149 	if (!shall_block) {
150 		flags |= ZSOCK_MSG_DONTWAIT;
151 	}
152 
153 	ret = zsock_recv(client->transport.tcp.sock, data, buflen, flags);
154 	if (ret < 0) {
155 		return -errno;
156 	}
157 
158 	return ret;
159 }
160 
mqtt_client_tcp_disconnect(struct mqtt_client * client)161 int mqtt_client_tcp_disconnect(struct mqtt_client *client)
162 {
163 	int ret;
164 
165 	NET_INFO("Closing socket %d", client->transport.tcp.sock);
166 
167 	ret = zsock_close(client->transport.tcp.sock);
168 	if (ret < 0) {
169 		return -errno;
170 	}
171 
172 	return 0;
173 }
174