Add multicast and broadcast support

pull/1/head
Emilio Monti 2013-03-01 17:02:35 +00:00
parent 6a57daf691
commit a80058dc5f
20 changed files with 284 additions and 28 deletions

View File

@ -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;
}

View File

@ -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();
};

View File

@ -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;

View File

@ -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

View File

@ -55,7 +55,7 @@ public:
int get_port(void);
protected:
char _ipAddress[16];
char _ipAddress[17];
struct sockaddr_in _remoteHost;
};

View File

@ -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);

View File

@ -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();

View File

@ -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)

View File

@ -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

View File

@ -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
*

View File

@ -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

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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
{