#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <malloc.h>
#include <sys/types.h>
#include <stropts.h>
#include <sys/conf.h>
#include <sys/socket.h>
#include <netdb.h>
#include <sys/param.h>
#include <netinet/in.h>

#include <poll.h>

#include "o1k_conf.h"
#include "o1k_network.h"
#include "packet.h"
#include "receive.h"


ReceiveState *
initialize_receive(O1kNetwork * network, int channel_offset)
{
    ReceiveState *receiver;
    int rsock;
    struct sockaddr_in *name;

    /*
     * .... create receiver state ....
     */
    receiver = (ReceiveState *) malloc(sizeof(ReceiveState));
    if (receiver == NULL)
	return (NULL);


    /*
     * .... open receiver socket and listen to anyone ....
     */
    if ((rsock = socket(AF_INET, network->type, 0)) < 0) {
	perror("socket");
	free(receiver);
	return (NULL);
    }
    name = &receiver->name;
    name->sin_family = AF_INET;
    name->sin_addr.s_addr = INADDR_ANY;
    name->sin_port = CHANNEL_BASE + network->rchannel + channel_offset;

    if (bind(rsock, (struct sockaddr *) name, sizeof(*name)) < 0) {
	perror("bind");
	close(rsock);
	free(receiver);
	return (NULL);
    }

    receiver->socket = rsock;

    {
	int value;

	ioctl(rsock, I_GRDOPT, &value);
	ioctl(rsock, I_SRDOPT, RMSGD);
    }

    /* for poll to tell us if there is a packet waiting for read */
    receiver->pollfds.fd = receiver->socket;;
    receiver->pollfds.events = POLLIN;
    receiver->pollfds.revents = 0;

    return (receiver);
}

int 
receive_packet(ReceiveState * receiver, PacketType * packet, O1kThread* thread)
{
    int len;
    int size;

    while (thread->isEnabled() && (receiver->pollfds.revents & POLLIN) == 0) {

      /* wait 100 msecs for packet */
      if (poll(&receiver->pollfds, 1, 100) < 0) {
        perror("poll failed");
        close(receiver->socket);
        free(receiver);
        return 0;
      }
    }
    
    if (!thread->isEnabled())
      return 0;
    
    /*
     * reset, so next time we will have to check at least once.
     */
    receiver->pollfds.revents &= ~POLLIN;

    len = read(receiver->socket, (char *) packet, sizeof(PacketType));
    size = sizeof(PacketHeader) + packet->header.size;
    if (len != size)
	return 0;
    return 1;
}


void 
close_receive(ReceiveState * receiver)
{
    close(receiver->socket);
    free(receiver);
}
