mbed OS5

Fork of UIPEthernet by Zoltan Hudak

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers UIPClient.cpp Source File

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