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 24static 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 60APR_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 94APR_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 */ 127APR_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 135APR_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 170APR_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