0

I want to set up a connection between my PC and an HTTP server on port 80. Is that feasible?

I tried the following code but it didn't work. It reports an error:

Connection setup failure: connection time out

From my perspective, UDT uses UDP, so is my plan going to work?

if ( UDT::startup() == UDT::ERROR )
{
    cout << "UDT::startup: " << UDT::getlasterror().getErrorMessage() << "and " << strerror ( errno ) << endl;
    exit ( -1 ); 
}

UDTSOCKET conn_serv_fd;
struct sockaddr_in serv_addr;

if (  ( conn_serv_fd = UDT::socket ( AF_INET, SOCK_STREAM, 0 ) ) == UDT::INVALID_SOCK  )
{
    cout << "create UDT::conn_serv_fd: " << UDT::getlasterror().getErrorMessage() << "and " << strerror ( errno ) << endl;
    exit ( -1 );
}

serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(80);
serv_addr.sin_addr = *((struct in_addr *)h->h_addr);
//if udt is udp based which is connectionless, why connect() API is needed ???
if (  UDT::ERROR == UDT::connect ( conn_serv_fd, (struct sockaddr*)&serv_addr, sizeof(struct sockaddr) )  )
{
    //bug: connect: Connection setup failure: connection time out.
    cout << "connect: " << UDT::getlasterror().getErrorMessage() << "and " << strerror ( errno ) << endl;
    exit ( -1 );
}

if (  UDT::ERROR == UDT::send ( conn_serv_fd, first_req, first_req_size, 0 )  )
{
    cout << "send: " << UDT::getlasterror().getErrorMessage();
    exit ( -1 );
}
else
{
    cout<<"send first req already!"<<endl;
}

And I get the server address as follow pseudocode

char* hostname = gethostname(char* request); // I printed it and it worked
struct hostent *h = gethostbyname ( hostName ); // I printed it and it worked   
struct sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(80);
serv_addr.sin_addr = *((struct in_addr *)h->h_addr);
UDT::connect ( conn_serv_fd, (struct sockaddr*)&serv_addr, sizeof(struct sockaddr) )

I replace gethostbyname() with getaddrinfo() and now it looks like:

        char *hostName = getHostName ( first_req, first_req_size );

        struct addrinfo* res, * cur;

        struct addrinfo hints;
        memset(&hints, 0, sizeof(struct addrinfo));
        hints.ai_family = AF_INET;
        hints.ai_socktype = SOCK_STREAM;

        if (0 != getaddrinfo( hostName, NULL, &hints, &res))
        {
            cout<<"can't getaddrinfo! "<<strerror ( errno )<<endl;
            exit ( -1 );
        }

        bool connected = 0;
        for ( cur = res; cur != NULL; cur = cur->ai_next ) 
        {

            struct sockaddr_in* addr = (struct sockaddr_in *)cur->ai_addr;

            char ipbuf[16];
            cout << "try to connect to ip: "<< inet_ntop ( AF_INET, &addr -> sin_addr, ipbuf, 16) << endl;

            serv_addr.sin_addr = addr->sin_addr;

            if (  UDT::ERROR == UDT::connect ( conn_serv_fd, (struct sockaddr*)&serv_addr, sizeof(struct sockaddr) )  )
            {
                cout << "connect: " << UDT::getlasterror().getErrorMessage() << "and sys error: " << strerror ( errno ) << endl;
                UDT::close ( conn_serv_fd );
                continue;
            }
            else
            {
                cout << "connect successfully!" << endl;
                connected = 1;
                break;
            }
        }

        freeaddrinfo(res);
        delete []hostName;
        delete []first_req;

        if ( !connected )
        {
            cout << "connection setup failure!" <<endl;
            exit ( -1 );
        }
mike1ocean
  • 11
  • 2
  • You can't use HTTP over UDP, but from what I can see in UDT's documentation, UDT supports TCP (otherwise you couldn't use `SOCK_STREAM` at all), so this code should work, provided `h->h_addr` contains a valid IPv4 address that is reachable by your PC. Where and how are you populating `h->h_addr`? You did not show that code. – Remy Lebeau Mar 30 '17 at 22:19
  • First, thanks for your editing which is very nice. Actually, I am working on a transparent proxy based on iptables, which receives requests and sends what received to server. I get the IPv4 address from the request I receive and in the request, whatever between `Host: ` and `\r\n` is my destination address (like www.stackoverflow.com). I use the `gethostbyname()`system API to get the IPv4 address.Thanks again!@Remy Lebeau – mike1ocean Mar 31 '17 at 01:51
  • I just post my code for getting address. @Remy Lebeau – mike1ocean Mar 31 '17 at 02:04
  • You are using an `AF_INET` (IPv4) socket, so make sure `h->h_addrtype` is `AF_INET` to match before using `h->h_addr`. A hostname could resolve to IPv6 (`AF_INET6`) instead of IPv4. Hostname resolution returns a list of IPs, so you should try to `connect()` to each IP until one of them succeeds. It is possible for the hostname to resolve to IP(s) that are not reachable from your current network location, so you should try them all. Right now, you are only trying the first one. Loop through `h->h_addr_list` instead of using `h->h_addr`. (Note: you should be using `getaddrinfo()` instead) – Remy Lebeau Mar 31 '17 at 02:13
  • I will try it out. It's very nice of you! Thanks! – mike1ocean Mar 31 '17 at 02:14
  • I have replace `gethostbyname()` with `getaddrinfo()` and tried to connect to every possible IP in the list. But the connection to the first IPv4 address always report `connect: Connection setup failure: connection time out.` and when I tried to connect to the next, it reported error: `connect: Operation not supported: Invalid socket ID.`. I google `close UDT socket after connection failure` and I found out it's a UDT bug not me... So, I wonder that can I really connect an HTTP server on port 80? The code will be posted soon. Thanks a lot! @Remy Lebeau – mike1ocean Mar 31 '17 at 03:39
  • The timeout very well could be expected, depending on the particular IP and your network connection. Just ignore the error and move on to the next IP. Don't log an error unless all of the IPs fail. But, if `connect()` fails, there is no guarantee that the same socket can be reused for another attempt. Some platforms allow that, some don't. You may have to just close the socket and create a new socket for the next attempt... – Remy Lebeau Mar 31 '17 at 04:16
  • ... which you should do anyway, since `getaddrinfo()` is capable of reporting *both* IPv4 and IPv6 addresses at the same time, if you let it (by setting `hints.ai_family` to `AF_UNSPEC`). `gethostbyname()` cannot do that. You should create a new socket based on the type of IP being connected to on each iteration. – Remy Lebeau Mar 31 '17 at 04:18
  • You are getting the "invalid socket ID" error because you are not creating a new socket after calling `close()` on `connect()` failure. And BTW, when calling `connect()`, using `sizeof(struct sockaddr)` is wrong. It *happens* to work for IPv4, because `sizeof(sockaddr) == sizeof(sockaddr_in)`, but it will fail for IPv6, because `sizeof(sockaddr) != sizeof(sockaddr_in6)`. If you choose to support IPv6, make sure you change `serv_addr` to `sockaddr_storage` and typecast it to `sockaddr_in` or `sockaddr_in6` appropriately. – Remy Lebeau Mar 31 '17 at 04:21

0 Answers0