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 #if defined(CONFIG_SOCKS)
33 	if (client->transport.proxy.addrlen != 0) {
34 		ret = setsockopt(client->transport.tcp.sock,
35 				 SOL_SOCKET, SO_SOCKS5,
36 				 &client->transport.proxy.addr,
37 				 client->transport.proxy.addrlen);
38 		if (ret < 0) {
39 			goto error;
40 		}
41 	}
42 #endif
43 
44 	NET_DBG("Created socket %d", client->transport.tcp.sock);
45 
46 	size_t peer_addr_size = sizeof(struct sockaddr_in6);
47 
48 	if (broker->sa_family == AF_INET) {
49 		peer_addr_size = sizeof(struct sockaddr_in);
50 	}
51 
52 	ret = zsock_connect(client->transport.tcp.sock, client->broker,
53 			    peer_addr_size);
54 	if (ret < 0) {
55 		goto error;
56 	}
57 
58 	NET_DBG("Connect completed");
59 	return 0;
60 
61 error:
62 	(void)zsock_close(client->transport.tcp.sock);
63 	return -errno;
64 }
65 
mqtt_client_tcp_write(struct mqtt_client * client,const uint8_t * data,uint32_t datalen)66 int mqtt_client_tcp_write(struct mqtt_client *client, const uint8_t *data,
67 			  uint32_t datalen)
68 {
69 	uint32_t offset = 0U;
70 	int ret;
71 
72 	while (offset < datalen) {
73 		ret = zsock_send(client->transport.tcp.sock, data + offset,
74 				 datalen - offset, 0);
75 		if (ret < 0) {
76 			return -errno;
77 		}
78 
79 		offset += ret;
80 	}
81 
82 	return 0;
83 }
84 
mqtt_client_tcp_write_msg(struct mqtt_client * client,const struct msghdr * message)85 int mqtt_client_tcp_write_msg(struct mqtt_client *client,
86 			      const struct msghdr *message)
87 
88 {
89 	int ret, i;
90 	size_t offset = 0;
91 	size_t total_len = 0;
92 
93 	for (i = 0; i < message->msg_iovlen; i++) {
94 		total_len += message->msg_iov[i].iov_len;
95 	}
96 
97 	while (offset < total_len) {
98 		ret = zsock_sendmsg(client->transport.tcp.sock, message, 0);
99 		if (ret < 0) {
100 			return -errno;
101 		}
102 
103 		offset += ret;
104 		if (offset >= total_len) {
105 			break;
106 		}
107 
108 		/* Update msghdr for the next iteration. */
109 		for (i = 0; i < message->msg_iovlen; i++) {
110 			if (ret < message->msg_iov[i].iov_len) {
111 				message->msg_iov[i].iov_len -= ret;
112 				message->msg_iov[i].iov_base =
113 					(uint8_t *)message->msg_iov[i].iov_base + ret;
114 				break;
115 			}
116 
117 			ret -= message->msg_iov[i].iov_len;
118 			message->msg_iov[i].iov_len = 0;
119 		}
120 	}
121 
122 	return 0;
123 }
124 
mqtt_client_tcp_read(struct mqtt_client * client,uint8_t * data,uint32_t buflen,bool shall_block)125 int mqtt_client_tcp_read(struct mqtt_client *client, uint8_t *data, uint32_t buflen,
126 			 bool shall_block)
127 {
128 	int flags = 0;
129 	int ret;
130 
131 	if (!shall_block) {
132 		flags |= ZSOCK_MSG_DONTWAIT;
133 	}
134 
135 	ret = zsock_recv(client->transport.tcp.sock, data, buflen, flags);
136 	if (ret < 0) {
137 		return -errno;
138 	}
139 
140 	return ret;
141 }
142 
mqtt_client_tcp_disconnect(struct mqtt_client * client)143 int mqtt_client_tcp_disconnect(struct mqtt_client *client)
144 {
145 	int ret;
146 
147 	NET_INFO("Closing socket %d", client->transport.tcp.sock);
148 
149 	ret = zsock_close(client->transport.tcp.sock);
150 	if (ret < 0) {
151 		return -errno;
152 	}
153 
154 	return 0;
155 }
156