Mbed library for ENC28J60 Ethernet modules. Full support for TCP/IP and UDP Server, Client and HTTP server (webserver). DHCP and DNS is included.
Dependents: mBuino_ENC28_MQTT Nucleo_Web_ENC28J60 Nucleo_Web_ENC28J60_ADC Serial_over_Ethernet ... more
TcpClient.cpp
00001 /* 00002 UIPClient.cpp - Arduino implementation of a UIP wrapper class. 00003 Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de> 00004 All rights reserved. 00005 00006 Modified (ported to mbed) by Zoltan Hudak <hudakz@inbox.com> 00007 00008 This program is free software: you can redistribute it and/or modify 00009 it under the terms of the GNU General Public License as published by 00010 the Free Software Foundation, either version 3 of the License, or 00011 (at your option) any later version. 00012 00013 This program is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 GNU General Public License for more details. 00017 00018 You should have received a copy of the GNU General Public License 00019 along with this program. If not, see <http://www.gnu.org/licenses/>. 00020 */ 00021 extern "C" 00022 { 00023 #include "utility/uip-conf.h" 00024 #include "utility/uip.h" 00025 #include "utility/uip_arp.h" 00026 #include "string.h" 00027 } 00028 #include "UipEthernet.h" 00029 #include "TcpClient.h" 00030 #include "DnsClient.h" 00031 00032 #define UIP_TCP_PHYH_LEN UIP_LLH_LEN + UIP_IPTCPH_LEN 00033 00034 uip_userdata_t TcpClient::all_data[UIP_CONNS]; 00035 00036 /** 00037 * @brief 00038 * @note 00039 * @param 00040 * @retval 00041 */ 00042 TcpClient::TcpClient() : 00043 data(NULL), 00044 _instance(NULL) 00045 { } 00046 00047 /** 00048 * @brief 00049 * @note 00050 * @param 00051 * @retval 00052 */ 00053 TcpClient::TcpClient(uip_userdata_t* conn_data) : 00054 data(conn_data), 00055 _instance(NULL) 00056 { } 00057 00058 /** 00059 * @brief 00060 * @note 00061 * @param 00062 * @retval 00063 */ 00064 int TcpClient::open(UipEthernet* ethernet) 00065 { 00066 if (UipEthernet::ethernet != ethernet) 00067 UipEthernet::ethernet = ethernet; 00068 00069 return 0; 00070 } 00071 00072 /** 00073 * @brief 00074 * @note 00075 * @param 00076 * @retval 00077 */ 00078 int TcpClient::connect(IpAddress ip, uint16_t port) 00079 { 00080 stop(); 00081 00082 uip_ipaddr_t ipaddr; 00083 uip_ip_addr(ipaddr, ip); 00084 00085 struct uip_conn* conn = uip_connect(&ipaddr, htons(port)); 00086 if (conn) 00087 { 00088 #if UIP_CONNECT_TIMEOUT > 0 00089 int32_t timeout = time(NULL) + UIP_CONNECT_TIMEOUT; 00090 #endif 00091 while ((conn->tcpstateflags & UIP_TS_MASK) != UIP_CLOSED) { 00092 UipEthernet::ethernet->tick(); 00093 if ((conn->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED) { 00094 data = (uip_userdata_t*)conn->appstate; 00095 #ifdef UIPETHERNET_DEBUG_CLIENT 00096 printf("connected, state: %d, first packet in: %d\r\n", data->state, data->packets_in[0]); 00097 #endif 00098 return 0; 00099 } 00100 00101 #if UIP_CONNECT_TIMEOUT > 0 00102 if (((int32_t) (time(NULL) - timeout)) > 0) { 00103 conn->tcpstateflags = UIP_CLOSED; 00104 break; 00105 } 00106 #endif 00107 } 00108 } 00109 00110 return 1; 00111 } 00112 00113 /** 00114 * @brief 00115 * @note 00116 * @param 00117 * @retval 00118 */ 00119 int TcpClient::connect(const char* host, uint16_t port) 00120 { 00121 // Look up the host first 00122 int ret = 0; 00123 #if UIP_UDP 00124 DnsClient dns; 00125 IpAddress remote_addr; 00126 00127 dns.begin(UipEthernet::dnsServerAddress); 00128 ret = dns.getHostByName(host, remote_addr); 00129 if (ret == 1) { 00130 return connect(remote_addr, port); 00131 } 00132 #endif 00133 return ret; 00134 } 00135 00136 /** 00137 * @brief 00138 * @note 00139 * @param 00140 * @retval 00141 */ 00142 void TcpClient::stop() 00143 { 00144 if (data && data->state) 00145 { 00146 #ifdef UIPETHERNET_DEBUG_CLIENT 00147 printf("before stop(), with data\r\n"); 00148 _dumpAllData(); 00149 #endif 00150 _flushBlocks(&data->packets_in[0]); 00151 if (data->state & UIP_CLIENT_REMOTECLOSED) { 00152 data->state = 0; 00153 } 00154 else { 00155 data->state |= UIP_CLIENT_CLOSE; 00156 } 00157 00158 #ifdef UIPETHERNET_DEBUG_CLIENT 00159 printf("after stop()\r\n"); 00160 _dumpAllData(); 00161 #endif 00162 } 00163 00164 #ifdef UIPETHERNET_DEBUG_CLIENT 00165 else { 00166 printf("stop(), data: NULL\r\n"); 00167 } 00168 #endif 00169 data = NULL; 00170 UipEthernet::ethernet->tick(); 00171 } 00172 00173 /** 00174 * @brief 00175 * @note 00176 * @param 00177 * @retval 00178 */ 00179 uint8_t TcpClient::connected() 00180 { 00181 return(data && (data->packets_in[0] != NOBLOCK || (data->state & UIP_CLIENT_CONNECTED))) ? 1 : 0; 00182 } 00183 00184 /** 00185 * @brief 00186 * @note 00187 * @param 00188 * @retval 00189 */ 00190 void TcpClient::setInstance(TcpClient *client) 00191 { 00192 _instance = client; 00193 } 00194 00195 /** 00196 * @brief 00197 * @note 00198 * @param 00199 * @retval 00200 */ 00201 bool TcpClient::operator==(const TcpClient& rhs) 00202 { 00203 return data && rhs.data && (data == rhs.data); 00204 } 00205 00206 /** 00207 * @brief 00208 * @note 00209 * @param 00210 * @retval 00211 */ 00212 TcpClient::operator bool() 00213 { 00214 UipEthernet::ethernet->tick(); 00215 return data && (!(data->state & UIP_CLIENT_REMOTECLOSED) || data->packets_in[0] != NOBLOCK); 00216 } 00217 00218 /** 00219 * @brief 00220 * @note 00221 * @param 00222 * @retval 00223 */ 00224 int TcpClient::send(uint8_t c) 00225 { 00226 return _write(data, &c, 1); 00227 } 00228 00229 /** 00230 * @brief 00231 * @note 00232 * @param 00233 * @retval 00234 */ 00235 int TcpClient::send(const uint8_t* buf, size_t size) 00236 { 00237 return _write(data, buf, size); 00238 } 00239 00240 /** 00241 * @brief 00242 * @note 00243 * @param 00244 * @retval 00245 */ 00246 int TcpClient::_write(uip_userdata_t* data, const uint8_t* buf, size_t size) 00247 { 00248 size_t remain = size; 00249 uint16_t written; 00250 #if UIP_ATTEMPTS_ON_WRITE > 0 00251 uint16_t attempts = UIP_ATTEMPTS_ON_WRITE; 00252 #endif 00253 repeat : UipEthernet::ethernet->tick(); 00254 if (data && !(data->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED))) { 00255 uint8_t p = _currentBlock(&data->packets_out[0]); 00256 if (data->packets_out[p] == NOBLOCK) 00257 { 00258 newpacket: 00259 data->packets_out[p] = UipEthernet::ethernet->enc28j60Eth.allocBlock(UIP_SOCKET_DATALEN); 00260 if (data->packets_out[p] == NOBLOCK) 00261 { 00262 #if UIP_ATTEMPTS_ON_WRITE > 0 00263 if (--attempts > 0) 00264 #endif 00265 #if UIP_ATTEMPTS_ON_WRITE != 0 00266 goto repeat; 00267 #endif 00268 goto ready; 00269 } 00270 00271 data->out_pos = 0; 00272 } 00273 00274 #ifdef UIPETHERNET_DEBUG_CLIENT 00275 printf 00276 ( 00277 "UIPClient.write: writePacket(%d) pos: %d, buf[%d-%d]\r\n", 00278 u->packets_out[p], 00279 u->out_pos, 00280 size - remain, 00281 remain 00282 ); 00283 #endif 00284 written = UipEthernet::ethernet->enc28j60Eth.writePacket 00285 ( 00286 data->packets_out[p], 00287 data->out_pos, 00288 (uint8_t*)buf + size - remain, 00289 remain 00290 ); 00291 remain -= written; 00292 data->out_pos += written; 00293 if (remain > 0) { 00294 if (p == UIP_SOCKET_NUMPACKETS - 1) 00295 { 00296 #if UIP_ATTEMPTS_ON_WRITE > 0 00297 if (--attempts > 0) 00298 #endif 00299 #if UIP_ATTEMPTS_ON_WRITE != 0 00300 goto repeat; 00301 #endif 00302 goto ready; 00303 } 00304 00305 p++; 00306 goto newpacket; 00307 } 00308 00309 ready: 00310 data->pollTimer.start(); 00311 return size - remain; 00312 } 00313 00314 return -1; 00315 } 00316 00317 /** 00318 * @brief 00319 * @note 00320 * @param 00321 * @retval 00322 */ 00323 size_t TcpClient::available() 00324 { 00325 if (*this) 00326 return _available(data); 00327 return 0; 00328 } 00329 00330 /** 00331 * @brief 00332 * @note 00333 * @param 00334 * @retval 00335 */ 00336 size_t TcpClient::_available(uip_userdata_t* u) 00337 { 00338 size_t len = 0; 00339 for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) { 00340 len += UipEthernet::ethernet->enc28j60Eth.blockSize(u->packets_in[i]); 00341 } 00342 00343 return len; 00344 } 00345 00346 /** 00347 * @brief 00348 * @note 00349 * @param 00350 * @retval 00351 */ 00352 int TcpClient::recv(uint8_t* buf, size_t size) 00353 { 00354 if (*this) { 00355 uint16_t remain = size; 00356 if (data->packets_in[0] == NOBLOCK) 00357 return 0; 00358 00359 uint16_t read; 00360 do { 00361 read = UipEthernet::ethernet->enc28j60Eth.readPacket(data->packets_in[0], 0, buf + size - remain, remain); 00362 if (read == UipEthernet::ethernet->enc28j60Eth.blockSize(data->packets_in[0])) { 00363 remain -= read; 00364 _eatBlock(&data->packets_in[0]); 00365 if 00366 ( 00367 uip_stopped(&uip_conns[data->state & UIP_CLIENT_SOCKETS]) && 00368 !(data->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED)) 00369 ) data->state |= UIP_CLIENT_RESTART; 00370 if (data->packets_in[0] == NOBLOCK) { 00371 if (data->state & UIP_CLIENT_REMOTECLOSED) { 00372 data->state = 0; 00373 data = NULL; 00374 } 00375 00376 return size - remain; 00377 } 00378 } 00379 else { 00380 UipEthernet::ethernet->enc28j60Eth.resizeBlock(data->packets_in[0], read); 00381 break; 00382 } 00383 } while (remain > 0); 00384 return size; 00385 } 00386 00387 return -1; 00388 } 00389 00390 /** 00391 * @brief 00392 * @note 00393 * @param 00394 * @retval 00395 */ 00396 int TcpClient::recv() 00397 { 00398 static uint8_t c; 00399 if (recv(&c, 1) < 0) 00400 return -1; 00401 return c; 00402 } 00403 00404 /** 00405 * @brief 00406 * @note 00407 * @param 00408 * @retval 00409 */ 00410 int TcpClient::peek() 00411 { 00412 static uint8_t c; 00413 if (*this) { 00414 if (data->packets_in[0] != NOBLOCK) { 00415 UipEthernet::ethernet->enc28j60Eth.readPacket(data->packets_in[0], 0, &c, 1); 00416 return c; 00417 } 00418 } 00419 00420 return -1; 00421 } 00422 00423 /** 00424 * @brief 00425 * @note 00426 * @param 00427 * @retval 00428 */ 00429 void TcpClient::flush() 00430 { 00431 if (*this) { 00432 _flushBlocks(&data->packets_in[0]); 00433 } 00434 } 00435 00436 /** 00437 * @brief 00438 * @note 00439 * @param 00440 * @retval 00441 */ 00442 IpAddress TcpClient::getRemoteIp() 00443 { 00444 return ip_addr_uip(data->ripaddr); 00445 } 00446 00447 /** 00448 * @brief 00449 * @note 00450 * @param 00451 * @retval 00452 */ 00453 const char* TcpClient::getpeername() 00454 { 00455 static char buf[16]; 00456 00457 return getRemoteIp().toString(buf); 00458 } 00459 00460 /** 00461 * @brief 00462 * @note 00463 * @param 00464 * @retval 00465 */ 00466 void TcpClient::close() 00467 { 00468 stop(); 00469 if (_instance) 00470 delete this; 00471 } 00472 00473 /** 00474 * @brief 00475 * @note 00476 * @param 00477 * @retval 00478 */ 00479 void uipclient_appcall() 00480 { 00481 uint16_t send_len = 0; 00482 uip_userdata_t* u = (uip_userdata_t*)uip_conn->appstate; 00483 if (!u && uip_connected()) 00484 { 00485 #ifdef UIPETHERNET_DEBUG_CLIENT 00486 printf("UIPClient uip_connected\r\n"); 00487 UIPClient::_dumpAllData(); 00488 #endif 00489 u = (uip_userdata_t*)TcpClient::_allocateData(); 00490 if (u) { 00491 uip_conn->appstate = u; 00492 #ifdef UIPETHERNET_DEBUG_CLIENT 00493 printf("UIPClient allocated state: %d", u->state); 00494 #endif 00495 } 00496 00497 #ifdef UIPETHERNET_DEBUG_CLIENT 00498 else 00499 printf("UIPClient allocation failed\r\n"); 00500 #endif 00501 } 00502 00503 if (u) { 00504 if (uip_newdata()) 00505 { 00506 #ifdef UIPETHERNET_DEBUG_CLIENT 00507 printf("UIPClient uip_newdata, uip_len: %d\r\n", uip_len); 00508 #endif 00509 if (uip_len && !(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED))) { 00510 for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) { 00511 if (u->packets_in[i] == NOBLOCK) { 00512 u->packets_in[i] = UipEthernet::ethernet->enc28j60Eth.allocBlock(uip_len); 00513 if (u->packets_in[i] != NOBLOCK) { 00514 UipEthernet::ethernet->enc28j60Eth.copyPacket 00515 ( 00516 u->packets_in[i], 00517 0, 00518 UipEthernet::inPacket, 00519 ((uint8_t*)uip_appdata) - uip_buf, 00520 uip_len 00521 ); 00522 if (i == UIP_SOCKET_NUMPACKETS - 1) 00523 uip_stop(); 00524 goto finish_newdata; 00525 } 00526 } 00527 } 00528 00529 UipEthernet::packetState &= ~UIPETHERNET_FREEPACKET; 00530 uip_stop(); 00531 } 00532 } 00533 00534 finish_newdata: 00535 if (u->state & UIP_CLIENT_RESTART) { 00536 u->state &= ~UIP_CLIENT_RESTART; 00537 uip_restart(); 00538 } 00539 00540 // If the connection has been closed, save received but unread data. 00541 if (uip_closed() || uip_timedout()) 00542 { 00543 #ifdef UIPETHERNET_DEBUG_CLIENT 00544 printf("UIPClient uip_closed\r\n"); 00545 UIPClient::_dumpAllData(); 00546 #endif 00547 // drop outgoing packets not sent yet: 00548 00549 TcpClient::_flushBlocks(&u->packets_out[0]); 00550 if (u->packets_in[0] != NOBLOCK) { 00551 ((uip_userdata_closed_t*)u)->lport = uip_conn->lport; 00552 u->state |= UIP_CLIENT_REMOTECLOSED; 00553 } 00554 else 00555 u->state = 0; 00556 00557 // disassociate appdata. 00558 #ifdef UIPETHERNET_DEBUG_CLIENT 00559 printf("after UIPClient uip_closed\r\n"); 00560 UIPClient::_dumpAllData(); 00561 #endif 00562 uip_conn->appstate = NULL; 00563 goto finish; 00564 } 00565 00566 if (uip_acked()) 00567 { 00568 #ifdef UIPETHERNET_DEBUG_CLIENT 00569 printf("UIPClient uip_acked\r\n"); 00570 #endif 00571 TcpClient::_eatBlock(&u->packets_out[0]); 00572 } 00573 00574 if (uip_poll() || uip_rexmit()) 00575 { 00576 #ifdef UIPETHERNET_DEBUG_CLIENT 00577 //printf("UIPClient uip_poll\r\n"); 00578 #endif 00579 if (u->packets_out[0] != NOBLOCK) { 00580 if (u->packets_out[1] == NOBLOCK) { 00581 send_len = u->out_pos; 00582 if (send_len > 0) { 00583 UipEthernet::ethernet->enc28j60Eth.resizeBlock(u->packets_out[0], 0, send_len); 00584 } 00585 } 00586 else 00587 send_len = UipEthernet::ethernet->enc28j60Eth.blockSize(u->packets_out[0]); 00588 if (send_len > 0) { 00589 UipEthernet::uipHeaderLen = ((uint8_t*)uip_appdata) - uip_buf; 00590 UipEthernet::uipPacket = UipEthernet::ethernet->enc28j60Eth.allocBlock(UipEthernet::uipHeaderLen + send_len); 00591 if (UipEthernet::uipPacket != NOBLOCK) { 00592 UipEthernet::ethernet->enc28j60Eth.copyPacket 00593 ( 00594 UipEthernet::uipPacket, 00595 UipEthernet::uipHeaderLen, 00596 u->packets_out[0], 00597 0, 00598 send_len 00599 ); 00600 UipEthernet::packetState |= UIPETHERNET_SENDPACKET; 00601 } 00602 } 00603 00604 goto finish; 00605 } 00606 } 00607 00608 // don't close connection unless all outgoing packets are sent 00609 if (u->state & UIP_CLIENT_CLOSE) 00610 { 00611 #ifdef UIPETHERNET_DEBUG_CLIENT 00612 printf("UIPClient state UIP_CLIENT_CLOSE\r\n"); 00613 UIPClient::_dumpAllData(); 00614 #endif 00615 if (u->packets_out[0] == NOBLOCK) { 00616 u->state = 0; 00617 uip_conn->appstate = NULL; 00618 uip_close(); 00619 #ifdef UIPETHERNET_DEBUG_CLIENT 00620 printf("no blocks out -> free userdata\r\n"); 00621 UIPClient::_dumpAllData(); 00622 #endif 00623 } 00624 else { 00625 uip_stop(); 00626 #ifdef UIPETHERNET_DEBUG_CLIENT 00627 printf("blocks outstanding transfer -> uip_stop()\r\n"); 00628 #endif 00629 } 00630 } 00631 } 00632 00633 finish: 00634 uip_send(uip_appdata, send_len); 00635 uip_len = send_len; 00636 } 00637 00638 /** 00639 * @brief 00640 * @note 00641 * @param 00642 * @retval 00643 */ 00644 uip_userdata_t* TcpClient::_allocateData() 00645 { 00646 for (uint8_t sock = 0; sock < UIP_CONNS; sock++) { 00647 uip_userdata_t* data = &TcpClient::all_data[sock]; 00648 if (!data->state) { 00649 data->pollTimer.reset(); 00650 data->state = sock | UIP_CLIENT_CONNECTED; 00651 data->ripaddr[0] = 0; 00652 data->ripaddr[1] = 0; 00653 memset(data->packets_in, 0, sizeof(data->packets_in) / sizeof(data->packets_in[0])); 00654 memset(&data->packets_out, 0, sizeof(data->packets_out) / sizeof(data->packets_out[0])); 00655 data->out_pos = 0; 00656 return data; 00657 } 00658 } 00659 00660 return NULL; 00661 } 00662 00663 /** 00664 * @brief 00665 * @note 00666 * @param 00667 * @retval 00668 */ 00669 uint8_t TcpClient::_currentBlock(memhandle* block) 00670 { 00671 for (uint8_t i = 1; i < UIP_SOCKET_NUMPACKETS; i++) { 00672 if (block[i] == NOBLOCK) 00673 return i - 1; 00674 } 00675 00676 return UIP_SOCKET_NUMPACKETS - 1; 00677 } 00678 00679 /** 00680 * @brief 00681 * @note 00682 * @param 00683 * @retval 00684 */ 00685 void TcpClient::_eatBlock(memhandle* block) 00686 { 00687 #ifdef UIPETHERNET_DEBUG_CLIENT 00688 memhandle* start = block; 00689 printf("eatblock(%d): ", *block); 00690 for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) { 00691 printf("%d ", start[i]); 00692 } 00693 00694 printf("-> "); 00695 #endif 00696 UipEthernet::ethernet->enc28j60Eth.freeBlock(block[0]); 00697 for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS - 1; i++) { 00698 block[i] = block[i + 1]; 00699 } 00700 00701 block[UIP_SOCKET_NUMPACKETS - 1] = NOBLOCK; 00702 #ifdef UIPETHERNET_DEBUG_CLIENT 00703 for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) { 00704 printf("%d ", start[i]); 00705 } 00706 00707 printf("\r\n"); 00708 #endif 00709 } 00710 00711 /** 00712 * @brief 00713 * @note 00714 * @param 00715 * @retval 00716 */ 00717 void TcpClient::_flushBlocks(memhandle* block) 00718 { 00719 for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) { 00720 UipEthernet::ethernet->enc28j60Eth.freeBlock(block[i]); 00721 block[i] = NOBLOCK; 00722 } 00723 } 00724 00725 #ifdef UIPETHERNET_DEBUG_CLIENT 00726 00727 /** 00728 * @brief 00729 * @note 00730 * @param 00731 * @retval 00732 */ 00733 void UIPClient::_dumpAllData() 00734 { 00735 for (uint8_t i = 0; i < UIP_CONNS; i++) { 00736 printf("UIPClient::all_data[%d], state:%d packets_in: ", i, all_data[i].state); 00737 for (uint8_t j = 0; j < UIP_SOCKET_NUMPACKETS; j++) { 00738 printf("%d ", all_data[i].packets_in[j]); 00739 } 00740 00741 printf("\r\n"); 00742 if (all_data[i].state & UIP_CLIENT_REMOTECLOSED) { 00743 printf("state remote closed, local port: %d", htons(((uip_userdata_closed_t *) (&all_data[i]))->lport)); 00744 printf("\r\n"); 00745 } 00746 else { 00747 printf("packets_out: "); 00748 for (uint8_t j = 0; j < UIP_SOCKET_NUMPACKETS; j++) { 00749 printf("%d ", all_data[i].packets_out[j]); 00750 } 00751 00752 printf("\r\n"); 00753 printf("out_pos: %d\r\n", all_data[i].out_pos); 00754 } 00755 } 00756 } 00757 #endif
Generated on Tue Jul 12 2022 18:48:00 by 1.7.2