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
17 #include "apr_private.h"
18 #if BEOS_BONE /* BONE uses the unix code - woohoo */
19 #include "../unix/sendrecv.c"
20 #else
21 #include "apr_arch_networkio.h"
22 #include "apr_time.h"
23
wait_for_io_or_timeout(apr_socket_t * sock,int for_read)24 static apr_status_t wait_for_io_or_timeout(apr_socket_t *sock, int for_read)
25 {
26 struct timeval tv, *tvptr;
27 fd_set fdset;
28 int srv;
29
30 do {
31 FD_ZERO(&fdset);
32 FD_SET(sock->socketdes, &fdset);
33 if (sock->timeout < 0) {
34 tvptr = NULL;
35 }
36 else {
37 tv.tv_sec = sock->timeout / APR_USEC_PER_SEC;
38 tv.tv_usec = sock->timeout % APR_USEC_PER_SEC;
39 tvptr = &tv;
40 }
41 srv = select(sock->socketdes + 1,
42 for_read ? &fdset : NULL,
43 for_read ? NULL : &fdset,
44 NULL,
45 tvptr);
46 /* TODO - timeout should be smaller on repeats of this loop */
47 } while (srv == -1 && errno == EINTR);
48
49 if (srv == 0) {
50 return APR_TIMEUP;
51 }
52 else if (srv < 0) {
53 return errno;
54 }
55 return APR_SUCCESS;
56 }
57
58 #define SEND_WAIT APR_USEC_PER_SEC / 10
59
apr_socket_send(apr_socket_t * sock,const char * buf,apr_size_t * len)60 APR_DECLARE(apr_status_t) apr_socket_send(apr_socket_t *sock, const char *buf,
61 apr_size_t *len)
62 {
63 apr_ssize_t rv;
64
65 do {
66 rv = send(sock->socketdes, buf, (*len), 0);
67 } while (rv == -1 && errno == EINTR);
68
69 if (rv == -1 && errno == EWOULDBLOCK && sock->timeout > 0) {
70 apr_int32_t snooze_val = SEND_WAIT;
71 apr_int32_t zzz = 0;
72
73 do {
74 rv = send(sock->socketdes, buf, (*len), 0);
75 if (rv == -1 && errno == EWOULDBLOCK){
76 apr_sleep (snooze_val);
77 zzz += snooze_val;
78 snooze_val += SEND_WAIT;
79 /* have we passed our timeout value */
80 if (zzz > (sock->timeout * APR_USEC_PER_SEC))
81 break;
82 }
83 } while (rv == -1 && (errno == EINTR || errno == EWOULDBLOCK));
84 }
85 if (rv == -1) {
86 *len = 0;
87 return errno;
88 }
89 (*len) = rv;
90
91 return APR_SUCCESS;
92 }
93
apr_socket_recv(apr_socket_t * sock,char * buf,apr_size_t * len)94 APR_DECLARE(apr_status_t) apr_socket_recv(apr_socket_t *sock, char *buf,
95 apr_size_t *len)
96 {
97 apr_ssize_t rv;
98
99 do {
100 rv = recv(sock->socketdes, buf, (*len), 0);
101 } while (rv == -1 && errno == EINTR);
102
103 if (rv == -1 && errno == EWOULDBLOCK && sock->timeout > 0) {
104 apr_status_t arv = wait_for_io_or_timeout(sock, 1);
105 if (arv != APR_SUCCESS) {
106 *len = 0;
107 return arv;
108 }
109 else {
110 do {
111 rv = recv(sock->socketdes, buf, (*len), 0);
112 } while (rv == -1 && errno == EINTR);
113 }
114 }
115 if (rv == -1) {
116 (*len) = 0;
117 return errno;
118 }
119 (*len) = rv;
120 if (rv == 0)
121 return APR_EOF;
122 return APR_SUCCESS;
123 }
124
125 /* BeOS doesn't have writev for sockets so we use the following instead...
126 */
apr_socket_sendv(apr_socket_t * sock,const struct iovec * vec,apr_int32_t nvec,apr_size_t * len)127 APR_DECLARE(apr_status_t) apr_socket_sendv(apr_socket_t * sock,
128 const struct iovec *vec,
129 apr_int32_t nvec, apr_size_t *len)
130 {
131 *len = vec[0].iov_len;
132 return apr_socket_send(sock, vec[0].iov_base, len);
133 }
134
apr_socket_sendto(apr_socket_t * sock,apr_sockaddr_t * where,apr_int32_t flags,const char * buf,apr_size_t * len)135 APR_DECLARE(apr_status_t) apr_socket_sendto(apr_socket_t *sock,
136 apr_sockaddr_t *where,
137 apr_int32_t flags, const char *buf,
138 apr_size_t *len)
139 {
140 apr_ssize_t rv;
141
142 do {
143 rv = sendto(sock->socketdes, buf, (*len), flags,
144 (const struct sockaddr*)&where->sa,
145 where->salen);
146 } while (rv == -1 && errno == EINTR);
147
148 if (rv == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)
149 && sock->timeout != 0) {
150 apr_status_t arv = wait_for_io_or_timeout(sock, 0);
151 if (arv != APR_SUCCESS) {
152 *len = 0;
153 return arv;
154 } else {
155 do {
156 rv = sendto(sock->socketdes, buf, (*len), flags,
157 (const struct sockaddr*)&where->sa,
158 where->salen);
159 } while (rv == -1 && errno == EINTR);
160 }
161 }
162 if (rv == -1) {
163 *len = 0;
164 return errno;
165 }
166 *len = rv;
167 return APR_SUCCESS;
168 }
169
apr_socket_recvfrom(apr_sockaddr_t * from,apr_socket_t * sock,apr_int32_t flags,char * buf,apr_size_t * len)170 APR_DECLARE(apr_status_t) apr_socket_recvfrom(apr_sockaddr_t *from,
171 apr_socket_t *sock,
172 apr_int32_t flags, char *buf,
173 apr_size_t *len)
174 {
175 apr_ssize_t rv;
176
177 if (from == NULL){
178 return APR_ENOMEM;
179 /* Not sure if this is correct. Maybe we should just allocate
180 the memory??
181 */
182 }
183
184 do {
185 rv = recvfrom(sock->socketdes, buf, (*len), flags,
186 (struct sockaddr*)&from->sa, &from->salen);
187 } while (rv == -1 && errno == EINTR);
188
189 if (rv == -1 && (errno == EAGAIN || errno == EWOULDBLOCK) &&
190 sock->timeout != 0) {
191 apr_status_t arv = wait_for_io_or_timeout(sock, 1);
192 if (arv != APR_SUCCESS) {
193 *len = 0;
194 return arv;
195 } else {
196 do {
197 rv = recvfrom(sock->socketdes, buf, (*len), flags,
198 (struct sockaddr*)&from->sa, &from->salen);
199 } while (rv == -1 && errno == EINTR);
200 }
201 }
202 if (rv == -1) {
203 (*len) = 0;
204 return errno;
205 }
206
207 from->port = ntohs(from->sa.sin.sin_port);
208
209 (*len) = rv;
210 if (rv == 0)
211 return APR_EOF;
212
213 return APR_SUCCESS;
214 }
215
216 #endif /* ! BEOS_BONE */
217