xref: /aosp_15_r20/external/cronet/third_party/apache-portable-runtime/src/network_io/win32/sendrecv.c (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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 
apr_socket_send(apr_socket_t * sock,const char * buf,apr_size_t * len)39 APR_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 
apr_socket_recv(apr_socket_t * sock,char * buf,apr_size_t * len)68 APR_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 
apr_socket_sendv(apr_socket_t * sock,const struct iovec * vec,apr_int32_t in_vec,apr_size_t * nbytes)97 APR_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 
apr_socket_sendto(apr_socket_t * sock,apr_sockaddr_t * where,apr_int32_t flags,const char * buf,apr_size_t * len)166 APR_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 
apr_socket_recvfrom(apr_sockaddr_t * from,apr_socket_t * sock,apr_int32_t flags,char * buf,apr_size_t * len)186 APR_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
collapse_iovec(char ** off,apr_size_t * len,struct iovec * iovec,int numvec,char * buf,apr_size_t buflen)214 static 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  */
apr_socket_sendfile(apr_socket_t * sock,apr_file_t * file,apr_hdtr_t * hdtr,apr_off_t * offset,apr_size_t * len,apr_int32_t flags)256 APR_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