RecvBytes() gives me no bytes



  • On 26/07/2016 at 07:13, xxxxxxxx wrote:

    User Information:
    Cinema 4D Version:    
    Platform:      
    Language(s) :

    ---------
    Hi! I'm trying to get a simple HTTP connection working with the c4d_networking API, but I can't
    get it to work. While the data appears to be sent correctly (tested with a local webserver and looking
    at the logs), I can't get any response.

    Here's a very very minimal example that tries to connect to google.com.

    void Send(NetworkIpConnection* conn, Char const* string) {
      size_t const len = strlen(string);
      SendBytes(conn, string, len);
    }
      
    void Example() {
      NetworkIpAddrPort addr(216, 58, 214, 142, 80);  // google.com:80
      NetworkIpConnection* conn = OpenOutgoing(addr, nullptr);
      if (!conn) {
        GePrint("error: could not connect to 216.58.214.142:80");
        return;
      }
      
      Send(conn, "GET / HTTP/1.1\r\n");
      Send(conn, "Host: google.com\r\n");
      Send(conn, "\r\n");
      
      Char buffer[8096] = {0};
      Int const count = RecvBytes(conn, buffer, sizeof(buffer) - 1);
      CloseConnection(conn);
      
      buffer[count] = 0;
      GePrint(">>> Response:");
      GePrint(String(buffer));
    }
    

    RecvBytes() reaches the sessionTimeout of 10 seconds (default in OpenOutgoing()) and returns 0 bytes.

    The same works when I do it eg. from Python:

    >>> import socket
    \>>> s = socket.socket()
    \>>> s.connect(('216.58.214.142', 80))
    \>>> s.send(b'GET / HTTP/1.1\r\nr"')
    18
    \>>> s.send(b'Host: google.com\r\n')
    18
    \>>> s.send(b'\r\n')
    2
    \>>> s.recv(8000)
    b'HTTP/1.1 302 Found\r\nCache-Control: private\r\nContent-Type: text/html; charset=UTF-8\r\nLocation: http://www.google.de/?gfe_rd=cr&ei=2G6XV_SrI4WQ8QeR94DwDw\r\nContent-Length: 258\r\nDate: Tue, 26 Jul 2016 14:08:24 GMT\r\n\r\n<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">\n<TITLE>302 Moved</TITLE></HEAD><BODY>\n<H1>302 Moved</H1>\nThe document has moved\n<A HREF="http://www.google.de/?gfe_rd=cr&amp;ei=2G6XV_SrI4WQ8QeR94DwDw">here</A>.\r\n</BODY></HTML>\r\n'
    

    What am I doing wrong?

    Thanks in advance,
    Niklas



  • On 27/07/2016 at 08:27, xxxxxxxx wrote:

    Hi Niklas,

    the point is RecvBytes(), tries to fill your buffer and while doing so, runs into a timeout, which leads to a error and count being returned as zero. The data is actually in your buffer, but by zero terminating the string on index count, you basically throw away the results.
    Instead use BytesInInputBuffer() to check, how much you got (probably waiting a bit for google to answer). Then call RecvBytes() with the number of bytes received.
    It's not the behavior I had expected, but I think, you'll be able to work with this.

    I'll add a note in the docs.



  • On 27/07/2016 at 09:12, xxxxxxxx wrote:

    Thanks Andreas, I'll give it a try and report back.

    I expected RecvBytes() to fill the buffer until its full, the timeout is reached or the connection is closed. I wonder what RecvBytes() is waiting for so it reaches the timeout..? Surely not for the 2kb that are sent as response from the google server?



  • On 27/07/2016 at 09:14, xxxxxxxx wrote:

    Well, as far as I understand it, yes, it is doing exactly this. It's using the specified timeout to try to fill your entire buffer. But as it doesn't receive enough data, it runs into the timeout.



  • On 27/07/2016 at 14:00, xxxxxxxx wrote:

    Hmm I might be too biased and used to the way things work in Python.. Is there a way to tell if the
    connection is closed? I really hope there is in the C4D network API, I just couldn't find it yet.

    Because that's how HTTP works if no Content-Length is specified in the response.
    (See https://www.w3.org/Protocols/HTTP/1.0/draft-ietf-http-spec.html#BodyLength)

    It also makes receiving the data much easier: it won't require me to parse the Content-Length header.

    I've implemented the BytesInInputBuffer() test. But right now, since I can not determine if the
    connection is closed, it so happens that my client side waits for data until the timeout is reached
    even though all data was already read.

    Thanks again,
    Niklas



  • On 28/07/2016 at 04:25, xxxxxxxx wrote:

    To be honest, this is not my main area of expertise.
    I looked through all related functions and classes, but didn't find anything about the connection status either. Sorry.
    I have forwarded the question to our development, just to be sure. Don't expect too much.



  • On 28/07/2016 at 06:12, xxxxxxxx wrote:

    Thanks for checking and forward the question. Eventually, could you attach a secondary question to it?
    Since I couldn't get any further with the C4D API, I was trying the raw Win32 API, but I can't get it to
    work at all inside  Cinema 4D.

    The code below compiled into a standalone executable prints "Connected successfully".

    #define WIN32_LEAN_AND_MEAN
    //#include "windows_include.h"    // Uncomment this in C4D!
    #include <winsock2.h>
    #include <ws2tcpip.h>
    #include <stdio.h>
    #pragma comment(lib, "Ws2_32.lib")
      
      
    int main() {
        WSADATA wsaData;
        int code = WSAStartup(MAKEWORD(2,2), &wsaData);
        if (code != 0) {
            printf("WSAStartup failed with error: %d\n", code);
            return 1;
        }
      
        addrinfo hints = {};
        hints.ai_family = AF_UNSPEC;
        hints.ai_socktype = SOCK_STREAM;
        hints.ai_protocol = IPPROTO_TCP;
      
        addrinfo* result = nullptr;
      
        // Resolve the server address and port
        code = getaddrinfo("google.com", "80", &hints, &result);
        if (code != 0) {
            printf("getaddrinfo failed with error: %d\n", code);
            WSACleanup();
            return 1;
        }
      
        // Attempt to connect to an address until one succeeds
        SOCKET conn = INVALID_SOCKET;
        for(auto ptr = result; ptr; ptr = ptr->ai_next) {
            // Create a SOCKET for connecting to server
            conn = socket(ptr->ai_family, ptr->ai_socktype,
                ptr->ai_protocol);
            if (conn == INVALID_SOCKET) {
                printf("socket failed with error: %ld\n", WSAGetLastError());
                WSACleanup();
                return 1;
            }
      
            // Connect to server.
            code = connect(conn, ptr->ai_addr, (int)ptr->ai_addrlen);
            if (code == SOCKET_ERROR) {
                printf("connect failed with error: %ld\n", WSAGetLastError());
                closesocket(conn);
                conn = INVALID_SOCKET;
                continue;
            }
            break;
        }
      
        freeaddrinfo(result);
      
        if (conn == INVALID_SOCKET) {
            printf("Unable to connect to server!\n");
            WSACleanup();
            return 1;
        }
        printf("Connected successfully.\n");
        closesocket(conn);
        WSACleanup();
        return 0;
    }
    

    But when I use exactly this code inside a Cinema 4D plugin, I get

    connect failed with error: 10038
    Unable to connect to server!
    

    (10038: WSAENOTSOCK)

    I also tried leaving out "WSAStartup()" and "WSACleanup()" since C4D probably does some initialization
    there already, but to no avail.

    Any chance this would get some love by a dev? I'm sure someone like Wilfried would know immediately
    why it doesn't work, considering his obvious expertise with Windows stuff. 😄

    Cheers,
    Niklas



  • On 02/08/2016 at 04:23, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    I have forwarded the question to our development, just to be sure. Don't expect too much.

    Hi Andreas, any news on this? Otherwise I'll just have to use something like libCURL. I wonder though,
    because it probably uses the same Win32 API, if it has the same problem as I described in my previous
    reply. We'll see after I tried.

    Cheers,
    Niklas



  • On 02/08/2016 at 04:52, xxxxxxxx wrote:

    No, no news, yet. Sorry.



  • On 02/12/2016 at 06:23, xxxxxxxx wrote:

    So apparently using cURL and cURLpp works. I was about to write that it doesn't but I was using an HTTPS
    URL and the cURL library I used was not compiled with https support.

    Cheers,
    -Niklas


Log in to reply