Embedded ESP32C6: Lightweight C wrapper around a socket having trouble formatting request bytes?

I'm writing an intentionally trivial wrapper around some socket code for an esp32C6 and I'm stuck at something that might be obvious to someone else.

I have code that works fine, but as I try to lift more out the C I get an timeout response from the server instead of the true response.

Both calls to write return 78 now. Originally the non-working one sent 77 so I figured it was a null termination issue, but appending a 0 didn't seem to work?

I am using a swiftly install of swift 6.2 release but happy to try a different toolchain, still on macOS 15 for a smidge longer, compiling with a CMake file and the esp-idf 5.5 tools.

Works

  //NOTE: none of the func mappings use socklen_t ?
  internal typealias SocketHandle = CInt  
  func wrappedWrite(with socket: SocketHandle, to host: String, at path: String) {
    let local_host = host.utf8CString
    let local_path = path.utf8CString
    //TODO: test with span/inline array (esp-idf 6? OS26)
    local_path.withContiguousStorageIfAvailable { route_buffer in
      local_host.withContiguousStorageIfAvailable { host_buffer in
        let resultCode = http_bridge_just_write(
          socket, host_buffer.baseAddress, route_buffer.baseAddress)
        print("write result code: \(resultCode)")
      }
    }
  }

// int http_bridge_just_write(const socklen_t s, const char *host, const char *path)
int http_bridge_just_write(const int s, const char *host, const char *path) {
    char req[128];
    printf("requestSize: %u", sizeof(req));
    snprintf(req, sizeof(req),
             "GET %s HTTP/1.0\r\n"
             "Host: %s\r\n"
             "User-Agent: esp-idf/5.5\r\n"
             "\r\n",
             path, host);

    printf("stringLength: %u", strlen(req));
    int err_or_count = write(s, req, strlen(req));
    if (err_or_count < 0) {
        printf("send failed");
        close(s);
        return 4;
    }
    return err_or_count;
}

Receives 408 (Server Timed Out):

func writeRequest(with socket: SocketHandle, to host: String, at path: String) throws(HTTPClientError) {
    let userAgent = "esp-idf/5.5"
    var request: ContiguousArray<CChar> =
    "GET \(path) HTTP/1.0\r\nHost: \(host)\r\nUser-Agent: \(userAgent)\r\n".utf8CString
    //made no change. 
    request.append(0)
    print("request length: \(request.count)")
    print("\(request)")

    let result = request.withContiguousStorageIfAvailable { request_buffer in
      let writeResponse = write(socket, request_buffer.baseAddress, request_buffer.count)
      print("writeResponse: \(writeResponse)")
      return writeResponse
    }

    if result != nil && result! < 0 {
      throw HTTPClientError.sendFailed
    }

    if result == nil {
      print("what happened?")
      throw HTTPClientError.unsendableRequest
    }
  }

Full project for context if it will help. There are some known glaring flaws but all feedback welcome: GitHub - carlynorama/swift_esp32c6_hello at e_ImproveHTTPClient

(NOTE: if anyone does run this, I find that I have to unplug it and plug it back in while the monitor is still running if I use idf.py build flash monitor, but that's a esp-idf uncleared cached DNS value thing I still have to chase down I'm pretty sure.)

1 Like

The Swift-only version has only one \r\n after the user agent.

2 Likes

Should have been reply, sorry

THAT WAS IT!!!

THANK YOU!

In the mean time I tried using requestinspector.com, but cloudflare intercepted my bad requests, so I updated my code to take a port, turned off my firewall, used ifconfig to find my IP address and ran netcat -l -p 8080....

... but I still wasn't picking up on the whitespace & newline difference so this was priceless.

Again, thank you.

1 Like