packages feed

second-transfer-0.1.0.0: cbits/tlsinc.c

#define _BSD_SOURCE       1
#define _XOPEN_SOURCE     1   /* or any value < 500 */
#define _POSIX_C_SOURCE     1



#include <sys/types.h>
#include <signal.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <bits/sigthread.h>
#include <sys/time.h>
#include <sys/types.h>

#include <openssl/rand.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

// Simple structure to keep track of the handle, and
// of what needs to be freed later.
typedef struct {
    int socket;
    SSL_CTX *sslContext;
    char* protocol_list;
    int protocol_list_length;
} connection_t;

// Simple structure representing a session here
typedef struct {
    int socket;
    SSL *sslHandle;
    // Protocol index selected during negotiation....
    int protocol_index;
} wired_session_t;

// This is the public API of this server...
// No arguments, all are wired here somewhere... for now
connection_t* make_connection();
// Call when you are done 
void close_connection(connection_t* conn);
// Wait for the next one...
#define ALL_OK  0 
#define BAD_HAPPENED 1
#define TIMEOUT_REACHED 3
// This is also a failed IO with SSL, but this one may be quite
// natural and we want to handle it differently
#define TRANSPORT_CLOSED 2
int wait_for_connection(connection_t* conn, int microseconds, wired_session_t** wired_session);
int send_data(wired_session_t* ws, char* buffer, int buffer_size);
int recv_data(wired_session_t* ws, char* inbuffer, int buffer_size, int* data_recvd);
int get_selected_protocol(wired_session_t* ws){ return ws->protocol_index; }
void dispose_wired_session(wired_session_t* ws);
static int thread_setup(void);


////////////////////////////////////////////////////////////////////////

 
static int threads_are_up = 0;

// Leaky implementation now 
void close_connection(connection_t* conn)
{
    if (conn->socket)
    {
      close (conn->socket);
      conn->socket = 0;
    }

    if (conn->sslContext)
    {
      SSL_CTX_free(conn->sslContext);
      conn->sslContext = 0;
    }

  free(conn);
}

// For this example, we'll be testing on openssl.org

// Wired-in data that I will need to use?

#define CERTIFICATE_PLACE "/home/alcides/projects/rede/mimic/config/servercert.pem"
#define PRIVKEY_PLACE     "/home/alcides/projects/rede/mimic/config/privkey.pem"
// This should bind to local interface
#define SERVER  "www.httpdos.com"
// Grr
#define PORT 1060

// Establish a regular tcp connection
static int tcpStart (char* hostname, int portno, int* errorh)
{
  int error, handle;
  *errorh = 0;
  struct hostent *host;
  struct sockaddr_in server;

  bzero((char *) &server, sizeof(server));
   

  host = gethostbyname (hostname);
  handle = socket (AF_INET, SOCK_STREAM, 0);
  int one = 1;
  setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
  if (handle == -1)
    {
      perror ("Socket");
      handle = 0;
      *errorh = BAD_HAPPENED;
    }
  else
    {
      server.sin_family = AF_INET;
      server.sin_port = htons (portno);
      server.sin_addr = *((struct in_addr *) host->h_addr);
      bzero (&(server.sin_zero), 8);

      error = bind (handle, (struct sockaddr *) &server,
                       sizeof (struct sockaddr));
      if (error == -1)
        {
          perror ("Bind");
          handle = 0;
          *errorh = BAD_HAPPENED;
        }
      else 
        {
          error = listen(handle, 5);
          if ( error != 0 )
          {
            perror("Listen");
            handle = 0;
            *errorh = BAD_HAPPENED;
          }
        }
    }

  return handle;
}

// Dh_Callback {{{
#ifndef HEADER_DH_H
#include <openssl/dh.h>
#endif
DH *get_dh2236()
{
    static unsigned char dh2236_p[]={
        0x08,0x32,0x3B,0x6A,0xE8,0xEA,0x55,0xE3,0x0C,0xD9,0x95,0x3D,
        0xE7,0x78,0xDA,0xF0,0x05,0x81,0x94,0x85,0x34,0x5C,0x26,0x5A,
        0xAE,0x9E,0x31,0x8F,0x0C,0xCC,0xFC,0xF3,0x30,0x88,0x20,0x0B,
        0x41,0xC3,0xC9,0xEC,0x13,0xA7,0xFF,0xDA,0xBB,0x11,0xFB,0x7B,
        0x19,0x92,0x3B,0x61,0xDF,0x31,0xEF,0x2C,0x4A,0x5C,0xD1,0x59,
        0x16,0x90,0xAC,0xFC,0xEA,0xFF,0xCB,0xC4,0x04,0x07,0x93,0x9D,
        0xF0,0x70,0x0B,0xCB,0x3E,0x79,0x0D,0xEB,0xD3,0x3E,0x06,0x0B,
        0x19,0xF2,0x97,0x1E,0xE1,0xBF,0xD2,0xBE,0x5E,0xA5,0xBD,0x5F,
        0x73,0x2C,0x57,0x0C,0xB0,0x97,0x78,0xAA,0x60,0xDC,0x98,0x89,
        0xAF,0xBF,0xCD,0x49,0x74,0x82,0x64,0x09,0x60,0x47,0xD0,0xD4,
        0x5D,0x25,0xDC,0x38,0xAC,0x17,0xE7,0xA4,0x47,0x59,0x94,0xFE,
        0xA8,0xAD,0x58,0xD0,0xD1,0x43,0x3C,0x20,0x2E,0x34,0xEE,0xA9,
        0x0F,0x71,0x20,0x93,0xB7,0x8E,0xEC,0xB1,0x75,0xB9,0xE9,0x9A,
        0xAB,0x73,0xBB,0x7F,0xA2,0x8F,0x11,0xDE,0x58,0x5E,0xB0,0x98,
        0xD6,0x95,0x84,0x62,0x90,0x87,0x90,0x32,0x34,0xF7,0x61,0x28,
        0xFF,0x17,0xD0,0x58,0x33,0xA6,0xC2,0xC6,0x58,0x65,0x1C,0x92,
        0xF3,0xDF,0x4D,0xB3,0xB0,0xFD,0xD2,0x4A,0x97,0x1B,0xA7,0xD2,
        0x7C,0x8D,0x8F,0x1F,0x69,0x98,0x54,0xD9,0x33,0x15,0xE5,0xEA,
        0xBA,0xAA,0x31,0xB1,0x17,0x65,0x21,0xFA,0xC7,0x54,0xC0,0xE4,
        0x72,0x3C,0x15,0x74,0x41,0xF2,0x9A,0xF6,0xD1,0x16,0x10,0x35,
        0x4F,0x36,0xA6,0x23,0x67,0x67,0x89,0x65,0xDD,0x77,0x5D,0x8F,
        0x69,0x49,0x22,0x24,0xB6,0xB8,0x45,0xCA,0x8F,0x35,0x71,0x45,
        0x4C,0x65,0x38,0x11,0x21,0xD5,0x39,0x03,0x4D,0x05,0xBB,0x95,
        0x43,0x58,0xBB,0xF3,
        };
    static unsigned char dh2236_g[]={
        0x02,
        };
    DH *dh;

    if ((dh=DH_new()) == NULL) return(NULL);
    dh->p=BN_bin2bn(dh2236_p,sizeof(dh2236_p),NULL);
    dh->g=BN_bin2bn(dh2236_g,sizeof(dh2236_g),NULL);
    if ((dh->p == NULL) || (dh->g == NULL))
        { DH_free(dh); return(NULL); }
    return(dh);
}
DH *get_dh2048()
{
static unsigned char dh2048_p[]={
        0xCE,0x28,0x14,0x1C,0xEF,0x22,0x1D,0x86,0xEA,0x10,0x00,0x50,
        0x24,0x42,0x95,0xC3,0x07,0x5A,0x87,0xED,0x0F,0xC5,0xDC,0x0F,
        0x5E,0x7E,0x69,0x25,0x85,0x90,0x39,0x60,0x1E,0x87,0x5C,0x4B,
        0xAD,0xDF,0xA8,0xF4,0x9C,0xC6,0x2D,0x6A,0x2E,0x7C,0xD1,0x5C,
        0xC5,0x1A,0x74,0xD3,0x9E,0xE1,0xBB,0x31,0xC4,0x23,0x2F,0x78,
        0xF5,0x61,0x5C,0x09,0x7E,0x29,0x06,0xC5,0x07,0x50,0x32,0x80,
        0x4A,0xBE,0x5F,0x7F,0x68,0x69,0x8F,0xB1,0x6D,0xA0,0x0C,0x7F,
        0x9E,0x28,0x77,0x9D,0x4F,0xEA,0xB5,0x38,0xB3,0x72,0x8E,0x1D,
        0x8D,0x1C,0x58,0x74,0x58,0xC4,0xDD,0x06,0x8E,0x80,0x91,0x36,
        0x2D,0x42,0x3D,0xF0,0x11,0xEC,0xDF,0x02,0xFD,0x84,0x54,0x32,
        0x90,0xFE,0x7C,0x74,0x3A,0x5F,0x87,0xBA,0xD3,0x21,0x0E,0xDD,
        0xF4,0xB3,0xFD,0xF9,0x89,0x8F,0x96,0x59,0x90,0x74,0xE8,0x45,
        0x5A,0x3A,0x7C,0x88,0x7F,0xD8,0x5F,0xD2,0x32,0x57,0x46,0x29,
        0x6B,0xA1,0x0A,0x05,0x1E,0xB6,0x49,0x8A,0x68,0xB4,0xEE,0x84,
        0x45,0xEF,0x56,0x7E,0x59,0x83,0x67,0x20,0x85,0x63,0x69,0x6B,
        0x39,0xCA,0x24,0x46,0x68,0x51,0x94,0x9E,0x3E,0xB4,0x69,0x1F,
        0x63,0x07,0x40,0x0E,0x84,0x8B,0x26,0x98,0xCE,0xE5,0x48,0x2C,
        0xD8,0xF9,0x6A,0x3F,0x20,0xFA,0xFA,0xDC,0x4E,0xFA,0xBD,0xC3,
        0x81,0x09,0x4D,0xCF,0x07,0xEF,0xE8,0x32,0x9B,0x63,0x32,0x5B,
        0x06,0x59,0x4F,0xE7,0x5B,0xD2,0xFC,0x25,0xC6,0x2C,0xA3,0xE8,
        0x05,0xE5,0x8D,0xC2,0x94,0x76,0x90,0x63,0x29,0xB4,0xEE,0x2D,
        0xD6,0x50,0x83,0x8B,
        };
static unsigned char dh2048_g[]={
        0x02,
        };
DH *dh;

if ((dh=DH_new()) == NULL) return(NULL);
dh->p=BN_bin2bn(dh2048_p,sizeof(dh2048_p),NULL);
dh->g=BN_bin2bn(dh2048_g,sizeof(dh2048_g),NULL);
if ((dh->p == NULL) || (dh->g == NULL))
        { DH_free(dh); return(NULL); }
return(dh);
}

DH *get_dh1024()
    {
    static unsigned char dh1024_p[]={
        0x87,0xF4,0xE5,0x5A,0x1E,0x7F,0x98,0x83,0xFD,0x23,0x6A,0xF3,
        0x8C,0xE8,0x2F,0x35,0x64,0x3D,0x13,0x34,0x5B,0x0A,0x52,0xEC,
        0x0B,0x3A,0xBF,0x92,0xE4,0x67,0x14,0x47,0x86,0x55,0x2C,0x83,
        0x1B,0xDD,0x0E,0xC8,0x2D,0x98,0x72,0x2A,0xB6,0x68,0xF1,0x32,
        0xD8,0xBD,0x6B,0x17,0x23,0x46,0x08,0xB6,0x19,0x58,0x01,0x30,
        0x32,0x68,0x60,0x78,0xD1,0x5B,0x5C,0x88,0x3F,0x20,0xD7,0xEB,
        0xE8,0xD5,0x80,0xB0,0x23,0x75,0xAE,0x97,0x26,0xBD,0xA5,0x11,
        0x7F,0x83,0x8C,0x21,0xD4,0x39,0x52,0xE0,0x25,0x1F,0x03,0xA9,
        0x69,0xF8,0x07,0x4F,0x33,0x17,0x72,0xCC,0xEB,0xBD,0x77,0xD1,
        0x9C,0x40,0xA6,0x55,0xE3,0x87,0x76,0x66,0x3B,0xE3,0xE4,0x6A,
        0x4B,0x6B,0xF1,0x92,0x1A,0x3A,0x25,0xC3,
        };
    static unsigned char dh1024_g[]={
        0x02,
        };
    DH *dh;

    if ((dh=DH_new()) == NULL) return(NULL);
    dh->p=BN_bin2bn(dh1024_p,sizeof(dh1024_p),NULL);
    dh->g=BN_bin2bn(dh1024_g,sizeof(dh1024_g),NULL);
    if ((dh->p == NULL) || (dh->g == NULL))
        { DH_free(dh); return(NULL); }
    return (dh);
}


static DH *tmp_dh_callback(SSL *s, int is_export, int keylength);


// Setup dh params 
static void setup_dh_parms(SSL_CTX *sslContext)
{
 /* Set up ephemeral DH stuff */
 SSL_CTX_set_tmp_dh_callback(sslContext, tmp_dh_callback);
}

static DH *tmp_dh_callback(SSL *s, int is_export, int keylength)
{
    static DH *dh_2048 = NULL;
    static DH *dh_1024 = NULL;
    DH *dh_tmp=NULL;
    switch (keylength) {
        case 2048:
            if (!dh_2048)
                dh_2048 = get_dh2048();
            dh_tmp = dh_2048;
            break;
        case 1024:
            if (!dh_1024)
                dh_1024 = get_dh1024();
            dh_tmp = dh_1024;
            break;
        default:
            /* Generating a key on the fly is very costly, so use what is there */
            printf("Keylength %d \n", keylength);
    }
    return(dh_tmp);
}
// dh_callback }}}



static int protocol_select (
     SSL *ssl,
     const unsigned char **out,
     unsigned char *outlen,
     const unsigned char *in,
     unsigned int inlen,
     void *arg)
{
  // Oh well, C is a verbose beast
  connection_t* conn = (connection_t*) arg;
  static char output[64];

  char* incursor = (char*) in;

  while (incursor < (char*)in + inlen )
  {
    // Got a protocol.... can I satisfy it?
    char sublen = *incursor;
    printf("offered prot %.*s \n", sublen, incursor+1);

    char* stored_cursor = conn->protocol_list;
    int sto_protocol = 0;

    while( stored_cursor < conn->protocol_list + conn->protocol_list_length)
    {
      char sublen2 = *stored_cursor;

      if (sublen != sublen2)
      {
        
      } else {
        int cmpresult = strncmp( incursor + 1, stored_cursor + 1, sublen);
        if (cmpresult == 0)
        {
          // They are equal, choose this one...
          strncpy( output, stored_cursor+1, sublen);
          *outlen = sublen;
          *out = output;


          return SSL_TLSEXT_ERR_OK;
        }
      }
      sto_protocol += 1;
      stored_cursor += (1+sublen2);
    }

    incursor += (1+sublen);
  }

   // I think this is what should be returned 
   return -1;
}


int lookup_protocol(
  char* selected, int selected_len, 
  char* myprotocol_list, int mpl_len
  )
{
  char* incursor = selected;

  char* stored_cursor = myprotocol_list;
  int sto_protocol = 0;

  if (selected_len == 0)
  {
    // No protocol was selected
    return -2;
  }

  while( stored_cursor < myprotocol_list + mpl_len)
  {
    char sublen2 = *stored_cursor;

    if (sublen2 != selected_len)
    {
      
    } else {
      int cmpresult = strncmp( selected, stored_cursor + 1, sublen2);
      if (cmpresult == 0)
      {
        // They are equal, choose this one...
        return sto_protocol;
      }
    }
    sto_protocol += 1;
    stored_cursor += (1+sublen2);
  }

   // I think this is what should be returned 
   return -1;
}

static int ssl_servername_cb(SSL *s, int *ad, void *arg)
{
    // TODO: Use this for something .... although I'm not sure what...

    // tlsextctx *p = (tlsextctx *) arg;
    // const char *servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name);
    // if (servername && p->biodebug)
    //     BIO_printf(p->biodebug, "Hostname in TLS extension: \"%s\"\n",
    //                servername);

    // if (!p->servername)
    //     return SSL_TLSEXT_ERR_NOACK;

    // if (servername) {
    //     if (strcasecmp(servername, p->servername))
    //         return p->extension_error;
    //     if (ctx2) {
    //         BIO_printf(p->biodebug, "Switching server context.\n");
    //         SSL_set_SSL_CTX(s, ctx2);
    //     }
    // }
    return SSL_TLSEXT_ERR_OK;
}


// Establish a connection using an SSL layer
static connection_t *sslStart (
  char* certificate_filename, char* privkey_filename, char* hostname, int portno,
  char* protocol_list, int protocol_list_length
  )
{
  int result;
  connection_t *c;

  if (! threads_are_up)
  {
    threads_are_up = 1;
    thread_setup();
  }

  c = malloc (sizeof (connection_t));
  c->sslContext = NULL;
  c->protocol_list  = (char*) malloc(protocol_list_length);
  strncpy( c->protocol_list, protocol_list, protocol_list_length );
  c->protocol_list_length = protocol_list_length;
  c->socket = tcpStart (hostname, portno, &result);

  if ( result )
  {
    return 0;
  }

  if (c->socket)
  {
    // Register the error strings for libcrypto & libssl
    SSL_load_error_strings ();
    // Register the available ciphers and digests
    SSL_library_init ();

    // New context saying we are a server, and using SSL 2 or 3
    c->sslContext = SSL_CTX_new( TLSv1_2_server_method() );
    if (c->sslContext == NULL)
    {
      ERR_print_errors_fp (stderr);
      perror("Could not create context");
      return 0;
    }


      // Now I set a few options....
      /*SSL_CTX_set_verify(c->sslContext, NULL );*/
      // const long flags = 
      //   SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION | SSL_OP_NO_COMPRESSION;
      const long flags = 
        SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION | SSL_OP_NO_COMPRESSION;
      SSL_CTX_set_options(c->sslContext, flags);
      setup_dh_parms( c->sslContext );
      SSL_CTX_set_ecdh_auto (c->sslContext, 1);

      // Give the impression that we are using SNI
      SSL_CTX_set_tlsext_servername_callback(c->sslContext, ssl_servername_cb);



      // The only cipher supported by HTTP/2 ... sort of.
      result = SSL_CTX_set_cipher_list(c->sslContext, "ECDHE-RSA-AES128-GCM-SHA256");
      /*result = SSL_CTX_set_cipher_list(c->sslContext, "DEFAULT");*/

      // Be sure we are able to do ALPN
      // void SSL_CTX_set_alpn_select_cb(SSL_CTX *ctx,
      //                           int (*cb) (SSL *ssl,
      //                                      const unsigned char **out,
      //                                      unsigned char *outlen,
      //                                      const unsigned char *in,
      //                                      unsigned int inlen,
      //                                      void *arg), void *arg);
      SSL_CTX_set_alpn_select_cb( c->sslContext, protocol_select, c);

      if ( result != 1 )
      {
        ERR_print_errors_fp (stderr);
        perror("Could not set cipher");
        return 0;
      }
      // The certificate (well-wired)
      SSL_CTX_use_certificate_file(c->sslContext, certificate_filename, SSL_FILETYPE_PEM);
      SSL_CTX_use_PrivateKey_file(c->sslContext,  privkey_filename, SSL_FILETYPE_PEM);
      // Check the private key 
      result = SSL_CTX_check_private_key(c->sslContext);
      if ( result != 1)
      {
        perror("Check private key failed");
        return 0;
      }
      // //////////////////////////////////////////

    }
  else
    {
      perror ("Connect failed");
    }

  return c;
}


connection_t* make_connection(char* certificate_filename, char* privkey_filename, char* hostname, int portno,
    char* my_protocol_list, int protocol_list_length
    )
{
  const int len = strlen(hostname);
  if ( len > 0 && hostname[len-1] == '\n' )
  { 
     printf("HELLO THERE. I'M A FLIMSY C FUNCTION AND I CAN NOT REMOVE THE END-OF-LINE IN THE PROVIDED HOST NAME WITHOUT A TON OF LINES. I'M GOING TO SEGFAULT NOW. BYE.\n");
     *( (int*) 0) = 42; // <-- This is the answer
  }


  return sslStart(
    certificate_filename, privkey_filename, hostname, 
    portno, my_protocol_list, protocol_list_length); 
}

int wait_for_connection(
  connection_t* c, 
  int microseconds,
  wired_session_t** wired_session)
{
    int clilen, newsockfd;
    // Don't return anything if there's a failure...
    *wired_session = 0;

    // Wait for a connection
    struct sockaddr_in cli_addr;
    clilen = sizeof(cli_addr);

    // Use select to get "interruptible" accepts 
    fd_set rfds;

    int can_go = 0;

    while( ! can_go )
    {
        FD_ZERO(&rfds);
        FD_SET(c->socket, &rfds);
        struct timeval tv;
        tv.tv_sec = microseconds / 1000000;
        tv.tv_usec = microseconds % 1000000;


        int retval = select(FD_SETSIZE, &rfds, NULL, NULL, &tv);


        if ( retval == -1 )
        {
          if ( errno == EINTR )
          {
             // printf(".");
             can_go = 0;
          } else {
             perror("select()");
             return BAD_HAPPENED;
          }
        } else if (retval > 0)
        {
          // We got data, just let it go...
          // printf("letitgo\n");
          can_go = 1;
        } else 
        {
          // We didn't get data, finish and terminate
          // printf("timeo\n");
          return TIMEOUT_REACHED;
        }

    }

    wired_session_t* result = (wired_session_t*) malloc(sizeof(wired_session_t) );
    if ( result == 0 )
    {
        perror("Malloc failed");
        return BAD_HAPPENED;
    }

    /* Accept actual connection from the client */
    newsockfd = accept(c->socket, (struct sockaddr *)&cli_addr, &clilen);

    if (newsockfd < 0)
    {
        perror("ERROR on accept");
        return BAD_HAPPENED;
    }
        
    // Create an SSL struct for the connection

    result->socket = newsockfd;
    result->sslHandle = SSL_new (c->sslContext);
    if (result->sslHandle == NULL)
    {
        perror("No handle on SSL new");
        ERR_print_errors_fp (stderr);
        return BAD_HAPPENED;
    }

    // Connect the SSL struct to our connection
    if (!SSL_set_fd (result->sslHandle, result->socket))
    {
        perror("Could not associate");
        ERR_print_errors_fp (stderr);
        return BAD_HAPPENED;
    }

    // Initiate SSL handshake
    if (SSL_accept (result->sslHandle) != 1)
    {
        perror("Could not accept");
        ERR_print_errors_fp (stderr);
        return BAD_HAPPENED;
    }

    // After this one is okej, see which protocol was selected
    const unsigned char* out_protocol; unsigned pr_len;
    SSL_get0_alpn_selected(result->sslHandle, &out_protocol,
                            &pr_len);
    // Wonder who is in charge of releasing that buffer...
    result -> protocol_index = lookup_protocol( 
      (char*)out_protocol, pr_len, 
      c->protocol_list, c->protocol_list_length);

    *wired_session = result;

    return ALL_OK;
}

// Disconnect & free connection struct
/*static void sslDisconnect (connection *c)*/
/*{*/
  /*if (c->socket)*/
    /*close (c->socket);*/
  /*if (c->sslHandle)*/
    /*{*/
      /*SSL_shutdown (c->sslHandle);*/
      /*SSL_free (c->sslHandle);*/
    /*}*/
  /*if (c->sslContext)*/
    /*SSL_CTX_free (c->sslContext);*/

  /*free (c);*/
/*}*/


int send_data(wired_session_t* ws, char* buffer, int buffer_size)
{
    if ( buffer_size == 0 )
    {
        return ALL_OK;
    }
    if (ws)
    {
        int result = SSL_write( ws->sslHandle, buffer, buffer_size);
        if ( result > 0 )
        {
            return ALL_OK;
        } else {
            return BAD_HAPPENED;
        }
    } else 
    {
        return BAD_HAPPENED;
    }
}

int recv_data(wired_session_t* ws, char* inbuffer, int buffer_size, int* data_recvd)
{
    int received=0, count = 0;
    char buffer[1024];

    // printf("Recvd entered\n");

    if (ws)
    {
        received = SSL_read (ws->sslHandle, inbuffer, buffer_size);
    }
    if ( received <= 0 )
    {
        ERR_print_errors_fp (stderr);
        return BAD_HAPPENED;
    }
    *data_recvd = received ;

    // printf("Recvd exited\n");

    return ALL_OK;
}

#define MUTEX_TYPE       pthread_mutex_t
#define MUTEX_SETUP(x)   pthread_mutex_init(&(x), NULL)
#define MUTEX_CLEANUP(x) pthread_mutex_destroy(&(x))
#define MUTEX_LOCK(x)    pthread_mutex_lock(&(x))
#define MUTEX_UNLOCK(x)  pthread_mutex_unlock(&(x))
#define THREAD_ID        pthread_self(  )
 
 
void handle_error(const char *file, int lineno, const char *msg){
     fprintf(stderr, "** %s:%d %s\n", file, lineno, msg);
     ERR_print_errors_fp(stderr);
     /* exit(-1); */ 
 }
 
/* This array will store all of the mutexes available to OpenSSL. */ 
static MUTEX_TYPE *mutex_buf= NULL;
 
 
static void locking_function(int mode, int n, const char * file, int line)
{
  if (mode & CRYPTO_LOCK)
    MUTEX_LOCK(mutex_buf[n]);
  else
    MUTEX_UNLOCK(mutex_buf[n]);
}
 
static unsigned long id_function(void)
{
  return ((unsigned long)THREAD_ID);
}

void dispose_wired_session(wired_session_t* ws)
{
  if (ws == 0)
    return ;
  if ( ws-> sslHandle )
  {
    SSL_shutdown( ws->sslHandle );
    ws -> sslHandle = 0;
  }
  if (ws->socket)
  {
    close(ws->socket);
    ws -> socket = 0;
  }
  free(ws);
}


int thread_setup(void)
{
  int i;

  // printf("Threads setup\n");
 
  mutex_buf = malloc(CRYPTO_num_locks(  ) * sizeof(MUTEX_TYPE));
  if (!mutex_buf)
    return 0;
  for (i = 0;  i < CRYPTO_num_locks(  );  i++)
    MUTEX_SETUP(mutex_buf[i]);
  CRYPTO_set_id_callback(id_function);
  CRYPTO_set_locking_callback(locking_function);
  return 1;
}
 
int thread_cleanup(void)
{
  int i;
 
  if (!mutex_buf)
    return 0;
  CRYPTO_set_id_callback(NULL);
  CRYPTO_set_locking_callback(NULL);
  for (i = 0;  i < CRYPTO_num_locks(  );  i++)
    MUTEX_CLEANUP(mutex_buf[i]);
  free(mutex_buf);
  mutex_buf = NULL;
  return 1;
}