2

I would like to make an HTTP request using sockets. Here is my code so far:

   #include "stdafx.h"
#ifndef UNICODE
#define UNICODE
#endif

#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define WIN32_LEAN_AND_MEAN

#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <iostream>

#pragma comment(lib, "ws2_32.lib")
using namespace std;

int main()
{
    try {
        WSADATA wsaData;
        int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
        sockaddr_in clientService;


        SOCKET Socket = socket(AF_INET, SOCK_STREAM, 0);

        memset(&clientService, 0, sizeof(clientService));
        clientService.sin_addr.s_addr = inet_addr("83.233.53.59"); // Proxy IP
        clientService.sin_family = AF_INET;
        clientService.sin_port = htons(10200);

        if (bind(Socket, (struct sockaddr *) &clientService, sizeof(clientService)) < 0) {
            perror("bind");
            exit(1);
        }
        system("pause");
        return 0;
        struct hostent *host;
        host = gethostbyname("www.google.com");
        SOCKADDR_IN SockAddr;
        SockAddr.sin_port = htons(80);
        SockAddr.sin_family = AF_INET;
        // SockAddr.sin_addr.s_addr = *((unsigned long*)host->h_addr);
        memcpy(host->h_addr, &(SockAddr.sin_addr.s_addr), host->h_length);
        std::cout << "Connecting...\n";

        iResult = connect(Socket, (SOCKADDR *)& clientService, sizeof(clientService));
        if (iResult != 0) {
            std::cout << "Could not connect";
            getchar();
            return 1;
        }
        std::cout << "Connected.\n";
        send(Socket, "GET / HTTP / 1.1\r\nHost: www.google.com\r\nConnection: close\r\n\r\n", strlen("GET / HTTP / 1.1\r\nHost: www.google.com\r\nConnection: close\r\n\r\n"), 0);
        char buffer[10000];
        int nDataLength;
        while ((nDataLength = recv(Socket, buffer, 10000, 0)) > 0) {
            int i = 0;
            while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r') {
                std::cout << buffer[i];
                i += 1;
            }
        }
        iResult = closesocket(Socket);
        WSACleanup();

        system("pause");
    }
    catch (...) {
        system("pause");

    }
    return 0;
}

But it doesn't work, without the program closes itself without leaving me the HTML source of the webpage. What's wrong?

How can I fix it?

  • 1
    What happened when you tried this? Did it give you errors? Did it hang? Did it crash? – erip Dec 17 '15 at 16:34
  • @erip everything is OK. But I don't know how to connect to a determinate host through a proxy, that's what I'm asking. – m8gtProgrammer Dec 17 '15 at 16:35
  • For http requests you can just `connect` to proxy address and port and send `GET http://www.google.com/ HTTP/1.1\r\nHost: www.google.com\r\nConnection: close\r\n\r\n` – dewaffled Dec 17 '15 at 16:38
  • @frymode That's what I didn't understand. Could you make me an example? – m8gtProgrammer Dec 17 '15 at 16:39
  • How hard is it to google how proxy requests are done instead of dropping your code here and asking for help. See for example http://forensicswiki.org/wiki/Proxy_server#HTTP_proxies – Steffen Ullrich Dec 17 '15 at 16:39
  • @SteffenUllrich and how do I connect to the proxy? That's the header which a proxy uses for an HTTP request. – m8gtProgrammer Dec 17 '15 at 16:42
  • @m8gtProgrammer you connect to server with `connect` call. Just replace address with proxy one. – dewaffled Dec 17 '15 at 16:44
  • http://stackoverflow.com/questions/9191860/how-to-connect-a-socket-to-an-http-server-through-proxy – dboals Dec 17 '15 at 16:54
  • @m8gtProgrammer: you connect the same way to a proxy as you connect to any other server - with a socket and the destination is the address of the proxy. The main difference between proxy and direct connection is that with proxy you connect to the proxy which then talks to the target server. – Steffen Ullrich Dec 17 '15 at 16:55
  • @SteffenUllrich I just edited my code, can you see what I did? Unfortunately I followed what you guys suggested me to do. But it doesn't work. – m8gtProgrammer Dec 17 '15 at 17:09
  • @dboals the program closes itself after it writes: "Connecting..." – m8gtProgrammer Dec 17 '15 at 17:11
  • It's been a while, but don't you need to bind the socket to a local IP/Port before you connect? like in this example http://stackoverflow.com/questions/6468113/binding-a-port-number-to-a-tcp-socket-outgoin-to-send-packets – dboals Dec 17 '15 at 17:15
  • The other bit that seems missing that I remember is always memset your sockaddr_in structures. – dboals Dec 17 '15 at 17:24
  • See the client program on the wikipedia https://en.wikipedia.org/wiki/Berkeley_sockets – dboals Dec 17 '15 at 17:26
  • @dboals thank you for your patience, I just edited my question. Can you see what I did wrong? – m8gtProgrammer Dec 17 '15 at 17:28
  • don't do" SockAddr.sin_addr.s_addr = *((unsigned long*)host->h_addr);" instead to something like "memcpy ( host->h_addr, &(SockAddr.sin_addr.s_addr, host->h_length);" – dboals Dec 17 '15 at 17:44
  • @dboals memcpy doesn't accept two arguments, but three. – m8gtProgrammer Dec 17 '15 at 17:51
  • whoops "memcpy ( &(SockAddr.sin_addr.s_addr), host->h_addr, host->h_length); I missed a a parenthesis and I flipped the src and dest – dboals Dec 17 '15 at 17:53
  • @dboals thanks again. But it still closes itself. Can you watch the code I just edited? – m8gtProgrammer Dec 17 '15 at 17:56
  • bind is for local ip and port. Any it looks like you don't need that anyway for a connect in most cases. Let me futz with your code a bit and I will get back to you. – dboals Dec 17 '15 at 18:07
  • @dboals: answering your question `don't you need to bind the socket to a local IP/Port before you connect?` - you only need to bind if you want to use a specific address:port on the client side - which is not necessary in most cases - OP's case doesn't need it. – jweyrich Dec 17 '15 at 18:14
  • @jweyrich well, at least he's the only one guy with patience who is helping me. what should I do, then? – m8gtProgrammer Dec 17 '15 at 18:20
  • ok, see the answer I posted below. It isn't "windows" code, but if you runs on my machine. – dboals Dec 17 '15 at 18:36

3 Answers3

2

This works on my machine, but I'm not on a windows machine. I'm on a freeBSD (OS X) machine. Having problems getting gethostbyname to resolve, not sure what that's about, but this worked and connected and downloaded the code from google.

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

#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define WIN32_LEAN_AND_MEAN

//#include <winsock2.h>
//#include <ws2tcpip.h>
#include <stdio.h>
#include <iostream>

#pragma comment(lib, "ws2_32.lib")
using namespace std;

int main()
{
    try {
        //        WSADATA wsaData;
        //        int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
        // sockaddr_in clientService;


        int Socket = socket(AF_INET, SOCK_STREAM, 0);
        /*
         memset(&clientService, 0, sizeof(clientService));
         clientService.sin_addr.s_addr = inet_addr("83.233.53.59"); // Proxy IP
         clientService.sin_family = AF_INET;
         clientService.sin_port = htons(10200);

         if (bind(Socket, (struct sockaddr *) &clientService, sizeof clientService) == -1) {
         perror("bind");
         exit(1);
         }
         system("pause");
         return 0;
         */
         const char hostname[] ="www.google.com";
         struct hostent * host;
//         host = gethostbyname(hostname);

        sockaddr_in SockAddr;
        memset(&SockAddr, 0, sizeof(SockAddr));
        SockAddr.sin_port = htons(80);
        SockAddr.sin_family = AF_INET;
        SockAddr.sin_addr.s_addr = inet_addr("83.233.53.59");
        //        memcpy(host->h_addr, &(SockAddr.sin_addr.s_addr), host->h_length);
        std::cout << "Connecting...\n";

        int iResult = connect(Socket, (struct sockaddr *)& SockAddr, sizeof(SockAddr));
        if (iResult != 0) {
            std::cout << "Could not connect";
            getchar();
            return 1;
        }
        std::cout << "Connected.\n";
        send(Socket, "GET / HTTP / 1.1\r\nHost: www.google.com\r\nConnection: close\r\n\r\n", strlen("GET / HTTP / 1.1\r\nHost: www.google.com\r\nConnection: close\r\n\r\n"), 0);
        char buffer[10000];
        int nDataLength;
        while ((nDataLength = recv(Socket, buffer, 10000, 0)) > 0) {
            int i = 0;
            while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r') {
                std::cout << buffer[i];
                i += 1;
            }
        }
        iResult = close(Socket);
        //        WSACleanup();

        system("pause");
    }
    catch (...) {
        system("pause");

    }
    return 0;
}

It had an authentication failure at the http: level, but Heres the output:

Connecting...
Connected.
HTTP/1.0 401 Unauthorized
Server: uhttpd/1.0.0
Date: Thu, 17 Dec 2015 18:29:04 GMT
WWW-Authenticate: Basic realm="                 "
Content-Type: text/html; charset="UTF-8"
Connection: close

<HTML><HEAD><META http-equiv='Pragma' content='no-cache'><META http-equiv='Cache-Control' content='no-cache'><TITLE> 401 Authorization</TITLE>
<script language=javascript type=text/javascript>
function cancelevent()
{
sh: pause: command not found
Program ended with exit code: 0
dboals
  • 610
  • 4
  • 10
  • Nice, but how can I make this on windows? – m8gtProgrammer Dec 17 '15 at 18:38
  • Berkeley sockets are pretty much the same on all systems. I've done them on windows with almost no changes except include files. That said change the include files back to what you had and it should work. – dboals Dec 17 '15 at 19:32
  • If you still want to go through a proxy, then you need to change your "GET / ..." string to a "CONNECT ..." string see the answer here: http://stackoverflow.com/questions/9191860/how-to-connect-a-socket-to-an-http-server-through-proxy – dboals Dec 17 '15 at 19:38
0

One thing that might go wrong is that your application may crash when it accesses an out-of-bound array index during the following loop:

while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r') {
    ...
    i += 1;
}

Your current code cannot guarantee the buffer contains a byte that would make your loop terminate, therefore it might continue indefinitely. You must prevent this by having an extra check before accessing the array index. Considering that nDataLength will always be smaller or equal to sizeof(buffer), try this:

while (i < nDataLength &&
    (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r'))
{
    // Do your printing.
    i++;
}

Or maybe simpler:

while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r')
{
    // Do your printing.
    i++;

    if (i >= nDataLength)
        break; // Exit the loop.
}
jweyrich
  • 31,198
  • 5
  • 66
  • 97
0
system("pause");
return 0;

This code prevents anything following from executing. Remove.

There are numerous other problems with your code. For example, you're binding the socket to the proxy address. That doesn't make sense. Remove. You're about to connect the socket, you don't need to bind it at all.

Then you're sending an invalid GET request to the proxy. The GET request in this case should contain the full URL, not just a relative URL.

You're overrunning the receive buffer when you search for the space etc. You need to bound that search by the count returned by recv().

And so on.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • Ofc I was intended to remove that. `system()` functions are bad. I can remove `return 0` and `using namespace std;`. I used that just for testing purposes. – m8gtProgrammer Dec 17 '15 at 20:50