#include <winsock2.h>
#include <Ws2tcpip.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char **argv)
{
    // Declare and initialize variables
    WSADATA wsaData;
	SOCKET				s;
	struct addrinfo 	hints, *res=NULL;
	char				*szRemoteAddress=NULL, *szRemotePort=NULL;
	int					rc;
	char				sendbuf[1024] = "This is a test string from client!";
	int					BytesSent;

	// Validate the parameters
    if (argc != 3)
	{
        printf("Usage: %s <remote_host_name> <port_number>\n", argv[0]);
		printf("Example: %s www.bodopiang.com 7777\n", argv[0]);
		// Just return with error
        return 1;
    }

	// Initialize Winsock
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
	{
        printf("Client: WSAStartup() failed with error code %ld\n", WSAGetLastError());
        return 1;
    }
	else
		printf("Client: WSAStartup() looks fine!\n");
	

	// Parse the command line to obtain the remote server's hostname
	// or IP address along with the port number, which are contained
	// in szRemoteAddress and szRemotePort.
	memset(&hints, 0, sizeof(hints));
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;
	
	szRemoteAddress = argv[1];
	szRemotePort = argv[2];

	// first resolve assuming string is a string literal address
	// The addrinfo structure is used by the ANSI getaddrinfo()
	// function to hold host address information. The addrinfoW()
	// structure is the version of this structure used by the
	// Unicode GetAddrInfoW() function
	// res struct contains info of the remote response
	rc = getaddrinfo(szRemoteAddress, szRemotePort, &hints, &res);
	if (rc != 0)
	{
		printf("Client: getaddrinfo() failed miserabily with error code %ld\n", WSAGetLastError());
		WSACleanup();
		return 1;
	}
	else
		printf("Client: getaddrinfo() seems fine!\n");

	// The res struct info
	// http://msdn.microsoft.com/en-us/library/ms737530(VS.85).aspx
	printf("\n The getaddrinfo() options used: %d\n", res->ai_flags);
	printf(" The address family: %d\n", res->ai_family);
	printf(" The socket type: %d\n", res->ai_socktype);
	printf(" The protocol type: %d\n", res->ai_protocol);

	// The hints struct info
	printf("\n The hints.ai_family: %d\n", hints.ai_family);
	printf(" The hints.ai_socktype: %d\n", hints.ai_socktype);
	printf(" The hints.ai_protocol: %d\n", hints.ai_protocol);

	// Use the res info to create a socket
	s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
	if (s == INVALID_SOCKET)
	{
		printf("\nClient: socket() failed miserabily with error code %ld\n", WSAGetLastError());
		WSACleanup();
		return 1;
	}
	else
		printf("\nClient: socket() is OK\n");
	
	// Then use the res to connect
	rc = connect(s, res->ai_addr, res->ai_addrlen);

	if (rc == SOCKET_ERROR)
	{
		printf("Client: connect() failed miserabily with error code %ld\n", WSAGetLastError());
		WSACleanup();
		return 1;
	}
	else
		printf("Client: connect() is OK\n");

	printf("Client: I\'m ready to send or receive data...\n");
	// Sends some data to server/receiver...
	printf("	Sending: \"%s\"\n", sendbuf);
	BytesSent = send(s, sendbuf, strlen(sendbuf), 0);

	if(BytesSent == SOCKET_ERROR)
	{
		printf("Client: send() failed with error code %ld.\n", WSAGetLastError());
		closesocket(s);
		WSACleanup();
		return 1;
	}
	else
		printf("Client: send() is OK - bytes sent: %ld\n", BytesSent);
	
	// If the socket type is TCP - IPPROTO_TCP, do the shutdown
	if(res->ai_protocol == 6)
	{
		if(shutdown(s, SD_SEND) != 0)
		{
			printf("Client: shutdown() failed with error code: %ld\n", WSAGetLastError());
			WSACleanup();
			return 1;
		}
		else
			printf("Client: shutdown() the sending part...\n");
	}

	// Deallocate resource
	freeaddrinfo(res);
	// Close socket
	if(closesocket(s) != 0)
	{
		printf("Client: Cannot close s socket. Error code: %ld\n", WSAGetLastError());
		WSACleanup();
		return 1;
	}
	else
		printf("Client: Closing s socket...\n");

	// Clean up the WSA
	if(WSACleanup() != 0)
	{
		printf("Client: WSACleanup() failed!...\n");
		return 1;
	}
	else
		printf("Client: WSACleanup() is OK...\n");
    return 0;
}
