view seobeo/s_ssl.c @ 279:b3b547563ec7

Add Google connector service and agent wiki Implement the C/Seobeo Google Drive and Gmail connector with encrypted OAuth storage, Zenbu authentication, browser testing, AI tool discovery, chunked HTTP decoding, and Bazel coverage. Consolidate repository guidance into progressive wiki documentation and enforce arena-first allocation for new first-party C code. Co-authored-by: Copilot <[email protected]> Copilot-Session: 84c338fd-0939-4bb3-b7f3-1062eb213e5d
author MrJuneJune <me@mrjunejune.com>
date Mon, 17 Aug 2026 22:22:36 -0700
parents 70401cf61e97
children
line wrap: on
line source

#include "seobeo/seobeo.h"

#ifndef SEOBEO_NO_SSL

void Seobeo_Web_SSL_Init()
{
  SSL_load_error_strings();
  OpenSSL_add_ssl_algorithms();
}

void Seobeo_Web_SSL_Cleanup(void)
{
  EVP_cleanup(); // I don't think these are needed...
}

int Seobeo_SSL_Setup_Client(Seobeo_Handle *p_handle, const char *host, int socket_fd)
{
  if (!p_handle) return -1;

  Seobeo_Log(SEOBEO_INFO, "Using SSL/TLS encryption\n");
  Seobeo_Web_SSL_Init();
  p_handle->ssl_ctx = SSL_CTX_new(TLS_client_method());
  if (!p_handle->ssl_ctx)
  {
    Seobeo_Log(SEOBEO_ERROR, "SSL_CTX_new failed\n");
    ERR_print_errors_fp(stderr);
    return -1;
  }

  SSL_CTX_set_default_verify_paths(p_handle->ssl_ctx);

  p_handle->ssl = SSL_new(p_handle->ssl_ctx);
  if (!p_handle->ssl)
  {
    Seobeo_Log(SEOBEO_ERROR, "SSL_new failed\n");
    ERR_print_errors_fp(stderr);
    SSL_CTX_free(p_handle->ssl_ctx);
    p_handle->ssl_ctx = NULL;
    return -1;
  }

  SSL_set_fd(p_handle->ssl, socket_fd);
  SSL_set_tlsext_host_name(p_handle->ssl, host);

  // Blocking for TLS handshake
  fcntl(socket_fd, F_SETFL, 0);

  if (SSL_connect(p_handle->ssl) != 1)
  {
    Seobeo_Log(SEOBEO_ERROR, "SSL_connect failed\n");
    ERR_print_errors_fp(stderr);
    SSL_free(p_handle->ssl);
    SSL_CTX_free(p_handle->ssl_ctx);
    p_handle->ssl = NULL;
    p_handle->ssl_ctx = NULL;
    return -1;
  }

  return 0;
}

void Seobeo_SSL_Cleanup(Seobeo_Handle *p_handle)
{
  if (!p_handle) return;

  if (p_handle->ssl)
  {
    SSL_shutdown(p_handle->ssl);
    SSL_free(p_handle->ssl);
    p_handle->ssl = NULL;
  }

  if (p_handle->ssl_ctx)
  {
    SSL_CTX_free(p_handle->ssl_ctx);
    p_handle->ssl_ctx = NULL;
  }
}

int32 Seobeo_SSL_Write(Seobeo_Handle *p_handle, const uint8 *data, uint32 length)
{
  if (!p_handle || !p_handle->ssl) return -1;

  int n = SSL_write(p_handle->ssl, data, length);
  if (n < 0)
  {
    int err = SSL_get_error(p_handle->ssl, n);
    if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE)
    {
      // caller must wait for socket readiness and retry
      return 0;
    }
    ERR_print_errors_fp(stderr);
    return -1;
  }
  return n;
}

int32 Seobeo_SSL_Read(Seobeo_Handle *p_handle, uint8 *buffer, uint32 length)
{
  if (!p_handle || !p_handle->ssl) return -1;

  int32 read_size = (int32)SSL_read(p_handle->ssl, buffer, length);
  if (read_size <= 0)
  {
    int err = SSL_get_error(p_handle->ssl, read_size);
    switch (err)
    {
      case SSL_ERROR_WANT_READ:
      case SSL_ERROR_WANT_WRITE:
        return 0;
      case SSL_ERROR_ZERO_RETURN:
      default:
        // TODO: Handle these errors
        return -2;
    }
  }
  return read_size;
}

#else

// Stub implementations when SSL is disabled
void Seobeo_Web_SSL_Init() {}
void Seobeo_Web_SSL_Cleanup(void) {}
int Seobeo_SSL_Setup_Client(Seobeo_Handle *p_handle, const char *host, int socket_fd)
{
  (void)p_handle; (void)host; (void)socket_fd;
  Seobeo_Log(SEOBEO_WARNING, "SSL support not compiled in\n");
  return -1;
}
void Seobeo_SSL_Cleanup(Seobeo_Handle *p_handle) { (void)p_handle; }
int32 Seobeo_SSL_Write(Seobeo_Handle *p_handle, const uint8 *data, uint32 length)
{
  (void)p_handle; (void)data; (void)length;
  return -1;
}
int32 Seobeo_SSL_Read(Seobeo_Handle *p_handle, uint8 *buffer, uint32 length)
{
  (void)p_handle; (void)buffer; (void)length;
  return -1;
}

#endif