#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/select.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

int main(int argc, char **argv)
{
    char *host = argv[1];
    char buffer[1024];
    int port;
    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    ssize_t recsize;
    socklen_t fromlen;
    sockaddr_in serverAddr, clientAddr;
    fd_set rset;
    FD_ZERO(&rset);
    bool eofSocket = false;
    bool eofStdin = false;
    if(argc == 3)
    {
        port = atoi(argv[2]);
        // Client
        clientAddr.sin_family = AF_INET;
        clientAddr.sin_port = htons(port);
        serverAddr.sin_addr.s_addr = inet_addr(host);
        if(serverAddr.sin_addr.s_addr == -1)
        {
            struct hostent *hp = gethostbyname(host);
            if(!hp)
            {
                fprintf(stderr, "unknown host %s\n", host);
                return(1);
            }
            else
            {
                memcpy(&(clientAddr.sin_addr.s_addr), hp->h_addr, hp->h_length);
            }
        }
        printf("Connecting to %s (port %i)...\n", host, port);
        // Server
        serverAddr.sin_family = AF_INET;
        serverAddr.sin_port = htons(port);
        serverAddr.sin_addr.s_addr = INADDR_ANY;
        fromlen = sizeof(serverAddr);
        if (-1 == bind(sock,(struct sockaddr *)&serverAddr, sizeof(serverAddr)))
        {
            perror("error bind failed");
            close(sock);
            exit(EXIT_FAILURE);
        }
        printf("Listening on port %i...\n", port);
    }
    else
    {
        fprintf(stderr, "Usage: %s <remote-host> <port>\n\n", argv[0]);
        return(1);
    }
    while(!eofSocket && !eofStdin)
    {
        int res = -1;
        if(!eofStdin) FD_SET(0,&rset);
        FD_SET(sock, &rset);
        res = select(sock+1, &rset, 0, 0, 0);
        if (res < 0) {
            fprintf(stderr, "select failed!\n");
            exit(EXIT_FAILURE);
        }
        if(FD_ISSET(0, &rset))
        {
            int len = read(0,buffer,1023);
            if(len>0)
            {
                buffer[len] = 0;
                sendto(sock, buffer, strlen(buffer)+1, 0,(struct sockaddr*)&clientAddr, sizeof(clientAddr));
            }
            else eofStdin = true; 
        }
        if(FD_ISSET(sock, &rset))
        {
            recsize = recvfrom(sock, (void *)buffer, 1024, 0, (struct sockaddr *)&serverAddr, &fromlen);
            if (recsize > 0) printf("<remote> %s", buffer);
            else eofSocket = true;
        }
    }
    return(0);
}

