Hi guys,
I'm having problems connecting to the SSL socket in my C++ application. I'm trying to write a simple HTTPS client for accessing Ollama openai-compatible API.
When I compile my app on Linux I can connect without issues. But when I build for morphos it fails to SSL_connect without any error.
SSL_connect returns -1 and that's it. Do I need to call OpenLibrary or do some special initialization not required in linux?
Below is my program (I added some ifdefs to build for linux) and the build script:
Code:
#ifdef __MORPHOS__
#include <proto/exec.h>
#include <proto/socket.h>
#endif
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <string>
#include <netdb.h>
#ifndef __MORPHOS__
#define UBYTE char
#endif
#define OLLAMA_API_HOST "some-host-with-ssl.com"
#define OLLAMA_API_PORT 443
#define OLLAMA_API_ENDPOINT "/ollama/v1/chat/completions"
#define OLLAMA_API_KEY "Bearer <base64 encoded credentials>"
#ifdef __MORPHOS__
struct Library *SocketBase;
#endif
SSL_CTX *ssl_ctx;
SSL *ssl;
const SSL_METHOD *method;
int sockfd;
bool init_network() {
#ifdef __MORPHOS__
SocketBase = OpenLibrary("bsdsocket.library", 4);
if (!SocketBase) {
printf("Can't open bsdsocket.libraryn");
return false;
}
#endif
SSL_library_init();
SSL_load_error_strings();
ERR_load_crypto_strings();
method = TLS_client_method();
ssl_ctx = SSL_CTX_new(method);
SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_3_VERSION);
SSL_CTX_set_cipher_list(ssl_ctx, "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256");
if (!ssl_ctx) {
printf("Error initializing OpenSSLn");
return false;
}
return true;
}
bool connect_to_openai() {
struct hostent *server;
struct sockaddr_in serv_addr;
std::string host = OLLAMA_API_HOST;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
printf("Can't create socketn");
return false;
}
server = gethostbyname((UBYTE*)host.c_str());
if (!server) {
printf("DNS Errorn");
return false;
}
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
memcpy(&serv_addr.sin_addr.s_addr, server->h_addr_list[0], server->h_length);
serv_addr.sin_port = htons(OLLAMA_API_PORT);
if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
printf("Connection errorn");
return false;
}
ssl = SSL_new(ssl_ctx);
SSL_set_fd(ssl, sockfd);
int ret,err;
if ((ret = SSL_connect(ssl)) < 0) {
printf("SSL_connect: %dn", ret);
ret = SSL_get_error(ssl, ret);
ERR_print_errors_fp(stdout);
if((err = ERR_get_error())) {
printf("SSL connect err code:[%lu](%s)n", err, ERR_error_string(err, NULL));
printf("Error is %s n",ERR_reason_error_string(err));
}
printf("SSL Error: %dn", err);
return false;
}
return true;
}
bool send_request() {
const char *request_body =
"{"
""model": "llama3.1:8b","
""messages": [{"role": "user", "content": "Hello, Ollama!"}],"
""temperature": 0.7"
"}";
char request[2048];
snprintf(request, sizeof(request),
"POST %s HTTP/1.1rn"
"Host: %srn"
"Authorization: %srn"
"Content-Type: application/jsonrn"
"Content-Length: %lurn"
"Connection: closern"
"rn"
"%s",
OLLAMA_API_ENDPOINT, OLLAMA_API_HOST, OLLAMA_API_KEY, strlen(request_body), request_body);
if (SSL_write(ssl, request, strlen(request)) <= 0) {
printf("Error sending datan");
return false;
}
return true;
}
void receive_response() {
char response[8192];
int bytes_received;
while ((bytes_received = SSL_read(ssl, response, sizeof(response) - 1)) > 0) {
response[bytes_received] = '';
printf("%s", response);
}
}
void cleanup() {
if (ssl) SSL_free(ssl);
#ifdef __MORPHOS__
if (sockfd) CloseSocket(sockfd);
if (SocketBase) CloseLibrary(SocketBase);
#else
if (sockfd) close(sockfd);
#endif
if (ssl_ctx) SSL_CTX_free(ssl_ctx);
}
int main(void) {
if (!init_network()) {
return 1;
}
if (!connect_to_openai()) {
cleanup();
return 1;
}
if (send_request()) {
receive_response();
}
cleanup();
return 0;
}
And here is the CMakeLists.txt I use to build it:
Code:
cmake_minimum_required(VERSION 3.9.0)
project(ollama-client VERSION 0.1.0 LANGUAGES C CXX)
add_executable(ollama-client main.cpp)
set(MORPHOS_BUILD ON)
set(LINK_LIBS ssl crypto pthread)
if(${MORPHOS_BUILD})
target_include_directories(ollama-client PUBLIC /gg/os-include)
target_compile_options(ollama-client PUBLIC -noixemul -D__MORPHOS__)
list(APPEND LINK_LIBS atomic)
endif()
target_link_libraries(ollama-client PUBLIC ${LINK_LIBS})
Thanks
Jarek