The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
/*
    Copyright (C) 2006 Nicholas J Humfrey
    Copyright (C) 2006 Jonathan Steinert
    
    This library is free software; you can redistribute it and/or modify
    it under the same terms as Perl itself, either Perl version 5.6.1 or,
    at your option, any later version of Perl 5 you may have available.
*/

#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"

#include "ppport.h"

#include <sys/socket.h>
#include <netinet/in.h>

#ifdef WIN32
// winsock.h is for winsock <= 1.1
// #include <winsock.h>

// ws2tcpip.h is for winsock >= 2.0
#include <ws2tcpip.h>
#endif

#include "const-c.inc"

MODULE = Socket::Multicast6		PACKAGE = Socket::Multicast6

INCLUDE: const-xs.inc

PROTOTYPES: ENABLE

void
pack_ip_mreq(imr_multiaddr_sv, imr_interface_sv)
	SV* imr_multiaddr_sv
	SV* imr_interface_sv
  CODE:
	{
	struct ip_mreq mreq;
	STRLEN addrlen;
	char * addr;
	
	// Clear out final struct
	Zero( &mreq, 1, struct ip_mreq );


	// Byte load multicast address
	addr = SvPVbyte(imr_multiaddr_sv, addrlen);

	if (addrlen == sizeof(mreq.imr_multiaddr) || addrlen == 4)

		// Copy across the multicast address
		Copy( addr, &mreq.imr_multiaddr, 1, struct in_addr );

	else
		croak("Bad arg length for %s, length is %d, should be %d",
		      "Socket::Multicast6::pack_ip_mreq",
		      addrlen, sizeof(mreq.imr_multiaddr));



	// Byte load interface address
	addr = SvPVbyte(imr_interface_sv, addrlen);

	if (addrlen == sizeof(mreq.imr_interface) || addrlen == 4)

		// Copy across the interface address
		Copy( addr, &mreq.imr_interface, 1, struct in_addr );

	else
		croak("Bad arg length for %s, length is %d, should be %d",
		      "Socket::Multicast6::pack_ip_mreq",
		      addrlen, sizeof(mreq.imr_interface));

	// new mortal string, return it.
	ST(0) = sv_2mortal(newSVpvn((char *)&mreq, sizeof(mreq)));
	}



void
pack_ip_mreq_source(imr_multiaddr_sv, imr_source_sv, imr_interface_sv)
	SV* imr_multiaddr_sv
	SV* imr_source_sv
	SV* imr_interface_sv
  CODE:
	{
#ifdef IP_ADD_SOURCE_MEMBERSHIP
	struct ip_mreq_source mreq;
	STRLEN addrlen;
	char * addr;
	
	// Clear out final struct
	Zero( &mreq, 1, struct ip_mreq_source );


	// Byte load multicast address
	addr = SvPVbyte(imr_multiaddr_sv, addrlen);

	if (addrlen == sizeof(mreq.imr_multiaddr) || addrlen == 4)

		// Copy across the multicast address
		Copy( addr, &mreq.imr_multiaddr, 1, struct in_addr );

	else
		croak("Bad arg length for %s, length is %d, should be %d",
		      "Socket::Multicast6::ip_mreq_source",
		      addrlen, sizeof(mreq.imr_multiaddr));



	// Byte load source address
	addr = SvPVbyte(imr_source_sv, addrlen);

	if (addrlen == sizeof(mreq.imr_sourceaddr) || addrlen == 4)

		// Copy across the source address
		Copy( addr, &mreq.imr_sourceaddr, 1, struct in_addr );

	else
		croak("Bad arg length for %s, length is %d, should be %d",
		      "Socket::Multicast6::ip_mreq_source",
		      addrlen, sizeof(mreq.imr_sourceaddr));



	// Byte load interface address
	addr = SvPVbyte(imr_interface_sv, addrlen);

	if (addrlen == sizeof(mreq.imr_interface) || addrlen == 4)

		// Copy across the interface address
		Copy( addr, &mreq.imr_interface, 1, struct in_addr );

	else
		croak("Bad arg length for %s, length is %d, should be %d",
		      "Socket::Multicast6::ip_mreq_source",
		      addrlen, sizeof(mreq.imr_interface));

	// new mortal string, return it.
	ST(0) = sv_2mortal(newSVpvn((char *)&mreq, sizeof(mreq)));
#else 
	XSRETURN_UNDEF;
#endif
	}


void
pack_ipv6_mreq(imr_multiaddr_sv, imr_interface_idx)
	SV* imr_multiaddr_sv
	unsigned int imr_interface_idx
  CODE:
	{

	struct ipv6_mreq mreq;
	STRLEN addrlen;
	char * addr;

	// Clear out final struct
	Zero( &mreq, sizeof mreq, char );

	// Copy across the interface number
	mreq.ipv6mr_interface = imr_interface_idx;


	// Byte load multicast address
	addr = SvPVbyte(imr_multiaddr_sv, addrlen);

	if (addrlen == sizeof(mreq.ipv6mr_multiaddr) || addrlen == 16)

		// Copy accross the multicast address
		Copy( addr, &mreq.ipv6mr_multiaddr, 1, struct in6_addr );

	else
		croak("Bad arg length for %s, length is %d, should be %d",
		      "Socket::Multicast6::pack_ipv6_mreq",
		      addrlen, sizeof(mreq.ipv6mr_multiaddr));

	// new mortal string, return it.
	ST(0) = sv_2mortal(newSVpvn((char *)&mreq, sizeof(mreq)));
	}