Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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 Sun Feb 26 2023 10:14:23 by
1.7.2