mbed OS5
Fork of UIPEthernet by
Embed:
(wiki syntax)
Show/hide line numbers
UIPClient.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 "utility/millis.h" 00027 #include "string.h" 00028 } 00029 #include "UIPEthernet.h" 00030 #include "UIPClient.h" 00031 #include "Dns.h" 00032 00033 #define UIP_TCP_PHYH_LEN UIP_LLH_LEN + UIP_IPTCPH_LEN 00034 00035 uip_userdata_t UIPClient::all_data[UIP_CONNS]; 00036 00037 /** 00038 * @brief 00039 * @note 00040 * @param 00041 * @retval 00042 */ 00043 UIPClient::UIPClient(void) : 00044 data(NULL) 00045 { } 00046 00047 /** 00048 * @brief 00049 * @note 00050 * @param 00051 * @retval 00052 */ 00053 UIPClient::UIPClient(uip_userdata_t* conn_data) : 00054 data(conn_data) 00055 { } 00056 00057 /** 00058 * @brief 00059 * @note 00060 * @param 00061 * @retval 00062 */ 00063 int UIPClient::connect(IPAddress ip, uint16_t port) { 00064 stop(); 00065 00066 uip_ipaddr_t ipaddr; 00067 uip_ip_addr(ipaddr, ip); 00068 00069 struct uip_conn* conn = uip_connect(&ipaddr, htons(port)); 00070 if (conn) 00071 { 00072 #if UIP_CONNECT_TIMEOUT > 0 00073 int32_t timeout = millis() + 1000 * UIP_CONNECT_TIMEOUT; 00074 #endif 00075 while ((conn->tcpstateflags & UIP_TS_MASK) != UIP_CLOSED) { 00076 uIPEthernet.tick(); 00077 if ((conn->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED) { 00078 data = (uip_userdata_t*)conn->appstate; 00079 #ifdef UIPETHERNET_DEBUG_CLIENT 00080 printf("connected, state: %d, first packet in: %d\r\n", data->state, data->packets_in[0]); 00081 #endif 00082 return 1; 00083 } 00084 00085 #if UIP_CONNECT_TIMEOUT > 0 00086 if (((int32_t) (millis() - timeout)) > 0) { 00087 conn->tcpstateflags = UIP_CLOSED; 00088 break; 00089 } 00090 #endif 00091 } 00092 } 00093 00094 return 0; 00095 } 00096 00097 /** 00098 * @brief 00099 * @note 00100 * @param 00101 * @retval 00102 */ 00103 int UIPClient::connect(const char* host, uint16_t port) { 00104 00105 // Look up the host first 00106 int ret = 0; 00107 #if UIP_UDP 00108 DNSClient dns; 00109 IPAddress remote_addr; 00110 00111 dns.begin(UIPEthernet::_dnsServerAddress); 00112 ret = dns.getHostByName(host, remote_addr); 00113 if (ret == 1) { 00114 return connect(remote_addr, port); 00115 } 00116 #endif 00117 return ret; 00118 } 00119 00120 /** 00121 * @brief 00122 * @note 00123 * @param 00124 * @retval 00125 */ 00126 void UIPClient::stop(void) { 00127 if (data && data->state) 00128 { 00129 #ifdef UIPETHERNET_DEBUG_CLIENT 00130 printf("before stop(), with data\r\n"); 00131 _dumpAllData(); 00132 #endif 00133 _flushBlocks(&data->packets_in[0]); 00134 if (data->state & UIP_CLIENT_REMOTECLOSED) { 00135 data->state = 0; 00136 } 00137 else { 00138 data->state |= UIP_CLIENT_CLOSE; 00139 } 00140 00141 #ifdef UIPETHERNET_DEBUG_CLIENT 00142 printf("after stop()\r\n"); 00143 _dumpAllData(); 00144 #endif 00145 } 00146 00147 #ifdef UIPETHERNET_DEBUG_CLIENT 00148 else { 00149 printf("stop(), data: NULL\r\n"); 00150 } 00151 #endif 00152 data = NULL; 00153 uIPEthernet.tick(); 00154 } 00155 00156 /** 00157 * @brief 00158 * @note 00159 * @param 00160 * @retval 00161 */ 00162 uint8_t UIPClient::connected(void) { 00163 return(data && (data->packets_in[0] != NOBLOCK || (data->state & UIP_CLIENT_CONNECTED))) ? 1 : 0; 00164 } 00165 00166 /** 00167 * @brief 00168 * @note 00169 * @param 00170 * @retval 00171 */ 00172 bool UIPClient::operator==(const UIPClient& rhs) { 00173 return data && rhs.data && (data == rhs.data); 00174 } 00175 00176 /** 00177 * @brief 00178 * @note 00179 * @param 00180 * @retval 00181 */ 00182 UIPClient::operator bool(void) { 00183 uIPEthernet.tick(); 00184 return data && (!(data->state & UIP_CLIENT_REMOTECLOSED) || data->packets_in[0] != NOBLOCK); 00185 } 00186 00187 /** 00188 * @brief 00189 * @note 00190 * @param 00191 * @retval 00192 */ 00193 size_t UIPClient::write(uint8_t c) { 00194 return _write(data, &c, 1); 00195 } 00196 00197 /** 00198 * @brief 00199 * @note 00200 * @param 00201 * @retval 00202 */ 00203 size_t UIPClient::write(const uint8_t* buf, size_t size) { 00204 return _write(data, buf, size); 00205 } 00206 00207 /** 00208 * @brief 00209 * @note 00210 * @param 00211 * @retval 00212 */ 00213 size_t UIPClient::_write(uip_userdata_t* u, const uint8_t* buf, size_t size) { 00214 int remain = size; 00215 uint16_t written; 00216 #if UIP_ATTEMPTS_ON_WRITE > 0 00217 uint16_t attempts = UIP_ATTEMPTS_ON_WRITE; 00218 #endif 00219 repeat : uIPEthernet.tick(); 00220 if (u && !(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED))) { 00221 uint8_t p = _currentBlock(&u->packets_out[0]); 00222 if (u->packets_out[p] == NOBLOCK) 00223 { 00224 newpacket: 00225 u->packets_out[p] = uIPEthernet.network.allocBlock(UIP_SOCKET_DATALEN); 00226 if (u->packets_out[p] == NOBLOCK) 00227 { 00228 #if UIP_ATTEMPTS_ON_WRITE > 0 00229 if ((--attempts) > 0) 00230 #endif 00231 #if UIP_ATTEMPTS_ON_WRITE != 0 00232 goto repeat; 00233 #endif 00234 goto ready; 00235 } 00236 00237 u->out_pos = 0; 00238 } 00239 00240 #ifdef UIPETHERNET_DEBUG_CLIENT 00241 printf("UIPClient.write: writePacket(%d) pos: %d, buf[%d-%d]\r\n", u->packets_out[p], u->out_pos, size - remain, remain); 00242 #endif 00243 written = uIPEthernet.network.writePacket 00244 ( 00245 u->packets_out[p], 00246 u->out_pos, 00247 (uint8_t*)buf + size - remain, 00248 remain 00249 ); 00250 remain -= written; 00251 u->out_pos += written; 00252 if (remain > 0) { 00253 if (p == UIP_SOCKET_NUMPACKETS - 1) 00254 { 00255 #if UIP_ATTEMPTS_ON_WRITE > 0 00256 if ((--attempts) > 0) 00257 #endif 00258 #if UIP_ATTEMPTS_ON_WRITE != 0 00259 goto repeat; 00260 #endif 00261 goto ready; 00262 } 00263 00264 p++; 00265 goto newpacket; 00266 } 00267 00268 ready: 00269 #if UIP_CLIENT_TIMER >= 0 00270 u->timer = millis() + UIP_CLIENT_TIMER; 00271 #endif 00272 return size - remain; 00273 } 00274 00275 return -1; 00276 } 00277 00278 /** 00279 * @brief 00280 * @note 00281 * @param 00282 * @retval 00283 */ 00284 int UIPClient::available(void) { 00285 if (*this) 00286 return _available(data); 00287 return 0; 00288 } 00289 00290 /** 00291 * @brief 00292 * @note 00293 * @param 00294 * @retval 00295 */ 00296 int UIPClient::_available(uip_userdata_t* u) { 00297 int len = 0; 00298 for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) { 00299 len += uIPEthernet.network.blockSize(u->packets_in[i]); 00300 } 00301 00302 return len; 00303 } 00304 00305 /** 00306 * @brief 00307 * @note 00308 * @param 00309 * @retval 00310 */ 00311 int UIPClient::read(uint8_t* buf, size_t size) { 00312 if (*this) { 00313 uint16_t remain = size; 00314 if (data->packets_in[0] == NOBLOCK) 00315 return 0; 00316 00317 uint16_t read; 00318 do { 00319 read = uIPEthernet.network.readPacket(data->packets_in[0], 0, buf + size - remain, remain); 00320 if (read == uIPEthernet.network.blockSize(data->packets_in[0])) { 00321 remain -= read; 00322 _eatBlock(&data->packets_in[0]); 00323 if 00324 ( 00325 uip_stopped(&uip_conns[data->state & UIP_CLIENT_SOCKETS]) 00326 && !(data->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED)) 00327 ) data->state |= UIP_CLIENT_RESTART; 00328 if (data->packets_in[0] == NOBLOCK) { 00329 if (data->state & UIP_CLIENT_REMOTECLOSED) { 00330 data->state = 0; 00331 data = NULL; 00332 } 00333 00334 return size - remain; 00335 } 00336 } 00337 else { 00338 uIPEthernet.network.resizeBlock(data->packets_in[0], read); 00339 break; 00340 } 00341 } while (remain > 0); 00342 return size; 00343 } 00344 00345 return -1; 00346 } 00347 00348 /** 00349 * @brief 00350 * @note 00351 * @param 00352 * @retval 00353 */ 00354 int UIPClient::read(void) { 00355 static uint8_t c; 00356 if (read(&c, 1) < 0) 00357 return -1; 00358 return c; 00359 } 00360 00361 /** 00362 * @brief 00363 * @note 00364 * @param 00365 * @retval 00366 */ 00367 int UIPClient::peek(void) { 00368 static uint8_t c; 00369 if (*this) { 00370 if (data->packets_in[0] != NOBLOCK) { 00371 uIPEthernet.network.readPacket(data->packets_in[0], 0, &c, 1); 00372 return c; 00373 } 00374 } 00375 00376 return -1; 00377 } 00378 00379 /** 00380 * @brief 00381 * @note 00382 * @param 00383 * @retval 00384 */ 00385 void UIPClient::flush(void) { 00386 if (*this) { 00387 _flushBlocks(&data->packets_in[0]); 00388 } 00389 } 00390 00391 /** 00392 * @brief 00393 * @note 00394 * @param 00395 * @retval 00396 */ 00397 void uipclient_appcall(void) { 00398 uint16_t send_len = 0; 00399 uip_userdata_t* u = (uip_userdata_t*)uip_conn->appstate; 00400 if (!u && uip_connected()) 00401 { 00402 #ifdef UIPETHERNET_DEBUG_CLIENT 00403 printf("UIPClient uip_connected\r\n"); 00404 UIPClient::_dumpAllData(); 00405 #endif 00406 u = (uip_userdata_t*)UIPClient::_allocateData(); 00407 if (u) { 00408 uip_conn->appstate = u; 00409 #ifdef UIPETHERNET_DEBUG_CLIENT 00410 printf("UIPClient allocated state: %d", u->state); 00411 #endif 00412 } 00413 00414 #ifdef UIPETHERNET_DEBUG_CLIENT 00415 else 00416 printf("UIPClient allocation failed\r\n"); 00417 #endif 00418 } 00419 00420 if (u) { 00421 if (uip_newdata()) 00422 { 00423 #ifdef UIPETHERNET_DEBUG_CLIENT 00424 printf("UIPClient uip_newdata, uip_len: %d\r\n", uip_len); 00425 #endif 00426 if (uip_len && !(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED))) { 00427 for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) { 00428 if (u->packets_in[i] == NOBLOCK) { 00429 u->packets_in[i] = uIPEthernet.network.allocBlock(uip_len); 00430 if (u->packets_in[i] != NOBLOCK) { 00431 uIPEthernet.network.copyPacket 00432 ( 00433 u->packets_in[i], 00434 0, 00435 UIPEthernet::in_packet, 00436 ((uint8_t*)uip_appdata) - uip_buf, 00437 uip_len 00438 ); 00439 if (i == UIP_SOCKET_NUMPACKETS - 1) 00440 uip_stop(); 00441 goto finish_newdata; 00442 } 00443 } 00444 } 00445 00446 UIPEthernet::packetstate &= ~UIPETHERNET_FREEPACKET; 00447 uip_stop(); 00448 } 00449 } 00450 00451 finish_newdata: 00452 if (u->state & UIP_CLIENT_RESTART) { 00453 u->state &= ~UIP_CLIENT_RESTART; 00454 uip_restart(); 00455 } 00456 00457 // If the connection has been closed, save received but unread data. 00458 if (uip_closed() || uip_timedout()) 00459 { 00460 #ifdef UIPETHERNET_DEBUG_CLIENT 00461 printf("UIPClient uip_closed\r\n"); 00462 UIPClient::_dumpAllData(); 00463 #endif 00464 // drop outgoing packets not sent yet: 00465 00466 UIPClient::_flushBlocks(&u->packets_out[0]); 00467 if (u->packets_in[0] != NOBLOCK) { 00468 ((uip_userdata_closed_t*)u)->lport = uip_conn->lport; 00469 u->state |= UIP_CLIENT_REMOTECLOSED; 00470 } 00471 else 00472 u->state = 0; 00473 00474 // disassociate appdata. 00475 #ifdef UIPETHERNET_DEBUG_CLIENT 00476 printf("after UIPClient uip_closed\r\n"); 00477 UIPClient::_dumpAllData(); 00478 #endif 00479 uip_conn->appstate = NULL; 00480 goto finish; 00481 } 00482 00483 if (uip_acked()) 00484 { 00485 #ifdef UIPETHERNET_DEBUG_CLIENT 00486 printf("UIPClient uip_acked\r\n"); 00487 #endif 00488 UIPClient::_eatBlock(&u->packets_out[0]); 00489 } 00490 00491 if (uip_poll() || uip_rexmit()) 00492 { 00493 #ifdef UIPETHERNET_DEBUG_CLIENT 00494 //printf("UIPClient uip_poll\r\n"); 00495 #endif 00496 if (u->packets_out[0] != NOBLOCK) { 00497 if (u->packets_out[1] == NOBLOCK) { 00498 send_len = u->out_pos; 00499 if (send_len > 0) { 00500 uIPEthernet.network.resizeBlock(u->packets_out[0], 0, send_len); 00501 } 00502 } 00503 else 00504 send_len = uIPEthernet.network.blockSize(u->packets_out[0]); 00505 if (send_len > 0) { 00506 UIPEthernet::uip_hdrlen = ((uint8_t*)uip_appdata) - uip_buf; 00507 UIPEthernet::uip_packet = uIPEthernet.network.allocBlock(UIPEthernet::uip_hdrlen + send_len); 00508 if (UIPEthernet::uip_packet != NOBLOCK) { 00509 uIPEthernet.network.copyPacket 00510 ( 00511 UIPEthernet::uip_packet, 00512 UIPEthernet::uip_hdrlen, 00513 u->packets_out[0], 00514 0, 00515 send_len 00516 ); 00517 UIPEthernet::packetstate |= UIPETHERNET_SENDPACKET; 00518 } 00519 } 00520 00521 goto finish; 00522 } 00523 } 00524 00525 // don't close connection unless all outgoing packets are sent 00526 if (u->state & UIP_CLIENT_CLOSE) 00527 { 00528 #ifdef UIPETHERNET_DEBUG_CLIENT 00529 printf("UIPClient state UIP_CLIENT_CLOSE\r\n"); 00530 UIPClient::_dumpAllData(); 00531 #endif 00532 if (u->packets_out[0] == NOBLOCK) { 00533 u->state = 0; 00534 uip_conn->appstate = NULL; 00535 uip_close(); 00536 #ifdef UIPETHERNET_DEBUG_CLIENT 00537 printf("no blocks out -> free userdata\r\n"); 00538 UIPClient::_dumpAllData(); 00539 #endif 00540 } 00541 else { 00542 uip_stop(); 00543 #ifdef UIPETHERNET_DEBUG_CLIENT 00544 printf("blocks outstanding transfer -> uip_stop()\r\n"); 00545 #endif 00546 } 00547 } 00548 } 00549 00550 finish: 00551 uip_send(uip_appdata, send_len); 00552 uip_len = send_len; 00553 } 00554 00555 /** 00556 * @brief 00557 * @note 00558 * @param 00559 * @retval 00560 */ 00561 uip_userdata_t* UIPClient::_allocateData(void) { 00562 for (uint8_t sock = 0; sock < UIP_CONNS; sock++) { 00563 uip_userdata_t* data = &UIPClient::all_data[sock]; 00564 if (!data->state) { 00565 data->state = sock | UIP_CLIENT_CONNECTED; 00566 memset(&data->packets_in[0], 0, sizeof(uip_userdata_t) - sizeof(data->state)); 00567 return data; 00568 } 00569 } 00570 00571 return NULL; 00572 } 00573 00574 /** 00575 * @brief 00576 * @note 00577 * @param 00578 * @retval 00579 */ 00580 uint8_t UIPClient::_currentBlock(memhandle* block) { 00581 for (uint8_t i = 1; i < UIP_SOCKET_NUMPACKETS; i++) { 00582 if (block[i] == NOBLOCK) 00583 return i - 1; 00584 } 00585 00586 return UIP_SOCKET_NUMPACKETS - 1; 00587 } 00588 00589 /** 00590 * @brief 00591 * @note 00592 * @param 00593 * @retval 00594 */ 00595 void UIPClient::_eatBlock(memhandle* block) 00596 { 00597 #ifdef UIPETHERNET_DEBUG_CLIENT 00598 memhandle* start = block; 00599 printf("eatblock(%d): ", *block); 00600 for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) { 00601 printf("%d ", start[i]); 00602 } 00603 00604 printf("-> "); 00605 #endif 00606 uIPEthernet.network.freeBlock(block[0]); 00607 for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS - 1; i++) { 00608 block[i] = block[i + 1]; 00609 } 00610 00611 block[UIP_SOCKET_NUMPACKETS - 1] = NOBLOCK; 00612 #ifdef UIPETHERNET_DEBUG_CLIENT 00613 for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) { 00614 printf("%d ", start[i]); 00615 } 00616 00617 printf("\r\n"); 00618 #endif 00619 } 00620 00621 /** 00622 * @brief 00623 * @note 00624 * @param 00625 * @retval 00626 */ 00627 void UIPClient::_flushBlocks(memhandle* block) { 00628 for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) { 00629 uIPEthernet.network.freeBlock(block[i]); 00630 block[i] = NOBLOCK; 00631 } 00632 } 00633 00634 #ifdef UIPETHERNET_DEBUG_CLIENT 00635 00636 /** 00637 * @brief 00638 * @note 00639 * @param 00640 * @retval 00641 */ 00642 void UIPClient::_dumpAllData(void) { 00643 for (uint8_t i = 0; i < UIP_CONNS; i++) { 00644 printf("UIPClient::all_data[%d], state:%d packets_in: ", i, all_data[i].state); 00645 for (uint8_t j = 0; j < UIP_SOCKET_NUMPACKETS; j++) { 00646 printf("%d ", all_data[i].packets_in[j]); 00647 } 00648 00649 printf("\r\n"); 00650 if (all_data[i].state & UIP_CLIENT_REMOTECLOSED) { 00651 printf("state remote closed, local port: %d", htons(((uip_userdata_closed_t *) (&all_data[i]))->lport)); 00652 printf("\r\n"); 00653 } 00654 else { 00655 printf("packets_out: "); 00656 for (uint8_t j = 0; j < UIP_SOCKET_NUMPACKETS; j++) { 00657 printf("%d ", all_data[i].packets_out[j]); 00658 } 00659 00660 printf("\r\n"); 00661 printf("out_pos: %d\r\n", all_data[i].out_pos); 00662 } 00663 } 00664 } 00665 #endif 00666
Generated on Tue Jul 12 2022 18:10:58 by 1.7.2