SSLClient socket errors

Greetings and thank-you for your time. I'm a hobbyist desktop c++ programmer and teacher by profession the embed world has been a bit of a learning curve.

I am trying to send camera images from my ESP32 (M5 Stack PoECAM) to my personal google drive.

I have setup SSLClient with the EthernetLarge library the jpgs arrive and but they are corrupted/incomplete. Any ideas why this might be happening, I have tried different chunk sizes no effect ?

I don't believe its hardware as the example sketches all work as intended

errors/warnings

SSLClient)(SSL_WARN)(connected): Socket was dropped unexpectedly (this can be an alternative to closing the connection)

(SSLClient)(SSL_ERROR)(m_print_ssl_error): SSL_CLIENT_WRITE_FAIL
(SSLClient)(SSL_ERROR)(available): Cannot operate if the write error is not reset:

The project is on github the code for the relevant function is posted below apologies I was halfway through refactoring it to use char bufs rather than strings:

#include <SSLClient.h>
#include "gdrive_trust.h"


#define WRITE_SIZE_MAX   1024 //


//#define API_PORT    443
//#define API_PATH_TOKEN   "/oauth2/v4/token"


const char* refreshServer = "oauth2.googleapis.com";
const char* refreshUri    = "/token";
const char* apiServer     = "www.googleapis.com";
const char* apiUri        = "/upload/drive/v3/files?uploadType=multipart";
char accessToken[2048];   

// ethClient is declared elsewhere but works perfectly outside this funciton
SSLClient httpsClient(ethClient, gdriveTAs, 1, 25);
//  SSLClient::write, is buffered does not actually write to the network. you must call SSLClient::available or SSLClient::flush, 


int waitingTime      = 10000; // Wait 10 seconds to google response.


// Send JPEG by Http POST
void postGoogleDriveByAPI() {
  Serial.println("Connect to " + String(apiServer));
  if (httpsClient.connect(apiServer, 443)) {
    Serial.println("Connection successful");

    // Get Time for save file name
    struct tm timeinfo;
    if(!getLocalTime(&timeinfo)){
      Serial.println("Failed to obtain time 1");
      return;
    } 
    char saveFilename[64];

    /*
    char metadata[256];

    const char* startBoundry = "--foo_bar_baz\r\n"
                      "Content-Type:image/jpeg\r\n\r\n";
    const char* endBoundry = "\r\n--foo_bar_baz--";
    */

    strftime (saveFilename,64,"ALERT_%A_%B_%d_%Y_%Hh%Mm%Ss.jpg",&timeinfo);

    Serial.println(saveFilename);


    /*
    snprintf( metadata, 256, "--foo_bar_baz\r\n"
                      "Content-Type: application/json; charset=UTF-8\r\n\r\n"
                      "{\"name\":\"%s\",\"parents\":[\"%s\"]}\r\n\r\n" , saveFilename, PARENT_ID ); 
    
    unsigned long contentsLength = strlen(metadata) + strlen(startBoundry) + fb->len + strlen(endBoundry);

    snprintf(header,256, "POST %s HTTP/1.1\r\n" 
                    "HOST: %s \r\n" 
                    "Connection: close\r\n" 
                    "content-type: multipart/related; boundary=foo_bar_baz\r\n" 
                    "content-length: %u \r\n" 
                    "authorization: Bearer %s \r\n\r\n", apiUri, apiServer, contentsLength, accessToken);
    */

    String metadata = "--foo_bar_baz\r\n"
                      "Content-Type: application/json; charset=UTF-8\r\n\r\n"
                      "{\"name\":\"" + String(saveFilename) + "\",\"parents\":[\"" + String(PARENT_ID) + "\"]}\r\n\r\n"; // parents:save folder
                      //"{\"name\":\"" + saveFilename + "\"}\r\n\r\n"; // parerents is Optional
    String startBoundry = "--foo_bar_baz\r\n"
                          "Content-Type:image/jpeg\r\n\r\n";
    String endBoundry   = "\r\n--foo_bar_baz--";

    unsigned long contentsLength = metadata.length() + startBoundry.length() + fb->len + endBoundry.length();
    String header = "POST " + String(apiUri) + " HTTP/1.1\r\n" +
                    "HOST: " + String(apiServer) + "\r\n" +
                    "Connection: close\r\n" +
                    "content-type: multipart/related; boundary=foo_bar_baz\r\n" +
                    "content-length: " + String(contentsLength) + "\r\n" +
                    "authorization: Bearer " + accessToken + "\r\n\r\n";
    
    Serial.println("Send JPEG DATA by API");
    httpsClient.print(header);
    httpsClient.print(metadata);
    httpsClient.print(startBoundry);
    // JPEG data is separated into 1000 bytes and POST


    int chunk = 1000;
    unsigned long dataLength = fb->len;
    uint8_t*      bufAddr    = fb->buf;
    for(unsigned long i = 0; i < dataLength ;i=i+chunk) {

      if ( (i + chunk) < dataLength ) {
        httpsClient.write(( bufAddr + i ), chunk);
      } else if (dataLength%chunk != 0) {
        httpsClient.write(( bufAddr + i ), dataLength%chunk);
      }
    }
    httpsClient.print(endBoundry);

    Serial.println("Waiting for response.");
    long int StartTime=millis();
    while (!httpsClient.available()) {
      Serial.print(".");
      delay(100);
      if ((StartTime+waitingTime) < millis()) {
        Serial.println();
        Serial.println("No response.");
        break;
      }
    }

  } else {
    Serial.println("Connected to " + String(refreshServer) + " failed.");
  }

  httpsClient.stop();
}

You don't check if the write was successful.

In which way are they corrupted? Is some data at the end missing? Is the intro wrong? Is one byte per chunk missing?

Hi Python,

thanks for the tip will add error checking.

found the error the frame buffer was being freed before the SSLClient had finished writing so the images I saw in google drive had random overwrites. The image appeared as large horizontal bands spliced together some of which contained the original image.

Now testing after fix and the camera has stop working after an hour, going to run it on serial overnight and see if I can find out why I suspect memory fragmentation courtesy of HTTPClient judicious use of strings.

i saw that in the sample website you linked too..
after getting image the frame buffer is returned..
curious, where did you move this too..

esp_camera_fb_return(fb);

should be after you send, successful or not..
if not returned, you'll run out..

sounds like your close..

good luck.. ~q

Hi qubits-us

I rewrote the camera function to inject the post command when an image is taken.

// Get JPEG image 
void getCameraJPEG(void * parameter){
for(;;){ 
  fb = esp_camera_fb_get();  // Get JPEG image
  if (!fb) {
    Serial.printf("Camera capture failed");
  }
  Serial.printf("JPG: %uB ", (uint32_t)(fb->len));
  Serial.println();

  postGoogleDriveByAPI();

  // Shooting end processing
  esp_camera_fb_return(fb);

      vTaskDelay(10000 / portTICK_PERIOD_MS);
  }
}

next problem was having multiple freertos tasks that want to use the ethernet at the same time so I have add mutexs to the offending function calls appears to be working. only issue now is the loop execution is somewhat unpredictable so the image timestampes vary by a few seconds the camera task is set to vTaskDelay(10000 / portTICK_PERIOD_MS) but it runs anywhere from 13-20 seconds apart. obviously the fix would be to use time not ticks but its suitable for my use so I think I'll just tidy up the code and call it a day.

Although the learning curve was a bit steep its a project I highly recommenced for those use to programming on an OS, you suddenly have to think about a lot of jobs your OS does for you.

maybe, it's the time it takes to upload the jpeg??

sounds like you got a handle on things, great job..

happy trails.. ~q

That's why we usually request complete code. Your error was once again in that part of the code you hided from us. I should be more consequent in the future and always require to post complete code.

Hi Pylon,

my mistake I'm a bit new to posting code and thought it best to post the repository as the code and include the excerpt to explain/illustrate what I was trying to do.

is the correct practice here to post all project files (ones I edit) in include order ?

I completely understand the frustration of trying to understand incomplete code/problems.

I overread the github link, sorry for that. That's fine too, as long as it's your code, the code you're using. Linking to another project which your project is based on but with changes isn't a good idea though.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.