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 "config.h" |
20 |
#include "flood_profile.h" |
21 |
#include "flood_net.h" |
22 |
|
23 |
/* Open the TCP connection to the server */ |
24 |
flood_socket_t* open_socket(apr_pool_t *pool, request_t *r, |
25 |
apr_status_t *status) |
26 |
{ |
27 |
apr_status_t rv = 0; |
28 |
apr_sockaddr_t *destsa; |
29 |
flood_socket_t* fs; |
30 |
apr_uri_t *u; |
31 |
|
32 |
fs = apr_palloc(pool, sizeof(flood_socket_t)); |
33 |
if (r->parsed_proxy_uri) { |
34 |
u = r->parsed_proxy_uri; |
35 |
} |
36 |
else { |
37 |
u = r->parsed_uri; |
38 |
} |
39 |
|
40 |
if ((rv = apr_sockaddr_info_get(&destsa, u->hostname, APR_INET, |
41 |
u->port, 0, pool)) |
42 |
!= APR_SUCCESS) { |
43 |
if (status) { |
44 |
*status = rv; |
45 |
} |
46 |
return NULL; |
47 |
} |
48 |
|
49 |
if ((rv = apr_socket_create(&fs->socket, APR_INET, SOCK_STREAM, |
50 |
APR_PROTO_TCP, pool)) != APR_SUCCESS) { |
51 |
if (status) { |
52 |
*status = rv; |
53 |
} |
54 |
return NULL; |
55 |
} |
56 |
|
57 |
if ((rv = apr_socket_connect(fs->socket, destsa)) != APR_SUCCESS) { |
58 |
if (APR_STATUS_IS_EINPROGRESS(rv)) { |
59 |
/* FIXME: Handle better */ |
60 |
close_socket(fs); |
61 |
if (status) { |
62 |
*status = rv; |
63 |
} |
64 |
return NULL; |
65 |
} |
66 |
else if (APR_STATUS_IS_EAGAIN(rv)) |
67 |
{ |
68 |
/* We have run out of ports available due to TIME_WAIT exhaustion. |
69 |
* Sleep for four minutes, and try again. |
70 |
* Note: Solaris returns EADDRNOTAVAIL, Linux returns EAGAIN. |
71 |
* XXX: Then APR'IZE THIS ALREADY |
72 |
*/ |
73 |
apr_sleep(4 * 60 * APR_USEC_PER_SEC); |
74 |
return open_socket(pool, r, status); |
75 |
} |
76 |
else |
77 |
{ |
78 |
/* FIXME: Handle */ |
79 |
close_socket(fs); |
80 |
if (status) { |
81 |
*status = rv; |
82 |
} |
83 |
return NULL; |
84 |
} |
85 |
} |
86 |
|
87 |
apr_socket_timeout_set(fs->socket, LOCAL_SOCKET_TIMEOUT); |
88 |
fs->read_pollset.desc_type = APR_POLL_SOCKET; |
89 |
fs->read_pollset.desc.s = fs->socket; |
90 |
fs->read_pollset.reqevents = APR_POLLIN; |
91 |
fs->read_pollset.p = pool; |
92 |
|
93 |
return fs; |
94 |
} |
95 |
|
96 |
/* close down TCP socket */ |
97 |
void close_socket(flood_socket_t *s) |
98 |
{ |
99 |
/* FIXME: recording and other stuff here? */ |
100 |
apr_socket_close(s->socket); |
101 |
} |
102 |
|
103 |
apr_status_t read_socket(flood_socket_t *s, char *buf, apr_size_t *buflen) |
104 |
{ |
105 |
apr_status_t e; |
106 |
apr_int32_t socketsRead; |
107 |
|
108 |
e = apr_poll(&s->read_pollset, 1, &socketsRead, LOCAL_SOCKET_TIMEOUT); |
109 |
if (e != APR_SUCCESS) |
110 |
return e; |
111 |
return apr_socket_recv(s->socket, buf, buflen); |
112 |
} |
113 |
|
114 |
apr_status_t write_socket(flood_socket_t *s, request_t *r) |
115 |
{ |
116 |
apr_size_t l; |
117 |
apr_status_t e; |
118 |
|
119 |
l = r->rbufsize; |
120 |
|
121 |
e = apr_socket_send(s->socket, r->rbuf, &l); |
122 |
|
123 |
/* FIXME: Better error and allow restarts? */ |
124 |
if (l != r->rbufsize) |
125 |
return APR_EGENERAL; |
126 |
|
127 |
return e; |
128 |
} |
129 |
|
130 |
apr_status_t check_socket(flood_socket_t *s, apr_pool_t *pool) |
131 |
{ |
132 |
apr_status_t e; |
133 |
apr_int32_t socketsRead; |
134 |
apr_pollfd_t pout; |
135 |
apr_int16_t event; |
136 |
|
137 |
pout.desc_type = APR_POLL_SOCKET; |
138 |
pout.desc.s = s->socket; |
139 |
pout.reqevents = APR_POLLIN | APR_POLLPRI | APR_POLLERR | APR_POLLHUP | APR_POLLNVAL; |
140 |
pout.p = pool; |
141 |
|
142 |
e = apr_poll(&pout, 1, &socketsRead, 1000); |
143 |
if (socketsRead && pout.rtnevents) { |
144 |
return APR_EGENERAL; |
145 |
} |
146 |
|
147 |
return APR_SUCCESS; |
148 |
} |