/**
 * @file interface.c
 *
 * @brief Service Placement interface implementation for Linux.
 *
 * Copyright 2007-2008, Freie Universitaet Berlin. All rights reserved.
 * Please refer to the COPYING file for detailed licensing information.
 *
 * @author Georg Wittenburg
 *
 * $Id: interface.c 2685 2008-06-25 16:38:56Z wittenbu $
 */



#include <stdio.h>
#include <stdlib.h>

#include <errno.h>
#include <error.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>

#include "../../types.h"
#include "../../vars.h"
#include "../../interface.h"
#include "../../util/debug.h"
#include "../../util/net.h"



/**
 * @brief Linux specific implemenation of __C_vprintf().
 */
void __C_vprintf(const char *format, va_list ap) {
	vprintf(format, ap);
}

/**
 * @brief Linux specific implemenation of __C_random().
 */
double __C_random(double max) {
	return (max * ((double) rand() / (double) RAND_MAX));
}

/**
 * @brief Linux specific implemenation of __C_time().
 */
C_time_t __C_time() {
	struct timeval tv;
	gettimeofday(&tv, NULL);
	return ((C_time_t) tv.tv_sec) + (((C_time_t) tv.tv_usec) / 1000000);
}

/**
 * @brief Linux specific implemenation of __C_send().
 */
void __C_send(const packet_header_t* header, const void* payload) {
	int packet_size = sizeof(packet_header_t) + header->payload_length;

	C_DEBUG(C_DEBUG_LEVEL_VERBOSE, "Sending packet of %d byte(s) to node %s (seqno=%d)...\n", packet_size, addr_to_str(header->to), header->seqno);

	// Copy packet header and payload to buffer.
	char *buffer;
	MALLOC_ARRAY(buffer, char, packet_size);
	memcpy(buffer, header, sizeof(packet_header_t));
	if(header->payload_length > 0)
		memcpy(buffer + sizeof(packet_header_t), payload, header->payload_length);

	// Assemable address information.
	struct sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = header->to;
	addr.sin_port = htons(C_DEFAULT_UDP_PORT);

	// Send packet.
	if(sendto(C_udp_socket, buffer, packet_size, 0, (struct sockaddr*) &addr, sizeof(struct sockaddr_in)) < 0) {
		int errsv = errno;
		C_DEBUG(C_DEBUG_LEVEL_ERROR, "Sending packet failed (%d).\n", errsv);
		error(0, errsv, NULL);
	}
}

/**
 * @brief Linux specific implemenation of C_active_callback().
 *
 * Callback activation is handled in the main loop, hence there is nothing to
 * do.
 */
void __C_activate_callback(C_time_t time) {
	// Nothing to do on Linux.
}
