Ensure all locks are properly cleaned up
[openssl.git] / crypto / bio / b_addr.c
index e92876ab99260124cb074149e1f9d78daf5c0142..eed40bf8b5f427225d43c59f7d2fae7c2e8b1a04 100644 (file)
 #include <string.h>
 
 #include "bio_lcl.h"
+#include "internal/threads.h"
 
+#ifndef OPENSSL_NO_SOCK
 #include <openssl/err.h>
 #include <openssl/buffer.h>
 #include <ctype.h>
 
+CRYPTO_RWLOCK *bio_lookup_lock;
+static CRYPTO_ONCE bio_lookup_init = CRYPTO_ONCE_STATIC_INIT;
+
 /*
  * Throughout this file and bio_lcl.h, the existence of the macro
  * AI_PASSIVE is used to detect the availability of struct addrinfo,
@@ -622,6 +627,11 @@ static int addrinfo_wrap(int family, int socktype,
     return 1;
 }
 
+static void do_bio_lookup_init(void)
+{
+    bio_lookup_lock = CRYPTO_THREAD_lock_new();
+}
+
 /*-
  * BIO_lookup - look up the node and service you want to connect to.
  * @node: the node you want to connect to.
@@ -680,18 +690,13 @@ int BIO_lookup(const char *host, const char *service,
         int gai_ret = 0;
 #ifdef AI_PASSIVE
         struct addrinfo hints;
+        memset(&hints, 0, sizeof hints);
 
-        hints.ai_flags = 0;
 # ifdef AI_ADDRCONFIG
         hints.ai_flags = AI_ADDRCONFIG;
 # endif
         hints.ai_family = family;
         hints.ai_socktype = socktype;
-        hints.ai_protocol = 0;
-        hints.ai_addrlen = 0;
-        hints.ai_addr = NULL;
-        hints.ai_canonname = NULL;
-        hints.ai_next = NULL;
 
         if (lookup_type == BIO_LOOKUP_SERVER)
             hints.ai_flags |= AI_PASSIVE;
@@ -717,6 +722,15 @@ int BIO_lookup(const char *host, const char *service,
     } else {
 #endif
         const struct hostent *he;
+/*
+ * Because struct hostent is defined for 32-bit pointers only with
+ * VMS C, we need to make sure that '&he_fallback_address' and
+ * '&he_fallback_addresses' are 32-bit pointers
+ */
+#if defined(OPENSSL_SYS_VMS) && defined(__DECC)
+# pragma pointer_size save
+# pragma pointer_size 32
+#endif
         /* Windows doesn't seem to have in_addr_t */
 #ifdef OPENSSL_SYS_WINDOWS
         static uint32_t he_fallback_address;
@@ -730,6 +744,10 @@ int BIO_lookup(const char *host, const char *service,
         static const struct hostent he_fallback =
             { NULL, NULL, AF_INET, sizeof(he_fallback_address),
               (char **)&he_fallback_addresses };
+#if defined(OPENSSL_SYS_VMS) && defined(__DECC)
+# pragma pointer_size restore
+#endif
+
         struct servent *se;
         /* Apprently, on WIN64, s_proto and s_port have traded places... */
 #ifdef _WIN64
@@ -737,10 +755,10 @@ int BIO_lookup(const char *host, const char *service,
 #else
         struct servent se_fallback = { NULL, NULL, 0, NULL };
 #endif
-        char *proto = NULL;
 
-        CRYPTO_w_lock(CRYPTO_LOCK_GETHOSTBYNAME);
-        CRYPTO_w_lock(CRYPTO_LOCK_GETSERVBYNAME);
+        CRYPTO_THREAD_run_once(&bio_lookup_init, do_bio_lookup_init);
+
+        CRYPTO_THREAD_write_lock(bio_lookup_lock);
         he_fallback_address = INADDR_ANY;
         if (host == NULL) {
             he = &he_fallback;
@@ -772,26 +790,40 @@ int BIO_lookup(const char *host, const char *service,
 
         if (service == NULL) {
             se_fallback.s_port = 0;
-            se_fallback.s_proto = proto;
+            se_fallback.s_proto = NULL;
             se = &se_fallback;
         } else {
             char *endp = NULL;
             long portnum = strtol(service, &endp, 10);
 
+/*
+ * Because struct servent is defined for 32-bit pointers only with
+ * VMS C, we need to make sure that 'proto' is a 32-bit pointer.
+ */
+#if defined(OPENSSL_SYS_VMS) && defined(__DECC)
+# pragma pointer_size save
+# pragma pointer_size 32
+#endif
+            char *proto = NULL;
+#if defined(OPENSSL_SYS_VMS) && defined(__DECC)
+# pragma pointer_size restore
+#endif
+
+            switch (socktype) {
+            case SOCK_STREAM:
+                proto = "tcp";
+                break;
+            case SOCK_DGRAM:
+                proto = "udp";
+                break;
+            }
+
             if (endp != service && *endp == '\0'
                     && portnum > 0 && portnum < 65536) {
                 se_fallback.s_port = htons(portnum);
                 se_fallback.s_proto = proto;
                 se = &se_fallback;
             } else if (endp == service) {
-                switch (socktype) {
-                case SOCK_STREAM:
-                    proto = "tcp";
-                    break;
-                case SOCK_DGRAM:
-                    proto = "udp";
-                    break;
-                }
                 se = getservbyname(service, proto);
 
                 if (se == NULL) {
@@ -812,7 +844,19 @@ int BIO_lookup(const char *host, const char *service,
         *res = NULL;
 
         {
+/*
+ * Because hostent::h_addr_list is an array of 32-bit pointers with VMS C,
+ * we must make sure our iterator designates the same element type, hence
+ * the pointer size dance.
+ */
+#if defined(OPENSSL_SYS_VMS) && defined(__DECC)
+# pragma pointer_size save
+# pragma pointer_size 32
+#endif
             char **addrlistp;
+#if defined(OPENSSL_SYS_VMS) && defined(__DECC)
+# pragma pointer_size restore
+#endif
             size_t addresses;
             BIO_ADDRINFO *tmp_bai = NULL;
 
@@ -842,9 +886,10 @@ int BIO_lookup(const char *host, const char *service,
             ret = 1;
         }
      err:
-        CRYPTO_w_unlock(CRYPTO_LOCK_GETSERVBYNAME);
-        CRYPTO_w_unlock(CRYPTO_LOCK_GETHOSTBYNAME);
+        CRYPTO_THREAD_unlock(bio_lookup_lock);
     }
 
     return ret;
 }
+
+#endif /* OPENSSL_NO_SOCK */