Complete real-life example usage that might be useful

```d
#!/usr/bin/env -S gdc -run -lssl -lcrypto

// gcc -E -P '-D__restrict= ' '-D__extension__= ' '-D__asm__(x)= ' -std=c11 /usr/include/openssl/ssl.h > ssl.i // gcc -E -P '-D__restrict= ' '-D__extension__= ' '-D__asm__(x)= ' -std=c11 /usr/include/openssl/err.h > err.i
//
// gdc example.d -lssl -lcrypto
//
// You can ignore most warnings about
// - conflicting types for built-in function ‘vsscanf’ and similar
// they are harmless to big extent.


import core.sys.posix.sys.socket;
import core.sys.posix.netinet.in_;
import core.sys.posix.arpa.inet;
import core.sys.posix.netdb : hostent, gethostbyname;
import core.sys.posix.unistd;
import core.stdc.string : memcpy;
import core.stdc.stdio : stderr;
import core.stdc.stdlib;

import std.string : toStringz;

// Explicitly define missing constants
enum SSL_VERIFY_PEER = 0x01;
enum SSL_VERIFY_NONE = 0x00;
enum SSL_VERIFY_FAIL_IF_NO_PEER_CERT = 0x02;


enum SSL_CTRL_SET_TLSEXT_HOSTNAME = 55;  // Defined in OpenSSL
enum TLSEXT_NAMETYPE_host_name = 0x0;  // Defined in OpenSSL


void main() {
  import ssl;
  import err;

  SSL_METHOD* method = TLS_client_method();
  SSL_CTX* ctx = SSL_CTX_new(method);
  if (ctx is null) {
    ERR_print_errors_fp(cast(_IO_FILE*)stderr);
    return;
  }
  scope(exit) SSL_CTX_free(ctx);

  SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, null);
  SSL_CTX_set_default_verify_paths(ctx);

  int sock = socket(AF_INET, SOCK_STREAM, 0);
  if (sock < 0) {
    perror("socket");
    return;
  }
  scope(exit) close(sock);

  string hostname = "example.com";

  hostent* host = gethostbyname(toStringz(hostname));
  if (host is null) {
    perror("gethostbyname");
    return;
  }

  sockaddr_in addr;
  addr.sin_family = AF_INET;
  addr.sin_port = htons(443);

  // Copy first IP address
  memcpy(&addr.sin_addr, host.h_addr_list[0], host.h_length);

if (connect(sock, cast(sockaddr*)&addr, sockaddr_in.sizeof) != 0) {
    return;
  }

  SSL* s = SSL_new(ctx);
  scope(exit) SSL_free(s);

  SSL_set_fd(s, sock);

// SSL_CTX_set_tlsext_host_name is a macro, so lets expand things.

if (SSL_ctrl(s, SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name, cast(void*)toStringz(hostname)) != 1) {
    ERR_print_errors_fp(cast(_IO_FILE*)stderr);
    return;
  }

  if (SSL_connect(s) <= 0) {
    ERR_print_errors_fp(cast(_IO_FILE*)stderr);
    return;
  }
  scope(exit) SSL_shutdown(s);

  string request =
    "GET / HTTP/1.1\r\n" ~
    "Host: example.com\r\n" ~
    "Connection: close\r\n\r\n";

  SSL_write(s, request.ptr, cast(int)request.length);

  ubyte[4096] buffer;
  int bytes;

  while ((bytes = SSL_read(s, buffer.ptr, buffer.length)) > 0) {
    fwrite(buffer.ptr, 1, bytes, stdout);
  }

  return;
}
```

Reply via email to