The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"

#include "ppport.h"

#include <sys/socket.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::Multicast		PACKAGE = Socket::Multicast

INCLUDE: const-xs.inc

PROTOTYPES: ENABLE

void
pack_ip_mreq(imr_multiaddr_sv, imr_interface_sv)
	SV* imr_multiaddr_sv
	SV* imr_interface_sv
	PREINIT:
	struct ip_mreq mreq;
	struct in_addr imr_multiaddr;
	struct in_addr imr_interface;
	CODE:
	{

	STRLEN addrlen;
	char * addr;
	
	// Byte load multicast address, machine order
	addr = SvPVbyte(imr_multiaddr_sv, addrlen);

	if (addrlen == sizeof(imr_multiaddr) || addrlen == 4)
		imr_multiaddr.s_addr =
	            (addr[0] & 0xFF) << 24 |
	            (addr[1] & 0xFF) << 16 |
	            (addr[2] & 0xFF) <<  8 |
	            (addr[3] & 0xFF);
	else
		croak("Bad arg length for %s, length is %d, should be %d",
		      "Socket::Multicast::pack_ip_mreq",
		      addrlen, sizeof(addr));

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

	if (addrlen == sizeof(imr_interface) || addrlen == 4)
		imr_interface.s_addr =
		    (addr[0] & 0xFF) << 24 |
		    (addr[1] & 0xFF) << 16 |
		    (addr[2] & 0xFF) << 8 |
		    (addr[3] & 0xFF);
	else
		croak("Bad arg length for %s, length is %d, should be %d",
		      "Socket::Multicast::pack_ip_mreq",
		      addrlen, sizeof(addr));

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

	// Load values into struct and convert to network order
	mreq.imr_multiaddr.s_addr = htonl(imr_multiaddr.s_addr);
	mreq.imr_interface.s_addr = htonl(imr_interface.s_addr);

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