"Fossies" - the Fresh Open Source Software Archive

Member "apr-1.7.0/file_io/win32/pipe.c" (25 Mar 2016, 16103 Bytes) of package /linux/www/apr-1.7.0.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "pipe.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.6.5_vs_1.7.0.

    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_file_io.h"
   19 #include "apr_general.h"
   20 #include "apr_strings.h"
   21 #include "apr_escape.h"
   22 #if APR_HAVE_ERRNO_H
   23 #include <errno.h>
   24 #endif
   25 #include <string.h>
   26 #include <stdio.h>
   27 #if APR_HAVE_SYS_TYPES_H
   28 #include <sys/types.h>
   29 #endif
   30 #ifdef HAVE_SYS_STAT_H
   31 #include <sys/stat.h>
   32 #endif
   33 #if APR_HAVE_PROCESS_H
   34 #include <process.h>            /* for getpid() on Win32 */
   35 #endif
   36 #include "apr_arch_misc.h"
   37 
   38 APR_DECLARE(apr_status_t) apr_file_pipe_timeout_set(apr_file_t *thepipe,
   39                                             apr_interval_time_t timeout)
   40 {
   41     /* Always OK to unset timeouts */
   42     if (timeout == -1) {
   43         thepipe->timeout = timeout;
   44         return APR_SUCCESS;
   45     }
   46     if (!thepipe->pipe) {
   47         return APR_ENOTIMPL;
   48     }
   49     if (timeout && !(thepipe->pOverlapped)) {
   50         /* Cannot be nonzero if a pipe was opened blocking
   51          */
   52         return APR_EINVAL;
   53     }
   54     thepipe->timeout = timeout;
   55     return APR_SUCCESS;
   56 }
   57 
   58 APR_DECLARE(apr_status_t) apr_file_pipe_timeout_get(apr_file_t *thepipe,
   59                                            apr_interval_time_t *timeout)
   60 {
   61     /* Always OK to get the timeout (even if it's unset ... -1) */
   62     *timeout = thepipe->timeout;
   63     return APR_SUCCESS;
   64 }
   65 
   66 APR_DECLARE(apr_status_t) apr_file_pipe_create(apr_file_t **in,
   67                                                apr_file_t **out,
   68                                                apr_pool_t *p)
   69 {
   70     /* Unix creates full blocking pipes. */
   71     return apr_file_pipe_create_pools(in, out, APR_FULL_BLOCK, p, p);
   72 }
   73 
   74 APR_DECLARE(apr_status_t) apr_file_pipe_create_ex(apr_file_t **in,
   75                                                   apr_file_t **out,
   76                                                   apr_int32_t blocking,
   77                                                   apr_pool_t *p)
   78 {
   79     return apr_file_pipe_create_pools(in, out, APR_FULL_BLOCK, p, p);
   80 }
   81 
   82 APR_DECLARE(apr_status_t) apr_file_pipe_create_pools(apr_file_t **in,
   83                                                      apr_file_t **out,
   84                                                      apr_int32_t blocking,
   85                                                      apr_pool_t *pool_in,
   86                                                      apr_pool_t *pool_out)
   87 {
   88 #ifdef _WIN32_WCE
   89     return APR_ENOTIMPL;
   90 #else
   91     SECURITY_ATTRIBUTES sa;
   92     static unsigned long id = 0;
   93     DWORD dwPipeMode;
   94     DWORD dwOpenMode;
   95 
   96     sa.nLength = sizeof(sa);
   97 
   98 #if APR_HAS_UNICODE_FS
   99     IF_WIN_OS_IS_UNICODE
  100         sa.bInheritHandle = FALSE;
  101 #endif
  102 #if APR_HAS_ANSI_FS
  103     ELSE_WIN_OS_IS_ANSI
  104         sa.bInheritHandle = TRUE;
  105 #endif
  106     sa.lpSecurityDescriptor = NULL;
  107 
  108     (*in) = (apr_file_t *)apr_pcalloc(pool_in, sizeof(apr_file_t));
  109     (*in)->pool = pool_in;
  110     (*in)->fname = NULL;
  111     (*in)->pipe = 1;
  112     (*in)->timeout = -1;
  113     (*in)->ungetchar = -1;
  114     (*in)->eof_hit = 0;
  115     (*in)->filePtr = 0;
  116     (*in)->bufpos = 0;
  117     (*in)->dataRead = 0;
  118     (*in)->direction = 0;
  119     (*in)->pOverlapped = NULL;
  120 #if APR_FILES_AS_SOCKETS
  121     (void) apr_pollset_create(&(*in)->pollset, 1, p, 0);
  122 #endif
  123     (*out) = (apr_file_t *)apr_pcalloc(pool_out, sizeof(apr_file_t));
  124     (*out)->pool = pool_out;
  125     (*out)->fname = NULL;
  126     (*out)->pipe = 1;
  127     (*out)->timeout = -1;
  128     (*out)->ungetchar = -1;
  129     (*out)->eof_hit = 0;
  130     (*out)->filePtr = 0;
  131     (*out)->bufpos = 0;
  132     (*out)->dataRead = 0;
  133     (*out)->direction = 0;
  134     (*out)->pOverlapped = NULL;
  135 #if APR_FILES_AS_SOCKETS
  136     (void) apr_pollset_create(&(*out)->pollset, 1, p, 0);
  137 #endif
  138     if (apr_os_level >= APR_WIN_NT) {
  139         char rand[8];
  140         int pid = getpid();
  141 #define FMT_PIPE_NAME "\\\\.\\pipe\\apr-pipe-%x.%lx."
  142         /*                                    ^   ^ ^
  143          *                                  pid   | |
  144          *                                        | |
  145          *                                       id |
  146          *                                          |
  147          *                        hex-escaped rand[8] (16 bytes)
  148          */
  149         char name[sizeof FMT_PIPE_NAME + 2 * sizeof(pid)
  150                                        + 2 * sizeof(id)
  151                                        + 2 * sizeof(rand)];
  152         apr_size_t pos;
  153 
  154         /* Create the read end of the pipe */
  155         dwOpenMode = PIPE_ACCESS_INBOUND;
  156 #ifdef FILE_FLAG_FIRST_PIPE_INSTANCE
  157         dwOpenMode |= FILE_FLAG_FIRST_PIPE_INSTANCE;
  158 #endif
  159         if (blocking == APR_WRITE_BLOCK /* READ_NONBLOCK */
  160                || blocking == APR_FULL_NONBLOCK) {
  161             dwOpenMode |= FILE_FLAG_OVERLAPPED;
  162             (*in)->pOverlapped =
  163                     (OVERLAPPED*) apr_pcalloc((*in)->pool, sizeof(OVERLAPPED));
  164             (*in)->pOverlapped->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  165             (*in)->timeout = 0;
  166         }
  167         dwPipeMode = 0;
  168 
  169         apr_generate_random_bytes(rand, sizeof rand);
  170         pos = apr_snprintf(name, sizeof name, FMT_PIPE_NAME, pid, id++);
  171         apr_escape_hex(name + pos, rand, sizeof rand, 0, NULL);
  172 
  173         (*in)->filehand = CreateNamedPipe(name,
  174                                           dwOpenMode,
  175                                           dwPipeMode,
  176                                           1,            /* nMaxInstances,   */
  177                                           0,            /* nOutBufferSize,  */
  178                                           65536,        /* nInBufferSize,   */
  179                                           1,            /* nDefaultTimeOut, */
  180                                           &sa);
  181         if ((*in)->filehand == INVALID_HANDLE_VALUE) {
  182             apr_status_t rv = apr_get_os_error();
  183             file_cleanup(*in);
  184             return rv;
  185         }
  186 
  187         /* Create the write end of the pipe */
  188         dwOpenMode = FILE_ATTRIBUTE_NORMAL;
  189         if (blocking == APR_READ_BLOCK /* WRITE_NONBLOCK */
  190                 || blocking == APR_FULL_NONBLOCK) {
  191             dwOpenMode |= FILE_FLAG_OVERLAPPED;
  192             (*out)->pOverlapped =
  193                     (OVERLAPPED*) apr_pcalloc((*out)->pool, sizeof(OVERLAPPED));
  194             (*out)->pOverlapped->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  195             (*out)->timeout = 0;
  196         }
  197 
  198         (*out)->filehand = CreateFile(name,
  199                                       GENERIC_WRITE,   /* access mode             */
  200                                       0,               /* share mode              */
  201                                       &sa,             /* Security attributes     */
  202                                       OPEN_EXISTING,   /* dwCreationDisposition   */
  203                                       dwOpenMode,      /* Pipe attributes         */
  204                                       NULL);           /* handle to template file */
  205         if ((*out)->filehand == INVALID_HANDLE_VALUE) {
  206             apr_status_t rv = apr_get_os_error();
  207             file_cleanup(*out);
  208             file_cleanup(*in);
  209             return rv;
  210         }
  211     }
  212     else {
  213         /* Pipes on Win9* are blocking. Live with it. */
  214         if (!CreatePipe(&(*in)->filehand, &(*out)->filehand, &sa, 65536)) {
  215             return apr_get_os_error();
  216         }
  217     }
  218 
  219     apr_pool_cleanup_register((*in)->pool, (void *)(*in), file_cleanup,
  220                         apr_pool_cleanup_null);
  221     apr_pool_cleanup_register((*out)->pool, (void *)(*out), file_cleanup,
  222                         apr_pool_cleanup_null);
  223     return APR_SUCCESS;
  224 #endif /* _WIN32_WCE */
  225 }
  226 
  227 
  228 APR_DECLARE(apr_status_t) apr_file_namedpipe_create(const char *filename,
  229                                                     apr_fileperms_t perm,
  230                                                     apr_pool_t *pool)
  231 {
  232     /* Not yet implemented, interface not suitable.
  233      * Win32 requires the named pipe to be *opened* at the time it's
  234      * created, and to do so, blocking or non blocking must be elected.
  235      */
  236     return APR_ENOTIMPL;
  237 }
  238 
  239 
  240 /* XXX: Problem; we need to choose between blocking and nonblocking based
  241  * on how *thefile was opened, and we don't have that information :-/
  242  * Hack; assume a blocking socket, since the most common use for the fn
  243  * would be to handle stdio-style or blocking pipes.  Win32 doesn't have
  244  * select() blocking for pipes anyways :(
  245  */
  246 APR_DECLARE(apr_status_t) apr_os_pipe_put_ex(apr_file_t **file,
  247                                              apr_os_file_t *thefile,
  248                                              int register_cleanup,
  249                                              apr_pool_t *pool)
  250 {
  251     (*file) = apr_pcalloc(pool, sizeof(apr_file_t));
  252     (*file)->pool = pool;
  253     (*file)->pipe = 1;
  254     (*file)->timeout = -1;
  255     (*file)->ungetchar = -1;
  256     (*file)->filehand = *thefile;
  257 #if APR_FILES_AS_SOCKETS
  258     (void) apr_pollset_create(&(*file)->pollset, 1, pool, 0);
  259 #endif
  260     if (register_cleanup) {
  261         apr_pool_cleanup_register(pool, *file, file_cleanup,
  262                                   apr_pool_cleanup_null);
  263     }
  264 
  265     return APR_SUCCESS;
  266 }
  267 
  268 
  269 APR_DECLARE(apr_status_t) apr_os_pipe_put(apr_file_t **file,
  270                                           apr_os_file_t *thefile,
  271                                           apr_pool_t *pool)
  272 {
  273     return apr_os_pipe_put_ex(file, thefile, 0, pool);
  274 }
  275 
  276 static apr_status_t create_socket_pipe(SOCKET *rd, SOCKET *wr)
  277 {
  278     static int id = 0;
  279     FD_SET rs;
  280     SOCKET ls;
  281     struct timeval socktm;
  282     struct sockaddr_in pa;
  283     struct sockaddr_in la;
  284     struct sockaddr_in ca;
  285     int nrd;
  286     apr_status_t rv = APR_SUCCESS;
  287     int ll = sizeof(la);
  288     int lc = sizeof(ca);
  289     unsigned long bm = 1;
  290     int uid[2];
  291     int iid[2];
  292 
  293     *rd = INVALID_SOCKET;
  294     *wr = INVALID_SOCKET;
  295 
  296     /* Create the unique socket identifier
  297      * so that we know the connection originated
  298      * from us.
  299      */
  300     uid[0] = getpid();
  301     uid[1] = id++;
  302     if ((ls = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {
  303         return apr_get_netos_error();
  304     }
  305 
  306     pa.sin_family = AF_INET;
  307     pa.sin_port   = 0;
  308     pa.sin_addr.s_addr = inet_addr("127.0.0.1");
  309 
  310     if (bind(ls, (SOCKADDR *)&pa, sizeof(pa)) == SOCKET_ERROR) {
  311         rv =  apr_get_netos_error();
  312         goto cleanup;
  313     }
  314     if (getsockname(ls, (SOCKADDR *)&la, &ll) == SOCKET_ERROR) {
  315         rv =  apr_get_netos_error();
  316         goto cleanup;
  317     }
  318     if (listen(ls, 1) == SOCKET_ERROR) {
  319         rv =  apr_get_netos_error();
  320         goto cleanup;
  321     }
  322     if ((*wr = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {
  323         rv = apr_get_netos_error();
  324         goto cleanup;
  325     }
  326     if (connect(*wr, (SOCKADDR *)&la, sizeof(la)) == SOCKET_ERROR) {
  327         rv =  apr_get_netos_error();
  328         goto cleanup;
  329     }
  330     if (send(*wr, (char *)uid, sizeof(uid), 0) != sizeof(uid)) {
  331         if ((rv =  apr_get_netos_error()) == 0) {
  332             rv = APR_EINVAL;
  333         }
  334         goto cleanup;
  335     }
  336     if (ioctlsocket(ls, FIONBIO, &bm) == SOCKET_ERROR) {
  337         rv = apr_get_netos_error();
  338         goto cleanup;
  339     }
  340     for (;;) {
  341         int ns;
  342         int nc = 0;
  343         /* Listening socket is nonblocking by now.
  344          * The accept should create the socket
  345          * immediatelly because we are connected already.
  346          * However on buys systems this can take a while
  347          * until winsock gets a chance to handle the events.
  348          */
  349         FD_ZERO(&rs);
  350         FD_SET(ls, &rs);
  351 
  352         socktm.tv_sec  = 1;
  353         socktm.tv_usec = 0;
  354         if ((ns = select(0, &rs, NULL, NULL, &socktm)) == SOCKET_ERROR) {
  355             /* Accept still not signaled */
  356             Sleep(100);
  357             continue;
  358         }
  359         if (ns == 0) {
  360             /* No connections in the last second */
  361             continue;
  362         }
  363         if ((*rd = accept(ls, (SOCKADDR *)&ca, &lc)) == INVALID_SOCKET) {
  364             rv =  apr_get_netos_error();
  365             goto cleanup;
  366         }
  367         /* Verify the connection by reading the send identification.
  368          */
  369         do {
  370             if (nc++)
  371                 Sleep(1);
  372             nrd = recv(*rd, (char *)iid, sizeof(iid), 0);
  373             rv = nrd == SOCKET_ERROR ? apr_get_netos_error() : APR_SUCCESS;
  374         } while (APR_STATUS_IS_EAGAIN(rv));
  375 
  376         if (nrd == sizeof(iid)) {
  377             if (memcmp(uid, iid, sizeof(uid)) == 0) {
  378                 /* Wow, we recived what we send.
  379                  * Put read side of the pipe to the blocking
  380                  * mode and return.
  381                  */
  382                 bm = 0;
  383                 if (ioctlsocket(*rd, FIONBIO, &bm) == SOCKET_ERROR) {
  384                     rv = apr_get_netos_error();
  385                     goto cleanup;
  386                 }
  387                 break;
  388             }
  389         }
  390         else if (nrd == SOCKET_ERROR) {
  391             goto cleanup;
  392         }
  393         closesocket(*rd);
  394     }
  395     /* We don't need the listening socket any more */
  396     closesocket(ls);
  397     return 0;
  398 
  399 cleanup:
  400     /* Don't leak resources */
  401     if (*rd != INVALID_SOCKET)
  402         closesocket(*rd);
  403     if (*wr != INVALID_SOCKET)
  404         closesocket(*wr);
  405 
  406     *rd = INVALID_SOCKET;
  407     *wr = INVALID_SOCKET;
  408     closesocket(ls);
  409     return rv;
  410 }
  411 
  412 static apr_status_t socket_pipe_cleanup(void *thefile)
  413 {
  414     apr_file_t *file = thefile;
  415     if (file->filehand != INVALID_HANDLE_VALUE) {
  416         shutdown((SOCKET)file->filehand, SD_BOTH);
  417         closesocket((SOCKET)file->filehand);
  418         file->filehand = INVALID_HANDLE_VALUE;
  419     }
  420     return APR_SUCCESS;
  421 }
  422 
  423 apr_status_t apr_file_socket_pipe_create(apr_file_t **in,
  424                                          apr_file_t **out,
  425                                          apr_pool_t *p)
  426 {
  427     apr_status_t rv;
  428     SOCKET rd;
  429     SOCKET wr;
  430 
  431     if ((rv = create_socket_pipe(&rd, &wr)) != APR_SUCCESS) {
  432         return rv;
  433     }
  434     (*in) = (apr_file_t *)apr_pcalloc(p, sizeof(apr_file_t));
  435     (*in)->pool = p;
  436     (*in)->fname = NULL;
  437     (*in)->pipe = 1;
  438     (*in)->timeout = -1;
  439     (*in)->ungetchar = -1;
  440     (*in)->eof_hit = 0;
  441     (*in)->filePtr = 0;
  442     (*in)->bufpos = 0;
  443     (*in)->dataRead = 0;
  444     (*in)->direction = 0;
  445     (*in)->pOverlapped = (OVERLAPPED*)apr_pcalloc(p, sizeof(OVERLAPPED));
  446     (*in)->filehand = (HANDLE)rd;
  447 
  448     (*out) = (apr_file_t *)apr_pcalloc(p, sizeof(apr_file_t));
  449     (*out)->pool = p;
  450     (*out)->fname = NULL;
  451     (*out)->pipe = 1;
  452     (*out)->timeout = -1;
  453     (*out)->ungetchar = -1;
  454     (*out)->eof_hit = 0;
  455     (*out)->filePtr = 0;
  456     (*out)->bufpos = 0;
  457     (*out)->dataRead = 0;
  458     (*out)->direction = 0;
  459     (*out)->pOverlapped = (OVERLAPPED*)apr_pcalloc(p, sizeof(OVERLAPPED));
  460     (*out)->filehand = (HANDLE)wr;
  461 
  462     apr_pool_cleanup_register(p, (void *)(*in), socket_pipe_cleanup,
  463                               apr_pool_cleanup_null);
  464     apr_pool_cleanup_register(p, (void *)(*out), socket_pipe_cleanup,
  465                               apr_pool_cleanup_null);
  466 
  467     return rv;
  468 }
  469 
  470 apr_status_t apr_file_socket_pipe_close(apr_file_t *file)
  471 {
  472     apr_status_t stat;
  473     if (!file->pipe)
  474         return apr_file_close(file);
  475     if ((stat = socket_pipe_cleanup(file)) == APR_SUCCESS) {
  476         apr_pool_cleanup_kill(file->pool, file, socket_pipe_cleanup);
  477 
  478         if (file->mutex) {
  479             apr_thread_mutex_destroy(file->mutex);
  480         }
  481 
  482         return APR_SUCCESS;
  483     }
  484     return stat;
  485 }
  486