1 |
/* Licensed to the Apache Software Foundation (ASF) under one or more |
2 |
* contributor license agreements. See the NOTICE file distributed with |
3 |
* this work for additional information regarding copyright ownership. |
4 |
* The ASF licenses this file to You under the Apache License, Version 2.0 |
5 |
* (the "License"); you may not use this file except in compliance with |
6 |
* the License. You may obtain a copy of the License at |
7 |
* |
8 |
* http://www.apache.org/licenses/LICENSE-2.0 |
9 |
* |
10 |
* Unless required by applicable law or agreed to in writing, software |
11 |
* distributed under the License is distributed on an "AS IS" BASIS, |
12 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 |
* See the License for the specific language governing permissions and |
14 |
* limitations under the License. |
15 |
* |
16 |
* Originally developed by Aaron Bannert and Justin Erenkrantz, eBuilt. |
17 |
*/ |
18 |
|
19 |
#include <apr.h> |
20 |
|
21 |
#if APR_HAVE_STDLIB_H |
22 |
#include <stdlib.h> /* rand/strtol */ |
23 |
#endif |
24 |
#if APR_HAVE_STRING_H |
25 |
#include <string.h> |
26 |
#endif |
27 |
|
28 |
#include "config.h" |
29 |
#include "flood_net.h" |
30 |
#include "flood_net_ssl.h" |
31 |
#include "flood_socket_generic.h" |
32 |
|
33 |
typedef struct { |
34 |
void *s; |
35 |
int wantresponse; /* A boolean */ |
36 |
int ssl; /* A boolean */ |
37 |
} generic_socket_t; |
38 |
|
39 |
apr_status_t generic_socket_init(socket_t **sock, apr_pool_t *pool) |
40 |
{ |
41 |
generic_socket_t *new_gsock; |
42 |
|
43 |
new_gsock = (generic_socket_t *)apr_palloc(pool, sizeof(generic_socket_t)); |
44 |
if (new_gsock == NULL) |
45 |
return APR_ENOMEM; |
46 |
new_gsock->s = NULL; |
47 |
|
48 |
*sock = new_gsock; |
49 |
return APR_SUCCESS; |
50 |
} |
51 |
|
52 |
/** |
53 |
* Generic implementation for begin_conn |
54 |
*/ |
55 |
apr_status_t generic_begin_conn(socket_t *sock, request_t *req, apr_pool_t *pool) |
56 |
{ |
57 |
apr_status_t rv; |
58 |
generic_socket_t *gsock = (generic_socket_t *)sock; |
59 |
|
60 |
if (strcasecmp(req->parsed_uri->scheme, "https") == 0) { |
61 |
/* If we don't have SSL, error out. */ |
62 |
#if FLOOD_HAS_OPENSSL |
63 |
gsock->ssl = 1; |
64 |
#else |
65 |
return APR_ENOTIMPL; |
66 |
#endif |
67 |
} |
68 |
else { |
69 |
gsock->ssl = 0; |
70 |
} |
71 |
|
72 |
/* The return types are not identical, so it can't be a ternary |
73 |
* operation. */ |
74 |
if (gsock->ssl) |
75 |
gsock->s = ssl_open_socket(pool, req, &rv); |
76 |
else |
77 |
gsock->s = open_socket(pool, req, &rv); |
78 |
|
79 |
if (gsock->s == NULL) |
80 |
return rv; |
81 |
|
82 |
req->keepalive = 0; /* FIXME: Maybe move this into flood_socket_t */ |
83 |
return APR_SUCCESS; |
84 |
} |
85 |
|
86 |
/** |
87 |
* Generic implementation for send_req. |
88 |
*/ |
89 |
apr_status_t generic_send_req(socket_t *sock, request_t *req, apr_pool_t *pool) |
90 |
{ |
91 |
generic_socket_t *gsock = (generic_socket_t *)sock; |
92 |
gsock->wantresponse = req->wantresponse; |
93 |
return gsock->ssl ? ssl_write_socket(gsock->s, req) : |
94 |
write_socket(gsock->s, req); |
95 |
} |
96 |
|
97 |
/** |
98 |
* Generic implementation for recv_resp. |
99 |
*/ |
100 |
apr_status_t generic_recv_resp(response_t **resp, socket_t *sock, apr_pool_t *pool) |
101 |
{ |
102 |
char b[MAX_DOC_LENGTH]; |
103 |
apr_size_t i; |
104 |
response_t *new_resp; |
105 |
apr_status_t status; |
106 |
|
107 |
generic_socket_t *gsock = (generic_socket_t *)sock; |
108 |
|
109 |
new_resp = apr_pcalloc(pool, sizeof(response_t)); |
110 |
new_resp->rbuftype = POOL; |
111 |
|
112 |
if (gsock->wantresponse) |
113 |
{ |
114 |
/* Ugh, we want everything. */ |
115 |
apr_size_t currentalloc; |
116 |
char *cp, *op; |
117 |
|
118 |
new_resp->rbufsize = 0; |
119 |
currentalloc = MAX_DOC_LENGTH; |
120 |
new_resp->rbuf = apr_palloc(pool, currentalloc); |
121 |
cp = new_resp->rbuf; |
122 |
do |
123 |
{ |
124 |
i = MAX_DOC_LENGTH - 1; |
125 |
status = gsock->ssl ? ssl_read_socket(gsock->s, b, &i) |
126 |
: read_socket(gsock->s, b, &i); |
127 |
if (new_resp->rbufsize + i > currentalloc) |
128 |
{ |
129 |
/* You can think why this always work. */ |
130 |
currentalloc *= 2; |
131 |
op = new_resp->rbuf; |
132 |
new_resp->rbuf = apr_palloc(pool, currentalloc); |
133 |
memcpy(new_resp->rbuf, op, cp - op); |
134 |
cp = new_resp->rbuf + (cp - op); |
135 |
} |
136 |
|
137 |
memcpy(cp, b, i); |
138 |
new_resp->rbufsize += i; |
139 |
cp += i; |
140 |
} |
141 |
while (status != APR_EOF && status != APR_TIMEUP); |
142 |
} |
143 |
else |
144 |
{ |
145 |
/* We just want to store the first chunk read. */ |
146 |
new_resp->rbufsize = MAX_DOC_LENGTH - 1; |
147 |
new_resp->rbuf = apr_palloc(pool, new_resp->rbufsize); |
148 |
status = gsock->ssl ? ssl_read_socket(gsock->s, new_resp->rbuf, |
149 |
&new_resp->rbufsize) : |
150 |
read_socket(gsock->s, new_resp->rbuf, |
151 |
&new_resp->rbufsize); |
152 |
|
153 |
while (status != APR_EOF && status != APR_TIMEUP) { |
154 |
i = MAX_DOC_LENGTH - 1; |
155 |
status = gsock->ssl ? ssl_read_socket(gsock->s, b, &i) : |
156 |
read_socket(gsock->s, b, &i); |
157 |
} |
158 |
if (status != APR_SUCCESS && status != APR_EOF) { |
159 |
return status; |
160 |
} |
161 |
|
162 |
} |
163 |
|
164 |
*resp = new_resp; |
165 |
|
166 |
return APR_SUCCESS; |
167 |
} |
168 |
|
169 |
/** |
170 |
* This implementation always retrieves the full response. |
171 |
* We temporarily set the "wantresponse" flag to true and |
172 |
* call generic_recv_resp() to do the real work. |
173 |
*/ |
174 |
apr_status_t generic_fullresp_recv_resp(response_t **resp, |
175 |
socket_t *sock, |
176 |
apr_pool_t *pool) |
177 |
{ |
178 |
generic_socket_t *gsock = (generic_socket_t *)sock; |
179 |
int orig_wantresponse = gsock->wantresponse; |
180 |
apr_status_t status; |
181 |
|
182 |
gsock->wantresponse = 1; |
183 |
status = generic_recv_resp(resp, sock, pool); |
184 |
gsock->wantresponse = orig_wantresponse; |
185 |
|
186 |
return status; |
187 |
} |
188 |
|
189 |
/** |
190 |
* Generic implementation for end_conn. |
191 |
*/ |
192 |
apr_status_t generic_end_conn(socket_t *sock, request_t *req, response_t *resp) |
193 |
{ |
194 |
generic_socket_t *gsock = (generic_socket_t *)sock; |
195 |
gsock->ssl ? ssl_close_socket(gsock->s) : close_socket(gsock->s); |
196 |
return APR_SUCCESS; |
197 |
} |
198 |
|
199 |
/** |
200 |
* Generic implementation for socket_destroy. |
201 |
*/ |
202 |
apr_status_t generic_socket_destroy(socket_t *socket) |
203 |
{ |
204 |
/* The socket is closed after each request (generic doesn't |
205 |
* support keepalive), so there's nothing to do here */ |
206 |
return APR_SUCCESS; |
207 |
} |