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(char addrstr[MAX_ADDRSTR_LEN])
     77 {
     78     m_port = GetCurrentProcessId();
     79     make_pipe_name(addrstr, MAX_ADDRSTR_LEN, m_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(const char* addr)
    124 {
    125     HANDLE pipe;
    126     int    tries = 10;
    127 
    128     /* We're going to loop in order to wait for the pipe server to
    129      * be setup properly.
    130      */
    131     for (; tries > 0; tries--) {
    132         pipe = ::CreateFile(
    133                     addr,                          // pipe name
    134                     GENERIC_READ | GENERIC_WRITE,  // read & write
    135                     0,                             // no sharing
    136                     NULL,                          // default security attrs
    137                     OPEN_EXISTING,                 // open existing pipe
    138                     0,                             // default attributes
    139                     NULL);                         // no template file
    140 
    141         /* If we have a valid pipe handle, break from the loop */
    142         if (pipe != INVALID_HANDLE_VALUE) {
    143             break;
    144         }
    145 
    146         /* We can get here if the pipe is busy, i.e. if the server hasn't
    147          * create a new pipe instance to service our request. In which case
    148          * GetLastError() will return ERROR_PIPE_BUSY.
    149          *
    150          * If so, then use WaitNamedPipe() to wait for a decent time
    151          * to try again.
    152          */
    153         if (GetLastError() != ERROR_PIPE_BUSY) {
    154             /* Not ERROR_PIPE_BUSY */
    155             ERR("%s: CreateFile failed: %d\n", __FUNCTION__, (int)GetLastError());
    156             errno = EINVAL;
    157             return -1;
    158         }
    159 
    160         /* Wait for 5 seconds */
    161         if ( !WaitNamedPipe(addr, 5000) ) {
    162             ERR("%s: WaitNamedPipe failed: %d\n", __FUNCTION__, (int)GetLastError());
    163             errno = EINVAL;
    164             return -1;
    165         }
    166     }
    167 
    168     m_pipe = pipe;
    169     return 0;
    170 }
    171 
    172 /* Special buffer methods, since we can't use socket functions here */
    173 
    174 int Win32PipeStream::commitBuffer(size_t size)
    175 {
    176     if (m_pipe == INVALID_HANDLE_VALUE)
    177         return -1;
    178 
    179     size_t res = size;
    180     int retval = 0;
    181 
    182     while (res > 0) {
    183         DWORD  written;
    184         if (! ::WriteFile(m_pipe, (const char *)m_buf + (size - res), res, &written, NULL)) {
    185             retval =  -1;
    186             ERR("%s: failed: %d\n", __FUNCTION__, (int)GetLastError());
    187             break;
    188         }
    189         res -= written;
    190     }
    191     return retval;
    192 }
    193 
    194 const unsigned char *Win32PipeStream::readFully(void *buf, size_t len)
    195 {
    196     const unsigned char* ret = NULL;
    197 
    198     if (m_pipe == INVALID_HANDLE_VALUE)
    199         return NULL;
    200 
    201     if (!buf) {
    202         return NULL;  // do not allow NULL buf in that implementation
    203     }
    204 
    205     size_t res = len;
    206     while (res > 0) {
    207         DWORD  readcount = 0;
    208         if (! ::ReadFile(m_pipe, (char *)buf + (len - res), res, &readcount, NULL) || readcount == 0) {
    209             errno = (int)GetLastError();
    210             return NULL;
    211         }
    212         res -= readcount;
    213     }
    214     return (const unsigned char *)buf;
    215 }
    216 
    217 const unsigned char *Win32PipeStream::read( void *buf, size_t *inout_len)
    218 {
    219     size_t len = *inout_len;
    220     DWORD  readcount;
    221 
    222     if (m_pipe == INVALID_HANDLE_VALUE)
    223         return NULL;
    224 
    225     if (!buf) {
    226         return NULL;  // do not allow NULL buf in that implementation
    227     }
    228 
    229     if (!::ReadFile(m_pipe, (char *)buf, len, &readcount, NULL)) {
    230         errno = (int)GetLastError();
    231         return NULL;
    232     }
    233 
    234     *inout_len = (size_t)readcount;
    235     return (const unsigned char *)buf;
    236 }
    237