/*
 * Copyright (C) 2008 The Trustees of Columbia University in the City of New York. 
 * All rights reserved.
 *
 * See the file LICENSE included in this distribution for details.
 */

#include "socketi.h"
#include "transport.h"

#include <string.h>

#ifdef _LINUX_
#include<sys/socket.h> //socket
#include <netinet/in.h> //hton, ntoh
#include <sys/types.h>  //socket
#include <fcntl.h>
#endif

#ifdef WIN32
#include <winsock.h>
#endif


int32 bindi(int32 sockid, uint16 port) {
  struct sockaddr_in myaddr;
  int ret;

  //bind UDP listener to UDP port
  myaddr.sin_family = AF_INET;
  myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  myaddr.sin_port = htons(port);
  memset(&(myaddr.sin_zero), '\0', 8);

  return bind(sockid, (struct sockaddr *)&myaddr, sizeof(myaddr));

  //port = ntohs(myaddr.sin_port);
  return ret;
}//bindi


int32 sendtoi(int32 sockfd, char* data, int32 size, char* ip, int32 port) {

  struct sockaddr_in dest_addr;
  int32 nbytes;

  dest_addr.sin_family = AF_INET;          // host byte order
  dest_addr.sin_port = htons(port);   // short, network byte order
  dest_addr.sin_addr.s_addr = inet_addr(ip);
  memset(&(dest_addr.sin_zero), '\0', 8);  // zero the rest of the struct

  nbytes = ::sendto(sockfd, data, size, 0, (struct sockaddr*)&dest_addr, sizeof(dest_addr));

  return nbytes;
}//sento


/*
 *sockfd: socket, timeoutval is value in ms
 */
int32 selectforsocket(int32 sockfd, int32 timeoutval) {
  fd_set selectfds;
  int32 sockmax;
  int readsocks=0;
  struct timeval timeout;
  
  //timeout value. set the timeout value in seconds
  timeout.tv_sec=timeoutval/1000;
  timeout.tv_usec=(timeoutval%1000) * 1000;

  FD_ZERO(&selectfds);
  FD_SET(sockfd, &selectfds);
  
  sockmax=sockfd+1;

  readsocks = select(sockmax, &selectfds, (fd_set*)0, (fd_set*)0, &timeout);

#ifdef WIN32
  if(0 == readsocks) {
    timeout.tv_sec = timeout.tv_usec = 0;
  }
#endif 

  //we do not have any data to read
  if(0 == timeout.tv_sec && 0 == timeout.tv_usec) {
    return 0;
  }//end if

  //we have data to read
  return 1;
}//selectforsocket


/*
 *FIXME BAD: if 1 set to NON-BLOCKING.
 *correct behavior is 1, then blocking
 */
int32 setBlocking(int32 sockid, int32 mode) {
  
  int32 ret=1;
  
  switch(mode) {
 
  case 0:
    //fcntl(sockid,F_SETFL,O_BLOCK);
    break;
  case 1:

#ifdef _LINUX_
    ret=fcntl(sockid,F_SETFL,O_NONBLOCK);
#endif
#ifdef WIN32
    u_long NonBlock=1;
    ret=ioctlsocket(sockid, FIONBIO, &NonBlock);
#endif
    break;
  }

  return ret;
}//setBlocking


/*
 *1 NON-BLOCKING
 *0 BLOCK
 */
int32 setNonblocking(int32 sockid, int32 mode) {
  
  int32 ret=1;
  
#ifdef WIN32
  u_long NonBlock;
#endif

  switch(mode) {
 
  case 0:
#ifdef _LINUX_
    //ret=fcntl(sockid,F_SETFL,O_BLOCK);
#endif
#ifdef WIN32
    NonBlock=0;
    ret=ioctlsocket(sockid, FIONBIO, &NonBlock);
#endif
    break;
  
  case 1:
#ifdef _LINUX_
    ret=fcntl(sockid,F_SETFL,O_NONBLOCK);
#endif
#ifdef WIN32
    NonBlock=1;
    ret=ioctlsocket(sockid, FIONBIO, &NonBlock);
#endif
    break;
  }//end switch

  return ret;
}//setBlocking



#ifdef WIN32
int close(int s) {
  return closesocket(s);
}//close

unsigned long inet_aton(const char* cp, struct in_addr* pin) {
  unsigned long temp;

  temp = inet_addr(cp);
  pin->s_addr = temp;

  return temp;
}
#endif

int32 getSockAddr_in(char *pchIP, int port, struct sockaddr_in *pstaddr) {
    pstaddr->sin_family=AF_INET;
    pstaddr->sin_addr.s_addr = inet_addr(pchIP);
    pstaddr->sin_port=htons(port);
    memset(pstaddr->sin_zero,'\0', sizeof(pstaddr->sin_zero));
	return 1;
}
