Mbed library for ENC28J60 Ethernet modules. Full support for TCP/IP and UDP Server, Client and HTTP server (webserver). DHCP and DNS is included.
Dependents: mBuino_ENC28_MQTT Nucleo_Web_ENC28J60 Nucleo_Web_ENC28J60_ADC Serial_over_Ethernet ... more
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 Tue Jul 12 2022 18:48:00 by 1.7.2