mbed OS5

Fork of UIPEthernet by Zoltan Hudak

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers UIPUdp.cpp Source File

UIPUdp.cpp

00001 /*
00002  UIPUdp.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  This program is free software: you can redistribute it and/or modify
00007  it under the terms of the GNU General Public License as published by
00008  the Free Software Foundation, either version 3 of the License, or
00009  (at your option) any later version.
00010 
00011  This program is distributed in the hope that it will be useful,
00012  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  GNU General Public License for more details.
00015 
00016  You should have received a copy of the GNU General Public License
00017  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00018  */
00019 #include "UIPEthernet.h"
00020 #include "UIPUdp.h"
00021 #include "Dns.h"
00022 
00023 extern "C"
00024 {
00025 #include "utility/uip-conf.h"
00026 #include "utility/uip.h"
00027 #include "utility/uip_arp.h"
00028 }
00029 #if UIP_UDP
00030 #define UIP_ARPHDRSIZE  42
00031 #define UDPBUF          ((struct uip_udpip_hdr*) &uip_buf[UIP_LLH_LEN])
00032 
00033 // Constructor
00034 UIPUDP::UIPUDP(void) :
00035     _uip_udp_conn(NULL) {
00036     memset(&appdata, 0, sizeof(appdata));
00037 }
00038 
00039 // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use
00040 uint8_t UIPUDP::begin(uint16_t port) {
00041     if (!_uip_udp_conn) {
00042         _uip_udp_conn = uip_udp_new(NULL, 0);
00043     }
00044 
00045     if (_uip_udp_conn) {
00046         uip_udp_bind(_uip_udp_conn, htons(port));
00047         _uip_udp_conn->appstate = &appdata;
00048         return 1;
00049     }
00050 
00051     return 0;
00052 }
00053 
00054 // Finish with the UDP socket
00055 void UIPUDP::stop(void) {
00056     if (_uip_udp_conn) {
00057         uip_udp_remove(_uip_udp_conn);
00058         _uip_udp_conn->appstate = NULL;
00059         _uip_udp_conn = NULL;
00060         uIPEthernet.network.freeBlock(appdata.packet_in);
00061         uIPEthernet.network.freeBlock(appdata.packet_next);
00062         uIPEthernet.network.freeBlock(appdata.packet_out);
00063         memset(&appdata, 0, sizeof(appdata));
00064     }
00065 }
00066 
00067 // Sending UDP packets
00068 // Start building up a packet to send to the remote host specific in ip and port
00069 
00070 // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port
00071 int UIPUDP::beginPacket(IPAddress ip, uint16_t port) {
00072     uIPEthernet.tick();
00073     if (ip && port) {
00074         uip_ipaddr_t    ripaddr;
00075         uip_ip_addr(&ripaddr, ip);
00076 #ifdef UIPETHERNET_DEBUG_UDP
00077         printf("udp beginPacket, ");
00078 #endif
00079         if (_uip_udp_conn) {
00080             _uip_udp_conn->rport = htons(port);
00081             uip_ipaddr_copy(_uip_udp_conn->ripaddr, &ripaddr);
00082         }
00083         else {
00084             _uip_udp_conn = uip_udp_new(&ripaddr, htons(port));
00085             if (_uip_udp_conn)
00086             {
00087 #ifdef UIPETHERNET_DEBUG_UDP
00088                 printf("new connection, ");
00089 #endif
00090                 _uip_udp_conn->appstate = &appdata;
00091             }
00092             else
00093             {
00094 #ifdef UIPETHERNET_DEBUG_UDP
00095                 printf("failed to allocate new connection\r\n");
00096 #endif
00097                 return 0;
00098             }
00099         }
00100 
00101 #ifdef UIPETHERNET_DEBUG_UDP
00102         printf("rip: %s, port: %d\r\n", ip.asString(), port);
00103 #endif
00104     }
00105 
00106     if (_uip_udp_conn) {
00107         if (appdata.packet_out == NOBLOCK) {
00108             appdata.packet_out = uIPEthernet.network.allocBlock(UIP_UDP_MAXPACKETSIZE);
00109             appdata.out_pos = UIP_UDP_PHYH_LEN;
00110             if (appdata.packet_out != NOBLOCK)
00111                 return 1;
00112 #ifdef UIPETHERNET_DEBUG_UDP
00113             else
00114                 printf("failed to allocate memory for packet\r\n");
00115 #endif
00116         }
00117 
00118 #ifdef UIPETHERNET_DEBUG_UDP
00119         else
00120             printf("previous packet on that connection not sent yet\r\n");
00121 #endif
00122     }
00123 
00124     return 0;
00125 }
00126 
00127 // Start building up a packet to send to the remote host specific in host and port
00128 
00129 // Returns 1 if successful, 0 if there was a problem resolving the hostname or port
00130 int UIPUDP::beginPacket(const char* host, uint16_t port) {
00131 
00132     // Look up the host first
00133     int         ret = 0;
00134     DNSClient   dns;
00135     IPAddress   remote_addr;
00136 
00137     dns.begin(uIPEthernet.dnsServerIP());
00138     ret = dns.getHostByName(host, remote_addr);
00139     if (ret == 1) {
00140         return beginPacket(remote_addr, port);
00141     }
00142     else {
00143         return ret;
00144     }
00145 }
00146 
00147 // Finish off this packet and send it
00148 
00149 // Returns 1 if the packet was sent successfully, 0 if there was an error
00150 int UIPUDP::endPacket(void) {
00151     if (_uip_udp_conn && appdata.packet_out != NOBLOCK) {
00152         appdata.send = true;
00153         uIPEthernet.network.resizeBlock(appdata.packet_out, 0, appdata.out_pos);
00154         uip_udp_periodic_conn(_uip_udp_conn);
00155         if (uip_len > 0) {
00156             _send(&appdata);
00157             return 1;
00158         }
00159     }
00160 
00161     return 0;
00162 }
00163 
00164 // Write a single byte into the packet
00165 size_t UIPUDP::write(uint8_t c) {
00166     return write(&c, 1);
00167 }
00168 
00169 // Write size bytes from buffer into the packet
00170 size_t UIPUDP::write(const uint8_t* buffer, size_t size) {
00171     if (appdata.packet_out != NOBLOCK) {
00172         size_t  ret = uIPEthernet.network.writePacket(appdata.packet_out, appdata.out_pos, (uint8_t*)buffer, size);
00173         appdata.out_pos += ret;
00174         return ret;
00175     }
00176 
00177     return 0;
00178 }
00179 
00180 // Start processing the next available incoming packet
00181 
00182 // Returns the size of the packet in bytes, or 0 if no packets are available
00183 int UIPUDP::parsePacket(void) {
00184     uIPEthernet.tick();
00185 #ifdef UIPETHERNET_DEBUG_UDP
00186     if (appdata.packet_in != NOBLOCK) {
00187         printf("udp parsePacket freeing previous packet: %d\r\n", appdata.packet_in);
00188     }
00189 #endif
00190     uIPEthernet.network.freeBlock(appdata.packet_in);
00191 
00192     appdata.packet_in = appdata.packet_next;
00193     appdata.packet_next = NOBLOCK;
00194 
00195 #ifdef UIPETHERNET_DEBUG_UDP
00196     if (appdata.packet_in != NOBLOCK) {
00197         printf("udp parsePacket received packet: %d", appdata.packet_in);
00198     }
00199 #endif
00200 
00201     int size = uIPEthernet.network.blockSize(appdata.packet_in);
00202 #ifdef UIPETHERNET_DEBUG_UDP
00203     if (appdata.packet_in != NOBLOCK) {
00204         printf(", size: %d\r\n", size);
00205     }
00206 #endif
00207     return size;
00208 }
00209 
00210 // Number of bytes remaining in the current packet
00211 int UIPUDP::available(void) {
00212     uIPEthernet.tick();
00213     return uIPEthernet.network.blockSize(appdata.packet_in);
00214 }
00215 
00216 // Read a single byte from the current packet
00217 int UIPUDP::read(void) {
00218     static unsigned char    c;
00219     if (read(&c, 1) > 0) {
00220         return c;
00221     }
00222 
00223     return -1;
00224 }
00225 
00226 // Read up to len bytes from the current packet and place them into buffer
00227 
00228 // Returns the number of bytes read, or 0 if none are available
00229 int UIPUDP::read(unsigned char* buffer, size_t len) {
00230     uIPEthernet.tick();
00231     if (appdata.packet_in != NOBLOCK) {
00232         memaddress  read = uIPEthernet.network.readPacket(appdata.packet_in, 0, buffer, len);
00233         if (read == uIPEthernet.network.blockSize(appdata.packet_in)) {
00234             uIPEthernet.network.freeBlock(appdata.packet_in);
00235             appdata.packet_in = NOBLOCK;
00236         }
00237         else
00238             uIPEthernet.network.resizeBlock(appdata.packet_in, read);
00239         return read;
00240     }
00241 
00242     return 0;
00243 }
00244 
00245 // Return the next byte from the current packet without moving on to the next byte
00246 int UIPUDP::peek(void) {
00247     uIPEthernet.tick();
00248     if (appdata.packet_in != NOBLOCK) {
00249         unsigned char   c;
00250         if (uIPEthernet.network.readPacket(appdata.packet_in, 0, &c, 1) == 1)
00251             return c;
00252     }
00253 
00254     return -1;
00255 }
00256 
00257 // Finish reading the current packet
00258 void UIPUDP::flush(void) {
00259     uIPEthernet.tick();
00260     uIPEthernet.network.freeBlock(appdata.packet_in);
00261     appdata.packet_in = NOBLOCK;
00262 }
00263 
00264 // Return the IP address of the host who sent the current incoming packet
00265 IPAddress UIPUDP::remoteIP(void) {
00266     return _uip_udp_conn ? ip_addr_uip(_uip_udp_conn->ripaddr) : IPAddress();
00267 }
00268 
00269 // Return the port of the host who sent the current incoming packet
00270 uint16_t UIPUDP::remotePort(void) {
00271     return _uip_udp_conn ? ntohs(_uip_udp_conn->rport) : 0;
00272 }
00273 
00274 // UIP callback function
00275 void uipudp_appcall(void) {
00276     if (uip_udp_userdata_t * data = (uip_udp_userdata_t *) (uip_udp_conn->appstate)) {
00277         if (uip_newdata()) {
00278             if (data->packet_next == NOBLOCK) {
00279                 uip_udp_conn->rport = UDPBUF->srcport;
00280                 uip_ipaddr_copy(uip_udp_conn->ripaddr, UDPBUF->srcipaddr);
00281                 data->packet_next = uIPEthernet.network.allocBlock(ntohs(UDPBUF->udplen) - UIP_UDPH_LEN);
00282 
00283                 //if we are unable to allocate memory the packet is dropped. udp doesn't guarantee packet delivery
00284                 if (data->packet_next != NOBLOCK) {
00285 
00286                     //discard Linklevel and IP and udp-header and any trailing bytes:
00287                     uIPEthernet.network.copyPacket
00288                         (
00289                             data->packet_next,
00290                             0,
00291                             UIPEthernet::in_packet,
00292                             UIP_UDP_PHYH_LEN,
00293                             uIPEthernet.network.blockSize(data->packet_next)
00294                         );
00295 #ifdef UIPETHERNET_DEBUG_UDP
00296                     printf
00297                     (
00298                         "udp, uip_newdata received packet: %d, size: %d\r\n",
00299                         data->packet_next,
00300                         UIPEthernet.network.blockSize(data->packet_next)
00301                     );
00302 #endif
00303                 }
00304             }
00305         }
00306 
00307         if (uip_poll() && data->send)
00308         {
00309             //set uip_slen (uip private) by calling uip_udp_send
00310 #ifdef UIPETHERNET_DEBUG_UDP
00311             printf
00312             (
00313                 "udp, uip_poll preparing packet to send: %d, size: %d\r\n",
00314                 data->packet_out,
00315                 UIPEthernet.network.blockSize(data->packet_out)
00316             );
00317 #endif
00318             UIPEthernet::uip_packet = data->packet_out;
00319             UIPEthernet::uip_hdrlen = UIP_UDP_PHYH_LEN;
00320             uip_udp_send(data->out_pos - (UIP_UDP_PHYH_LEN));
00321         }
00322     }
00323 }
00324 
00325 /**
00326  * @brief
00327  * @note
00328  * @param
00329  * @retval
00330  */
00331 void UIPUDP::_send(uip_udp_userdata_t* data) {
00332     uip_arp_out();  //add arp
00333     if (uip_len == UIP_ARPHDRSIZE) {
00334         UIPEthernet::uip_packet = NOBLOCK;
00335         UIPEthernet::packetstate &= ~UIPETHERNET_SENDPACKET;
00336 #ifdef UIPETHERNET_DEBUG_UDP
00337         printf("udp, uip_poll results in ARP-packet\r\n");
00338 #endif
00339     }
00340     else {
00341 
00342         //arp found ethaddr for ip (otherwise packet is replaced by arp-request)
00343         data->send = false;
00344         data->packet_out = NOBLOCK;
00345         UIPEthernet::packetstate |= UIPETHERNET_SENDPACKET;
00346 #ifdef UIPETHERNET_DEBUG_UDP
00347         printf("udp, uip_packet to send: %d\r\n", UIPEthernet::uip_packet);
00348 #endif
00349     }
00350 
00351     uIPEthernet.network_send();
00352 }
00353 #endif
00354