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