UpdSocket: Add multicast support.

[GB.NET]
* NEW: UpdSocket: Add multicast support.
This commit is contained in:
gambas 2020-08-18 23:16:05 +02:00
parent 5be18a279d
commit a86cb7430f
2 changed files with 190 additions and 59 deletions

View file

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

View file

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