Fork for fixes
Embed:
(wiki syntax)
Show/hide line numbers
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