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