xref: /aosp_15_r20/external/cronet/third_party/apache-portable-runtime/src/file_io/unix/pipe.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_file_io.h"
18 #include "apr_strings.h"
19 #include "apr_portable.h"
20 
21 #include "apr_arch_inherit.h"
22 
23 /* Figure out how to get pipe block/nonblock on BeOS...
24  * Basically, BONE7 changed things again so that ioctl didn't work,
25  * but now fcntl does, hence we need to do this extra checking.
26  * The joys of beta programs. :-)
27  */
28 #if defined(BEOS)
29 #if !defined(BONE7)
30 # define BEOS_BLOCKING 1
31 #else
32 # define BEOS_BLOCKING 0
33 #endif
34 #endif
35 
pipeblock(apr_file_t * thepipe)36 static apr_status_t pipeblock(apr_file_t *thepipe)
37 {
38 #if !defined(BEOS) || !BEOS_BLOCKING
39       int fd_flags;
40 
41       fd_flags = fcntl(thepipe->filedes, F_GETFL, 0);
42 #  if defined(O_NONBLOCK)
43       fd_flags &= ~O_NONBLOCK;
44 #  elif defined(O_NDELAY)
45       fd_flags &= ~O_NDELAY;
46 #  elif defined(O_FNDELAY)
47       fd_flags &= ~O_FNDELAY;
48 #  else
49       /* XXXX: this breaks things, but an alternative isn't obvious...*/
50       return APR_ENOTIMPL;
51 #  endif
52       if (fcntl(thepipe->filedes, F_SETFL, fd_flags) == -1) {
53           return errno;
54       }
55 #else /* BEOS_BLOCKING */
56 
57 #  if BEOS_BONE /* This only works on BONE 0-6 */
58       int on = 0;
59       if (ioctl(thepipe->filedes, FIONBIO, &on, sizeof(on)) < 0) {
60           return errno;
61       }
62 #  else /* "classic" BeOS doesn't support this at all */
63       return APR_ENOTIMPL;
64 #  endif
65 
66 #endif /* !BEOS_BLOCKING */
67 
68     thepipe->blocking = BLK_ON;
69     return APR_SUCCESS;
70 }
71 
pipenonblock(apr_file_t * thepipe)72 static apr_status_t pipenonblock(apr_file_t *thepipe)
73 {
74 #if !defined(BEOS) || !BEOS_BLOCKING
75       int fd_flags = fcntl(thepipe->filedes, F_GETFL, 0);
76 
77 #  if defined(O_NONBLOCK)
78       fd_flags |= O_NONBLOCK;
79 #  elif defined(O_NDELAY)
80       fd_flags |= O_NDELAY;
81 #  elif defined(O_FNDELAY)
82       fd_flags |= O_FNDELAY;
83 #  else
84       /* XXXX: this breaks things, but an alternative isn't obvious...*/
85       return APR_ENOTIMPL;
86 #  endif
87       if (fcntl(thepipe->filedes, F_SETFL, fd_flags) == -1) {
88           return errno;
89       }
90 
91 #else /* BEOS_BLOCKING */
92 
93 #  if BEOS_BONE /* This only works on BONE 0-6 */
94       int on = 1;
95       if (ioctl(thepipe->filedes, FIONBIO, &on, sizeof(on)) < 0) {
96           return errno;
97       }
98 #  else /* "classic" BeOS doesn't support this at all */
99       return APR_ENOTIMPL;
100 #  endif
101 
102 #endif /* !BEOS_BLOCKING */
103 
104     thepipe->blocking = BLK_OFF;
105     return APR_SUCCESS;
106 }
107 
apr_file_pipe_timeout_set(apr_file_t * thepipe,apr_interval_time_t timeout)108 APR_DECLARE(apr_status_t) apr_file_pipe_timeout_set(apr_file_t *thepipe, apr_interval_time_t timeout)
109 {
110     if (thepipe->is_pipe == 1) {
111         thepipe->timeout = timeout;
112         if (timeout >= 0) {
113             if (thepipe->blocking != BLK_OFF) { /* blocking or unknown state */
114                 return pipenonblock(thepipe);
115             }
116         }
117         else {
118             if (thepipe->blocking != BLK_ON) { /* non-blocking or unknown state */
119                 return pipeblock(thepipe);
120             }
121         }
122         return APR_SUCCESS;
123     }
124     return APR_EINVAL;
125 }
126 
apr_file_pipe_timeout_get(apr_file_t * thepipe,apr_interval_time_t * timeout)127 APR_DECLARE(apr_status_t) apr_file_pipe_timeout_get(apr_file_t *thepipe, apr_interval_time_t *timeout)
128 {
129     if (thepipe->is_pipe == 1) {
130         *timeout = thepipe->timeout;
131         return APR_SUCCESS;
132     }
133     return APR_EINVAL;
134 }
135 
apr_os_pipe_put_ex(apr_file_t ** file,apr_os_file_t * thefile,int register_cleanup,apr_pool_t * pool)136 APR_DECLARE(apr_status_t) apr_os_pipe_put_ex(apr_file_t **file,
137                                              apr_os_file_t *thefile,
138                                              int register_cleanup,
139                                              apr_pool_t *pool)
140 {
141     int *dafile = thefile;
142 
143     (*file) = apr_pcalloc(pool, sizeof(apr_file_t));
144     (*file)->pool = pool;
145     (*file)->eof_hit = 0;
146     (*file)->is_pipe = 1;
147     (*file)->blocking = BLK_UNKNOWN; /* app needs to make a timeout call */
148     (*file)->timeout = -1;
149     (*file)->ungetchar = -1; /* no char avail */
150     (*file)->filedes = *dafile;
151     if (!register_cleanup) {
152         (*file)->flags = APR_FOPEN_NOCLEANUP;
153     }
154     (*file)->buffered = 0;
155 #if APR_HAS_THREADS
156     (*file)->thlock = NULL;
157 #endif
158     if (register_cleanup) {
159         apr_pool_cleanup_register((*file)->pool, (void *)(*file),
160                                   apr_unix_file_cleanup,
161                                   apr_pool_cleanup_null);
162     }
163 #ifndef WAITIO_USES_POLL
164     /* Start out with no pollset.  apr_wait_for_io_or_timeout() will
165      * initialize the pollset if needed.
166      */
167     (*file)->pollset = NULL;
168 #endif
169     return APR_SUCCESS;
170 }
171 
apr_os_pipe_put(apr_file_t ** file,apr_os_file_t * thefile,apr_pool_t * pool)172 APR_DECLARE(apr_status_t) apr_os_pipe_put(apr_file_t **file,
173                                           apr_os_file_t *thefile,
174                                           apr_pool_t *pool)
175 {
176     return apr_os_pipe_put_ex(file, thefile, 0, pool);
177 }
178 
apr_file_pipe_create(apr_file_t ** in,apr_file_t ** out,apr_pool_t * pool)179 APR_DECLARE(apr_status_t) apr_file_pipe_create(apr_file_t **in, apr_file_t **out, apr_pool_t *pool)
180 {
181     int filedes[2];
182 
183     if (pipe(filedes) == -1) {
184         return errno;
185     }
186 
187     (*in) = (apr_file_t *)apr_pcalloc(pool, sizeof(apr_file_t));
188     (*in)->pool = pool;
189     (*in)->filedes = filedes[0];
190     (*in)->is_pipe = 1;
191     (*in)->fname = NULL;
192     (*in)->buffered = 0;
193     (*in)->blocking = BLK_ON;
194     (*in)->timeout = -1;
195     (*in)->ungetchar = -1;
196     (*in)->flags = APR_INHERIT;
197 #if APR_HAS_THREADS
198     (*in)->thlock = NULL;
199 #endif
200 #ifndef WAITIO_USES_POLL
201     (*in)->pollset = NULL;
202 #endif
203     (*out) = (apr_file_t *)apr_pcalloc(pool, sizeof(apr_file_t));
204     (*out)->pool = pool;
205     (*out)->filedes = filedes[1];
206     (*out)->is_pipe = 1;
207     (*out)->fname = NULL;
208     (*out)->buffered = 0;
209     (*out)->blocking = BLK_ON;
210     (*out)->flags = APR_INHERIT;
211     (*out)->timeout = -1;
212 #if APR_HAS_THREADS
213     (*out)->thlock = NULL;
214 #endif
215 #ifndef WAITIO_USES_POLL
216     (*out)->pollset = NULL;
217 #endif
218     apr_pool_cleanup_register((*in)->pool, (void *)(*in), apr_unix_file_cleanup,
219                          apr_pool_cleanup_null);
220     apr_pool_cleanup_register((*out)->pool, (void *)(*out), apr_unix_file_cleanup,
221                          apr_pool_cleanup_null);
222     return APR_SUCCESS;
223 }
224 
apr_file_pipe_create_ex(apr_file_t ** in,apr_file_t ** out,apr_int32_t blocking,apr_pool_t * pool)225 APR_DECLARE(apr_status_t) apr_file_pipe_create_ex(apr_file_t **in,
226                                                   apr_file_t **out,
227                                                   apr_int32_t blocking,
228                                                   apr_pool_t *pool)
229 {
230     apr_status_t status;
231 
232     if ((status = apr_file_pipe_create(in, out, pool)) != APR_SUCCESS)
233         return status;
234 
235     switch (blocking) {
236         case APR_FULL_BLOCK:
237             break;
238         case APR_READ_BLOCK:
239             apr_file_pipe_timeout_set(*out, 0);
240             break;
241         case APR_WRITE_BLOCK:
242             apr_file_pipe_timeout_set(*in, 0);
243             break;
244         default:
245             apr_file_pipe_timeout_set(*out, 0);
246             apr_file_pipe_timeout_set(*in, 0);
247     }
248 
249     return APR_SUCCESS;
250 }
251 
apr_file_namedpipe_create(const char * filename,apr_fileperms_t perm,apr_pool_t * pool)252 APR_DECLARE(apr_status_t) apr_file_namedpipe_create(const char *filename,
253                                                     apr_fileperms_t perm, apr_pool_t *pool)
254 {
255     mode_t mode = apr_unix_perms2mode(perm);
256 
257     if (mkfifo(filename, mode) == -1) {
258         return errno;
259     }
260     return APR_SUCCESS;
261 }
262 
263 
264 
265