title: How to read from Windows Named Pipe with timeout?
body: <p>I'm trying to port something that is very easy in Unix to Windows: reading from a named pipe (fifo) with timeout when nothing happened.
  I'm trying to do it in a simple way (using <code>PeekNamedPipe</code>), without using overlapped IO. Is this possible?</p>
  
  <p>Below is a complete example. It doesn't work for the moment: The written string is not received, and the reader gets</p>
  
  <blockquote>
    <p>ERROR_NO_DATA    232 (0xE8)    The pipe is being closed</p>
  </blockquote>
  
  <p>after the first read, and the writer gets this after some tries</p>
  
  <blockquote>
    <p>ERROR_SEM_TIMEOUT    121 (0x79)    The semaphore timeout period has expired</p>
  </blockquote>
  
  <p>The test writer (pipe client):</p>
  
  <pre><code>#include "Windows.h"
  #include &lt;iostream&gt;
  #include &lt;stdio.h&gt;
  #include &lt;errno.h&gt;
  
  int main()
  {
      HANDLE hpipe;
      DWORD written;
      const char *pname = "\\\\.\\pipe\\isp-control";
      char msg[] = "play asdf.wav";
  
      printf("waiting for pipe %s\n", pname);
      bool stat = WaitNamedPipeA(pname, 4000);
      printf("  --&gt; %d, error %d\n", stat, GetLastError());
  
      if (stat)
      {
          hpipe = CreateFileA(pname, GENERIC_WRITE | GENERIC_READ,
              0, NULL, OPEN_EXISTING, 0, NULL);
  
          if (hpipe != INVALID_HANDLE_VALUE)
          {
              bool stat = WriteFile(hpipe, msg, strlen(msg) + 1, &amp;written, NULL);
              printf("  wrote %d bytes of %d: '%s'\n", written, strlen(msg) + 1, msg);
              printf("  --&gt; %d, error %d\n", stat, GetLastError());
  
              CloseHandle(hpipe);
          }
          else
          {
              printf("error %d opening pipe (handle %d)\n", GetLastError(), (int) hpipe);
              return 1;
          }
      }
      return 0;
  }
  </code></pre>
  
  <p>The test reader (pipe server and client):</p>
  
  <pre><code>#include &lt;stdio.h&gt;
  #include &lt;iostream&gt;
  #include &lt;string&gt;
  #include "pipeio.hpp"
  
  int main (int argc, char *argv[])
  {
    std::string pipename = "\\\\.\\pipe\\isp-control";    // command input filename
    ISP::WindowsPipeIO io(pipename, 2);
  
    while (true)
    {
      // wait for pipe input in command string or timeout
      std::string cmdstr = io.wait();
      printf("got response: '%s'\n", cmdstr.c_str());
    }
  }
  </code></pre>
  
  <p>and the pipeio.hpp class, in the first #ifdef I left the Unix version to show what I'm trying to achieve:</p>
  
  <pre><code>#ifndef _PIPEIO_HPP_
  #define _PIPEIO_HPP_
  
  namespace ISP {
  
  /// interface for wrapper around named pipe
  class PipeIO
  {
  public:
    //virtual ~PipeIO ();
    virtual std::string wait () = 0;
  };
  
  #ifndef WIN32  /////////// Unix version
  #include &lt;errno.h&gt;
  
  /// MacOS/Linux wrapper around named pipe
  class UnixPipeIO : public PipeIO
  {
  public:
    UnixPipeIO (std::string name, double timeout)
    : name_(name)
    {
      // open control and status pipes
      filedes_ = open(name_.c_str(), O_RDWR | O_NONBLOCK);
      if (filedes_ &lt; 0)
        throw std::runtime_error("can't open pipe");
  
      timeout_.tv_sec  = timeout; // todo: use fractional
      timeout_.tv_usec = 0;
    }
  
    std::string wait ()
    {
      FD_ZERO(&amp;input_);
      FD_SET(filedes_, &amp;input_);
  
      // wait for commands
      //db printf("waiting for fd %d...\n", filedes_);
      int ready = select(filedes_ + 1, &amp;input_, NULL, NULL, &amp;timeout_);
  
      if (ready &gt; 0  &amp;&amp;  FD_ISSET(filedes_, &amp;input_))
      { // ctl input has data, read and parse
        //db printf("fd %d is ready.\n", filedes_);
        int nread = read(filedes_, command_, CTL_INPUT_SIZE);
        command_[nread] = 0;  // null-terminate
        //db printf("read command (nread %d): '%s'\n", nread, nread &gt; 0 ? command_ : "");
  
        //todo: continue reading when more than CTL_INPUT_SIZE chars are available
        //todo: stop at \0? continue when called again
        return std::string(command_);
      }
      else if (ready == 0)
      {
        //db printf("timeout\n");
        return "timeout";
      }
      else
      {
        fprintf(stderr, "error %d in select: %s\n", errno, strerror(errno));
        return "ioerror";
      }
    }
  
  private:
    std::string name_;    //&lt; name of pipe
    int filedes_;
    struct timeval timeout_;
    fd_set input_;
    static const long CTL_INPUT_SIZE = 65535;
    char command_[CTL_INPUT_SIZE];
  };
  
  #else   /////////////////////// Windows
  
  #define NOMINMAX
  #include "Windows.h"
  #include &lt;errno.h&gt;
  
  /// Windows wrapper around named pipe
  class WindowsPipeIO : public PipeIO
  {
  public:
    WindowsPipeIO (std::string name, double timeout)
    : name_(name), timeout_((int) (timeout * 1000.))
    {
      printf("windowspipeio %s timeout %d ms\n", name_.c_str(), timeout_);
  
      // open control and status pipes
      hpipe_ = CreateNamedPipeA(name_.c_str(),
                   PIPE_ACCESS_DUPLEX,
                   PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_NOWAIT,
                   4, // num. instances
                   1024 * 16, // output buffer size
                   CTL_INPUT_SIZE,  // input size
                   timeout_, // default timeout ms 
                   NULL);
      if (hpipe_ == INVALID_HANDLE_VALUE)
        throw std::runtime_error("can't create pipe " + name);
  
      // open read handle
      hread_ = CreateFileA(name_.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
  
      if (hread_ == INVALID_HANDLE_VALUE)
        throw std::runtime_error("can't open read handle " + name);
  
      printf("  windowspipeio created pipe %d, read %d\n", (int) hpipe_, (int) hread_);
    }
  
    ~WindowsPipeIO()
    {
      CloseHandle(hread_);
  
      printf("~windowspipeio disconnect %s\n", name_.c_str());
      DisconnectNamedPipe(hpipe_);
      printf("~windowspipeio close %s\n", name_.c_str());
      CloseHandle(hpipe_);
    }
  
    std::string wait ()
    {
      DWORD dwRead;
  
      // wait for commands
      if (hpipe_ != INVALID_HANDLE_VALUE  &amp;&amp;  hread_ != INVALID_HANDLE_VALUE)
      {
        //db
        printf("waiting for connection for pipe %s handle %d\n", name_.c_str(), (int) hpipe_);
        bool stat   = ConnectNamedPipe(hpipe_, NULL);
        int  winerr = GetLastError();
        printf("  --&gt; status %d error %d\n", stat, winerr);
  
        if (winerr == ERROR_PIPE_CONNECTED)
        { // connection is good
  
      // instead of going through implementing "overlapped i/o", we simply peek into the pipe to see if data is available
      DWORD nready = 0;
      if (PeekNamedPipe(hpipe_, NULL, 0, NULL, &amp;nready, NULL) == 0)
        fprintf(stderr, "error %d peeking into pipe: %s\n", GetLastError(), strerror(errno));
  
      printf("pipe connected and peeked at %d bytes\n", nready);
  
      if (nready &gt; 0)
      { // data available
        printf("  pipe %s has available %d bytes\n", name_.c_str(), nready);
  
        while (ReadFile(hread_, command_, CTL_INPUT_SIZE - 1, &amp;dwRead, NULL) != FALSE)
        {
          /* add terminating zero */
          command_[dwRead] = '\0';
          //db
          printf("  read command (%d bytes): '%s'\n", dwRead, dwRead &gt; 0 ? command_ : "");
  
          //todo: continue reading when more than CTL_INPUT_SIZE chars are available
          //todo: stop at \0? continue when called again
          return std::string(command_);
        }
  
        printf("  hmmm, read %d, but there should have been %d bytes (error %d)\n", dwRead, nready, GetLastError());
      }
      // else: no data available: timeout
  
      DisconnectNamedPipe(hpipe_);
      printf("disconnected from pipe (error %d)\n", GetLastError());
        }
        // else: no client connected: timeout
  
        //db
        printf("timeout\n");
        Sleep(timeout_);
        return "timeout";
      }
      else
      {
        fprintf(stderr, "error %d (invalid pipe handle): %s\n", errno, strerror(errno));
        return "ioerror";
      }
    }
  
  private:
    std::string name_;    //&lt; name of pipe
    int timeout_; //ms
    HANDLE hpipe_;
    HANDLE hread_;
    static const long CTL_INPUT_SIZE = 65535;
    char command_[CTL_INPUT_SIZE];
  };
  
  #endif
  
  } // end namespace ISP
  
  #endif // _PIPEIO_HPP_
  </code></pre>