FabGL
ESP32 Display Controller and Graphics Library
netutils.cpp
1 /*
2  Created by Fabrizio Di Vittorio (fdivitto2013@gmail.com) - <http://www.fabgl.com>
3  Copyright (c) 2019-2021 Fabrizio Di Vittorio.
4  All rights reserved.
5 
6 
7 * Please contact fdivitto2013@gmail.com if you need a commercial license.
8 
9 
10 * This library and related software is available under GPL v3. Feel free to use FabGL in free software and hardware:
11 
12  FabGL is free software: you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation, either version 3 of the License, or
15  (at your option) any later version.
16 
17  FabGL is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with FabGL. If not, see <http://www.gnu.org/licenses/>.
24  */
25 
26 
27 #include <string.h>
28 
29 #include "fabutils.h"
30 #include "netutils.h"
31 
32 
33 
34 namespace fabgl {
35 
36 
37 void printIP(in_addr ip)
38 {
39  char ipstr[INET_ADDRSTRLEN];
40  inet_ntop(AF_INET, &ip, ipstr, INET_ADDRSTRLEN);
41  printf("%s", ipstr);
42 }
43 
44 
47 // NSLookup (DNS client)
48 
49 
50 in_addr hostToIP(char const * host)
51 {
52  in_addr ret = { };
53  addrinfo * addrinfo;
54  if (lwip_getaddrinfo(host, NULL, NULL, &addrinfo) == 0 && addrinfo) {
55  ret = ((sockaddr_in *)addrinfo->ai_addr)->sin_addr;
56  lwip_freeaddrinfo(addrinfo);
57  }
58  return ret;
59 }
60 
61 
62 
65 // Socket
66 
67 
68 bool Socket::connect(in_addr host, uint16_t port)
69 {
70  if (m_socket < 0) {
71  m_socket = lwip_socket(AF_INET, SOCK_STREAM, 0);
72  if (m_socket < 0)
73  return false;
74  }
75 
76  sockaddr_in dest_addr;
77  dest_addr.sin_addr = host;
78  dest_addr.sin_family = AF_INET;
79  dest_addr.sin_port = htons(port);
80  m_connected = lwip_connect(m_socket, (sockaddr *)&dest_addr, sizeof(sockaddr_in)) == 0;
81  //printf("host="); printIP(host); printf(" port=%d m_connected=%d\n", port, m_connected);
82  return m_connected;
83 }
84 
85 
86 uint16_t Socket::checkEndiannessWord(uint16_t value)
87 {
88  return m_littleEndian ? value : changeEndiannesWord(value);
89 }
90 
91 
92 uint32_t Socket::checkEndiannessDWord(uint32_t value)
93 {
94  return m_littleEndian ? value : changeEndiannesDWord(value);
95 }
96 
97 
98 // ret -1 = error, ret 0 = disconnected
99 int Socket::read(void * buffer, size_t length)
100 {
101  /*
102  int bytesRecv = lwip_recv(m_socket, buffer, length, MSG_WAITALL);
103  m_connected = (bytesRecv > 0);
104  printf("bytesRecv=%d, requested=%d\n", bytesRecv, length);
105  return bytesRecv;
106  */
107  uint8_t * buf = (uint8_t*) buffer;
108  size_t len = length;
109  while (len > 0) {
110  int bytesRecv = lwip_recv(m_socket, buf, len, MSG_WAITALL);
111  if (bytesRecv == 0) {
112  m_connected = false;
113  break;
114  }
115  len -= bytesRecv;
116  buf += bytesRecv;
117  }
118  return length - len;
119 }
120 
121 
122 uint8_t Socket::readByte()
123 {
124  uint8_t buf;
125  return read(&buf, 1) == 1 ? buf : 0x00;
126 }
127 
128 
129 uint16_t Socket::readWord()
130 {
131  uint16_t buf;
132  return read(&buf, 2) == 2 ? checkEndiannessWord(buf) : 0;
133 }
134 
135 
136 uint32_t Socket::readDWord()
137 {
138  uint32_t buf;
139  return read(&buf, 4) == 4 ? checkEndiannessDWord(buf) : 0;
140 }
141 
142 
143 void Socket::readDiscard(size_t length)
144 {
145  uint8_t buf;
146  for (; length; --length)
147  read(&buf, 1);
148 }
149 
150 
151 void Socket::writeFillBytes(size_t length, uint8_t value)
152 {
153  for (; length; --length)
154  write(&value, 1);
155 }
156 
157 
158 void Socket::writeByte(uint8_t value)
159 {
160  write(&value, 1);
161 }
162 
163 
164 void Socket::writeWord(uint16_t value)
165 {
166  value = checkEndiannessWord(value);
167  write(&value, 2);
168 }
169 
170 
171 void Socket::writeDWord(uint32_t value)
172 {
173  value = checkEndiannessDWord(value);
174  write(&value, 4);
175 }
176 
177 
178 // ret -1 = error
179 int Socket::read(void * buffer, size_t maxLength, in_addr * sourceAddress, uint16_t * sourcePort)
180 {
181  sockaddr_in from;
182  int fromlen;
183  int bytesRecv = lwip_recvfrom(m_socket, buffer, maxLength, 0, (sockaddr *)&from, (socklen_t *)&fromlen);
184  if (bytesRecv > 0) {
185  *sourceAddress = from.sin_addr;
186  *sourcePort = ntohs(from.sin_port);
187  }
188  return bytesRecv;
189 }
190 
191 
192 // ret -1 = error, ret 0 = disconnected
193 int Socket::write(void const * buffer, size_t length)
194 {
195  if (!isConnected())
196  return -1;
197 
198  int32_t bytesSent = 0;
199  // send in chunks of up to TCP_MSS bytes
200  auto src = (uint8_t const *) buffer;
201  while (bytesSent < length) {
202  int bytesToSend = imin(TCP_MSS, length - bytesSent);
203  int chunkBytesSent = m_remoteAddress.sin_len == 0 ? lwip_send(m_socket, src, bytesToSend, MSG_DONTWAIT)
204  : lwip_sendto(m_socket, src, bytesToSend, 0, (sockaddr *)&m_remoteAddress, sizeof(m_remoteAddress));
205  int lasterr = getLastError();
206  if (lasterr == EAGAIN || lasterr == EWOULDBLOCK) {
207  chunkBytesSent = 0;
208  } else if (chunkBytesSent <= 0 || lasterr != 0) {
209  // error
210  bytesSent = -1;
211  break;
212  }
213  bytesSent += chunkBytesSent;
214  src += chunkBytesSent;
215  }
216  if (length > 0)
217  m_connected = (bytesSent > 0);
218  return bytesSent;
219 }
220 
221 
222 // ret -1 = error, ret 0 = disconnected
223 int32_t Socket::write(char const *str)
224 {
225  return write((uint8_t const *)str, strlen(str));
226 }
227 
228 
229 // like printf
230 int Socket::writeFmt(char const * format, ...)
231 {
232  va_list ap;
233  va_start(ap, format);
234  int len = vsnprintf(nullptr, 0, format, ap);
235  va_end(ap);
236  va_start(ap, format);
237  char buf[len + 1];
238  vsnprintf(buf, len + 1, format, ap);
239  va_end(ap);
240  write(buf, len);
241  return len;
242 }
243 
244 
245 void Socket::close()
246 {
247  if (m_socket > -1) {
248  lwip_shutdown(m_socket, SHUT_RDWR);
249  lwip_close(m_socket);
250  m_socket = -1;
251  }
252  m_connected = false;
253 }
254 
255 
256 void Socket::setNoDelay(bool value)
257 {
258  int one = (int)value;
259  lwip_setsockopt(m_socket, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
260 }
261 
262 
263 // from now Socket will use "sendto" instead of "send"
264 void Socket::setRemoteAddress(in_addr remoteAddress, uint16_t remotePort)
265 {
266  memset(&m_remoteAddress, 0, sizeof(sockaddr_in));
267  m_remoteAddress.sin_family = AF_INET;
268  m_remoteAddress.sin_len = sizeof(sockaddr_in);
269  m_remoteAddress.sin_addr = remoteAddress;
270  m_remoteAddress.sin_port = htons(remotePort);
271 }
272 
273 
274 // timeOut in ms (0 = no timeout)
275 void Socket::setTimeOut(int timeOut)
276 {
277  timeval receiving_timeout;
278  receiving_timeout.tv_sec = timeOut / 1000;
279  receiving_timeout.tv_usec = (timeOut - timeOut / 1000) * 1000;
280  lwip_setsockopt(m_socket, SOL_SOCKET, SO_RCVTIMEO, &receiving_timeout, sizeof(receiving_timeout));
281 }
282 
283 
284 
285 
286 int32_t Socket::getLastError()
287 {
288  int r = 0;
289  socklen_t l = sizeof(int);
290  lwip_getsockopt(m_socket, SOL_SOCKET, SO_ERROR, (void *)&r, &l);
291  return r;
292 }
293 
294 
295 } // fabgl namespace
This file contains some utility classes and functions.
Definition: canvas.cpp:36
This file contains RFBClient class.