From f4907bc0c23c6c8c389dde3125af89f7b9f163a9 Mon Sep 17 00:00:00 2001
From: valenok <devnull@localhost>
Date: Mon, 23 Aug 2010 21:36:35 +0100
Subject: [PATCH] introdused NO_SSL. Explicitely linking against SSL library.

---
 Makefile   |  14 ++--
 mongoose.c | 188 +++++++++++++++--------------------------------------
 2 files changed, 62 insertions(+), 140 deletions(-)

diff --git a/Makefile b/Makefile
index 7e267fb97..793c13104 100644
--- a/Makefile
+++ b/Makefile
@@ -23,7 +23,8 @@ all:
 
 CFLAGS=		-W -Wall -std=c99 -pedantic -Os -fomit-frame-pointer $(COPT)
 MAC_SHARED=	-flat_namespace -bundle -undefined suppress
-LINFLAGS=	-ldl -pthread $(CFLAGS)
+SSLFLAGS=	-lssl -lcrypto
+LINFLAGS=	-ldl -pthread $(SSLFLAGS) $(CFLAGS)
 LIB=		_$(PROG).so
 
 linux:
@@ -32,16 +33,17 @@ linux:
 
 bsd:
 	$(CC) $(CFLAGS) mongoose.c -shared -pthread -s -fpic -fPIC -o $(LIB)
-	$(CC) $(CFLAGS) mongoose.c main.c -pthread -s -o $(PROG)
+	$(CC) $(CFLAGS) mongoose.c main.c -pthread -s $(SSLFLAGS) -o $(PROG)
 
 mac:
-	$(CC) $(CFLAGS) $(MAC_SHARED) mongoose.c -pthread -o $(LIB)
-	$(CC) $(CFLAGS) mongoose.c main.c -pthread -o $(PROG)
+	$(CC) $(CFLAGS) $(MAC_SHARED) mongoose.c -pthread $(SSLFLAGS) -o $(LIB)
+	$(CC) $(CFLAGS) mongoose.c main.c -pthread $(SSLFLAGS) -o $(PROG)
 
 solaris:
 	gcc $(CFLAGS) mongoose.c -pthread -lnsl \
-		-lsocket -s -fpic -fPIC -shared -o $(LIB)
-	gcc $(CFLAGS) mongoose.c main.c -pthread -lnsl -lsocket -s -o $(PROG)
+		-lsocket $(SSLFLAGS) -s -fpic -fPIC -shared -o $(LIB)
+	gcc $(CFLAGS) mongoose.c main.c -pthread -lnsl -lsocket $(SSLFLAGS) \
+		-s -o $(PROG)
 
 
 ##########################################################################
diff --git a/mongoose.c b/mongoose.c
index 66c8b21b0..0fa326f2c 100644
--- a/mongoose.c
+++ b/mongoose.c
@@ -90,8 +90,6 @@ typedef long off_t;
 
 #define ERRNO   GetLastError()
 #define NO_SOCKLEN_T
-#define SSL_LIB   "ssleay32.dll"
-#define CRYPTO_LIB  "libeay32.dll"
 #define DIRSEP '\\'
 #define IS_DIRSEP_CHAR(c) ((c) == '/' || (c) == '\\')
 #define O_NONBLOCK  0
@@ -174,8 +172,6 @@ typedef struct DIR {
 #include <dirent.h>
 #include <dlfcn.h>
 #include <pthread.h>
-#define SSL_LIB   "libssl.so"
-#define CRYPTO_LIB  "libcrypto.so"
 #define DIRSEP   '/'
 #define IS_DIRSEP_CHAR(c) ((c) == '/')
 #define O_BINARY  0
@@ -234,76 +230,27 @@ typedef struct ssl_ctx_st SSL_CTX;
 #define SSL_FILETYPE_PEM 1
 #define CRYPTO_LOCK  1
 
-// Dynamically loaded SSL functionality
-struct ssl_func {
-  const char *name;   // SSL function name
-  void  (*ptr)(void); // Function pointer
-};
-
-#define SSL_free(x) (* (void (*)(SSL *)) ssl_sw[0].ptr)(x)
-#define SSL_accept(x) (* (int (*)(SSL *)) ssl_sw[1].ptr)(x)
-#define SSL_connect(x) (* (int (*)(SSL *)) ssl_sw[2].ptr)(x)
-#define SSL_read(x,y,z) (* (int (*)(SSL *, void *, int))   \
-    ssl_sw[3].ptr)((x),(y),(z))
-#define SSL_write(x,y,z) (* (int (*)(SSL *, const void *,int))  \
-    ssl_sw[4].ptr)((x), (y), (z))
-#define SSL_get_error(x,y)(* (int (*)(SSL *, int)) ssl_sw[5])((x), (y))
-#define SSL_set_fd(x,y) (* (int (*)(SSL *, SOCKET)) ssl_sw[6].ptr)((x), (y))
-#define SSL_new(x) (* (SSL * (*)(SSL_CTX *)) ssl_sw[7].ptr)(x)
-#define SSL_CTX_new(x) (* (SSL_CTX * (*)(SSL_METHOD *)) ssl_sw[8].ptr)(x)
-#define SSLv23_server_method() (* (SSL_METHOD * (*)(void)) ssl_sw[9].ptr)()
-#define SSL_library_init() (* (int (*)(void)) ssl_sw[10].ptr)()
-#define SSL_CTX_use_PrivateKey_file(x,y,z) (* (int (*)(SSL_CTX *, \
-        const char *, int)) ssl_sw[11].ptr)((x), (y), (z))
-#define SSL_CTX_use_certificate_file(x,y,z) (* (int (*)(SSL_CTX *, \
-        const char *, int)) ssl_sw[12].ptr)((x), (y), (z))
-#define SSL_CTX_set_default_passwd_cb(x,y) \
-  (* (void (*)(SSL_CTX *, mg_callback_t)) ssl_sw[13].ptr)((x),(y))
-#define SSL_CTX_free(x) (* (void (*)(SSL_CTX *)) ssl_sw[14].ptr)(x)
-#define ERR_get_error() (* (unsigned long (*)(void)) ssl_sw[15].ptr)()
-#define ERR_error_string(x, y) (* (char * (*)(unsigned long, char *)) ssl_sw[16].ptr)((x), (y))
-#define SSL_load_error_strings() (* (void (*)(void)) ssl_sw[17].ptr)()
-
-#define CRYPTO_num_locks() (* (int (*)(void)) crypto_sw[0].ptr)()
-#define CRYPTO_set_locking_callback(x)     \
-  (* (void (*)(void (*)(int, int, const char *, int))) \
-   crypto_sw[1].ptr)(x)
-#define CRYPTO_set_id_callback(x)     \
-  (* (void (*)(unsigned long (*)(void))) crypto_sw[2].ptr)(x)
-
-// set_ssl_option() function updates this array.
-// It loads SSL library dynamically and changes NULLs to the actual addresses
-// of respective functions. The macros above (like SSL_connect()) are really
-// just calling these functions indirectly via the pointer.
-static struct ssl_func ssl_sw[] = {
-  {"SSL_free",   NULL},
-  {"SSL_accept",   NULL},
-  {"SSL_connect",   NULL},
-  {"SSL_read",   NULL},
-  {"SSL_write",   NULL},
-  {"SSL_get_error",  NULL},
-  {"SSL_set_fd",   NULL},
-  {"SSL_new",   NULL},
-  {"SSL_CTX_new",   NULL},
-  {"SSLv23_server_method", NULL},
-  {"SSL_library_init",  NULL},
-  {"SSL_CTX_use_PrivateKey_file", NULL},
-  {"SSL_CTX_use_certificate_file",NULL},
-  {"SSL_CTX_set_default_passwd_cb",NULL},
-  {"SSL_CTX_free",  NULL},
-  {"ERR_get_error",  NULL},
-  {"ERR_error_string", NULL},
-  {"SSL_load_error_strings", NULL},
-  {NULL,    NULL}
-};
-
-// Similar array as ssl_sw. These functions could be located in different lib.
-static struct ssl_func crypto_sw[] = {
-  {"CRYPTO_num_locks",  NULL},
-  {"CRYPTO_set_locking_callback", NULL},
-  {"CRYPTO_set_id_callback", NULL},
-  {NULL,    NULL}
-};
+extern void SSL_free(SSL *);
+extern int SSL_accept(SSL *);
+extern int SSL_connect(SSL *);
+extern int SSL_read(SSL *, void *, int);
+extern int SSL_write(SSL *, const void *, int);
+extern int SSL_get_error(const SSL *, int);
+extern int SSL_set_fd(SSL *, int);
+extern SSL *SSL_new(SSL_CTX *);
+extern SSL_CTX *SSL_CTX_new(SSL_METHOD *);
+extern SSL_METHOD *SSLv23_server_method(void);
+extern int SSL_library_init(void);
+extern void SSL_load_error_strings(void);
+extern int SSL_CTX_use_PrivateKey_file(SSL_CTX *, const char *, int);
+extern int SSL_CTX_use_certificate_file(SSL_CTX *, const char *, int);
+extern void SSL_CTX_set_default_passwd_cb(SSL_CTX *, mg_callback_t);
+extern void SSL_CTX_free(SSL_CTX *);
+extern unsigned long ERR_get_error(void);
+extern char *ERR_error_string(unsigned long, char *);
+extern int CRYPTO_num_locks(void);
+extern void CRYPTO_set_locking_callback(void (*)(int, int, const char *, int));
+extern void CRYPTO_set_id_callback(unsigned long (*)(void));
 
 static const char *month_names[] = {
   "Jan", "Feb", "Mar", "Apr", "May", "Jun",
@@ -344,15 +291,15 @@ struct socket {
 };
 
 struct mg_context {
-  int stop_flag;     // Should we stop event loop
-  SSL_CTX *ssl_ctx;  // SSL context
+  int stop_flag;             // Should we stop event loop
+  SSL_CTX *ssl_ctx;          // SSL context
   const struct mg_config *config; // Mongoose configuration
 
   struct socket *listening_sockets;
 
-  int num_threads;         // Number of threads
-  pthread_mutex_t mutex;   // Protects (max|num)_threads
-  pthread_cond_t  cond;    // Condvar for tracking workers terminations
+  int num_threads;           // Number of threads
+  pthread_mutex_t mutex;     // Protects (max|num)_threads
+  pthread_cond_t  cond;      // Condvar for tracking workers terminations
 
   struct socket queue[20];   // Accepted sockets
   int sq_head;               // Head of the socket queue
@@ -426,13 +373,6 @@ static void cry(struct mg_connection *conn, const char *fmt, ...) {
   conn->request_info.log_message = NULL;
 }
 
-// Return OpenSSL error message
-static const char *ssl_error(void) {
-  unsigned long err;
-  err = ERR_get_error();
-  return err == 0 ? "" : ERR_error_string(err, NULL);
-}
-
 // Return fake connection structure. Used for logging, if connection
 // is not applicable at the moment of logging.
 static struct mg_connection *fc(struct mg_context *ctx) {
@@ -1180,9 +1120,12 @@ static int64_t push(FILE *fp, SOCKET sock, SSL *ssl, const char *buf,
     /* How many bytes we send in this iteration */
     k = len - sent > INT_MAX ? INT_MAX : (int) (len - sent);
 
+#if !defined(NO_SSL)
     if (ssl != NULL) {
       n = SSL_write(ssl, buf + sent, k);
-    } else if (fp != NULL) {
+    } else 
+#endif // !NO_SSL
+    if (fp != NULL) {
       n = fwrite(buf + sent, 1, k, fp);
       if (ferror(fp))
         n = -1;
@@ -1204,9 +1147,12 @@ static int64_t push(FILE *fp, SOCKET sock, SSL *ssl, const char *buf,
 static int pull(FILE *fp, SOCKET sock, SSL *ssl, char *buf, int len) {
   int nread;
 
+#if !defined(NO_SSL)
   if (ssl != NULL) {
     nread = SSL_read(ssl, buf, len);
-  } else if (fp != NULL) {
+  } else
+#endif // !NO_SSL
+  if (fp != NULL) {
     nread = fread(buf, 1, (size_t) len, fp);
     if (ferror(fp))
       nread = -1;
@@ -3299,68 +3245,33 @@ static unsigned long ssl_id_callback(void) {
   return (unsigned long) pthread_self();
 }
 
-static bool_t load_dll(struct mg_context *ctx, const char *dll_name,
-                       struct ssl_func *sw) {
-  union {void *p; void (*fp)(void);} u;
-  void  *dll_handle;
-  struct ssl_func *fp;
-
-  if ((dll_handle = dlopen(dll_name, RTLD_LAZY)) == NULL) {
-    cry(fc(ctx), "%s: cannot load %s", __func__, dll_name);
-    return MG_FALSE;
-  }
-
-  for (fp = sw; fp->name != NULL; fp++) {
-#ifdef _WIN32
-    // GetProcAddress() returns pointer to function
-    u.fp = (void (*)(void)) dlsym(dll_handle, fp->name);
-#else
-    // dlsym() on UNIX returns void *. ISO C forbids casts of data pointers to
-    // function pointers. We need to use a union to make a cast.
-    u.p = dlsym(dll_handle, fp->name);
-#endif /* _WIN32 */
-    if (u.fp == NULL) {
-      cry(fc(ctx), "%s: cannot find %s", __func__, fp->name);
-      return MG_FALSE;
-    } else {
-      fp->ptr = u.fp;
-    }
-  }
-
-  return MG_TRUE;
+// Return OpenSSL error message
+static const char *ssl_error(void) {
+  unsigned long err;
+  err = ERR_get_error();
+  return err == 0 ? "" : ERR_error_string(err, NULL);
 }
 
-// Dynamically load SSL library. Set up ctx->ssl_ctx pointer.
 static enum mg_error_t set_ssl_option(struct mg_context *ctx) {
   SSL_CTX *CTX;
   int i, size;
   const char *pem = ctx->config->ssl_certificate;
 
-  if (pem == NULL) {
-    return MG_SUCCESS;
-  }
-
-  if (load_dll(ctx, SSL_LIB, ssl_sw) == MG_FALSE ||
-      load_dll(ctx, CRYPTO_LIB, crypto_sw) == MG_FALSE) {
-    return MG_ERROR;
-  }
-
   // Initialize SSL crap
   SSL_library_init();
   SSL_load_error_strings();
 
   if ((CTX = SSL_CTX_new(SSLv23_server_method())) == NULL) {
     cry(fc(ctx), "SSL_CTX_new error: %s", ssl_error());
+    return MG_ERROR;
   } else if (ctx->config->ssl_password_handler != NULL) {
     SSL_CTX_set_default_passwd_cb(CTX, ctx->config->ssl_password_handler);
   }
 
-  if (CTX != NULL && SSL_CTX_use_certificate_file(CTX, pem,
-        SSL_FILETYPE_PEM) == 0) {
+  if (SSL_CTX_use_certificate_file(CTX, pem, SSL_FILETYPE_PEM) == 0) {
     cry(fc(ctx), "%s: cannot open %s: %s", __func__, pem, ssl_error());
     return MG_ERROR;
-  } else if (CTX != NULL && SSL_CTX_use_PrivateKey_file(CTX, pem,
-        SSL_FILETYPE_PEM) == 0) {
+  } else if (SSL_CTX_use_PrivateKey_file(CTX, pem, SSL_FILETYPE_PEM) == 0) {
     cry(fc(ctx), "%s: cannot open %s: %s", NULL, pem, ssl_error());
     return MG_ERROR;
   }
@@ -3448,10 +3359,12 @@ static void close_socket_gracefully(SOCKET sock) {
 }
 
 static void close_connection(struct mg_connection *conn) {
+#if !defined(NO_SSL)
   if (conn->ssl) {
     SSL_free(conn->ssl);
     conn->ssl = NULL;
   }
+#endif // !NO_SSL
 
   if (conn->client.sock != INVALID_SOCKET) {
     close_socket_gracefully(conn->client.sock);
@@ -3567,6 +3480,7 @@ static void worker_thread(struct mg_context *ctx) {
     conn->request_info.remote_ip = ntohl(conn->request_info.remote_ip);
     conn->request_info.is_ssl = conn->client.is_ssl;
 
+#if !defined(NO_SSL)
     if (conn->client.is_ssl && (conn->ssl = SSL_new(ctx->ssl_ctx)) == NULL) {
       cry(conn, "%s: SSL_new: %s", __func__, ssl_error());
     } else if (conn->client.is_ssl &&
@@ -3574,7 +3488,9 @@ static void worker_thread(struct mg_context *ctx) {
       cry(conn, "%s: SSL_set_fd: %s", __func__, ssl_error());
     } else if (conn->client.is_ssl && SSL_accept(conn->ssl) != 1) {
       cry(conn, "%s: SSL handshake error: %s", __func__, ssl_error());
-    } else {
+    } else
+#endif // !NO_SSL
+    {
       process_new_connection(conn);
     }
 
@@ -3682,10 +3598,12 @@ static void master_thread(struct mg_context *ctx) {
   }
   (void) pthread_mutex_unlock(&ctx->mutex);
 
+#if !defined(NO_SSL)
   // Deallocate SSL context
   if (ctx->ssl_ctx != NULL) {
     SSL_CTX_free(ctx->ssl_ctx);
   }
+#endif // !NO_SSL
 
   // All threads exited, no sync is needed. Destroy mutex and condvars
   (void) pthread_mutex_destroy(&ctx->mutex);
@@ -3743,9 +3661,11 @@ struct mg_context * mg_start(const struct mg_config *config) {
 
   // NOTE(lsm): order is important here. SSL certificates must
   // be initialized before listening ports. UID must be set last.
-  if (set_ssl_option(ctx) == MG_ERROR ||
+  if (set_gpass_option(ctx) == MG_ERROR ||
+#if !defined(NO_SSL)
+      (config->ssl_certificate != NULL && set_ssl_option(ctx) == MG_ERROR) ||
+#endif // !NO_SSL
       set_ports_option(ctx) == MG_ERROR ||
-      set_gpass_option(ctx) == MG_ERROR ||
 #if !defined(_WIN32)
       set_uid_option(ctx) == MG_ERROR ||
 #endif
-- 
GitLab