Apache Mesos
net.hpp
Go to the documentation of this file.
1 // Licensed under the Apache License, Version 2.0 (the "License");
2 // you may not use this file except in compliance with the License.
3 // You may obtain a copy of the License at
4 //
5 // http://www.apache.org/licenses/LICENSE-2.0
6 //
7 // Unless required by applicable law or agreed to in writing, software
8 // distributed under the License is distributed on an "AS IS" BASIS,
9 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 // See the License for the specific language governing permissions and
11 // limitations under the License.
12 
13 #ifndef __STOUT_NET_HPP__
14 #define __STOUT_NET_HPP__
15 
16 #ifndef __WINDOWS__
17 #include <netdb.h>
18 #endif // __WINDOWS__
19 
20 #include <stdint.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 
24 #ifndef __WINDOWS__
25 #include <arpa/inet.h>
26 #endif // __WINDOWS__
27 
28 #ifdef __APPLE__
29 #include <net/if.h>
30 #include <net/if_dl.h>
31 #include <net/if_types.h>
32 #endif // __APPLE__
33 
34 #ifdef __FreeBSD__
35 #include <ifaddrs.h>
36 #endif // __FreeBSD__
37 
38 // Note: Header grouping and ordering is considered before
39 // inclusion/exclusion by platform.
40 #ifndef __WINDOWS__
41 #include <sys/param.h>
42 #endif // __WINDOWS__
43 
44 #include <curl/curl.h>
45 
46 #include <iostream>
47 #include <set>
48 #include <string>
49 
50 #include <stout/bytes.hpp>
51 #include <stout/error.hpp>
52 #include <stout/ip.hpp>
53 #include <stout/option.hpp>
54 #include <stout/stringify.hpp>
55 #include <stout/try.hpp>
56 
57 #include <stout/os/int_fd.hpp>
58 #include <stout/os/open.hpp>
59 
60 #ifdef __WINDOWS__
61 #include <stout/windows/net.hpp>
62 #else
63 #include <stout/posix/net.hpp>
64 #endif // __WINDOWS__
65 
66 
67 // Network utilities.
68 namespace net {
69 
70 // Initializes libraries that net:: functions depend on, in a
71 // thread-safe way. This does not have to be called explicitly by
72 // the user of any functions in question. They will call this
73 // themselves by need.
74 inline void initialize()
75 {
76  // We use a static struct variable to initialize in a thread-safe
77  // way, at least with respect to calls within net::*, since there
78  // is no way to guarantee that another library is not concurrently
79  // initializing CURL. Thread safety is provided by the fact that
80  // the value 'curl' should get constructed (i.e., the CURL
81  // constructor invoked) in a thread safe way (as of GCC 4.3 and
82  // required for C++11).
83  struct CURL
84  {
85  CURL()
86  {
87  // This is the only one function in libcurl that is not deemed
88  // thread-safe. (And it must be called at least once before any
89  // other libcurl function is used.)
90  curl_global_init(CURL_GLOBAL_ALL);
91  }
92  };
93 
94  static CURL curl;
95 }
96 
97 
98 // Downloads the header of the specified HTTP URL with a HEAD request
99 // and queries its "content-length" field. (Note that according to the
100 // HTTP specification there is no guarantee that this field contains
101 // any useful value.)
102 inline Try<Bytes> contentLength(const std::string& url)
103 {
104  initialize();
105 
106  CURL* curl = curl_easy_init();
107  if (curl == nullptr) {
108  curl_easy_cleanup(curl);
109  return Error("Failed to initialize libcurl");
110  }
111 
112  curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
113  curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, true);
114  curl_easy_setopt(curl, CURLOPT_HEADER, 1);
115  curl_easy_setopt(curl, CURLOPT_NOBODY, 1);
116 
117  CURLcode curlErrorCode = curl_easy_perform(curl);
118  if (curlErrorCode != 0) {
119  curl_easy_cleanup(curl);
120  return Error(curl_easy_strerror(curlErrorCode));
121  }
122 
123  double result;
124  curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &result);
125 
126  curl_easy_cleanup(curl);
127 
128  if (result < 0) {
129  return Error("No URL content-length available");
130  }
131 
132  return Bytes(uint64_t(result));
133 }
134 
135 
136 // Returns the HTTP response code resulting from attempting to
137 // download the specified HTTP or FTP URL into a file at the specified
138 // path.
139 inline Try<int> download(const std::string& url, const std::string& path)
140 {
141  initialize();
142 
143  Try<int_fd> fd = os::open(
144  path,
147 
148  if (fd.isError()) {
149  return Error(fd.error());
150  }
151 
152  CURL* curl = curl_easy_init();
153 
154  if (curl == nullptr) {
155  curl_easy_cleanup(curl);
156  os::close(fd.get());
157  return Error("Failed to initialize libcurl");
158  }
159 
160  curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
161  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, nullptr);
162  curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, true);
163 
164  // We don't bother introducing a `os::fdopen` since this is the only place
165  // we use `fdopen` in the entire codebase as of writing this comment.
166 #ifdef __WINDOWS__
167  // We open in "binary" mode on Windows to avoid line-ending translation.
168  FILE* file = ::_fdopen(fd->crt(), "wb");
169 #else
170  FILE* file = ::fdopen(fd.get(), "w");
171 #endif
172  if (file == nullptr) {
173  curl_easy_cleanup(curl);
174  os::close(fd.get());
175  return ErrnoError("Failed to open file handle of '" + path + "'");
176  }
177  curl_easy_setopt(curl, CURLOPT_WRITEDATA, file);
178 
179  CURLcode curlErrorCode = curl_easy_perform(curl);
180  if (curlErrorCode != 0) {
181  curl_easy_cleanup(curl);
182  fclose(file);
183  return Error(curl_easy_strerror(curlErrorCode));
184  }
185 
186  long code;
187  curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code);
188  curl_easy_cleanup(curl);
189 
190  if (fclose(file) != 0) {
191  return ErrnoError("Failed to close file handle of '" + path + "'");
192  }
193 
194  return Try<int>::some(code);
195 }
196 
197 } // namespace net {
198 
199 #endif // __STOUT_NET_HPP__
#define O_WRONLY
Definition: fcntl.hpp:26
Definition: errorbase.hpp:35
const mode_t S_IRGRP
Definition: windows.hpp:319
Definition: try.hpp:34
#define O_CLOEXEC
Definition: fcntl.hpp:31
const mode_t S_IWUSR
Definition: windows.hpp:312
Definition: errorbase.hpp:49
#define O_CREAT
Definition: fcntl.hpp:28
const mode_t S_IRUSR
Definition: windows.hpp:311
void initialize()
Definition: net.hpp:74
URI file(const std::string &path)
Creates a file URI with the given path on the local host.
Definition: file.hpp:33
Try< Nothing > close(int fd)
Definition: close.hpp:24
Try< int > download(const std::string &url, const std::string &path)
Definition: net.hpp:139
static Try error(const E &e)
Definition: try.hpp:42
static Try some(const T &t)
Definition: try.hpp:41
bool isError() const
Definition: try.hpp:71
Try< int_fd > open(const std::string &path, int oflag, mode_t mode=0)
Definition: open.hpp:39
Try< Bytes > contentLength(const std::string &url)
Definition: net.hpp:102
Definition: bytes.hpp:30
const mode_t S_IROTH
Definition: windows.hpp:327
const T & get() const
Definition: try.hpp:73