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.
UdpSocket.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 "UdpSocket.h" 00021 #include "DnsClient.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 /** 00034 * @brief 00035 * @note 00036 * @param 00037 * @retval 00038 */ 00039 UdpSocket::UdpSocket() : 00040 _uip_udp_conn(NULL), 00041 _timeout_ms(1000) 00042 { 00043 memset(&appdata, 0, sizeof(appdata)); 00044 } 00045 00046 /** 00047 * @brief 00048 * @note 00049 * @param 00050 * @retval 00051 */ 00052 UdpSocket::UdpSocket(int timeout_ms) : 00053 _uip_udp_conn(NULL), 00054 _timeout_ms(timeout_ms) 00055 { 00056 memset(&appdata, 0, sizeof(appdata)); 00057 } 00058 00059 /** 00060 * @brief 00061 * @note 00062 * @param 00063 * @retval 00064 */ 00065 UdpSocket::UdpSocket(UipEthernet* net, int timeout_ms /*= 1000*/ ) : 00066 _uip_udp_conn(NULL), 00067 _timeout_ms(timeout_ms) 00068 { 00069 memset(&appdata, 0, sizeof(appdata)); 00070 if (UipEthernet::ethernet != net) 00071 UipEthernet::ethernet = net; 00072 } 00073 00074 // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use 00075 uint8_t UdpSocket::begin(uint16_t port) 00076 { 00077 if (!_uip_udp_conn) { 00078 _uip_udp_conn = uip_udp_new(NULL, 0); 00079 } 00080 00081 if (_uip_udp_conn) { 00082 uip_udp_bind(_uip_udp_conn, htons(port)); 00083 _uip_udp_conn->appstate = &appdata; 00084 return 1; 00085 } 00086 00087 return 0; 00088 } 00089 00090 // Finish with the UDP socket 00091 void UdpSocket::stop() 00092 { 00093 if (_uip_udp_conn) { 00094 uip_udp_remove(_uip_udp_conn); 00095 _uip_udp_conn->appstate = NULL; 00096 _uip_udp_conn = NULL; 00097 UipEthernet::ethernet->enc28j60Eth.freeBlock(appdata.packet_in); 00098 UipEthernet::ethernet->enc28j60Eth.freeBlock(appdata.packet_next); 00099 UipEthernet::ethernet->enc28j60Eth.freeBlock(appdata.packet_out); 00100 memset(&appdata, 0, sizeof(appdata)); 00101 } 00102 } 00103 00104 /** 00105 * @brief 00106 * @note 00107 * @param 00108 * @retval 00109 */ 00110 void UdpSocket::close() 00111 { 00112 stop(); 00113 } 00114 00115 // Sending UDP packets 00116 // Start building up a packet to send to the remote host specific in ip and port 00117 00118 // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port 00119 int UdpSocket::beginPacket(IpAddress ip, uint16_t port) 00120 { 00121 UipEthernet::ethernet->tick(); 00122 if (ip && port) { 00123 uip_ipaddr_t ripaddr; 00124 uip_ip_addr(&ripaddr, ip); 00125 #ifdef UIPETHERNET_DEBUG_UDP 00126 printf("udp beginPacket, "); 00127 #endif 00128 if (_uip_udp_conn) { 00129 _uip_udp_conn->rport = htons(port); 00130 uip_ipaddr_copy(_uip_udp_conn->ripaddr, &ripaddr); 00131 } 00132 else { 00133 _uip_udp_conn = uip_udp_new(&ripaddr, htons(port)); 00134 if (_uip_udp_conn) 00135 { 00136 #ifdef UIPETHERNET_DEBUG_UDP 00137 printf("new connection, "); 00138 #endif 00139 _uip_udp_conn->appstate = &appdata; 00140 } 00141 else 00142 { 00143 #ifdef UIPETHERNET_DEBUG_UDP 00144 printf("failed to allocate new connection\r\n"); 00145 #endif 00146 return 0; 00147 } 00148 } 00149 00150 #ifdef UIPETHERNET_DEBUG_UDP 00151 char buf[16]; 00152 printf("rip: %s, port: %d\r\n", ip.toString(buf), port); 00153 #endif 00154 } 00155 00156 if (_uip_udp_conn) { 00157 if (appdata.packet_out == NOBLOCK) { 00158 appdata.packet_out = UipEthernet::ethernet->enc28j60Eth.allocBlock(UIP_UDP_MAXPACKETSIZE); 00159 appdata.out_pos = UIP_UDP_PHYH_LEN; 00160 if (appdata.packet_out != NOBLOCK) { 00161 return 1; 00162 } 00163 #ifdef UIPETHERNET_DEBUG_UDP 00164 else { 00165 printf("failed to allocate memory for packet\r\n"); 00166 } 00167 #endif 00168 } 00169 00170 #ifdef UIPETHERNET_DEBUG_UDP 00171 else { 00172 printf("previous packet on that connection not sent yet\r\n"); 00173 } 00174 #endif 00175 } 00176 00177 return 0; 00178 } 00179 00180 // Start building up a packet to send to the remote host specific in host and port 00181 00182 // Returns 1 if successful, 0 if there was a problem resolving the hostname or port 00183 int UdpSocket::beginPacket(const char* host, uint16_t port) 00184 { 00185 // Look up the host first 00186 int ret = 0; 00187 DnsClient dns; 00188 IpAddress remote_addr; 00189 00190 dns.begin(UipEthernet::ethernet->dnsServerIP()); 00191 ret = dns.getHostByName(host, remote_addr); 00192 if (ret == 1) { 00193 return beginPacket(remote_addr, port); 00194 } 00195 else { 00196 return ret; 00197 } 00198 } 00199 00200 // Finish off this packet and send it 00201 00202 // Returns 1 if the packet was sent successfully, 0 if there was an error 00203 int UdpSocket::endPacket() 00204 { 00205 if (_uip_udp_conn && appdata.packet_out != NOBLOCK) { 00206 appdata.send = true; 00207 UipEthernet::ethernet->enc28j60Eth.resizeBlock(appdata.packet_out, 0, appdata.out_pos); 00208 uip_udp_periodic_conn(_uip_udp_conn); 00209 if (uip_len > 0) { 00210 _send(&appdata); 00211 return 1; 00212 } 00213 } 00214 00215 return 0; 00216 } 00217 00218 // Write a single byte into the packet 00219 size_t UdpSocket::write(uint8_t c) 00220 { 00221 return write(&c, 1); 00222 } 00223 00224 // Write size bytes from buffer into the packet 00225 size_t UdpSocket::write(const uint8_t* buffer, size_t size) 00226 { 00227 if (appdata.packet_out != NOBLOCK) { 00228 size_t ret = UipEthernet::ethernet->enc28j60Eth.writePacket 00229 ( 00230 appdata.packet_out, 00231 appdata.out_pos, 00232 (uint8_t*)buffer, 00233 size 00234 ); 00235 appdata.out_pos += ret; 00236 return ret; 00237 } 00238 00239 return 0; 00240 } 00241 00242 // Start processing the next available incoming packet 00243 00244 // Returns the size of the packet in bytes, or 0 if no packets are available 00245 int UdpSocket::parsePacket() 00246 { 00247 UipEthernet::ethernet->tick(); 00248 #ifdef UIPETHERNET_DEBUG_UDP 00249 if (appdata.packet_in != NOBLOCK) { 00250 printf("udp parsePacket freeing previous packet: %d\r\n", appdata.packet_in); 00251 } 00252 #endif 00253 UipEthernet::ethernet->enc28j60Eth.freeBlock(appdata.packet_in); 00254 00255 appdata.packet_in = appdata.packet_next; 00256 appdata.packet_next = NOBLOCK; 00257 00258 #ifdef UIPETHERNET_DEBUG_UDP 00259 if (appdata.packet_in != NOBLOCK) { 00260 printf("udp parsePacket received packet: %d", appdata.packet_in); 00261 } 00262 #endif 00263 00264 int size = UipEthernet::ethernet->enc28j60Eth.blockSize(appdata.packet_in); 00265 #ifdef UIPETHERNET_DEBUG_UDP 00266 if (appdata.packet_in != NOBLOCK) { 00267 printf(", size: %d\r\n", size); 00268 } 00269 #endif 00270 return size; 00271 } 00272 00273 // Number of bytes remaining in the current packet 00274 size_t UdpSocket::available() 00275 { 00276 UipEthernet::ethernet->tick(); 00277 return UipEthernet::ethernet->enc28j60Eth.blockSize(appdata.packet_in); 00278 } 00279 00280 // Read a single byte from the current packet. Returns -1 if no byte is available. 00281 int UdpSocket::read() 00282 { 00283 static unsigned char c; 00284 if (read(&c, 1) > 0) { 00285 return c; 00286 } 00287 00288 return -1; 00289 } 00290 00291 // Read up to len bytes from the current packet and place them into buffer 00292 00293 // Returns the number of bytes read, or 0 if none are available 00294 size_t UdpSocket::read(unsigned char* buffer, size_t len) 00295 { 00296 UipEthernet::ethernet->tick(); 00297 if (appdata.packet_in != NOBLOCK) { 00298 memaddress read = UipEthernet::ethernet->enc28j60Eth.readPacket(appdata.packet_in, 0, buffer, len); 00299 if (read == UipEthernet::ethernet->enc28j60Eth.blockSize(appdata.packet_in)) { 00300 UipEthernet::ethernet->enc28j60Eth.freeBlock(appdata.packet_in); 00301 appdata.packet_in = NOBLOCK; 00302 } 00303 else 00304 UipEthernet::ethernet->enc28j60Eth.resizeBlock(appdata.packet_in, read); 00305 return read; 00306 } 00307 00308 return 0; 00309 } 00310 00311 // Return the next byte from the current packet without moving on to the next byte 00312 int UdpSocket::peek() 00313 { 00314 UipEthernet::ethernet->tick(); 00315 if (appdata.packet_in != NOBLOCK) { 00316 unsigned char c; 00317 if (UipEthernet::ethernet->enc28j60Eth.readPacket(appdata.packet_in, 0, &c, 1) == 1) 00318 return c; 00319 } 00320 00321 return -1; 00322 } 00323 00324 // Finish reading the current packet 00325 void UdpSocket::flush() 00326 { 00327 UipEthernet::ethernet->tick(); 00328 UipEthernet::ethernet->enc28j60Eth.freeBlock(appdata.packet_in); 00329 appdata.packet_in = NOBLOCK; 00330 } 00331 00332 // Return the IP address of the host who sent the current incoming packet 00333 IpAddress UdpSocket::remoteIP() 00334 { 00335 return _uip_udp_conn ? ip_addr_uip(_uip_udp_conn->ripaddr) : IpAddress(); 00336 } 00337 00338 // Return the port of the host who sent the current incoming packet 00339 uint16_t UdpSocket::remotePort() 00340 { 00341 return _uip_udp_conn ? ntohs(_uip_udp_conn->rport) : 0; 00342 } 00343 00344 // UIP callback function 00345 void uipudp_appcall() 00346 { 00347 if (uip_udp_userdata_t * data = (uip_udp_userdata_t *) (uip_udp_conn->appstate)) { 00348 if (uip_newdata()) { 00349 if (data->packet_next == NOBLOCK) { 00350 uip_udp_conn->rport = UDPBUF->srcport; 00351 uip_ipaddr_copy(uip_udp_conn->ripaddr, UDPBUF->srcipaddr); 00352 data->packet_next = UipEthernet::ethernet->enc28j60Eth.allocBlock(ntohs(UDPBUF->udplen) - UIP_UDPH_LEN); 00353 00354 //if we are unable to allocate memory the packet is dropped. udp doesn't guarantee packet delivery 00355 if (data->packet_next != NOBLOCK) { 00356 //discard Linklevel and IP and udp-header and any trailing bytes: 00357 UipEthernet::ethernet->enc28j60Eth.copyPacket 00358 ( 00359 data->packet_next, 00360 0, 00361 UipEthernet::inPacket, 00362 UIP_UDP_PHYH_LEN, 00363 UipEthernet::ethernet->enc28j60Eth.blockSize(data->packet_next) 00364 ); 00365 #ifdef UIPETHERNET_DEBUG_UDP 00366 printf 00367 ( 00368 "udp, uip_newdata received packet: %d, size: %d\r\n", 00369 data->packet_next, 00370 UipEthernet::ethernet->enc28j60Eth.blockSize(data->packet_next) 00371 ); 00372 #endif 00373 } 00374 } 00375 } 00376 00377 if (uip_poll() && data->send) 00378 { 00379 //set uip_slen (uip private) by calling uip_udp_send 00380 #ifdef UIPETHERNET_DEBUG_UDP 00381 printf 00382 ( 00383 "udp, uip_poll preparing packet to send: %d, size: %d\r\n", 00384 data->packet_out, 00385 UipEthernet::ethernet->enc28j60Eth.blockSize(data->packet_out) 00386 ); 00387 #endif 00388 UipEthernet::uipPacket = data->packet_out; 00389 UipEthernet::uipHeaderLen = UIP_UDP_PHYH_LEN; 00390 uip_udp_send(data->out_pos - (UIP_UDP_PHYH_LEN)); 00391 } 00392 } 00393 } 00394 00395 /** 00396 * @brief 00397 * @note 00398 * @param 00399 * @retval 00400 */ 00401 void UdpSocket::_send(uip_udp_userdata_t* data) 00402 { 00403 uip_arp_out(); //add arp 00404 if (uip_len == UIP_ARPHDRSIZE) { 00405 UipEthernet::uipPacket = NOBLOCK; 00406 UipEthernet::packetState &= ~UIPETHERNET_SENDPACKET; 00407 #ifdef UIPETHERNET_DEBUG_UDP 00408 printf("udp, uip_poll results in ARP-packet\r\n"); 00409 #endif 00410 } 00411 else { 00412 //arp found ethaddr for ip (otherwise packet is replaced by arp-request) 00413 data->send = false; 00414 data->packet_out = NOBLOCK; 00415 UipEthernet::packetState |= UIPETHERNET_SENDPACKET; 00416 #ifdef UIPETHERNET_DEBUG_UDP 00417 printf("udp, uip_packet to send: %d\r\n", UipEthernet::uipPacket); 00418 #endif 00419 } 00420 00421 UipEthernet::ethernet->network_send(); 00422 } 00423 #endif 00424 00425 /** 00426 * @brief 00427 * @note 00428 * @param 00429 * @retval 00430 */ 00431 nsapi_size_or_error_t UdpSocket::sendto(const char* host, uint16_t port, const void* data, size_t size) 00432 { 00433 DnsClient dns; 00434 IpAddress address; 00435 uint32_t address_bytes; 00436 00437 dns.begin(UipEthernet::ethernet->dnsServerIP()); 00438 if (dns.getHostByName(host, address) == 1) { 00439 address_bytes = address; 00440 _remote_addr = SocketAddress(&address_bytes, NSAPI_IPv4 , port); 00441 } 00442 else { 00443 _remote_addr = SocketAddress(host, port); 00444 } 00445 00446 if (beginPacket(host, port) == 0) { 00447 stop(); 00448 return NSAPI_ERROR_NO_ADDRESS ; 00449 } 00450 00451 if (write((uint8_t*)data, size) == 0) { 00452 stop(); 00453 return NSAPI_ERROR_WOULD_BLOCK ; 00454 }; 00455 00456 if (endPacket() <= 0) { 00457 stop(); 00458 return NSAPI_ERROR_WOULD_BLOCK ; 00459 } 00460 00461 return NSAPI_ERROR_OK ; 00462 } 00463 00464 /** 00465 * @brief 00466 * @note 00467 * @param 00468 * @retval 00469 */ 00470 nsapi_size_or_error_t UdpSocket::sendto(const SocketAddress& address, const void* data, size_t size) 00471 { 00472 IpAddress ip_addr(address.get_addr().bytes); 00473 uint16_t port = address.get_port(); 00474 00475 _remote_addr = address; 00476 00477 if (beginPacket(ip_addr, port) == 0) { 00478 stop(); 00479 return NSAPI_ERROR_NO_ADDRESS ; 00480 } 00481 00482 if (write((uint8_t*)data, size) == 0) { 00483 stop(); 00484 return NSAPI_ERROR_WOULD_BLOCK ; 00485 }; 00486 00487 if (endPacket() <= 0) { 00488 stop(); 00489 return NSAPI_ERROR_WOULD_BLOCK ; 00490 } 00491 00492 return NSAPI_ERROR_OK ; 00493 } 00494 00495 /** 00496 * @brief 00497 * @note 00498 * @param 00499 * @retval 00500 */ 00501 nsapi_size_or_error_t UdpSocket::recvfrom(SocketAddress* address, void* data, size_t size) 00502 { 00503 *address = _remote_addr; 00504 00505 Timer timer; 00506 int success; 00507 00508 timer.start(); 00509 do { 00510 success = parsePacket(); 00511 } while (!success && (timer.read_ms() < _timeout_ms)); 00512 00513 if (!success) { 00514 stop(); 00515 return NSAPI_ERROR_WOULD_BLOCK ; 00516 } 00517 00518 size_t n; 00519 size_t recv_count = 0; 00520 uint8_t* pos = (uint8_t*)data; 00521 00522 do { 00523 if (recv_count + available() <= size) { 00524 n = read(pos, available()); 00525 pos += n; 00526 recv_count += n; 00527 } 00528 else { 00529 return NSAPI_ERROR_NO_MEMORY ; 00530 } 00531 } while ((available() > 0) && (recv_count < size)); 00532 00533 flush(); 00534 00535 return NSAPI_ERROR_OK ; 00536 }
Generated on Sun Feb 26 2023 10:14:23 by
1.7.2