j0h

EthernetClient.cpp

j0h
May 8th, 2026
109
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.75 KB | None | 0 0
  1. /* Copyright 2018 Paul Stoffregen
  2. *
  3. * Permission is hereby granted, free of charge, to any person obtaining a copy of this
  4. * software and associated documentation files (the "Software"), to deal in the Software
  5. * without restriction, including without limitation the rights to use, copy, modify,
  6. * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
  7. * permit persons to whom the Software is furnished to do so, subject to the following
  8. * conditions:
  9. *
  10. * The above copyright notice and this permission notice shall be included in all
  11. * copies or substantial portions of the Software.
  12. *
  13. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  14. * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  15. * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  16. * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  17. * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  18. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  19. */
  20.  
  21. #include <Arduino.h>
  22. #include "Ethernet.h"
  23. #include "Dns.h"
  24. #include "utility/w5100.h"
  25.  
  26. int EthernetClient::connect(const char * host, uint16_t port)
  27. {
  28. DNSClient dns; // Look up the host first
  29. IPAddress remote_addr;
  30.  
  31. if (_sockindex < MAX_SOCK_NUM) {
  32. if (Ethernet.socketStatus(_sockindex) != SnSR::CLOSED) {
  33. Ethernet.socketDisconnect(_sockindex); // TODO: should we call stop()?
  34. }
  35. _sockindex = MAX_SOCK_NUM;
  36. }
  37. dns.begin(Ethernet.dnsServerIP());
  38. if (!dns.getHostByName(host, remote_addr)) return 0; // TODO: use _timeout
  39. return connect(remote_addr, port);
  40. }
  41.  
  42. int EthernetClient::connect(IPAddress ip, uint16_t port)
  43. {
  44. if (_sockindex < MAX_SOCK_NUM) {
  45. if (Ethernet.socketStatus(_sockindex) != SnSR::CLOSED) {
  46. Ethernet.socketDisconnect(_sockindex); // TODO: should we call stop()?
  47. }
  48. _sockindex = MAX_SOCK_NUM;
  49. }
  50. #if defined(ESP8266) || defined(ESP32)
  51. if (ip == IPAddress((uint32_t)0) || ip == IPAddress(0xFFFFFFFFul)) return 0;
  52. #else
  53. if (ip == IPAddress((uint32_t)0) || ip == IPAddress((uint32_t)0xFFFFFFFF)) return 0;
  54. #endif
  55. _sockindex = Ethernet.socketBegin(SnMR::TCP, 0);
  56. if (_sockindex >= MAX_SOCK_NUM) return 0;
  57. Ethernet.socketConnect(_sockindex, rawIPAddress(ip), port);
  58. uint32_t start = millis();
  59. while (1) {
  60. uint8_t stat = Ethernet.socketStatus(_sockindex);
  61. if (stat == SnSR::ESTABLISHED) return 1;
  62. if (stat == SnSR::CLOSE_WAIT) return 1;
  63. if (stat == SnSR::CLOSED) return 0;
  64. if (millis() - start > _timeout) break;
  65. delay(1);
  66. }
  67. Ethernet.socketClose(_sockindex);
  68. _sockindex = MAX_SOCK_NUM;
  69. return 0;
  70. }
  71.  
  72. int EthernetClient::availableForWrite(void)
  73. {
  74. if (_sockindex >= MAX_SOCK_NUM) return 0;
  75. return Ethernet.socketSendAvailable(_sockindex);
  76. }
  77.  
  78. size_t EthernetClient::write(uint8_t b)
  79. {
  80. return write(&b, 1);
  81. }
  82.  
  83. size_t EthernetClient::write(const uint8_t *buf, size_t size)
  84. {
  85. if (_sockindex >= MAX_SOCK_NUM) return 0;
  86. if (Ethernet.socketSend(_sockindex, buf, size)) return size;
  87. setWriteError();
  88. return 0;
  89. }
  90.  
  91. int EthernetClient::available()
  92. {
  93. if (_sockindex >= MAX_SOCK_NUM) return 0;
  94. return Ethernet.socketRecvAvailable(_sockindex);
  95. // TODO: do the WIZnet chips automatically retransmit TCP ACK
  96. // packets if they are lost by the network? Someday this should
  97. // be checked by a man-in-the-middle test which discards certain
  98. // packets. If ACKs aren't resent, we would need to check for
  99. // returning 0 here and after a timeout do another Sock_RECV
  100. // command to cause the WIZnet chip to resend the ACK packet.
  101. }
  102.  
  103. int EthernetClient::read(uint8_t *buf, size_t size)
  104. {
  105. if (_sockindex >= MAX_SOCK_NUM) return 0;
  106. return Ethernet.socketRecv(_sockindex, buf, size);
  107. }
  108.  
  109. int EthernetClient::peek()
  110. {
  111. if (_sockindex >= MAX_SOCK_NUM) return -1;
  112. if (!available()) return -1;
  113. return Ethernet.socketPeek(_sockindex);
  114. }
  115.  
  116. int EthernetClient::read()
  117. {
  118. uint8_t b;
  119. if (Ethernet.socketRecv(_sockindex, &b, 1) > 0) return b;
  120. return -1;
  121. }
  122.  
  123. void EthernetClient::flush()
  124. {
  125. while (_sockindex < MAX_SOCK_NUM) {
  126. uint8_t stat = Ethernet.socketStatus(_sockindex);
  127. if (stat != SnSR::ESTABLISHED && stat != SnSR::CLOSE_WAIT) return;
  128. if (Ethernet.socketSendAvailable(_sockindex) >= W5100.SSIZE) return;
  129. }
  130. }
  131.  
  132. void EthernetClient::stop()
  133. {
  134. if (_sockindex >= MAX_SOCK_NUM) return;
  135.  
  136. // attempt to close the connection gracefully (send a FIN to other side)
  137. Ethernet.socketDisconnect(_sockindex);
  138. unsigned long start = millis();
  139.  
  140. // wait up to a second for the connection to close
  141. do {
  142. if (Ethernet.socketStatus(_sockindex) == SnSR::CLOSED) {
  143. _sockindex = MAX_SOCK_NUM;
  144. return; // exit the loop
  145. }
  146. delay(1);
  147. } while (millis() - start < _timeout);
  148.  
  149. // if it hasn't closed, close it forcefully
  150. Ethernet.socketClose(_sockindex);
  151. _sockindex = MAX_SOCK_NUM;
  152. }
  153.  
  154. uint8_t EthernetClient::connected()
  155. {
  156. if (_sockindex >= MAX_SOCK_NUM) return 0;
  157.  
  158. uint8_t s = Ethernet.socketStatus(_sockindex);
  159. return !(s == SnSR::LISTEN || s == SnSR::CLOSED || s == SnSR::FIN_WAIT ||
  160. (s == SnSR::CLOSE_WAIT && !available()));
  161. }
  162.  
  163. uint8_t EthernetClient::status()
  164. {
  165. if (_sockindex >= MAX_SOCK_NUM) return SnSR::CLOSED;
  166. return Ethernet.socketStatus(_sockindex);
  167. }
  168.  
  169. // the next function allows us to use the client returned by
  170. // EthernetServer::available() as the condition in an if-statement.
  171. bool EthernetClient::operator==(const EthernetClient& rhs)
  172. {
  173. if (_sockindex != rhs._sockindex) return false;
  174. if (_sockindex >= MAX_SOCK_NUM) return false;
  175. if (rhs._sockindex >= MAX_SOCK_NUM) return false;
  176. return true;
  177. }
  178.  
  179. // https://github.com/per1234/EthernetMod
  180. // from: https://github.com/ntruchsess/Arduino-1/commit/937bce1a0bb2567f6d03b15df79525569377dabd
  181. uint16_t EthernetClient::localPort()
  182. {
  183. if (_sockindex >= MAX_SOCK_NUM) return 0;
  184. uint16_t port;
  185. SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
  186. port = W5100.readSnPORT(_sockindex);
  187. SPI.endTransaction();
  188. return port;
  189. }
  190.  
  191. // https://github.com/per1234/EthernetMod
  192. // returns the remote IP address: https://forum.arduino.cc/index.php?topic=82416.0
  193. IPAddress EthernetClient::remoteIP()
  194. {
  195. if (_sockindex >= MAX_SOCK_NUM) return IPAddress((uint32_t)0);
  196. uint8_t remoteIParray[4];
  197. SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
  198. W5100.readSnDIPR(_sockindex, remoteIParray);
  199. SPI.endTransaction();
  200. return IPAddress(remoteIParray);
  201. }
  202.  
  203. // https://github.com/per1234/EthernetMod
  204. // from: https://github.com/ntruchsess/Arduino-1/commit/ca37de4ba4ecbdb941f14ac1fe7dd40f3008af75
  205. uint16_t EthernetClient::remotePort()
  206. {
  207. if (_sockindex >= MAX_SOCK_NUM) return 0;
  208. uint16_t port;
  209. SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
  210. port = W5100.readSnDPORT(_sockindex);
  211. SPI.endTransaction();
  212. return port;
  213. }
Advertisement
Add Comment
Please, Sign In to add comment