vfs_default: use correct flag in vfswrap_fs_file_id
[Samba.git] / libcli / http / http_conn.c
blobde1be3f2d8e85f3e8500dcd3d9e1cf474cc2cfb7
1 /*
2 Unix SMB/CIFS implementation.
4 HTTP library
6 Copyright (C) 2019 Ralph Boehme <slow@samba.org>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "includes.h"
23 #include "lib/util/tevent_ntstatus.h"
24 #include "libcli/dns/dns_lookup.h"
25 #include "lib/tsocket/tsocket.h"
26 #include "lib/util/util_net.h"
27 #include "lib/tls/tls.h"
28 #include "lib/util/tevent_unix.h"
29 #include "http.h"
30 #include "http_internal.h"
32 struct http_connect_state {
33 struct tevent_context *ev;
34 const char *http_server;
35 const char *http_server_ip;
36 uint16_t http_port;
37 struct tsocket_address *local_address;
38 struct tsocket_address *remote_address;
39 struct cli_credentials *credentials;
40 struct tstream_tls_params *tls_params;
42 struct http_conn *http_conn;
45 static void http_connect_dns_done(struct tevent_req *subreq);
46 static void http_connect_tcp_connect(struct tevent_req *req);
47 static void http_connect_tcp_done(struct tevent_req *subreq);
48 static void http_connect_tls_done(struct tevent_req *subreq);
50 struct tevent_req *http_connect_send(TALLOC_CTX *mem_ctx,
51 struct tevent_context *ev,
52 const char *http_server,
53 uint16_t http_port,
54 struct cli_credentials *credentials,
55 struct tstream_tls_params *tls_params)
57 struct tevent_req *req = NULL;
58 struct tevent_req *subreq = NULL;
59 struct http_connect_state *state = NULL;
60 int ret;
62 DBG_DEBUG("Connecting to [%s] over HTTP%s\n",
63 http_server, tls_params != NULL ? "S" : "");
65 req = tevent_req_create(mem_ctx, &state, struct http_connect_state);
66 if (req == NULL) {
67 return NULL;
70 *state = (struct http_connect_state) {
71 .ev = ev,
72 .http_port = http_port,
73 .credentials = credentials,
74 .tls_params = tls_params,
77 state->http_server = talloc_strdup(state, http_server);
78 if (tevent_req_nomem(state->http_server, req)) {
79 return tevent_req_post(req, ev);
82 state->http_conn = talloc_zero(state, struct http_conn);
83 if (tevent_req_nomem(state->http_conn, req)) {
84 return tevent_req_post(req, ev);
87 state->http_conn->send_queue = tevent_queue_create(state->http_conn,
88 "HTTP send queue");
89 if (tevent_req_nomem(state->http_conn->send_queue, req)) {
90 return tevent_req_post(req, ev);
93 ret = tsocket_address_inet_from_strings(state,
94 "ip",
95 NULL,
97 &state->local_address);
98 if (ret != 0) {
99 tevent_req_error(req, errno);
100 return tevent_req_post(req, ev);
103 if (!is_ipaddress(http_server)) {
104 subreq = dns_lookup_send(state,
106 NULL,
107 http_server,
108 DNS_QCLASS_IN,
109 DNS_QTYPE_A);
110 if (tevent_req_nomem(subreq, req)) {
111 return tevent_req_post(req, ev);
113 tevent_req_set_callback(subreq, http_connect_dns_done, req);
114 return req;
116 state->http_server_ip = state->http_server;
118 http_connect_tcp_connect(req);
119 if (!tevent_req_is_in_progress(req)) {
120 return tevent_req_post(req, ev);
123 return req;
126 static void http_connect_dns_done(struct tevent_req *subreq)
128 struct tevent_req *req = tevent_req_callback_data(
129 subreq, struct tevent_req);
130 struct http_connect_state *state = tevent_req_data(
131 req, struct http_connect_state);
132 struct dns_name_packet *dns_reply = NULL;
133 struct dns_res_rec *an = NULL;
134 uint16_t i;
135 int ret;
137 ret = dns_lookup_recv(subreq, state, &dns_reply);
138 TALLOC_FREE(subreq);
139 if (ret != 0) {
140 tevent_req_error(req, ret);
141 return;
144 for (i = 0; i < dns_reply->ancount; i++) {
145 an = &dns_reply->answers[i];
146 if (an->rr_type == DNS_QTYPE_A) {
147 break;
150 if (i >= dns_reply->ancount) {
151 tevent_req_error(req, ENOENT);
152 return;
155 state->http_server_ip = talloc_strdup(state, an->rdata.ipv4_record);
156 if (tevent_req_nomem(state->http_server_ip, req)) {
157 return;
160 return http_connect_tcp_connect(req);
163 static void http_connect_tcp_connect(struct tevent_req *req)
165 struct http_connect_state *state = tevent_req_data(
166 req, struct http_connect_state);
167 struct tevent_req *subreq = NULL;
168 int ret;
170 ret = tsocket_address_inet_from_strings(state,
171 "ip",
172 state->http_server_ip,
173 state->http_port,
174 &state->remote_address);
175 if (ret != 0) {
176 int saved_errno = errno;
178 DBG_ERR("Cannot create remote socket address, error: %s (%d)\n",
179 strerror(errno), errno);
180 tevent_req_error(req, saved_errno);
181 return;
184 subreq = tstream_inet_tcp_connect_send(state,
185 state->ev,
186 state->local_address,
187 state->remote_address);
188 if (tevent_req_nomem(subreq, req)) {
189 return;
191 tevent_req_set_callback(subreq, http_connect_tcp_done, req);
194 static void http_connect_tcp_done(struct tevent_req *subreq)
196 struct tevent_req *req = tevent_req_callback_data(
197 subreq, struct tevent_req);
198 struct http_connect_state *state = tevent_req_data(
199 req, struct http_connect_state);
200 int error;
201 int ret;
203 ret = tstream_inet_tcp_connect_recv(subreq,
204 &error,
205 state->http_conn,
206 &state->http_conn->tstreams.raw,
207 NULL);
208 TALLOC_FREE(subreq);
209 if (ret != 0) {
210 tevent_req_error(req, error);
211 return;
214 state->http_conn->tstreams.active = state->http_conn->tstreams.raw;
215 DBG_DEBUG("Socket connected\n");
217 if (state->tls_params == NULL) {
218 tevent_req_done(req);
219 return;
222 DBG_DEBUG("Starting TLS\n");
224 subreq = tstream_tls_connect_send(state,
225 state->ev,
226 state->http_conn->tstreams.active,
227 state->tls_params);
228 if (tevent_req_nomem(subreq, req)) {
229 return;
231 tevent_req_set_callback(subreq, http_connect_tls_done, req);
234 static void http_connect_tls_done(struct tevent_req *subreq)
236 struct tevent_req *req = tevent_req_callback_data(
237 subreq, struct tevent_req);
238 struct http_connect_state *state = tevent_req_data(
239 req, struct http_connect_state);
240 int error;
241 int ret;
243 ret = tstream_tls_connect_recv(subreq,
244 &error,
245 state->http_conn,
246 &state->http_conn->tstreams.tls);
247 TALLOC_FREE(subreq);
248 if (ret != 0) {
249 tevent_req_error(req, error);
250 return;
253 state->http_conn->tstreams.active = state->http_conn->tstreams.tls;
255 DBG_DEBUG("TLS handshake completed\n");
256 tevent_req_done(req);
259 int http_connect_recv(struct tevent_req *req,
260 TALLOC_CTX *mem_ctx,
261 struct http_conn **http_conn)
263 struct http_connect_state *state = tevent_req_data(
264 req, struct http_connect_state);
265 int error;
267 if (tevent_req_is_unix_error(req, &error)) {
268 tevent_req_received(req);
269 return error;
272 *http_conn = talloc_move(mem_ctx, &state->http_conn);
273 tevent_req_received(req);
275 return 0;
278 struct tevent_queue *http_conn_send_queue(struct http_conn *http_conn)
280 return http_conn->send_queue;
283 struct tstream_context *http_conn_tstream(struct http_conn *http_conn)
285 return http_conn->tstreams.active;
288 struct http_conn_disconnect_state {
289 struct tevent_context *ev;
290 struct http_conn *http_conn;
293 static void http_conn_disconnect_done(struct tevent_req *subreq);
295 struct tevent_req *http_disconnect_send(TALLOC_CTX *mem_ctx,
296 struct tevent_context *ev,
297 struct http_conn *http_conn)
299 struct tevent_req *req = NULL;
300 struct tevent_req *subreq = NULL;
301 struct http_conn_disconnect_state *state = NULL;
303 req = tevent_req_create(mem_ctx, &state,
304 struct http_conn_disconnect_state);
305 if (req == NULL) {
306 return NULL;
309 *state = (struct http_conn_disconnect_state) {
310 .ev = ev,
311 .http_conn = http_conn,
314 if (http_conn->tstreams.active == NULL) {
315 tevent_req_error(req, ENOTCONN);
316 return tevent_req_post(req, ev);
319 subreq = tstream_disconnect_send(state, ev, http_conn->tstreams.active);
320 if (tevent_req_nomem(subreq, req)) {
321 return tevent_req_post(req, ev);
323 tevent_req_set_callback(subreq, http_conn_disconnect_done, req);
325 return req;
328 static void http_conn_disconnect_done(struct tevent_req *subreq)
330 struct tevent_req *req = tevent_req_callback_data(
331 subreq, struct tevent_req);
332 int ret;
333 int error;
335 ret = tstream_disconnect_recv(subreq, &error);
336 TALLOC_FREE(subreq);
337 if (ret == -1) {
338 tevent_req_error(req, error);
339 return;
342 tevent_req_done(req);
345 int http_disconnect_recv(struct tevent_req *req)
347 return tevent_req_simple_recv_unix(req);