1 // Copyright 2020 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 // Sandboxed version of multi-poll.c
16 // HTTP GET request with polling
17
18 #include <cstdlib>
19
20 #include "../curl_util.h" // NOLINT(build/include)
21 #include "../sandbox.h" // NOLINT(build/include)
22 #include "curl_sapi.sapi.h" // NOLINT(build/include)
23 #include "absl/strings/str_cat.h"
24 #include "sandboxed_api/util/status_macros.h"
25
26 namespace {
27
Example4()28 absl::Status Example4() {
29 // Initialize sandbox2 and sapi
30 curl::CurlSapiSandbox sandbox;
31 SAPI_RETURN_IF_ERROR(sandbox.Init());
32 curl::CurlApi api(&sandbox);
33
34 // Number of running handles
35 sapi::v::Int still_running(1);
36
37 int curl_code;
38
39 // Initialize curl (CURL_GLOBAL_DEFAULT = 3)
40 SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_global_init(3l));
41 if (curl_code != 0) {
42 return absl::UnavailableError(absl::StrCat(
43 "curl_global_init failed: ", curl::StrError(&api, curl_code)));
44 }
45
46 // Initialize http_handle
47 curl::CURL* curl_handle;
48 SAPI_ASSIGN_OR_RETURN(curl_handle, api.curl_easy_init());
49 sapi::v::RemotePtr http_handle(curl_handle);
50 if (!curl_handle) {
51 return absl::UnavailableError("curl_easy_init failed: Invalid curl handle");
52 }
53
54 // Specify URL to get
55 sapi::v::ConstCStr url("http://example.com");
56 SAPI_ASSIGN_OR_RETURN(
57 curl_code, api.curl_easy_setopt_ptr(&http_handle, curl::CURLOPT_URL,
58 url.PtrBefore()));
59 if (curl_code != 0) {
60 return absl::UnavailableError(absl::StrCat(
61 "curl_easy_setopt_ptr failed: ", curl::StrError(&api, curl_code)));
62 }
63
64 // Initialize multi_handle
65 curl::CURLM* curlm_handle;
66 SAPI_ASSIGN_OR_RETURN(curlm_handle, api.curl_multi_init());
67 sapi::v::RemotePtr multi_handle(curlm_handle);
68 if (!curlm_handle) {
69 return absl::UnavailableError(
70 "curl_multi_init failed: multi_handle is invalid");
71 }
72
73 // Add http_handle to the multi stack
74 SAPI_ASSIGN_OR_RETURN(curl_code,
75 api.curl_multi_add_handle(&multi_handle, &http_handle));
76 if (curl_code != 0) {
77 return absl::UnavailableError(absl::StrCat(
78 "curl_multi_add_handle failed: ", curl::StrError(&api, curl_code)));
79 }
80
81 while (still_running.GetValue()) {
82 sapi::v::Int numfds(0);
83
84 // Perform the request
85 SAPI_ASSIGN_OR_RETURN(
86 curl_code,
87 api.curl_multi_perform(&multi_handle, still_running.PtrBoth()));
88 if (curl_code != 0) {
89 return absl::UnavailableError(absl::StrCat(
90 "curl_mutli_perform failed: ", curl::StrError(&api, curl_code)));
91 }
92
93 if (still_running.GetValue()) {
94 // Wait for an event or timeout
95 SAPI_ASSIGN_OR_RETURN(
96 curl_code, api.curl_multi_poll_sapi(&multi_handle, nullptr, 0, 1000,
97 numfds.PtrBoth()));
98 if (curl_code != 0) {
99 return absl::UnavailableError(absl::StrCat(
100 "curl_multi_poll_sapi failed: ", curl::StrError(&api, curl_code)));
101 }
102 }
103 }
104
105 // Remove http_handle from the multi stack
106 SAPI_ASSIGN_OR_RETURN(
107 curl_code, api.curl_multi_remove_handle(&multi_handle, &http_handle));
108 if (curl_code != 0) {
109 return absl::UnavailableError(absl::StrCat(
110 "curl_multi_remove_handle failed: ", curl::StrError(&api, curl_code)));
111 }
112
113 // Cleanup http_handle
114 SAPI_RETURN_IF_ERROR(api.curl_easy_cleanup(&http_handle));
115
116 // Cleanup multi_handle
117 SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_multi_cleanup(&multi_handle));
118 if (curl_code != 0) {
119 return absl::UnavailableError(absl::StrCat(
120 "curl_multi_cleanup failed: ", curl::StrError(&api, curl_code)));
121 }
122
123 // Cleanup curl
124 SAPI_RETURN_IF_ERROR(api.curl_global_cleanup());
125
126 return absl::OkStatus();
127 }
128
129 } // namespace
130
main(int argc,char * argv[])131 int main(int argc, char* argv[]) {
132 gflags::ParseCommandLineFlags(&argc, &argv, true);
133 sapi::InitLogging(argv[0]);
134
135 if (absl::Status status = Example4(); !status.ok()) {
136 LOG(ERROR) << "Example4 failed: " << status.ToString();
137 return EXIT_FAILURE;
138 }
139
140 return EXIT_SUCCESS;
141 }
142