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_arch_networkio.h" 18#include "apr_errno.h" 19#include "apr_general.h" 20#include "apr_network_io.h" 21#include "apr_lib.h" 22#include "apr_arch_file_io.h" 23#if APR_HAVE_TIME_H 24#include <time.h> 25#endif 26 27/* MAX_SEGMENT_SIZE is the maximum amount of data that will be sent to a client 28 * in one call of TransmitFile. This number must be small enough to give the 29 * slowest client time to receive the data before the socket timeout triggers. 30 * The same problem can exist with apr_socket_send(). In that case, we rely on 31 * the application to adjust socket timeouts and max send segment 32 * sizes appropriately. 33 * For example, Apache will in most cases call apr_socket_send() with less 34 * than 8193 bytes. 35 */ 36#define MAX_SEGMENT_SIZE 65536 37#define WSABUF_ON_STACK 50 38 39APR_DECLARE(apr_status_t) apr_socket_send(apr_socket_t *sock, const char *buf, 40 apr_size_t *len) 41{ 42 apr_ssize_t rv; 43 WSABUF wsaData; 44 int lasterror; 45 DWORD dwBytes = 0; 46 47 wsaData.len = (u_long)*len; 48 wsaData.buf = (char*) buf; 49 50#ifndef _WIN32_WCE 51 rv = WSASend(sock->socketdes, &wsaData, 1, &dwBytes, 0, NULL, NULL); 52#else 53 rv = send(sock->socketdes, wsaData.buf, wsaData.len, 0); 54 dwBytes = rv; 55#endif 56 if (rv == SOCKET_ERROR) { 57 lasterror = apr_get_netos_error(); 58 *len = 0; 59 return lasterror; 60 } 61 62 *len = dwBytes; 63 64 return APR_SUCCESS; 65} 66 67 68APR_DECLARE(apr_status_t) apr_socket_recv(apr_socket_t *sock, char *buf, 69 apr_size_t *len) 70{ 71 apr_ssize_t rv; 72 WSABUF wsaData; 73 int lasterror; 74 DWORD dwBytes = 0; 75 DWORD flags = 0; 76 77 wsaData.len = (u_long)*len; 78 wsaData.buf = (char*) buf; 79 80#ifndef _WIN32_WCE 81 rv = WSARecv(sock->socketdes, &wsaData, 1, &dwBytes, &flags, NULL, NULL); 82#else 83 rv = recv(sock->socketdes, wsaData.buf, wsaData.len, 0); 84 dwBytes = rv; 85#endif 86 if (rv == SOCKET_ERROR) { 87 lasterror = apr_get_netos_error(); 88 *len = 0; 89 return lasterror; 90 } 91 92 *len = dwBytes; 93 return dwBytes == 0 ? APR_EOF : APR_SUCCESS; 94} 95 96 97APR_DECLARE(apr_status_t) apr_socket_sendv(apr_socket_t *sock, 98 const struct iovec *vec, 99 apr_int32_t in_vec, apr_size_t *nbytes) 100{ 101 apr_status_t rc = APR_SUCCESS; 102 apr_ssize_t rv; 103 apr_size_t cur_len; 104 apr_int32_t nvec = 0; 105 int i, j = 0; 106 DWORD dwBytes = 0; 107 WSABUF *pWsaBuf; 108 109 for (i = 0; i < in_vec; i++) { 110 cur_len = vec[i].iov_len; 111 nvec++; 112 while (cur_len > APR_DWORD_MAX) { 113 nvec++; 114 cur_len -= APR_DWORD_MAX; 115 } 116 } 117 118 pWsaBuf = (nvec <= WSABUF_ON_STACK) ? _alloca(sizeof(WSABUF) * (nvec)) 119 : malloc(sizeof(WSABUF) * (nvec)); 120 if (!pWsaBuf) 121 return APR_ENOMEM; 122 123 for (i = 0; i < in_vec; i++) { 124 char * base = vec[i].iov_base; 125 cur_len = vec[i].iov_len; 126 127 do { 128 if (cur_len > APR_DWORD_MAX) { 129 pWsaBuf[j].buf = base; 130 pWsaBuf[j].len = APR_DWORD_MAX; 131 cur_len -= APR_DWORD_MAX; 132 base += APR_DWORD_MAX; 133 } 134 else { 135 pWsaBuf[j].buf = base; 136 pWsaBuf[j].len = (DWORD)cur_len; 137 cur_len = 0; 138 } 139 j++; 140 141 } while (cur_len > 0); 142 } 143#ifndef _WIN32_WCE 144 rv = WSASend(sock->socketdes, pWsaBuf, nvec, &dwBytes, 0, NULL, NULL); 145 if (rv == SOCKET_ERROR) { 146 rc = apr_get_netos_error(); 147 } 148#else 149 for (i = 0; i < nvec; i++) { 150 rv = send(sock->socketdes, pWsaBuf[i].buf, pWsaBuf[i].len, 0); 151 if (rv == SOCKET_ERROR) { 152 rc = apr_get_netos_error(); 153 break; 154 } 155 dwBytes += rv; 156 } 157#endif 158 if (nvec > WSABUF_ON_STACK) 159 free(pWsaBuf); 160 161 *nbytes = dwBytes; 162 return rc; 163} 164 165 166APR_DECLARE(apr_status_t) apr_socket_sendto(apr_socket_t *sock, 167 apr_sockaddr_t *where, 168 apr_int32_t flags, const char *buf, 169 apr_size_t *len) 170{ 171 apr_ssize_t rv; 172 173 rv = sendto(sock->socketdes, buf, (int)*len, flags, 174 (const struct sockaddr*)&where->sa, 175 where->salen); 176 if (rv == SOCKET_ERROR) { 177 *len = 0; 178 return apr_get_netos_error(); 179 } 180 181 *len = rv; 182 return APR_SUCCESS; 183} 184 185 186APR_DECLARE(apr_status_t) apr_socket_recvfrom(apr_sockaddr_t *from, 187 apr_socket_t *sock, 188 apr_int32_t flags, 189 char *buf, apr_size_t *len) 190{ 191 apr_ssize_t rv; 192 193 from->salen = sizeof(from->sa); 194 195 rv = recvfrom(sock->socketdes, buf, (int)*len, flags, 196 (struct sockaddr*)&from->sa, &from->salen); 197 if (rv == SOCKET_ERROR) { 198 (*len) = 0; 199 return apr_get_netos_error(); 200 } 201 202 apr_sockaddr_vars_set(from, from->sa.sin.sin_family, 203 ntohs(from->sa.sin.sin_port)); 204 205 (*len) = rv; 206 if (rv == 0 && sock->type == SOCK_STREAM) 207 return APR_EOF; 208 209 return APR_SUCCESS; 210} 211 212 213#if APR_HAS_SENDFILE 214static apr_status_t collapse_iovec(char **off, apr_size_t *len, 215 struct iovec *iovec, int numvec, 216 char *buf, apr_size_t buflen) 217{ 218 if (numvec == 1) { 219 *off = iovec[0].iov_base; 220 *len = iovec[0].iov_len; 221 } 222 else { 223 int i; 224 for (i = 0; i < numvec; i++) { 225 *len += iovec[i].iov_len; 226 } 227 228 if (*len > buflen) { 229 *len = 0; 230 return APR_INCOMPLETE; 231 } 232 233 *off = buf; 234 235 for (i = 0; i < numvec; i++) { 236 memcpy(buf, iovec[i].iov_base, iovec[i].iov_len); 237 buf += iovec[i].iov_len; 238 } 239 } 240 return APR_SUCCESS; 241} 242 243 244/* 245 * apr_status_t apr_socket_sendfile(apr_socket_t *, apr_file_t *, apr_hdtr_t *, 246 * apr_off_t *, apr_size_t *, apr_int32_t flags) 247 * Send a file from an open file descriptor to a socket, along with 248 * optional headers and trailers 249 * arg 1) The socket to which we're writing 250 * arg 2) The open file from which to read 251 * arg 3) A structure containing the headers and trailers to send 252 * arg 4) Offset into the file where we should begin writing 253 * arg 5) Number of bytes to send out of the file 254 * arg 6) APR flags that are mapped to OS specific flags 255 */ 256APR_DECLARE(apr_status_t) apr_socket_sendfile(apr_socket_t *sock, 257 apr_file_t *file, 258 apr_hdtr_t *hdtr, 259 apr_off_t *offset, 260 apr_size_t *len, 261 apr_int32_t flags) 262{ 263 apr_status_t status = APR_SUCCESS; 264 apr_status_t rv; 265 apr_off_t curoff = *offset; 266 DWORD dwFlags = 0; 267 apr_size_t nbytes; 268 TRANSMIT_FILE_BUFFERS tfb, *ptfb = NULL; 269 apr_size_t bytes_to_send; /* Bytes to send out of the file (not including headers) */ 270 int disconnected = 0; 271 int sendv_trailers = 0; 272 char hdtrbuf[4096]; 273 274 if (apr_os_level < APR_WIN_NT) { 275 return APR_ENOTIMPL; 276 } 277 278 /* Use len to keep track of number of total bytes sent (including headers) */ 279 bytes_to_send = *len; 280 *len = 0; 281 282 /* Handle the goofy case of sending headers/trailers and a zero byte file */ 283 if (!bytes_to_send && hdtr) { 284 if (hdtr->numheaders) { 285 rv = apr_socket_sendv(sock, hdtr->headers, hdtr->numheaders, 286 &nbytes); 287 if (rv != APR_SUCCESS) 288 return rv; 289 *len += nbytes; 290 } 291 if (hdtr->numtrailers) { 292 rv = apr_socket_sendv(sock, hdtr->trailers, hdtr->numtrailers, 293 &nbytes); 294 if (rv != APR_SUCCESS) 295 return rv; 296 *len += nbytes; 297 } 298 return APR_SUCCESS; 299 } 300 301 memset(&tfb, '\0', sizeof (tfb)); 302 303 /* Collapse the headers into a single buffer */ 304 if (hdtr && hdtr->numheaders) { 305 apr_size_t head_length = tfb.HeadLength; 306 ptfb = &tfb; 307 nbytes = 0; 308 rv = collapse_iovec((char **)&ptfb->Head, &head_length, 309 hdtr->headers, hdtr->numheaders, 310 hdtrbuf, sizeof(hdtrbuf)); 311 312 tfb.HeadLength = (DWORD)head_length; 313 314 /* If not enough buffer, punt to sendv */ 315 if (rv == APR_INCOMPLETE) { 316 rv = apr_socket_sendv(sock, hdtr->headers, hdtr->numheaders, &nbytes); 317 if (rv != APR_SUCCESS) 318 return rv; 319 *len += nbytes; 320 ptfb = NULL; 321 } 322 } 323 324 /* Initialize the overlapped structure used on TransmitFile 325 */ 326 if (!sock->overlapped) { 327 sock->overlapped = apr_pcalloc(sock->pool, sizeof(OVERLAPPED)); 328 sock->overlapped->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); 329 } 330 while (bytes_to_send) { 331 DWORD xmitbytes; 332 333 if (bytes_to_send > MAX_SEGMENT_SIZE) { 334 xmitbytes = MAX_SEGMENT_SIZE; 335 } 336 else { 337 /* Last call to TransmitFile() */ 338 xmitbytes = (DWORD)bytes_to_send; 339 /* Collapse the trailers into a single buffer */ 340 if (hdtr && hdtr->numtrailers) { 341 apr_size_t tail_length = tfb.TailLength; 342 ptfb = &tfb; 343 rv = collapse_iovec((char**) &ptfb->Tail, &tail_length, 344 hdtr->trailers, hdtr->numtrailers, 345 hdtrbuf + ptfb->HeadLength, 346 sizeof(hdtrbuf) - ptfb->HeadLength); 347 348 tfb.TailLength = (DWORD)tail_length; 349 350 if (rv == APR_INCOMPLETE) { 351 /* If not enough buffer, punt to sendv, later */ 352 sendv_trailers = 1; 353 } 354 } 355 /* Disconnect the socket after last send */ 356 if ((flags & APR_SENDFILE_DISCONNECT_SOCKET) 357 && !sendv_trailers) { 358 dwFlags |= TF_REUSE_SOCKET; 359 dwFlags |= TF_DISCONNECT; 360 disconnected = 1; 361 } 362 } 363 364 sock->overlapped->Offset = (DWORD)(curoff); 365#if APR_HAS_LARGE_FILES 366 sock->overlapped->OffsetHigh = (DWORD)(curoff >> 32); 367#endif 368 /* XXX BoundsChecker claims dwFlags must not be zero. */ 369 rv = TransmitFile(sock->socketdes, /* socket */ 370 file->filehand, /* open file descriptor of the file to be sent */ 371 xmitbytes, /* number of bytes to send. 0=send all */ 372 0, /* Number of bytes per send. 0=use default */ 373 sock->overlapped, /* OVERLAPPED structure */ 374 ptfb, /* header and trailer buffers */ 375 dwFlags); /* flags to control various aspects of TransmitFile */ 376 if (!rv) { 377 status = apr_get_netos_error(); 378 if ((status == APR_FROM_OS_ERROR(ERROR_IO_PENDING)) || 379 (status == APR_FROM_OS_ERROR(WSA_IO_PENDING))) 380 { 381 rv = WaitForSingleObject(sock->overlapped->hEvent, 382 (DWORD)(sock->timeout >= 0 383 ? sock->timeout_ms : INFINITE)); 384 if (rv == WAIT_OBJECT_0) { 385 status = APR_SUCCESS; 386 if (!disconnected) { 387 if (!WSAGetOverlappedResult(sock->socketdes, 388 sock->overlapped, 389 &xmitbytes, 390 FALSE, 391 &dwFlags)) { 392 status = apr_get_netos_error(); 393 } 394 /* Ugly code alert: WSAGetOverlappedResult returns 395 * a count of all bytes sent. This loop only 396 * tracks bytes sent out of the file. 397 */ 398 else if (ptfb) { 399 xmitbytes -= (ptfb->HeadLength + ptfb->TailLength); 400 } 401 } 402 } 403 else if (rv == WAIT_TIMEOUT) { 404 status = APR_FROM_OS_ERROR(WAIT_TIMEOUT); 405 } 406 else if (rv == WAIT_ABANDONED) { 407 /* Hummm... WAIT_ABANDONDED is not an error code. It is 408 * a return specific to the Win32 WAIT functions that 409 * indicates that a thread exited while holding a 410 * mutex. Should consider triggering an assert 411 * to detect the condition... 412 */ 413 status = APR_FROM_OS_ERROR(WAIT_TIMEOUT); 414 } 415 else 416 status = apr_get_os_error(); 417 } 418 } 419 if (status != APR_SUCCESS) 420 break; 421 422 bytes_to_send -= xmitbytes; 423 curoff += xmitbytes; 424 *len += xmitbytes; 425 /* Adjust len for any headers/trailers sent */ 426 if (ptfb) { 427 *len += (ptfb->HeadLength + ptfb->TailLength); 428 memset(&tfb, '\0', sizeof (tfb)); 429 ptfb = NULL; 430 } 431 } 432 433 if (status == APR_SUCCESS) { 434 if (sendv_trailers) { 435 rv = apr_socket_sendv(sock, hdtr->trailers, hdtr->numtrailers, &nbytes); 436 if (rv != APR_SUCCESS) 437 return rv; 438 *len += nbytes; 439 } 440 441 442 /* Mark the socket as disconnected, but do not close it. 443 * Note: The application must have stored the socket prior to making 444 * the call to apr_socket_sendfile in order to either reuse it 445 * or close it. 446 */ 447 if (disconnected) { 448 sock->disconnected = 1; 449 sock->socketdes = INVALID_SOCKET; 450 } 451 } 452 453 return status; 454} 455 456#endif 457 458