mirror of https://github.com/ARMmbed/mbed-os.git
Add multicast and broadcast support
parent
6a57daf691
commit
a80058dc5f
|
@ -31,7 +31,8 @@
|
|||
/* TCP/IP and Network Interface Initialisation */
|
||||
static struct netif lpcNetif;
|
||||
|
||||
static char ip_addr[16] = "\0";
|
||||
static char mac_addr[19];
|
||||
static char ip_addr[17] = "\0";
|
||||
static bool use_dhcp = false;
|
||||
|
||||
static Semaphore tcpip_inited(0);
|
||||
|
@ -67,14 +68,23 @@ static void init_netif(ip_addr_t *ipaddr, ip_addr_t *netmask, ip_addr_t *gw) {
|
|||
netif_set_status_callback(&lpcNetif, netif_status_callback);
|
||||
}
|
||||
|
||||
static void set_mac_address(void) {
|
||||
char mac[6];
|
||||
mbed_mac_address(mac);
|
||||
snprintf(mac_addr, 19, "%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
}
|
||||
|
||||
int EthernetInterface::init() {
|
||||
use_dhcp = true;
|
||||
set_mac_address();
|
||||
init_netif(NULL, NULL, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int EthernetInterface::init(const char* ip, const char* mask, const char* gateway) {
|
||||
use_dhcp = false;
|
||||
|
||||
set_mac_address();
|
||||
strcpy(ip_addr, ip);
|
||||
|
||||
ip_addr_t ip_n, mask_n, gateway_n;
|
||||
|
@ -94,7 +104,7 @@ int EthernetInterface::connect(unsigned int timeout_ms) {
|
|||
if (use_dhcp) {
|
||||
dhcp_start(&lpcNetif);
|
||||
|
||||
// Wait for an IP
|
||||
// Wait for an IP Address
|
||||
// -1: error, 0: timeout
|
||||
inited = netif_up.wait(timeout_ms);
|
||||
} else {
|
||||
|
@ -120,6 +130,10 @@ int EthernetInterface::disconnect() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
char* EthernetInterface::getMACAddress() {
|
||||
return mac_addr;
|
||||
}
|
||||
|
||||
char* EthernetInterface::getIPAddress() {
|
||||
return ip_addr;
|
||||
}
|
||||
|
|
|
@ -49,10 +49,10 @@ public:
|
|||
|
||||
/** Connect
|
||||
* Bring the interface up, start DHCP if needed.
|
||||
* \param timeout_ms timeout in ms (default: (10)s).
|
||||
* \param timeout_ms timeout in ms (default: (15)s).
|
||||
* \return 0 on success, a negative number on failure
|
||||
*/
|
||||
static int connect(unsigned int timeout_ms=10000);
|
||||
static int connect(unsigned int timeout_ms=15000);
|
||||
|
||||
/** Disconnect
|
||||
* Bring the interface down
|
||||
|
@ -60,6 +60,14 @@ public:
|
|||
*/
|
||||
static int disconnect();
|
||||
|
||||
/** Get the MAC address of your Ethernet interface
|
||||
* \return a pointer to a string containing the MAC address
|
||||
*/
|
||||
static char* getMACAddress();
|
||||
|
||||
/** Get the IP address of your Ethernet interface
|
||||
* \return a pointer to a string containing the IP address
|
||||
*/
|
||||
static char* getIPAddress();
|
||||
};
|
||||
|
||||
|
|
|
@ -402,6 +402,8 @@ static struct pbuf *lpc_low_level_input(struct netif *netif)
|
|||
LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
|
||||
("lpc_low_level_input: Packet dropped with errors (0x%x)\n",
|
||||
lpc_enetif->prxs[idx].statusinfo));
|
||||
|
||||
p = NULL;
|
||||
} else {
|
||||
/* A packet is waiting, get length */
|
||||
length = (lpc_enetif->prxs[idx].statusinfo & 0x7FF) + 1;
|
||||
|
|
|
@ -18,8 +18,7 @@
|
|||
#include "Socket/Socket.h"
|
||||
#include "Socket/Endpoint.h"
|
||||
#include <cstring>
|
||||
|
||||
using std::memset;
|
||||
#include <cstdio>
|
||||
|
||||
Endpoint::Endpoint() {
|
||||
reset_address();
|
||||
|
@ -27,21 +26,34 @@ Endpoint::Endpoint() {
|
|||
Endpoint::~Endpoint() {}
|
||||
|
||||
void Endpoint::reset_address(void) {
|
||||
memset(&_remoteHost, 0, sizeof(struct sockaddr_in));
|
||||
std::memset(&_remoteHost, 0, sizeof(struct sockaddr_in));
|
||||
_ipAddress[0] = '\0';
|
||||
}
|
||||
|
||||
#include "stdio.h"
|
||||
|
||||
int Endpoint::set_address(const char* host, const int port) {
|
||||
//Resolve DNS address or populate hard-coded IP address
|
||||
struct hostent *server = ::gethostbyname(host);
|
||||
if (server == NULL)
|
||||
return -1; //Could not resolve address
|
||||
|
||||
reset_address();
|
||||
|
||||
// Set IP address
|
||||
std::memcpy((char*) &_remoteHost.sin_addr.s_addr,
|
||||
(char*) server->h_addr_list[0], server->h_length);
|
||||
// IP Address
|
||||
char address[5];
|
||||
char *p_address = address;
|
||||
|
||||
// Dot-decimal notation
|
||||
int result = std::sscanf(host, "%3u.%3u.%3u.%3u",
|
||||
(unsigned int*)&address[0], (unsigned int*)&address[1],
|
||||
(unsigned int*)&address[2], (unsigned int*)&address[3]);
|
||||
|
||||
if (result != 4) {
|
||||
// Resolve address with DNS
|
||||
struct hostent *host_address = lwip_gethostbyname(host);
|
||||
if (host_address == NULL)
|
||||
return -1; //Could not resolve address
|
||||
p_address = (char*)host_address->h_addr_list[0];
|
||||
}
|
||||
std::memcpy((char*)&_remoteHost.sin_addr.s_addr, p_address, 4);
|
||||
|
||||
// Address family
|
||||
_remoteHost.sin_family = AF_INET;
|
||||
|
||||
// Set port
|
||||
|
|
|
@ -55,7 +55,7 @@ public:
|
|||
int get_port(void);
|
||||
|
||||
protected:
|
||||
char _ipAddress[16];
|
||||
char _ipAddress[17];
|
||||
struct sockaddr_in _remoteHost;
|
||||
|
||||
};
|
||||
|
|
|
@ -41,6 +41,14 @@ int Socket::init_socket(int type) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int Socket::set_option(int level, int optname, const void *optval, socklen_t optlen) {
|
||||
return lwip_setsockopt(_sock_fd, level, optname, optval, optlen);
|
||||
}
|
||||
|
||||
int Socket::get_option(int level, int optname, void *optval, socklen_t *optlen) {
|
||||
return lwip_getsockopt(_sock_fd, level, optname, optval, optlen);
|
||||
}
|
||||
|
||||
int Socket::select(struct timeval *timeout, bool read, bool write) {
|
||||
fd_set fdSet;
|
||||
FD_ZERO(&fdSet);
|
||||
|
|
|
@ -47,6 +47,24 @@ public:
|
|||
*/
|
||||
void set_blocking(bool blocking, unsigned int timeout=1500);
|
||||
|
||||
/** Set socket options
|
||||
\param level stack level (see: lwip/sockets.h)
|
||||
\param optname option ID
|
||||
\param optval option value
|
||||
\param socklen_t length of the option value
|
||||
\return 0 on success, -1 on failure
|
||||
*/
|
||||
int set_option(int level, int optname, const void *optval, socklen_t optlen);
|
||||
|
||||
/** Get socket options
|
||||
\param level stack level (see: lwip/sockets.h)
|
||||
\param optname option ID
|
||||
\param optval buffer pointer where to write the option value
|
||||
\param socklen_t length of the option value
|
||||
\return 0 on success, -1 on failure
|
||||
*/
|
||||
int get_option(int level, int optname, void *optval, socklen_t *optlen);
|
||||
|
||||
/** Close the socket file descriptor
|
||||
*/
|
||||
int close();
|
||||
|
|
|
@ -49,6 +49,21 @@ int UDPSocket::bind(int port) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int UDPSocket::join_multicast_group(const char* address) {
|
||||
struct ip_mreq mreq;
|
||||
|
||||
// Set up group address
|
||||
mreq.imr_multiaddr.s_addr = inet_addr(address);
|
||||
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
return set_option(IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
|
||||
}
|
||||
|
||||
int UDPSocket::set_broadcasting(void) {
|
||||
int option = 1;
|
||||
return set_option(SOL_SOCKET, SO_BROADCAST, &option, sizeof(option));
|
||||
}
|
||||
|
||||
// -1 if unsuccessful, else number of bytes written
|
||||
int UDPSocket::sendTo(Endpoint &remote, char *packet, int length) {
|
||||
if (_sock_fd < 0)
|
||||
|
|
|
@ -45,6 +45,17 @@ public:
|
|||
*/
|
||||
int bind(int port);
|
||||
|
||||
/** Join the multicast group at the given address
|
||||
\param address The address of the multicast group
|
||||
\return 0 on success, -1 on failure.
|
||||
*/
|
||||
int join_multicast_group(const char* address);
|
||||
|
||||
/** Set the socket in broadcasting mode
|
||||
\return 0 on success, -1 on failure.
|
||||
*/
|
||||
int set_broadcasting(void);
|
||||
|
||||
/** Send a packet to a remote endpoint
|
||||
\param remote The remote endpoint
|
||||
\param packet The packet to be sent
|
||||
|
|
|
@ -139,7 +139,6 @@ static struct igmp_group *igmp_lookup_group(struct netif *ifp, ip_addr_t *addr);
|
|||
static err_t igmp_remove_group(struct igmp_group *group);
|
||||
static void igmp_timeout( struct igmp_group *group);
|
||||
static void igmp_start_timer(struct igmp_group *group, u8_t max_time);
|
||||
static void igmp_stop_timer(struct igmp_group *group);
|
||||
static void igmp_delaying_member(struct igmp_group *group, u8_t maxresp);
|
||||
static err_t igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif);
|
||||
static void igmp_send(struct igmp_group *group, u8_t type);
|
||||
|
@ -706,17 +705,6 @@ igmp_start_timer(struct igmp_group *group, u8_t max_time)
|
|||
group->timer = (LWIP_RAND() % (max_time - 1)) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop a timer for an igmp_group
|
||||
*
|
||||
* @param group the igmp_group for which to stop the timer
|
||||
*/
|
||||
static void
|
||||
igmp_stop_timer(struct igmp_group *group)
|
||||
{
|
||||
group->timer = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delaying membership report for a group if necessary
|
||||
*
|
||||
|
|
|
@ -59,6 +59,11 @@
|
|||
#define LWIP_DHCP 1
|
||||
#define LWIP_DNS 1
|
||||
|
||||
// Support Multicast
|
||||
#include "stdlib.h"
|
||||
#define LWIP_IGMP 1
|
||||
#define LWIP_RAND() rand()
|
||||
|
||||
#define LWIP_COMPAT_SOCKETS 0
|
||||
#define LWIP_POSIX_SOCKETS_IO_NAMES 0
|
||||
#define LWIP_SO_RCVTIMEO 1
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
#include "mbed.h"
|
||||
#include "EthernetInterface.h"
|
||||
|
||||
const int BROADCAST_PORT = 58083;
|
||||
|
||||
int main() {
|
||||
EthernetInterface eth;
|
||||
eth.init(); //Use DHCP
|
||||
eth.connect();
|
||||
|
||||
UDPSocket socket;
|
||||
socket.bind(BROADCAST_PORT);
|
||||
socket.set_broadcasting();
|
||||
|
||||
Endpoint broadcaster;
|
||||
char buffer[256];
|
||||
while (true) {
|
||||
printf("\nWait for packet...\n");
|
||||
int n = socket.receiveFrom(broadcaster, buffer, sizeof(buffer));
|
||||
buffer[n] = '\0';
|
||||
printf("Packet from \"%s\": %s\n", broadcaster.get_address(), buffer);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
#include "mbed.h"
|
||||
#include "EthernetInterface.h"
|
||||
|
||||
const int BROADCAST_PORT = 58083;
|
||||
|
||||
int main() {
|
||||
EthernetInterface eth;
|
||||
eth.init(); //Use DHCP
|
||||
eth.connect();
|
||||
|
||||
UDPSocket sock;
|
||||
sock.init();
|
||||
sock.set_broadcasting();
|
||||
|
||||
Endpoint broadcast;
|
||||
broadcast.set_address("255.255.255.255", BROADCAST_PORT);
|
||||
|
||||
char out_buffer[] = "very important data";
|
||||
|
||||
while (true) {
|
||||
printf("Broadcasting...\n");
|
||||
sock.sendTo(broadcast, out_buffer, sizeof(out_buffer));
|
||||
Thread::wait(1000);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
#include "mbed.h"
|
||||
#include "EthernetInterface.h"
|
||||
|
||||
const char* MCAST_GRP = "224.1.1.1";
|
||||
const int MCAST_PORT = 5007;
|
||||
|
||||
int main() {
|
||||
EthernetInterface eth;
|
||||
eth.init(); //Use DHCP
|
||||
eth.connect();
|
||||
|
||||
UDPSocket server;
|
||||
server.bind(MCAST_PORT);
|
||||
if (server.join_multicast_group(MCAST_GRP) != 0) {
|
||||
printf("Error joining the multicast group\n");
|
||||
while (true) {}
|
||||
}
|
||||
|
||||
Endpoint client;
|
||||
char buffer[256];
|
||||
while (true) {
|
||||
printf("\nWait for packet...\n");
|
||||
int n = server.receiveFrom(client, buffer, sizeof(buffer));
|
||||
|
||||
printf("Packet from \"%s\": %s\n", client.get_address(), buffer);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
#include "mbed.h"
|
||||
#include "EthernetInterface.h"
|
||||
|
||||
const char* MCAST_GRP = "224.1.1.1";
|
||||
const int MCAST_PORT = 5007;
|
||||
|
||||
int main() {
|
||||
EthernetInterface eth;
|
||||
eth.init(); //Use DHCP
|
||||
eth.connect();
|
||||
|
||||
UDPSocket sock;
|
||||
sock.init();
|
||||
|
||||
Endpoint multicast_group;
|
||||
multicast_group.set_address(MCAST_GRP, MCAST_PORT);
|
||||
|
||||
char out_buffer[] = "very important data";
|
||||
while (true) {
|
||||
printf("Multicast to group: %s\n", MCAST_GRP);
|
||||
sock.sendTo(multicast_group, out_buffer, sizeof(out_buffer));
|
||||
Thread::wait(1000);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
import socket
|
||||
|
||||
BROADCAST_PORT = 58083
|
||||
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
s.bind(('0.0.0.0', BROADCAST_PORT))
|
||||
|
||||
while True:
|
||||
print s.recvfrom(256)
|
|
@ -0,0 +1,14 @@
|
|||
import socket
|
||||
from time import sleep, time
|
||||
|
||||
BROADCAST_PORT = 58083
|
||||
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
s.bind(('', 0))
|
||||
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
|
||||
|
||||
while True:
|
||||
print "Broadcasting..."
|
||||
data = 'Hello World: ' + repr(time()) + '\n'
|
||||
s.sendto(data, ('<broadcast>', BROADCAST_PORT))
|
||||
sleep(1)
|
|
@ -0,0 +1,15 @@
|
|||
import socket
|
||||
import struct
|
||||
|
||||
MCAST_GRP = '224.1.1.1'
|
||||
MCAST_PORT = 5007
|
||||
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
sock.bind(('', MCAST_PORT))
|
||||
mreq = struct.pack("4sl", socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)
|
||||
|
||||
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
|
||||
|
||||
while True:
|
||||
print sock.recv(10240)
|
|
@ -0,0 +1,14 @@
|
|||
import socket
|
||||
from time import sleep, time
|
||||
|
||||
MCAST_GRP = '224.1.1.1'
|
||||
MCAST_PORT = 5007
|
||||
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
|
||||
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2)
|
||||
|
||||
while True:
|
||||
print "Multicast to group: %s\n" % MCAST_GRP
|
||||
data = 'Hello World: ' + repr(time()) + '\n'
|
||||
sock.sendto(data, (MCAST_GRP, MCAST_PORT))
|
||||
sleep(1)
|
|
@ -402,6 +402,30 @@ TESTS = [
|
|||
"dependencies": [MBED_LIBRARIES, RTOS_LIBRARIES, ETH_LIBRARY],
|
||||
"supported": CORTEX_ARM_SUPPORT,
|
||||
},
|
||||
{
|
||||
"id": "NET_9", "description": "NET: Multicast Send",
|
||||
"source_dir": join(TEST_DIR, "net", "helloworld", "multicast_send"),
|
||||
"dependencies": [MBED_LIBRARIES, RTOS_LIBRARIES, ETH_LIBRARY],
|
||||
"supported": CORTEX_ARM_SUPPORT,
|
||||
},
|
||||
{
|
||||
"id": "NET_10", "description": "NET: Multicast Receive",
|
||||
"source_dir": join(TEST_DIR, "net", "helloworld", "multicast_receive"),
|
||||
"dependencies": [MBED_LIBRARIES, RTOS_LIBRARIES, ETH_LIBRARY],
|
||||
"supported": CORTEX_ARM_SUPPORT,
|
||||
},
|
||||
{
|
||||
"id": "NET_11", "description": "NET: Broadcast Send",
|
||||
"source_dir": join(TEST_DIR, "net", "helloworld", "broadcast_send"),
|
||||
"dependencies": [MBED_LIBRARIES, RTOS_LIBRARIES, ETH_LIBRARY],
|
||||
"supported": CORTEX_ARM_SUPPORT,
|
||||
},
|
||||
{
|
||||
"id": "NET_12", "description": "NET: Broadcast Receive",
|
||||
"source_dir": join(TEST_DIR, "net", "helloworld", "broadcast_receive"),
|
||||
"dependencies": [MBED_LIBRARIES, RTOS_LIBRARIES, ETH_LIBRARY],
|
||||
"supported": CORTEX_ARM_SUPPORT,
|
||||
},
|
||||
|
||||
# Vodafone tests
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue