[package] uhttpd: add explicit stdin eof notification for Lua and CGI childs
[openwrt.git] / package / uhttpd / src / uhttpd-tls.c
index 008f8e0df6a7e873a96ec0a3182cad60243155a5..9c6eb81db3f5283934295930f8eead45b605beed 100644 (file)
 #include "uhttpd-tls.h"
 #include "uhttpd-utils.h"
 
+#include <syslog.h>
+#define dbg(...) syslog(LOG_INFO, __VA_ARGS__)
 
-SSL_CTX * uh_tls_ctx_init()
+SSL_CTX * uh_tls_ctx_init(void)
 {
-       SSL_CTX *c = NULL;
+       SSL_CTX *c;
+
        SSL_load_error_strings();
        SSL_library_init();
 
-       if( (c = SSL_CTX_new(TLSv1_server_method())) != NULL )
+#if TLS_IS_OPENSSL
+       if ((c = SSL_CTX_new(SSLv23_server_method())) != NULL)
+#else
+       if ((c = SSL_CTX_new(TLSv1_server_method())) != NULL)
+#endif
                SSL_CTX_set_verify(c, SSL_VERIFY_NONE, NULL);
 
        return c;
@@ -59,36 +66,105 @@ void uh_tls_ctx_free(struct listener *l)
 }
 
 
-void uh_tls_client_accept(struct client *c)
+int uh_tls_client_accept(struct client *c)
 {
-       if( c->server && c->server->tls )
+       int rv, err;
+       int fd = c->fd.fd;
+
+       if (!c->server || !c->server->tls)
+       {
+               c->tls = NULL;
+               return 1;
+       }
+
+       if ((c->tls = SSL_new(c->server->tls)))
        {
-               c->tls = SSL_new(c->server->tls);
-               SSL_set_fd(c->tls, c->socket);
+               if ((rv = SSL_set_fd(c->tls, fd)) < 1)
+               {
+                       SSL_free(c->tls);
+                       c->tls = NULL;
+               }
+               else
+               {
+                       while (true)
+                       {
+                               rv = SSL_accept(c->tls);
+                               err = SSL_get_error(c->tls, rv);
+
+                               if ((rv != 1) &&
+                                       (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE))
+                               {
+                                       if (uh_socket_wait(fd, c->server->conf->network_timeout,
+                                                                          (err == SSL_ERROR_WANT_WRITE)))
+                                       {
+                                               D("TLS: accept(%d) = retry\n", fd);
+                                               continue;
+                                       }
+
+                                       D("TLS: accept(%d) = timeout\n", fd);
+                               }
+                               else if (rv == 1)
+                               {
+                                       D("TLS: accept(%d) = %p\n", fd, c->tls);
+                                       return 1;
+                               }
+
+#ifdef TLS_IS_OPENSSL
+                               D("TLS: accept(%d) = failed: %s\n",
+                                 fd, ERR_error_string(ERR_get_error(), NULL));
+#endif
+
+                               SSL_free(c->tls);
+                               c->tls = NULL;
+                               break;
+                       }
+               }
        }
+
+       return 0;
 }
 
-int uh_tls_client_recv(struct client *c, void *buf, int len)
+int uh_tls_client_recv(struct client *c, char *buf, int len)
 {
        int rv = SSL_read(c->tls, buf, len);
-       return (rv > 0) ? rv : -1;
+       int err = SSL_get_error(c->tls, 0);
+
+       if ((rv == -1) && (err == SSL_ERROR_WANT_READ))
+       {
+               D("TLS: recv(%d, %d) = retry\n", c->fd.fd, len);
+               errno = EAGAIN;
+               return -1;
+       }
+
+       D("TLS: recv(%d, %d) = %d\n", c->fd.fd, len, rv);
+       return rv;
 }
 
-int uh_tls_client_send(struct client *c, void *buf, int len)
+int uh_tls_client_send(struct client *c, const char *buf, int len)
 {
        int rv = SSL_write(c->tls, buf, len);
-       return (rv > 0) ? rv : -1;
+       int err = SSL_get_error(c->tls, 0);
+
+       if ((rv == -1) && (err == SSL_ERROR_WANT_WRITE))
+       {
+               D("TLS: send(%d, %d) = retry\n", c->fd.fd, len);
+               errno = EAGAIN;
+               return -1;
+       }
+
+       D("TLS: send(%d, %d) = %d\n", c->fd.fd, len, rv);
+       return rv;
 }
 
 void uh_tls_client_close(struct client *c)
 {
-       if( c->tls )
+       if (c->tls)
        {
+               D("TLS: close(%d)\n", c->fd.fd);
+
                SSL_shutdown(c->tls);
                SSL_free(c->tls);
 
                c->tls = NULL;
        }
 }
-
-