UpdSocket: Add multicast support.
[GB.NET] * NEW: UpdSocket: Add multicast support.
This commit is contained in:
parent
5be18a279d
commit
a86cb7430f
2 changed files with 190 additions and 59 deletions
|
@ -23,6 +23,7 @@
|
|||
|
||||
#define __CUDPSOCKET_C
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
@ -289,20 +290,56 @@ int CUdpSocket_stream_write(GB_STREAM *stream, char *buffer, int len)
|
|||
################################################################################################
|
||||
***********************************************************************************************/
|
||||
|
||||
static bool update_broadcast(CUDPSOCKET *_object)
|
||||
static bool return_error(int err, const char *msg)
|
||||
{
|
||||
if (SOCKET->socket < 0)
|
||||
return FALSE;
|
||||
|
||||
if (setsockopt(SOCKET->socket, SOL_SOCKET, SO_BROADCAST, (char *)&THIS->broadcast, sizeof(int)) < 0)
|
||||
if (err != 0)
|
||||
{
|
||||
GB.Error("Cannot set broadcast socket option");
|
||||
GB.Error(msg, strerror(errno));
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static bool update_broadcast(CUDPSOCKET *_object)
|
||||
{
|
||||
int broadcast;
|
||||
|
||||
if (SOCKET->socket < 0)
|
||||
return FALSE;
|
||||
|
||||
broadcast = THIS->broadcast;
|
||||
return return_error(setsockopt(SOCKET->socket, SOL_SOCKET, SO_BROADCAST, (char *)&broadcast, sizeof(int)),
|
||||
"Cannot set broadcast socket option: &1");
|
||||
}
|
||||
|
||||
static bool update_multicast_loop(CUDPSOCKET *_object)
|
||||
{
|
||||
if (SOCKET->socket < 0)
|
||||
return FALSE;
|
||||
|
||||
return return_error(setsockopt(SOCKET->socket, IPPROTO_IP, IP_MULTICAST_LOOP, &THIS->mc_loop, sizeof(unsigned char)),
|
||||
"Cannot set multicast loop socket option: &1");
|
||||
}
|
||||
|
||||
static bool update_multicast_ttl(CUDPSOCKET *_object)
|
||||
{
|
||||
if (SOCKET->socket < 0)
|
||||
return FALSE;
|
||||
|
||||
return return_error(setsockopt(SOCKET->socket, IPPROTO_IP, IP_MULTICAST_TTL, &THIS->mc_ttl, sizeof(unsigned char)),
|
||||
"Cannot set multicast ttl socket option: &1");
|
||||
}
|
||||
|
||||
static void fill_in_addr(struct in_addr *addr, const char *str)
|
||||
{
|
||||
addr->sin_family = PF_INET;
|
||||
if (!str || !*str)
|
||||
addr->sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
else
|
||||
addr->sin_addr.s_addr = inet_addr(str);
|
||||
}
|
||||
|
||||
static void dgram_start(CUDPSOCKET *_object)
|
||||
{
|
||||
sa_family_t domain;
|
||||
|
@ -328,28 +365,13 @@ static void dgram_start(CUDPSOCKET *_object)
|
|||
else
|
||||
{
|
||||
domain = PF_INET;
|
||||
if (THIS->port < 0 || THIS->port > 65535)
|
||||
{
|
||||
GB.Error("Invalid port number");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ((SOCKET->socket = socket(domain, SOCK_DGRAM, 0)) < 0)
|
||||
{
|
||||
SOCKET->status = NET_CANNOT_CREATE_SOCKET;
|
||||
GB.Ref(THIS);
|
||||
GB.Post(CUdpSocket_post_error, (intptr_t)THIS);
|
||||
return;
|
||||
}
|
||||
goto CANNOT_CREATE_SOCKET;
|
||||
|
||||
if (update_broadcast(THIS) || SOCKET_update_timeout(SOCKET))
|
||||
{
|
||||
SOCKET->status = NET_CANNOT_CREATE_SOCKET;
|
||||
GB.Ref(THIS);
|
||||
GB.Post(CUdpSocket_post_error,(intptr_t)THIS);
|
||||
return;
|
||||
}
|
||||
goto CANNOT_CREATE_SOCKET;
|
||||
|
||||
CLEAR(&THIS->addr);
|
||||
|
||||
|
@ -364,16 +386,29 @@ static void dgram_start(CUDPSOCKET *_object)
|
|||
}
|
||||
else
|
||||
{
|
||||
struct in_addr mc_interface_addr;
|
||||
|
||||
THIS->addr.in.sin_family = domain;
|
||||
if (!THIS->host)
|
||||
THIS->addr.in.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
else
|
||||
THIS->addr.in.sin_addr.s_addr = inet_addr(THIS->host);
|
||||
//THIS->addr.in.sin_addr.s_addr = inet_addr(THIS->host);
|
||||
inet_aton(THIS->hist, &THIS->addr.in.sin_addr));
|
||||
|
||||
THIS->addr.in.sin_port = htons(THIS->port);
|
||||
size = sizeof(struct sockaddr_in);
|
||||
addr = (struct sockaddr *)&THIS->addr.in;
|
||||
//bzero(&(THIS->addr.in.sin_zero), 8);
|
||||
|
||||
if (update_multicast_loop(THIS) || update_multicast_ttl(THIS))
|
||||
goto CANNOT_CREATE_SOCKET;
|
||||
|
||||
|
||||
if (THIS->mc_interface && *THIS->mc_interface)
|
||||
inet_aton(THIS->mc_interface, &mc_interface_addr));
|
||||
else
|
||||
mc_interface_addr.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
setsockopt(SOCKET->socket, IPPROTO_IP, IP_MULTICAST_IF, &mc_interface_addr, sizeof(mc_interface_addr));
|
||||
}
|
||||
|
||||
if (bind(SOCKET->socket, addr, size) < 0)
|
||||
|
@ -390,6 +425,14 @@ static void dgram_start(CUDPSOCKET *_object)
|
|||
GB.Stream.SetSwapping(&SOCKET->stream, htons(0x1234) != 0x1234);
|
||||
|
||||
GB.Watch(SOCKET->socket, GB_WATCH_READ, (void *)CUdpSocket_CallBack, (intptr_t)THIS);
|
||||
return;
|
||||
|
||||
CANNOT_CREATE_SOCKET:
|
||||
|
||||
SOCKET->status = NET_CANNOT_CREATE_SOCKET;
|
||||
GB.Ref(THIS);
|
||||
GB.Post(CUdpSocket_post_error, (intptr_t)THIS);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
@ -427,23 +470,32 @@ BEGIN_PROPERTY(UdpSocket_SourcePath)
|
|||
|
||||
END_PROPERTY
|
||||
|
||||
static void handle_address_property(void *_object, void *_param, char **store, bool allow_any)
|
||||
{
|
||||
char *addr;
|
||||
struct in_addr rem_ip;
|
||||
|
||||
if (READ_PROPERTY)
|
||||
{
|
||||
GB.ReturnString(*store);
|
||||
}
|
||||
else
|
||||
{
|
||||
addr = GB.ToZeroString(PROP(GB_STRING));
|
||||
|
||||
if ((*addr == 0 && !allow_any) || !inet_aton(addr, &rem_ip))
|
||||
{
|
||||
GB.Error("Invalid IP address");
|
||||
return;
|
||||
}
|
||||
|
||||
GB.StoreString(PROP(GB_STRING), store);
|
||||
}
|
||||
}
|
||||
|
||||
BEGIN_PROPERTY(UdpSocket_TargetHost)
|
||||
|
||||
char *strtmp;
|
||||
struct in_addr rem_ip;
|
||||
if (READ_PROPERTY)
|
||||
{
|
||||
GB.ReturnString(THIS->thost);
|
||||
return;
|
||||
}
|
||||
|
||||
strtmp=GB.ToZeroString(PROP(GB_STRING));
|
||||
if ( !inet_aton(strtmp,&rem_ip) )
|
||||
{
|
||||
GB.Error("Invalid IP address");
|
||||
return;
|
||||
}
|
||||
GB.StoreString(PROP(GB_STRING), &THIS->thost);
|
||||
handle_address_property(_object, _param, &THIS->thost, FALSE);
|
||||
|
||||
END_PROPERTY
|
||||
|
||||
|
@ -485,10 +537,13 @@ END_PROPERTY
|
|||
/*************************************************
|
||||
Gambas object "Constructor"
|
||||
*************************************************/
|
||||
|
||||
BEGIN_METHOD_VOID(UdpSocket_new)
|
||||
|
||||
SOCKET->stream.tag = _object;
|
||||
SOCKET->socket = -1;
|
||||
THIS->mc_loop = 1;
|
||||
THIS->mc_ttl = 1;
|
||||
|
||||
END_METHOD
|
||||
|
||||
|
@ -612,29 +667,100 @@ END_PROPERTY
|
|||
|
||||
BEGIN_PROPERTY(UdpSocket_Host)
|
||||
|
||||
struct in_addr rem_ip;
|
||||
|
||||
if (READ_PROPERTY)
|
||||
{
|
||||
GB.ReturnString(THIS->host);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!inet_aton(GB.ToZeroString(PROP(GB_STRING)), &rem_ip))
|
||||
{
|
||||
GB.Error("Invalid IP address");
|
||||
return;
|
||||
}
|
||||
|
||||
GB.StoreString(PROP(GB_STRING), &THIS->host);
|
||||
handle_address_property(_object, _param, &THIS->host, FALSE);
|
||||
|
||||
END_PROPERTY
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
BEGIN_PROPERTY(UdpSocketMulticast_Loop)
|
||||
|
||||
if (READ_PROPERTY)
|
||||
GB.ReturnBoolean(THIS->mc_loop);
|
||||
else
|
||||
{
|
||||
THIS->mc_loop = VPROP(GB_BOOLEAN);
|
||||
update_multicast_loop(THIS);
|
||||
}
|
||||
|
||||
END_PROPERTY
|
||||
|
||||
BEGIN_PROPERTY(UdpSocketMulticast_Ttl)
|
||||
|
||||
if (READ_PROPERTY)
|
||||
GB.ReturnInteger(THIS->mc_ttl);
|
||||
else
|
||||
{
|
||||
int ttl = VPROP(GB_INTEGER);
|
||||
if (ttl < 0 || ttl > 255)
|
||||
{
|
||||
GB.Error(GB_ERR_ARG);
|
||||
return;
|
||||
}
|
||||
THIS->mc_ttl = ttl;
|
||||
update_multicast_ttl(THIS);
|
||||
}
|
||||
|
||||
END_PROPERTY
|
||||
|
||||
BEGIN_PROPERTY(UdpSocketMulticast_Interface)
|
||||
|
||||
handle_address_property(_object, _param, &THIS->mc_interface, TRUE);
|
||||
|
||||
END_PROPERTY
|
||||
|
||||
static void handle_multicast_membership(CUDPSOCKET *_object, bool add, GB_STRING *group, GB_STRING *interface)
|
||||
{
|
||||
struct ip_mreq membership;
|
||||
|
||||
if (SOCKET->socket < 0)
|
||||
{
|
||||
GB.Error("UDP socket is not binded");
|
||||
return;
|
||||
}
|
||||
|
||||
membership.imr_multiaddr.s_addr = inet_addr(GB.ToZeroString(group));
|
||||
if (interface)
|
||||
membership.imr_interface.s_addr = inet_addr(GB.ToZeroString(interface));
|
||||
else
|
||||
membership.imr_interface.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
if (setsockopt(SOCKET->socket, IPPROTO_IP, add ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, &membership, sizeof(membership)))
|
||||
GB.Error(add ? "Cannot join multicast group: &1" : "Cannot leave multicast group: &1", strerror(errno));
|
||||
}
|
||||
|
||||
BEGIN_METHOD(UdpSocketMulticast_Join, GB_STRING group; GB_STRING interface)
|
||||
|
||||
handle_multicast_membership(THIS, TRUE, ARG(group), MISSING(interface) ? NULL : ARG(interface));
|
||||
|
||||
END_METHOD
|
||||
|
||||
BEGIN_METHOD(UdpSocketMulticast_Leave, GB_STRING group; GB_STRING interface)
|
||||
|
||||
handle_multicast_membership(THIS, FALSE, ARG(group), MISSING(interface) ? NULL : ARG(interface));
|
||||
|
||||
END_METHOD
|
||||
|
||||
|
||||
/***************************************************************
|
||||
Here we declare the public interface of UdpSocket class
|
||||
***************************************************************/
|
||||
|
||||
GB_DESC CUdpSocketMulticastDesc[] =
|
||||
{
|
||||
GB_DECLARE_VIRTUAL(".UdpSocket.Multicast"),
|
||||
|
||||
GB_PROPERTY("Loop", "b", UdpSocketMulticast_Loop),
|
||||
GB_PROPERTY("Ttl", "i", UdpSocketMulticast_Ttl),
|
||||
GB_PROPERTY("Interface", "s", UdpSocketMulticast_Interface),
|
||||
|
||||
GB_METHOD("Join", NULL, UdpSocketMulticast_Join, "(Group)s[(Interface)s])"),
|
||||
GB_METHOD("Leave", NULL, UdpSocketMulticast_Leave, "(Group)s[(Interface)s])"),
|
||||
|
||||
GB_END_DECLARE
|
||||
};
|
||||
|
||||
GB_DESC CUdpSocketDesc[] =
|
||||
{
|
||||
GB_DECLARE("UdpSocket", sizeof(CUDPSOCKET)),
|
||||
|
@ -647,7 +773,7 @@ GB_DESC CUdpSocketDesc[] =
|
|||
GB_METHOD("_new", NULL, UdpSocket_new, NULL),
|
||||
GB_METHOD("_free", NULL, UdpSocket_free, NULL),
|
||||
GB_METHOD("Bind", NULL, UdpSocket_Bind, NULL),
|
||||
GB_METHOD("Peek","s",UdpSocket_Peek,NULL),
|
||||
GB_METHOD("Peek", "s", UdpSocket_Peek,NULL),
|
||||
|
||||
GB_PROPERTY_READ("Status", "i", UdpSocket_Status),
|
||||
GB_PROPERTY_READ("SourceHost", "s", UdpSocket_SourceHost),
|
||||
|
@ -663,6 +789,8 @@ GB_DESC CUdpSocketDesc[] =
|
|||
|
||||
GB_PROPERTY("Broadcast", "b", UdpSocket_Broadcast),
|
||||
GB_PROPERTY("Timeout", "i", Socket_Timeout),
|
||||
|
||||
GB_PROPERTY_SELF("Multicast", ".UdpSocket.Multicast"),
|
||||
|
||||
GB_CONSTANT("_IsControl", "b", TRUE),
|
||||
GB_CONSTANT("_IsVirtual", "b", TRUE),
|
||||
|
|
|
@ -46,15 +46,18 @@ typedef
|
|||
CSOCKET_COMMON common;
|
||||
NET_ADDRESS addr;
|
||||
char *thost;
|
||||
int tport;
|
||||
char *tpath;
|
||||
int broadcast;
|
||||
char *buffer;
|
||||
int buffer_pos;
|
||||
int buffer_len;
|
||||
char *path;
|
||||
char *host;
|
||||
int port;
|
||||
char *mc_interface;
|
||||
unsigned short tport;
|
||||
unsigned short port;
|
||||
unsigned char mc_loop;
|
||||
unsigned char mc_ttl;
|
||||
unsigned broadcast : 1;
|
||||
}
|
||||
CUDPSOCKET;
|
||||
|
||||
|
|
Loading…
Reference in a new issue