From 5825e3ea749cccc3350284dc425885673614f03a Mon Sep 17 00:00:00 2001
From: Sergey Lyubka <valenok@gmail.com>
Date: Mon, 20 Jan 2014 08:55:03 +0000
Subject: [PATCH] Adding use_ssl to mg_connect()

---
 mongoose.c  | 85 +++++++++++++++++++++++++++++------------------------
 mongoose.h  |  6 ++--
 unit_test.c | 10 +++----
 3 files changed, 54 insertions(+), 47 deletions(-)

diff --git a/mongoose.c b/mongoose.c
index 4218a7d83..7c67569e0 100644
--- a/mongoose.c
+++ b/mongoose.c
@@ -13,7 +13,7 @@
 // See the GNU General Public License for more details.
 //
 // Alternatively, you can license this library under a commercial
-// license, as set out in <http://cesanta.com/products.html>.
+// license, as set out in <http://cesanta.com/>.
 
 #undef UNICODE                  // Use ANSI WinAPI functions
 #undef _UNICODE                 // Use multibyte encoding on Windows
@@ -117,31 +117,10 @@ typedef struct stat file_stat_t;
 #endif
 
 #ifdef USE_SSL
-// Following define gets rid of openssl deprecation messages
-#define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_6
-
-#ifdef USE_CYASSL
-#include <openssl/ssl.h>
-#else
-typedef struct ssl_ctx_st SSL_CTX;
-typedef struct ssl_st SSL;
-typedef struct ssl_method_st SSL_METHOD;
-
-extern void __cdecl SSL_free(SSL *);
-extern int __cdecl SSL_accept(SSL *);
-extern int __cdecl SSL_connect(SSL *);
-extern int __cdecl SSL_read(SSL *, void *, int);
-extern int __cdecl SSL_write(SSL *, const void *, int);
-extern int __cdecl SSL_set_fd(SSL *, int);
-extern SSL * __cdecl SSL_new(SSL_CTX *);
-extern SSL_CTX * __cdecl SSL_CTX_new(SSL_METHOD *);
-extern SSL_METHOD * __cdecl SSLv23_server_method(void);
-extern int __cdecl SSL_library_init(void);
-extern int __cdecl SSL_CTX_use_PrivateKey_file(SSL_CTX *, const char *, int);
-extern int __cdecl SSL_CTX_use_certificate_file(SSL_CTX *, const char *, int);
-extern int __cdecl SSL_CTX_use_certificate_chain_file(SSL_CTX *, const char *);
-extern void __cdecl SSL_CTX_free(SSL_CTX *);
+#ifdef __APPLE__
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
 #endif
+#include <openssl/ssl.h>
 #endif
 
 #include "mongoose.h"
@@ -291,7 +270,10 @@ struct mg_server {
   mg_handler_t error_handler;
   char *config_options[NUM_OPTIONS];
   void *server_data;
-  void *ssl_ctx;    // SSL context
+#ifdef USE_SSL
+  SSL_CTX *ssl_ctx;            // Server SSL context
+  SSL_CTX *client_ssl_ctx;     // Client SSL context
+#endif
   sock_t ctl[2];    // Control socketpair. Used to wake up from select() call
 };
 
@@ -339,8 +321,10 @@ struct connection {
   int64_t cl;             // Reply content length, for Range support
   int request_len;  // Request length, including last \r\n after last header
   int flags;        // CONN_* flags: CONN_CLOSE, CONN_SPOOL_DONE, etc
-  void *ssl;        // SSL descriptor
   mg_handler_t handler;  // Callback for HTTP client
+#ifdef USE_SSL
+  SSL *ssl;        // SSL descriptor
+#endif
 };
 
 static void close_local_endpoint(struct connection *conn);
@@ -3523,11 +3507,20 @@ static void callback_http_client_on_connect(struct connection *conn) {
   int ok;
   socklen_t len = sizeof(ok);
 
+  conn->flags &= ~CONN_CONNECTING;
   if (getsockopt(conn->client_sock, SOL_SOCKET, SO_ERROR, (char *) &ok,
                  &len) == 0 && ok == 0) {
     conn->mg_conn.status_code = MG_CONNECT_SUCCESS;
+#ifdef USE_SSL
+    if (conn->ssl != NULL) {
+      switch (SSL_connect(conn->ssl)) {
+        case 1: conn->flags = CONN_SSL_HANDS_SHAKEN; break;
+        case 0: conn->flags &= ~CONN_CONNECTING;  // Call this function again
+        default: ok = 1; break;
+      }
+    }
+#endif
   }
-  conn->flags &= ~CONN_CONNECTING;
   if (conn->handler(&conn->mg_conn) || ok != 0) {
     conn->flags |= CONN_CLOSE;
   }
@@ -3575,7 +3568,7 @@ static void read_from_socket(struct connection *conn) {
 }
 
 int mg_connect(struct mg_server *server, const char *host, int port,
-               mg_handler_t handler, void *param) {
+               int use_ssl, mg_handler_t handler, void *param) {
   sock_t sock = INVALID_SOCKET;
   struct sockaddr_in sin;
   struct hostent *he = NULL;
@@ -3584,6 +3577,9 @@ int mg_connect(struct mg_server *server, const char *host, int port,
 
   if (host == NULL || (he = gethostbyname(host)) == NULL ||
       (sock = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) return 0;
+#ifndef USE_SSL
+  if (use_ssl) return 0;
+#endif
 
   sin.sin_family = AF_INET;
   sin.sin_port = htons((uint16_t) port);
@@ -3606,6 +3602,11 @@ int mg_connect(struct mg_server *server, const char *host, int port,
   conn->birth_time = conn->last_activity_time = time(NULL);
   conn->flags = CONN_CONNECTING;
   conn->mg_conn.status_code = MG_CONNECT_FAILURE;
+#ifdef USE_SSL
+  if (use_ssl && (conn->ssl = SSL_new(server->client_ssl_ctx)) != NULL) {
+    SSL_set_fd(conn->ssl, sock);
+  }
+#endif
   LINKED_LIST_ADD_TO_FRONT(&server->active_connections, &conn->link);
   DBG(("%p %s:%d", conn, host, port));
 
@@ -3826,25 +3827,27 @@ void mg_destroy_server(struct mg_server **server) {
   struct ll *lp, *tmp;
 
   if (server != NULL && *server != NULL) {
+    struct mg_server *s = *server;
     // Do one last poll, see https://github.com/cesanta/mongoose/issues/286
-    mg_poll_server(*server, 0);
-    closesocket((*server)->listening_sock);
-    closesocket((*server)->ctl[0]);
-    closesocket((*server)->ctl[1]);
-    LINKED_LIST_FOREACH(&(*server)->active_connections, lp, tmp) {
+    mg_poll_server(s, 0);
+    closesocket(s->listening_sock);
+    closesocket(s->ctl[0]);
+    closesocket(s->ctl[1]);
+    LINKED_LIST_FOREACH(&s->active_connections, lp, tmp) {
       close_conn(LINKED_LIST_ENTRY(lp, struct connection, link));
     }
-    LINKED_LIST_FOREACH(&(*server)->uri_handlers, lp, tmp) {
+    LINKED_LIST_FOREACH(&s->uri_handlers, lp, tmp) {
       free(LINKED_LIST_ENTRY(lp, struct uri_handler, link)->uri);
       free(LINKED_LIST_ENTRY(lp, struct uri_handler, link));
     }
-    for (i = 0; i < (int) ARRAY_SIZE((*server)->config_options); i++) {
-      free((*server)->config_options[i]);  // It is OK to free(NULL)
+    for (i = 0; i < (int) ARRAY_SIZE(s->config_options); i++) {
+      free(s->config_options[i]);  // It is OK to free(NULL)
     }
 #ifdef USE_SSL
-    if ((*server)->ssl_ctx != NULL) SSL_CTX_free((*server)->ssl_ctx);
+    if (s->ssl_ctx != NULL) SSL_CTX_free((*server)->ssl_ctx);
+    if (s->client_ssl_ctx != NULL) SSL_CTX_free(s->client_ssl_ctx);
 #endif
-    free(*server);
+    free(s);
     *server = NULL;
   }
 }
@@ -4130,6 +4133,10 @@ struct mg_server *mg_create_server(void *server_data) {
     mg_socketpair(server->ctl);
   } while (server->ctl[0] == INVALID_SOCKET);
 
+#ifdef USE_SSL
+  server->client_ssl_ctx = SSL_CTX_new(SSLv23_client_method());
+#endif
+
   server->server_data = server_data;
   server->listening_sock = INVALID_SOCKET;
   set_default_option_values(server->config_options);
diff --git a/mongoose.h b/mongoose.h
index b4998c5b6..bf419b38b 100644
--- a/mongoose.h
+++ b/mongoose.h
@@ -13,9 +13,9 @@
 // See the GNU General Public License for more details.
 //
 // Alternatively, you can license this library under a commercial
-// license, as set out in <http://cesanta.com/products.html>.
+// license, as set out in <http://cesanta.com/>.
 //
-// NOTE: Detailed API documentation is at http://cesanta.com/docs.html
+// NOTE: Detailed API documentation is at http://cesanta.com/#docs
 
 #ifndef MONGOOSE_HEADER_INCLUDED
 #define  MONGOOSE_HEADER_INCLUDED
@@ -106,7 +106,7 @@ enum {
   MG_CONNECT_SUCCESS, MG_CONNECT_FAILURE,
   MG_DOWNLOAD_SUCCESS, MG_DOWNLOAD_FAILURE
 };
-int mg_connect(struct mg_server *server, const char *host, int port,
+int mg_connect(struct mg_server *, const char *host, int port, int use_ssl,
                mg_handler_t handler, void *param);
 
 #ifdef __cplusplus
diff --git a/unit_test.c b/unit_test.c
index 6c9f945bc..d8d32aecb 100644
--- a/unit_test.c
+++ b/unit_test.c
@@ -407,8 +407,8 @@ static const char *test_server(void) {
   mg_add_uri_handler(server, "/cb1", cb1);
   mg_set_http_error_handler(server, error_handler);
 
-  ASSERT(mg_connect(server, "127.0.0.1", atoi(HTTP_PORT), ts1, buf1) == 1);
-  ASSERT(mg_connect(server, "127.0.0.1", atoi(HTTP_PORT), ts2, buf2) == 1);
+  ASSERT(mg_connect(server, "127.0.0.1", atoi(HTTP_PORT),  0, ts1, buf1) == 1);
+  ASSERT(mg_connect(server, "127.0.0.1", atoi(HTTP_PORT), 0, ts2, buf2) == 1);
 
   { int i; for (i = 0; i < 50; i++) mg_poll_server(server, 0); }
   ASSERT(strcmp(buf1, "foo ? 127.0.0.1") == 0);
@@ -468,9 +468,9 @@ static const char *test_mg_connect(void) {
 
   ASSERT(mg_set_option(server, "listening_port", LISTENING_ADDR) == NULL);
   ASSERT(mg_set_option(server, "document_root", ".") == NULL);
-  ASSERT(mg_connect(server, "", 0, NULL, NULL) == 0);
-  ASSERT(mg_connect(server, "127.0.0.1", atoi(HTTP_PORT), cb2, buf2) == 1);
-  ASSERT(mg_connect(server, "127.0.0.1", 1, cb3, buf3) == 1);
+  ASSERT(mg_connect(server, "", 0, 0, NULL, NULL) == 0);
+  ASSERT(mg_connect(server, "127.0.0.1", atoi(HTTP_PORT), 0, cb2, buf2) == 1);
+  ASSERT(mg_connect(server, "127.0.0.1", 1, 0, cb3, buf3) == 1);
 
   { int i; for (i = 0; i < 50; i++) mg_poll_server(server, 0); }
 
-- 
GitLab