Home | History | Annotate | Download | only in OpenglCodecCommon
      1 /*
      2 * Copyright (C) 2011 The Android Open Source Project
      3 *
      4 * Licensed under the Apache License, Version 2.0 (the "License");
      5 * you may not use this file except in compliance with the License.
      6 * 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 #include "Win32PipeStream.h"
     17 
     18 #include <errno.h>
     19 #include <stdio.h>
     20 #include <stdlib.h>
     21 #include <unistd.h>
     22 #include <string.h>
     23 #include <windows.h>
     24 
     25 #ifndef _WIN32
     26 #error ONLY BUILD THIS SOURCE FILE FOR WINDOWS!
     27 #endif
     28 
     29 /* The official documentation states that the name of a given named
     30  * pipe cannot be more than 256 characters long.
     31  */
     32 #define NAMED_PIPE_MAX 256
     33 
     34 Win32PipeStream::Win32PipeStream(size_t bufSize) :
     35     SocketStream(bufSize),
     36     m_pipe(INVALID_HANDLE_VALUE)
     37 {
     38 }
     39 
     40 Win32PipeStream::Win32PipeStream(HANDLE pipe, size_t bufSize) :
     41     SocketStream(-1, bufSize),
     42     m_pipe(pipe)
     43 {
     44 }
     45 
     46 Win32PipeStream::~Win32PipeStream()
     47 {
     48     if (m_pipe != INVALID_HANDLE_VALUE) {
     49         CloseHandle(m_pipe);
     50         m_pipe = INVALID_HANDLE_VALUE;
     51     }
     52 }
     53 
     54 /* Initialize the pipe name corresponding to a given port
     55  */
     56 static void
     57 make_pipe_name(char *path, size_t  pathlen, int port_number)
     58 {
     59     snprintf(path, pathlen, "\\\\.\\pipe\\qemu-gles-%d", port_number);
     60 }
     61 
     62 
     63 /* Technical note: Named pipes work differently from BSD Sockets.
     64  * One does not create/bind a pipe, and collect a new handle each
     65  * time a client connects with accept().
     66  *
     67  * Instead, the server creates a new pipe instance each time it wants
     68  * to get a new client connection, then calls ConnectNamedPipe() to
     69  * wait for a connection.
     70  *
     71  * So listen() is a no-op, and accept() really creates the pipe handle.
     72  *
     73  * Also, connect() must create a pipe handle with CreateFile() and
     74  * wait for a server instance with WaitNamedPipe()
     75  */
     76 int Win32PipeStream::listen(unsigned short port)
     77 {
     78     // just save the port number for accept()
     79     m_port = port;
     80     return 0;
     81 }
     82 
     83 SocketStream * Win32PipeStream::accept()
     84 {
     85     char path[NAMED_PIPE_MAX+1];
     86     SocketStream*  clientStream;
     87     HANDLE pipe;
     88 
     89     make_pipe_name(path, sizeof(path), m_port);
     90 
     91     pipe = ::CreateNamedPipe(
     92                 path,                // pipe name
     93                 PIPE_ACCESS_DUPLEX,  // read-write access
     94                 PIPE_TYPE_BYTE |     // byte-oriented writes
     95                 PIPE_READMODE_BYTE | // byte-oriented reads
     96                 PIPE_WAIT,           // blocking operations
     97                 PIPE_UNLIMITED_INSTANCES, // no limit on clients
     98                 4096,                // input buffer size
     99                 4096,                // output buffer size
    100                 0,                   // client time-out
    101                 NULL);               // default security attributes
    102 
    103     if (pipe == INVALID_HANDLE_VALUE) {
    104         ERR("%s: CreateNamedPipe failed %d\n", __FUNCTION__, (int)GetLastError());
    105         return NULL;
    106     }
    107 
    108     // Stupid Win32 API design: If a client is already connected, then
    109     // ConnectNamedPipe will return 0, and GetLastError() will return
    110     // ERROR_PIPE_CONNECTED. This is not an error! It just means that the
    111     // function didn't have to wait.
    112     //
    113     if (::ConnectNamedPipe(pipe, NULL) == 0 && GetLastError() != ERROR_PIPE_CONNECTED) {
    114         ERR("%s: ConnectNamedPipe failed: %d\n", __FUNCTION__, (int)GetLastError());
    115         CloseHandle(pipe);
    116         return NULL;
    117     }
    118 
    119     clientStream = new Win32PipeStream(pipe, m_bufsize);
    120     return clientStream;
    121 }
    122 
    123 int Win32PipeStream::connect(unsigned short port)
    124 {
    125     char   path[NAMED_PIPE_MAX+1];
    126     HANDLE pipe;
    127     int    tries = 10;
    128 
    129     make_pipe_name(path, sizeof(path), port);
    130 
    131     /* We're going to loop in order to wait for the pipe server to
    132      * be setup properly.
    133      */
    134     for (; tries > 0; tries--) {
    135         pipe = ::CreateFile(
    136                     path,                          // pipe name
    137                     GENERIC_READ | GENERIC_WRITE,  // read & write
    138                     0,                             // no sharing
    139                     NULL,                          // default security attrs
    140                     OPEN_EXISTING,                 // open existing pipe
    141                     0,                             // default attributes
    142                     NULL);                         // no template file
    143 
    144         /* If we have a valid pipe handle, break from the loop */
    145         if (pipe != INVALID_HANDLE_VALUE) {
    146             break;
    147         }
    148 
    149         /* We can get here if the pipe is busy, i.e. if the server hasn't
    150          * create a new pipe instance to service our request. In which case
    151          * GetLastError() will return ERROR_PIPE_BUSY.
    152          *
    153          * If so, then use WaitNamedPipe() to wait for a decent time
    154          * to try again.
    155          */
    156         if (GetLastError() != ERROR_PIPE_BUSY) {
    157             /* Not ERROR_PIPE_BUSY */
    158             ERR("%s: CreateFile failed: %d\n", __FUNCTION__, (int)GetLastError());
    159             errno = EINVAL;
    160             return -1;
    161         }
    162 
    163         /* Wait for 5 seconds */
    164         if ( !WaitNamedPipe(path, 5000) ) {
    165             ERR("%s: WaitNamedPipe failed: %d\n", __FUNCTION__, (int)GetLastError());
    166             errno = EINVAL;
    167             return -1;
    168         }
    169     }
    170 
    171     m_pipe = pipe;
    172     return 0;
    173 }
    174 
    175 /* Special buffer methods, since we can't use socket functions here */
    176 
    177 int Win32PipeStream::commitBuffer(size_t size)
    178 {
    179     if (m_pipe == INVALID_HANDLE_VALUE)
    180         return -1;
    181 
    182     size_t res = size;
    183     int retval = 0;
    184 
    185     while (res > 0) {
    186         DWORD  written;
    187         if (! ::WriteFile(m_pipe, (const char *)m_buf + (size - res), res, &written, NULL)) {
    188             retval =  -1;
    189             ERR("%s: failed: %d\n", __FUNCTION__, (int)GetLastError());
    190             break;
    191         }
    192         res -= written;
    193     }
    194     return retval;
    195 }
    196 
    197 const unsigned char *Win32PipeStream::readFully(void *buf, size_t len)
    198 {
    199     const unsigned char* ret = NULL;
    200 
    201     if (m_pipe == INVALID_HANDLE_VALUE)
    202         return NULL;
    203 
    204     if (!buf) {
    205         return NULL;  // do not allow NULL buf in that implementation
    206     }
    207 
    208     size_t res = len;
    209     while (res > 0) {
    210         DWORD  readcount = 0;
    211         if (! ::ReadFile(m_pipe, (char *)buf + (len - res), res, &readcount, NULL) || readcount == 0) {
    212             errno = (int)GetLastError();
    213             return NULL;
    214         }
    215         res -= readcount;
    216     }
    217     return (const unsigned char *)buf;
    218 }
    219 
    220 const unsigned char *Win32PipeStream::read( void *buf, size_t *inout_len)
    221 {
    222     size_t len = *inout_len;
    223     DWORD  readcount;
    224 
    225     if (m_pipe == INVALID_HANDLE_VALUE)
    226         return NULL;
    227 
    228     if (!buf) {
    229         return NULL;  // do not allow NULL buf in that implementation
    230     }
    231 
    232     if (!::ReadFile(m_pipe, (char *)buf, len, &readcount, NULL)) {
    233         errno = (int)GetLastError();
    234         return NULL;
    235     }
    236 
    237     *inout_len = (size_t)readcount;
    238     return (const unsigned char *)buf;
    239 }
    240