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 "TcpClient.write: writePacket(%d) pos: %d, buf[%d-%d]\r\n", 00278 data->packets_out[p], 00279 data->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 #ifdef UIPETHERNET_DEBUG_CLIENT 00482 printf("uipclient_appcall why ? : %d\r\n",uip_flags); 00483 #endif 00484 uint16_t send_len = 0; 00485 uip_userdata_t* u = (uip_userdata_t*)uip_conn->appstate; 00486 if (!u && uip_connected()) 00487 { 00488 #ifdef UIPETHERNET_DEBUG_CLIENT 00489 printf("uipclient_appcall uip_connected\r\n"); 00490 TcpClient::_dumpAllData(); 00491 #endif 00492 u = (uip_userdata_t*)TcpClient::_allocateData(); 00493 if (u) { 00494 uip_conn->appstate = u; 00495 #ifdef UIPETHERNET_DEBUG_CLIENT 00496 printf("uipclient_appcall allocated state: %d", u->state); 00497 #endif 00498 } 00499 00500 #ifdef UIPETHERNET_DEBUG_CLIENT 00501 else 00502 printf("uipclient_appcall allocation failed\r\n"); 00503 #endif 00504 } 00505 00506 if (u) { 00507 if (uip_newdata()) 00508 { 00509 #ifdef UIPETHERNET_DEBUG_CLIENT 00510 printf("uipclient_appcall uip_newdata, uip_len: %d\r\n", uip_len); 00511 #endif 00512 if (uip_len && !(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED))) { 00513 for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) { 00514 if (u->packets_in[i] == NOBLOCK) { 00515 u->packets_in[i] = UipEthernet::ethernet->enc28j60Eth.allocBlock(uip_len); 00516 if (u->packets_in[i] != NOBLOCK) { 00517 UipEthernet::ethernet->enc28j60Eth.copyPacket 00518 ( 00519 u->packets_in[i], 00520 0, 00521 UipEthernet::inPacket, 00522 ((uint8_t*)uip_appdata) - uip_buf, 00523 uip_len 00524 ); 00525 if (i == UIP_SOCKET_NUMPACKETS - 1) 00526 uip_stop(); 00527 goto finish_newdata; 00528 } 00529 } 00530 } 00531 00532 UipEthernet::packetState &= ~UIPETHERNET_FREEPACKET; 00533 uip_stop(); 00534 } 00535 } 00536 00537 finish_newdata: 00538 if (u->state & UIP_CLIENT_RESTART) { 00539 u->state &= ~UIP_CLIENT_RESTART; 00540 uip_restart(); 00541 } 00542 00543 // If the connection has been closed, save received but unread data. 00544 if (uip_closed() || uip_timedout()) 00545 { 00546 #ifdef UIPETHERNET_DEBUG_CLIENT 00547 printf("uipclient_appcall uip_closed\r\n"); 00548 TcpClient::_dumpAllData(); 00549 #endif 00550 // drop outgoing packets not sent yet: 00551 00552 TcpClient::_flushBlocks(&u->packets_out[0]); 00553 if (u->packets_in[0] != NOBLOCK) { 00554 ((uip_userdata_closed_t*)u)->lport = uip_conn->lport; 00555 u->state |= UIP_CLIENT_REMOTECLOSED; 00556 } 00557 else 00558 u->state = 0; 00559 00560 // disassociate appdata. 00561 #ifdef UIPETHERNET_DEBUG_CLIENT 00562 printf("after uipclient_appcall uip_closed\r\n"); 00563 TcpClient::_dumpAllData(); 00564 #endif 00565 uip_conn->appstate = NULL; 00566 goto finish; 00567 } 00568 00569 if (uip_acked()) 00570 { 00571 #ifdef UIPETHERNET_DEBUG_CLIENT 00572 printf("uipclient_appcall uip_acked\r\n"); 00573 #endif 00574 TcpClient::_eatBlock(&u->packets_out[0]); 00575 uip_len = 0; 00576 } 00577 00578 if (uip_poll() || uip_rexmit()) 00579 { 00580 #ifdef UIPETHERNET_DEBUG_CLIENT 00581 //printf("uipclient_appcall uip_poll\r\n"); 00582 #endif 00583 if (u->packets_out[0] != NOBLOCK) { 00584 if (u->packets_out[1] == NOBLOCK) { 00585 send_len = u->out_pos; 00586 if (send_len > 0) { 00587 UipEthernet::ethernet->enc28j60Eth.resizeBlock(u->packets_out[0], 0, send_len); 00588 } 00589 } 00590 else 00591 send_len = UipEthernet::ethernet->enc28j60Eth.blockSize(u->packets_out[0]); 00592 if (send_len > 0) { 00593 UipEthernet::uipHeaderLen = ((uint8_t*)uip_appdata) - uip_buf; 00594 UipEthernet::uipPacket = UipEthernet::ethernet->enc28j60Eth.allocBlock(UipEthernet::uipHeaderLen + send_len); 00595 if (UipEthernet::uipPacket != NOBLOCK) { 00596 UipEthernet::ethernet->enc28j60Eth.copyPacket 00597 ( 00598 UipEthernet::uipPacket, 00599 UipEthernet::uipHeaderLen, 00600 u->packets_out[0], 00601 0, 00602 send_len 00603 ); 00604 UipEthernet::packetState |= UIPETHERNET_SENDPACKET; 00605 } 00606 } 00607 00608 goto finish; 00609 } 00610 } 00611 00612 // don't close connection unless all outgoing packets are sent 00613 if (u->state & UIP_CLIENT_CLOSE) 00614 { 00615 #ifdef UIPETHERNET_DEBUG_CLIENT 00616 printf("uipclient_appcall state UIP_CLIENT_CLOSE\r\n"); 00617 TcpClient::_dumpAllData(); 00618 #endif 00619 if (u->packets_out[0] == NOBLOCK) { 00620 u->state = 0; 00621 uip_conn->appstate = NULL; 00622 uip_close(); 00623 #ifdef UIPETHERNET_DEBUG_CLIENT 00624 printf("no blocks out -> free userdata\r\n"); 00625 TcpClient::_dumpAllData(); 00626 #endif 00627 } 00628 else { 00629 uip_stop(); 00630 #ifdef UIPETHERNET_DEBUG_CLIENT 00631 printf("blocks outstanding transfer -> uip_stop()\r\n"); 00632 #endif 00633 } 00634 } 00635 } 00636 00637 finish: 00638 uip_send(uip_appdata, send_len); 00639 uip_len = send_len; 00640 } 00641 00642 /** 00643 * @brief 00644 * @note 00645 * @param 00646 * @retval 00647 */ 00648 uip_userdata_t* TcpClient::_allocateData() 00649 { 00650 for (uint8_t sock = 0; sock < UIP_CONNS; sock++) { 00651 uip_userdata_t* data = &TcpClient::all_data[sock]; 00652 if (!data->state) { 00653 data->pollTimer.reset(); 00654 data->state = sock | UIP_CLIENT_CONNECTED; 00655 data->ripaddr[0] = 0; 00656 data->ripaddr[1] = 0; 00657 memset(data->packets_in, 0, sizeof(data->packets_in) / sizeof(data->packets_in[0])); 00658 memset(&data->packets_out, 0, sizeof(data->packets_out) / sizeof(data->packets_out[0])); 00659 data->out_pos = 0; 00660 return data; 00661 } 00662 } 00663 00664 return NULL; 00665 } 00666 00667 /** 00668 * @brief 00669 * @note 00670 * @param 00671 * @retval 00672 */ 00673 uint8_t TcpClient::_currentBlock(memhandle* block) 00674 { 00675 for (uint8_t i = 1; i < UIP_SOCKET_NUMPACKETS; i++) { 00676 if (block[i] == NOBLOCK) 00677 return i - 1; 00678 } 00679 00680 return UIP_SOCKET_NUMPACKETS - 1; 00681 } 00682 00683 /** 00684 * @brief 00685 * @note 00686 * @param 00687 * @retval 00688 */ 00689 void TcpClient::_eatBlock(memhandle* block) 00690 { 00691 #ifdef UIPETHERNET_DEBUG_CLIENT 00692 memhandle* start = block; 00693 printf("eatblock(%d): ", *block); 00694 for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) { 00695 printf("%d ", start[i]); 00696 } 00697 00698 printf("-> "); 00699 #endif 00700 UipEthernet::ethernet->enc28j60Eth.freeBlock(block[0]); 00701 for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS - 1; i++) { 00702 block[i] = block[i + 1]; 00703 } 00704 00705 block[UIP_SOCKET_NUMPACKETS - 1] = NOBLOCK; 00706 #ifdef UIPETHERNET_DEBUG_CLIENT 00707 for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) { 00708 printf("%d ", start[i]); 00709 } 00710 00711 printf("\r\n"); 00712 #endif 00713 } 00714 00715 /** 00716 * @brief 00717 * @note 00718 * @param 00719 * @retval 00720 */ 00721 void TcpClient::_flushBlocks(memhandle* block) 00722 { 00723 for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) { 00724 UipEthernet::ethernet->enc28j60Eth.freeBlock(block[i]); 00725 block[i] = NOBLOCK; 00726 } 00727 } 00728 00729 #ifdef UIPETHERNET_DEBUG_CLIENT 00730 00731 /** 00732 * @brief 00733 * @note 00734 * @param 00735 * @retval 00736 */ 00737 void TcpClient::_dumpAllData() 00738 { 00739 for (uint8_t i = 0; i < UIP_CONNS; i++) { 00740 printf("UIPClient::all_data[%d], state:%d packets_in: ", i, all_data[i].state); 00741 for (uint8_t j = 0; j < UIP_SOCKET_NUMPACKETS; j++) { 00742 printf("%d ", all_data[i].packets_in[j]); 00743 } 00744 00745 printf("\r\n"); 00746 if (all_data[i].state & UIP_CLIENT_REMOTECLOSED) { 00747 printf("state remote closed, local port: %d", htons(((uip_userdata_closed_t *) (&all_data[i]))->lport)); 00748 printf("\r\n"); 00749 } 00750 else { 00751 printf("packets_out: "); 00752 for (uint8_t j = 0; j < UIP_SOCKET_NUMPACKETS; j++) { 00753 printf("%d ", all_data[i].packets_out[j]); 00754 } 00755 00756 printf("\r\n"); 00757 printf("out_pos: %d\r\n", all_data[i].out_pos); 00758 } 00759 } 00760 } 00761 #endif
Generated on Fri Jul 15 2022 22:55:10 by
1.7.2