/* A simple server in the Internet domain using TCP
   The port number is passed as an argument to this class */

#include "stdafx.h"
#include "EtherServer.h"

#pragma comment(lib, "ws2_32.lib")

// The constructor:
EtherServer::EtherServer(){	
        return;
}

EtherServer::~EtherServer() 
{ 
    CloseFileDescriptor();
    return;
}

unsigned int EtherServer::OpenEthernetPort(unsigned int port_number)
{
     unsigned int portno;

     struct sockaddr_in serv_addr;

	//The MAKEWORD macro creates a WORD value by concatenating the specified values.
	//The returned version is 0x0202 , modern windows versions can support Windows 
	//Sockets specification from 0x0101 to 0x0202
     version=MAKEWORD(2,2);                                        

	 //Initiates use of the Winsock DLL by a process.
     //If successful, the WSAStartup function returns zero. 
     //Otherwise, it returns an error code
     int returnCode = WSAStartup(version,&wsaData);         
     
	 //If Connection failed                         
     if(returnCode!=0)                                             
     {
          return EXIT_FAILURE;
     }
     
     // Create a new socket
     sockfd = socket(AF_INET, SOCK_DGRAM, PROTOCOL);
     
     // Make sure the socket was able to open correctly
     if (sockfd < 0)
     {
         return ERROR_OPENING_SOCKET;
     }
     
     // Set all values in the buffer to '0'
     //bzero((char *) &serv_addr, sizeof(serv_addr));
	 memset((void *)&serv_addr, '\0', sizeof(struct sockaddr_in));     //Clear information inside server struct
     
     // Set the port number
     portno = port_number;
     
     // Setup the server address
     serv_addr.sin_family = AF_INET; // Should always be this
     serv_addr.sin_addr.s_addr = INADDR_ANY; // EtherServer IP-Address
     
     /* htons() - converts a port number in host byte order to a port 
        number in network byte order. */
     serv_addr.sin_port = htons(portno);
     
     // Attempt to bind the port to the server
     if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0){
         return ERROR_ON_BINDING;
     } 
          
     return EXIT_SUCCESS; 
     
}

// Close the file descriptor
void EtherServer::CloseFileDescriptor()
{
    //close(sockfd);
}

// Get the client address
struct sockaddr_in EtherServer::GetClientInformation()
{
    return clientAddress;
}

// Write data bytes to the Ethernet interface
int EtherServer::Write(const char *charArray, unsigned int length)
{
    signed int n;
    unsigned int cli_addr_len;
    
    // Get the length of the client address structure
    cli_addr_len = sizeof(clientAddress);
    
    // Write something to the client
    n = sendto(sockfd, charArray, length, NO_FLAG, (struct sockaddr *) &clientAddress, cli_addr_len);

    // Make sure we were able to write the data to the client
    if (n < 0) return EXIT_FAILURE;  
    
    return EXIT_SUCCESS;
    
}

// This function will read data from the Ethernet port and will not wait (block)
int EtherServer::Retrieve(char *msg, unsigned int * size)
{    
    int cli_addr_len;
    
    // Get the length of the client address structure
    cli_addr_len = sizeof(clientAddress);    
    
    // Read the data... 
    *size = (int)recvfrom(sockfd,msg,MAX_BUFFER_SIZE, MSG_DONTWAIT, 
                (struct sockaddr *) &clientAddress, &cli_addr_len);  
    
    // n is the number of chars read... check to make sure it was positive
    if (*size < 0) 
        return EXIT_FAILURE;    
            
    return EXIT_SUCCESS;
}

// Read data bytes from the Ethernet interface and block until bytes are read
int EtherServer::RetrieveWait(char *msg, signed int * size)
{       
    int cli_addr_len;
    
    // Get the length of the client address structure
    cli_addr_len = sizeof(clientAddress);    
    
    // Read the data... Process to block until data is available 
    *size = (int)recvfrom(sockfd,msg,MAX_BUFFER_SIZE, NO_FLAG, 
                (struct sockaddr *) &clientAddress, &cli_addr_len);  
    
    // n is the number of chars read... check to make sure it was positive
    if (*size < 0) 
        return EXIT_FAILURE;    
            
    return EXIT_SUCCESS;
    
}


