Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    RecvBytes() gives me no bytes

    SDK Help
    0
    10
    1.0k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • H
      Helper
      last edited by

      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

      1 Reply Last reply Reply Quote 0
      • H
        Helper
        last edited by

        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.

        1 Reply Last reply Reply Quote 0
        • H
          Helper
          last edited by

          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?

          1 Reply Last reply Reply Quote 0
          • H
            Helper
            last edited by

            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.

            1 Reply Last reply Reply Quote 0
            • H
              Helper
              last edited by

              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

              1 Reply Last reply Reply Quote 0
              • H
                Helper
                last edited by

                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.

                1 Reply Last reply Reply Quote 0
                • H
                  Helper
                  last edited by

                  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

                  1 Reply Last reply Reply Quote 0
                  • H
                    Helper
                    last edited by

                    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

                    1 Reply Last reply Reply Quote 0
                    • H
                      Helper
                      last edited by

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

                      No, no news, yet. Sorry.

                      1 Reply Last reply Reply Quote 0
                      • H
                        Helper
                        last edited by

                        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

                        1 Reply Last reply Reply Quote 0
                        • First post
                          Last post