/*
 *
 */
/* Includes used for some general things */
#include <stdio.h>
#include <stdlib.h>

#if defined(_WIN32)
#   include <winsock2.h>
#   include <ws2tcpip.h>
#   include <sys\types.h>
#   include <sys\timeb.h>
#   include <time.h>
#   define perror(x) fprintf(stderr,"%s: %d\n",x,::GetLastError());
#else
/* Includes used for most socket operations */
#   include <sys/types.h>
#   include <sys/socket.h>
#   include <netinet/in.h>
#   include <unistd.h>
#   include <netdb.h>
#   include <netinet/tcp.h>
/* Need this for UNIX socket */
#   include <sys/un.h>
/* Includes used for auxiliary calls: memset, etc. */
#   include <strings.h>
#   include <arpa/inet.h>
#   include <sys/time.h>
#   include <string.h>
typedef int SOCKET;
const int INVALID_SOCKET = -1;
const int SOCKET_ERROR = -1;
#endif /* _WIN32 */

typedef unsigned int u_int32;
typedef unsigned int u_int;

/*
 * msrc groupaddr groupport [groupttl]
 */
int main(int argc, char **argv)
{
    SOCKET sock;
    char buff[1024];
    struct sockaddr_in sin;
    char *interface = NULL;
	u_long groupaddr, count = 0, ifaceaddr = INADDR_ANY;
	u_short groupport;
	struct timeval tv = {1,0};
	u_char groupttl = 1;
	u_char ttlvar = groupttl;
	unsigned long int iface_addr = 0;
#if defined(_WIN32)
	unsigned long int iface_in;
#else
	struct in_addr iface_in;
#endif /* _WIN32 */

#if defined(_WIN32)
	WSADATA wsadata;
	int status;

	if ((status = WSAStartup(MAKEWORD(2,2),&wsadata)) != 0) {
		fprintf(stderr,"%s: WSA startup error - %d\n",argv[0],status);
		exit(1);
	}
#endif /* _WIN32 */

    if (argc == 3) {
		groupaddr = inet_addr(argv[1]);
		groupport = (u_short)atoi(argv[2]);
    } else if (argc == 4) {
		groupaddr = inet_addr(argv[1]);
		groupport = (u_short)atoi(argv[2]);
		ttlvar = groupttl = (u_char)atoi(argv[3]);
	} else if (argc == 5) {
		groupaddr = inet_addr(argv[1]);
		groupport = (u_short)atoi(argv[2]);
		ttlvar = groupttl = (u_char)atoi(argv[3]);
		iface_addr = inet_addr(argv[4]);
    } else {
		printf("usage: %s group port [ttl] [interface]\n", argv[0]);
		exit(1);
	}
		
    if((sock = socket(PF_INET,SOCK_DGRAM,0)) == INVALID_SOCKET) {
        perror("socket");
        exit(1);
    }

	memset((char *)&sin,0,sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = groupaddr;
    sin.sin_port = htons(groupport);
	if (connect(sock,(struct sockaddr *)&sin,sizeof(sin)) == SOCKET_ERROR) {
		perror("connect");
		exit(1);
	}

#if defined(_WIN32)
	unsigned int wttl = ttlvar;
	if (setsockopt(sock,IPPROTO_IP,IP_MULTICAST_TTL,(char *)&wttl,
				   sizeof(wttl)) == SOCKET_ERROR) {
		perror("setsockopt - TTL");
		exit(1);
	}
#else
	if (setsockopt(sock,IPPROTO_IP,IP_MULTICAST_TTL,(char *)&ttlvar,
				   sizeof(ttlvar)) == SOCKET_ERROR) {
		perror("setsockopt - TTL");
		exit(1);
	}
#endif /* _WIN32 */

	if (iface_addr != 0) {
#if !defined(_WIN32)
		::memset((char *)&iface_in,0,sizeof(iface_in));
		iface_in.s_addr = iface_addr;
#else
		iface_in = iface_addr;
#endif /* !_WIN32 */
		if(setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, (const char*)&iface_in, 
					  sizeof(iface_in)) == SOCKET_ERROR) {
			perror("setsockopt - IP_MULTICAST_IF");
			exit(1);
		}
	}

	for (;; count++) {
		sprintf(buff,"Message %x",count);
		if (send(sock,buff,strlen(buff),0) == SOCKET_ERROR) {
			perror("send");
			exit(1);
		}
#if defined(_WIN32)
		Sleep(1000);
#else
		sleep(1);
#endif /* _WIN32 */
		printf("Sending %d bytes\n",strlen(buff));
    }

#if defined(_WIN32)
	closesocket(sock);
#else
    close(sock);
#endif /* _WIN32 */
    return(0);
}



