summaryrefslogtreecommitdiffstats
path: root/src/rgw/rgw_http_client_curl.cc
blob: 346813484690bea21094b4fb1e586d9524ed7454 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab

#include "rgw_http_client_curl.h"
#include <mutex>
#include <vector>
#include <curl/curl.h>

#include "rgw_common.h"
#define dout_context g_ceph_context
#define dout_subsys ceph_subsys_rgw

#ifdef WITH_CURL_OPENSSL
#include <openssl/crypto.h>
#endif

#if defined(WITH_CURL_OPENSSL) && OPENSSL_API_COMPAT < 0x10100000L
namespace openssl {

class RGWSSLSetup
{
  std::vector <std::mutex> locks;
public:
  explicit RGWSSLSetup(int n) : locks (n){}

  void set_lock(int id){
    try {
      locks.at(id).lock();
    } catch (std::out_of_range& e) {
      dout(0) << __func__ << " failed to set locks" << dendl;
    }
  }

  void clear_lock(int id){
    try {
      locks.at(id).unlock();
    } catch (std::out_of_range& e) {
      dout(0) << __func__ << " failed to unlock" << dendl;
    }
  }
};


void rgw_ssl_locking_callback(int mode, int id, const char *file, int line)
{
  static RGWSSLSetup locks(CRYPTO_num_locks());
  if (mode & CRYPTO_LOCK)
    locks.set_lock(id);
  else
    locks.clear_lock(id);
}

unsigned long rgw_ssl_thread_id_callback(){
  return (unsigned long)pthread_self();
}

void init_ssl(){
  CRYPTO_set_id_callback((unsigned long (*) ()) rgw_ssl_thread_id_callback);
  CRYPTO_set_locking_callback(rgw_ssl_locking_callback);
}

} /* namespace openssl */
#endif // WITH_CURL_OPENSSL


namespace rgw {
namespace curl {

static void check_curl()
{
#ifndef HAVE_CURL_MULTI_WAIT
  derr << "WARNING: libcurl doesn't support curl_multi_wait()" << dendl;
  derr << "WARNING: cross zone / region transfer performance may be affected" << dendl;
#endif
}

#if defined(WITH_CURL_OPENSSL) && OPENSSL_API_COMPAT < 0x10100000L
void init_ssl() {
  ::openssl::init_ssl();
}

bool fe_inits_ssl(boost::optional <const fe_map_t&> m, long& curl_global_flags){
  if (m) {
    for (const auto& kv: *m){
      if (kv.first == "civetweb" || kv.first == "beast"){
        std::string cert;
        kv.second->get_val("ssl_certificate","", &cert);
        if (!cert.empty()){
         /* TODO this flag is no op for curl > 7.57 */
          curl_global_flags &= ~CURL_GLOBAL_SSL;
          return true;
        }
      }
    }
  }
  return false;
}
#endif // WITH_CURL_OPENSSL

std::once_flag curl_init_flag;

void setup_curl(boost::optional<const fe_map_t&> m) {
  check_curl();

  long curl_global_flags = CURL_GLOBAL_ALL;

  #if defined(WITH_CURL_OPENSSL) && OPENSSL_API_COMPAT < 0x10100000L
  if (!fe_inits_ssl(m, curl_global_flags))
    init_ssl();
  #endif

  std::call_once(curl_init_flag, curl_global_init, curl_global_flags);
  rgw_setup_saved_curl_handles();
}

void cleanup_curl() {
  rgw_release_all_curl_handles();
  curl_global_cleanup();
}

} /* namespace curl */
} /* namespace rgw */