You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@thrift.apache.org by Peace <pc...@yahoo.com> on 2011/12/02 00:24:18 UTC

Pipe transport for Windows

Hello group,

I am implementing Named and Anonymous Pipes transport for Thrift on the Windows platform.  The motivation for this is to provide a lightweight local IPC transport for applications that run entirely on one system. Unix already has domain sockets support in the TSocket transport but that does not work on Windows.  I would have preferred a cross-platform solution but Windows pipes are much too different from the Unix implementations. What are your thoughts on submitting this for possible inclusion?  Would a Windows-only transport bother people?  Is there a better way to accomplish this?


Regards,
Peace

Re: Pipe transport for Windows

Posted by Peace <pc...@yahoo.com>.
Hey guys, sorry for the late response. I've been heads down implementing anonymous pipe transport and now have that working in the TPipe / TPipeServer classes.  Now that I've got something working I can start mapping that onto cross-platform code. I'm still digesting Rush's Asio implementation and agree it's an impressive body of work.  I may have to take some of this discussion offline with Rush & Alex to try to get this pulled together.  For instance I'm still trying to understand why a sockets style transport is used for the local transports.  The Windows Pipe transports are a much better fit in the file type of transports. There are significant differences though and a number of Windows-specific calls that I'm afraid can't avoid #ifdef's.


-Peace


________________________________
 From: Rush Manbert <ru...@manbert.com>
To: user@thrift.apache.org 
Sent: Tuesday, December 6, 2011 4:29 PM
Subject: Re: Pipe transport for Windows
 
Hi Alex,

Replies inline.

On Dec 5, 2011, at 10:13 PM, Alex Parenteau wrote:

> I was looking at the patch, and it is fantastic! Very inlined with what I would have hoped for thrift (i.e. a boost::asio implementation)

Gosh, thanks. I'm blushing. ;-)

> 
> Me wondering whether re-submitting the patch, on top of actual thrift trunk, would have more chances to go in this time. I did not read yet the arguments that lead to suspend it, but from what I see the boost::asio implementation is fairly large, and would benefit IMHO to:

I think the JIRA incident contains a long, extended conversation about the patch contents. At the time I submitted it, there was no one who could maintain it. I certainly can't. It was also a BIG piece of work to review and digest, and there wasn't anyone else around who needed it enough to take that on. I fixed bugs in places that were unexpected, like the threading implementation, and that made the whole thing more "dangerous" in some sense. Eventually, the code base passed it by, and I don't know how hard it would be to resurrect it now.

> 
> - create a parallel structure, for easy integration, and comparison sake between libevent/threadpool.

I'm not sure I understand this comment. Everything I did was done in parallel with the original implementation. The ASIO-based classes are parallel with the original classes, and at config time you decide which implementation you use. The class names do not change, only the underlying implementation. I did it this way because I knew there were users (Facebook) that would not be interested in an ASIO re-implementation. They had honed the *nix code and it had to be undisturbed.

> - make it a linux/windows/mac story, not windows-only (or may be I'm misunderstanding the purpose for the patch)

The patched code is indeed a linux/windows/mac story. My goal was to have Mac and Windows, because that's what we support where I work. But a very knowledgable fellow named Bruce Simpson became interested in it just as I was getting to the point where a beta tester would be a good thing. He tested it in a number of Linux environments and helped me a great deal to work through the issues he discovered.

> - integrate/enhance the existing thrift test infrastructure with the stress program you created (as opposed to something else, not sure what I'm saying here)

The stress test existed before I started. I just added capability to it. It's really useful. Is it not available in the current sources?

I think I also wrote a pretty good test of the thread scheduler that's in there somewhere. My version probably runs it as part of "make check".

> 
> Let me know if I could help somehow, I would love to work on a github fork on this matter (may be helping Peace?!), with the goal to present a case to Roger and al, and all the thrift developers.

We would love for this work to be included in the trunk, so we're not forked forever. I know that Thrift 1031 is a version that uses the Windows version of pthreads, but we need something that is unencumbered with LGPL licensing, so the total boost approach works well for us.

As I said in my JIRA comment of 7 October 2010, I'm not in a position where I can work on this. I did the original work because the company I work for needed it and I did the work during my normal work day. I really don't have time to work on this outside of work. Steven Knight worked on applying the work to the 0.4.0 code base, but wasn't able to finish. He uploaded a patch for what he had. Richard Swift was interested, but they must have gone some other way, because AFAICT, he disappeared after Oct. 2010.

I haver found a couple of bugs in my implementation over the past couple years. I thought I uploaded corrected files, but I don't see them in the JIRA. I could certainly fish them out of our local SVN repository.

> 
> One feature I did not see though, is the usage of thread pool for client connections: I guess it would not be too hard to implement, but I digress.

I implemented all of the clients and servers that existed in the C++ library at the time I did the work. And now it's been more than 2 years since I finished, so my memories of what's there have dimmed somewhat. I would think that if this was resurrected now, the same approach would apply. Just do a parallel implementation of everything the *nix library does.

Best regards,
Rush 

> 
> alex
> 
> -----Original Message-----
> From: Rush Manbert [mailto:rush@manbert.com] 
> Sent: Friday, December 02, 2011 6:07 PM
> To: user@thrift.apache.org
> Subject: Re: Pipe transport for Windows
> 
> Hi Peace,
> 
> No, I'm sorry to say that none of that code ever got brought into the trunk. We use it, and I know of a couple other commercial sites that use it as well, but that's all. (Although an interesting side effect is that I get occasional job offer feelers that are obviously motivated by someone knowing about that code.)
> 
> If you take a look at the 591 JIRA, you will see a file named "thrift-818530-patched.zip". That has the patch applied to the thrift source tree at svn rev 818530, which was current when I submitted it. So you can just download that and unzip it.
> 
> I don't know how well it meshes with the current sources, and if you have already done the work it's probably not that useful to you anyway, but it's written in the Thrift style, and is just another socket type that can be used with the other pieces. We use it all the time in our code.
> 
> One thing I'll mention that might be helpful to you. When I was doing my Windows port the most useful test I found was the stress test program. It can really hammer on the server side and it revealed quite a few bugs for me. My patched code includes a greatly (IMHO) improved version of the stress test that can use many different server and socket types, including the domain sockets and named pipe sockets. You'd have to make some changes, because I put the two types under (IIRC) TLocalSocket or some such, so the code that uses it can be cross platform. But it might be worth your while to see if it can help you. I found a lot of strange, undocumented named pipe behaviors that way.
> 
> Best regards,
> Rush
> 
> On Dec 2, 2011, at 12:32 PM, Peace wrote:
> 
>> Rush - Would you mind uploading your individual files (not in patch form) relevant to the pipes code? Did you incorporate it into the TSocket transport?  I appreciate your work in this area and apologize for overlooking 591. I may have viewed it a while ago and there has been so much activity on the Windows front that I assumed its contents had been incorporated by now.
>> 
>> 
>> Alex - Thanks for the example code and suggesting boost::asio (same to Rush). Is your approach intended to create a new server type?
>> 
>> 
>> 
>> Architecturally my preference is for an independent pipe transport that can be mixed & matched with any server. Well, any server that accepts a Thrift transport. With the Windows fix for 'regular' servers (THRIFT-1433), I am able to pass either TSocket / TServerSocket -or- TPipe / TServerPipe transports to the same TThreadPoolServer (TPipe is my unsubmitted named pipe transport). It just works by leveraging Thrift's layered architecture.
>> In the process of creating the pipe transport, I spent a good amount of time wading through the T[Server]Socket code trying to understand how the callbacks were processed. The TPipe transport is far less wordy by comparison. Cramming windows pipes into the existing TSocket transport would add to its complexity making it that much more difficult to maintain & debug.  I'm not intimately familiar with programming Unix domain sockets but at a high level it seems to mesh directly with sockets calls. It would make sense for that to stay there since it leverages so much of the TSocket code.  Windows named pipes are quite a different beast though and TSocket isn't the best fit.
>> 
>> 
>> I've been fortunate to be able to take the time to work on pipes but work priorities will change soon. I'd hate to see this implementation fall by the wayside as it seems to be working well and is cleanly partitioned from other modules.
>> 
>> 
>> -Peace
>> 
>> 
>> 
>> ________________________________
>> From: Rush Manbert <ru...@manbert.com>
>> To: user@thrift.apache.org 
>> Cc: 'Peace' <pc...@yahoo.com> 
>> Sent: Friday, December 2, 2011 1:04 PM
>> Subject: Re: Pipe transport for Windows
>> 
>> I don't want to be snarky, but you guys who are interested in having WIndows libraries are slowly reproducing the work I already did and submitted as part of https://issues.apache.org/jira/browse/THRIFT-591.
>> 
>> This includes a full ASIO based implementation of local sockets, implemented as Unix domain sockets on *nix, and Windows named pipes on Windows. It won't apply against the current sources, but the named pipe stuff was all new code anyway.
>> 
>> - Rush
>> 
>> On Dec 2, 2011, at 10:47 AM, Alex Parenteau wrote:
>> 
>>> Hi Peace,
>>> 
>>> I would use boost::asio, and use the ability of it to handle Windows/Posix file descriptors.
>>> 
>>> Below are some snippets of code that might help illustrate this (don't try to compile!)
>>> 
>>> I don't know much of the pipe transport in thrift, so this may not be applicable to your question.
>>> 
>>> As an orthogonal thought, I was wondering if anybody has put some thought around using boost::asio for async thrift servers (right now using libevent).
>>> 
>>> Regards,
>>> alex
>>> 
>>> #include <boost/asio.hpp> 
>>> #include <boost/system/windows_error.hpp>
>>> 
>>> #ifdef DVA_OS_WIN
>>>    using boost::asio::windows::stream_handle;
>>>    typedef stream_handle platform_stream;
>>>    typedef HANDLE platform_descriptor;
>>> #    define PIPE_EOF_ERROR_CODE boost::system::windows_error::broken_pipe
>>> #else
>>>    using boost::asio::posix::stream_descriptor;
>>>    typedef stream_descriptor platform_stream;
>>>    typedef int platform_descriptor;
>>> #    define PIPE_EOF_ERROR_CODE boost::asio::error::eof
>>> #endif
>>> 
>>>    boost::asio::io_service io_service_;
>>>    platform_stream pipe_;
>>>    std::vector<char> data_;
>>>    bool done_;
>>>    bool error_;
>>>    size_t total_size_;
>>>    boost::asio::strand strand_;
>>>    boost::thread thread_;
>>> 
>>> PipeSession(platform_descriptor fd) :
>>>        io_service_(), pipe_(io_service_, fd),
>>> {
>>> }
>>> 
>>> bool PipeSession ::start()
>>> {
>>> #ifdef LINUX
>>>    for (;;)
>>>    {
>>>        boost::asio::posix::descriptor_base::bytes_readable command(true);
>>>        pipe_.io_control(command);
>>>        std::size_t bytes_readable = command.get();
>>> 
>>>        if(bytes_readable) {
>>>            break;
>>>        }
>>>    }
>>> #endif
>>>    _thread = boost::thread(boost::bind(&PipeSession::run))
>>> 
>>>    return true;
>>> }
>>> 
>>> void PipeSession ::run() {
>>>    try {
>>>        pipe_.async_read_some(boost::asio::buffer(data_),
>>>            strand_.wrap(boost::bind(&PipeSession::handle_read,
>>>            this, boost::asio::placeholders::error,
>>>            boost::asio::placeholders::bytes_transferred)));
>>> 
>>>            std::size_t num = io_service_.run();
>>> 
>>>        } catch(const boost::system::system_error& e) {
>>>            done_ = true;
>>>            if(e.code() != PIPE_EOF_ERROR_CODE)
>>>                throw;
>>>        }
>>> 
>>>    static platform_descriptor CreatePipeFD(const std::string& pipeName, bool readFlag) {
>>> #ifdef WIN32
>>>        HANDLE fd = CreateNamedPipe( 
>>>            pipeName.c_str(),    // pipe name 
>>>            PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,       // read/write access TODO PIPE_ACCESS_INBOUND? PIPE_ACCESS_OUTBOUND?
>>>            PIPE_TYPE_BYTE |          // byte type pipe 
>>>            PIPE_READMODE_BYTE |      // byte-read mode 
>>>            PIPE_WAIT,                // blocking mode 
>>>            PIPE_UNLIMITED_INSTANCES, // max. instances  
>>>            BUFSIZE,                  // output buffer size 
>>>            BUFSIZE,                  // input buffer size 
>>>            0,                        // client time-out 
>>>            NULL);                    // default security attribute 
>>> 
>>>        if(fd == INVALID_HANDLE_VALUE) {
>>>            throw std::runtime_error("CreateNamedPipe failed");
>>>        }
>>> 
>>>        OVERLAPPED overlapped = {0};
>>>        overlapped.hEvent = CreateEvent(0,TRUE,FALSE,0);
>>>        if(ConnectNamedPipe(fd, &overlapped) != FALSE || GetLastError() != ERROR_IO_PENDING) {
>>>            CloseHandle(overlapped.hEvent);
>>>            CloseHandle(fd);
>>>            throw std::runtime_error("ConnectNamedPipe failed");
>>>        }
>>> #else
>>>        if(mkfifo(pipeName .c_str(), 0660) < 0) {
>>>            throw std::runtime_error("fifo failed");
>>>        }
>>> 
>>>        int fd = open(pipeName c_str(), (readFlag ? O_RDONLY : O_RDWR) | O_NONBLOCK);
>>>        if(fd <= 0) {
>>>            throw std::runtime_error("open failed");
>>>        }
>>> #endif
>>> 
>>> #ifdef WIN32
>>>        DWORD waitRes;
>>>        if((waitRes = WaitForSingleObject(overlapped.hEvent, LAUNCH_TIMEOUT * 1000)) != WAIT_OBJECT_0) {
>>>            CloseHandle(overlapped.hEvent);
>>>            CloseHandle(fd);
>>>            throw std::runtime_error("WaitForSingleObject failed");
>>>        }
>>>        CloseHandle(overlapped.hEvent);
>>> 
>>> #endif
>>> 
>>>        return fd;
>>>    }
>>> }
>>> 
>>> -----Original Message-----
>>> From: Peace [mailto:pc_5@yahoo.com] 
>>> Sent: Thursday, December 01, 2011 3:24 PM
>>> To: user@thrift.apache.org
>>> Subject: Pipe transport for Windows
>>> 
>>> Hello group,
>>> 
>>> I am implementing Named and Anonymous Pipes transport for Thrift on the Windows platform.  The motivation for this is to provide a lightweight local IPC transport for applications that run entirely on one system. Unix already has domain sockets support in the TSocket transport but that does not work on Windows.  I would have preferred a cross-platform solution but Windows pipes are much too different from the Unix implementations. What are your thoughts on submitting this for possible inclusion?  Would a Windows-only transport bother people?  Is there a better way to accomplish this?
>>> 
>>> 
>>> Regards,
>>> Peace

Re: Pipe transport for Windows

Posted by Rush Manbert <ru...@manbert.com>.
Hi Alex,

Replies inline.

On Dec 5, 2011, at 10:13 PM, Alex Parenteau wrote:

> I was looking at the patch, and it is fantastic! Very inlined with what I would have hoped for thrift (i.e. a boost::asio implementation)

Gosh, thanks. I'm blushing. ;-)

> 
> Me wondering whether re-submitting the patch, on top of actual thrift trunk, would have more chances to go in this time. I did not read yet the arguments that lead to suspend it, but from what I see the boost::asio implementation is fairly large, and would benefit IMHO to:

I think the JIRA incident contains a long, extended conversation about the patch contents. At the time I submitted it, there was no one who could maintain it. I certainly can't. It was also a BIG piece of work to review and digest, and there wasn't anyone else around who needed it enough to take that on. I fixed bugs in places that were unexpected, like the threading implementation, and that made the whole thing more "dangerous" in some sense. Eventually, the code base passed it by, and I don't know how hard it would be to resurrect it now.

> 
> - create a parallel structure, for easy integration, and comparison sake between libevent/threadpool.

I'm not sure I understand this comment. Everything I did was done in parallel with the original implementation. The ASIO-based classes are parallel with the original classes, and at config time you decide which implementation you use. The class names do not change, only the underlying implementation. I did it this way because I knew there were users (Facebook) that would not be interested in an ASIO re-implementation. They had honed the *nix code and it had to be undisturbed.

> - make it a linux/windows/mac story, not windows-only (or may be I'm misunderstanding the purpose for the patch)

The patched code is indeed a linux/windows/mac story. My goal was to have Mac and Windows, because that's what we support where I work. But a very knowledgable fellow named Bruce Simpson became interested in it just as I was getting to the point where a beta tester would be a good thing. He tested it in a number of Linux environments and helped me a great deal to work through the issues he discovered.

> - integrate/enhance the existing thrift test infrastructure with the stress program you created (as opposed to something else, not sure what I'm saying here)

The stress test existed before I started. I just added capability to it. It's really useful. Is it not available in the current sources?

I think I also wrote a pretty good test of the thread scheduler that's in there somewhere. My version probably runs it as part of "make check".

> 
> Let me know if I could help somehow, I would love to work on a github fork on this matter (may be helping Peace?!), with the goal to present a case to Roger and al, and all the thrift developers.

We would love for this work to be included in the trunk, so we're not forked forever. I know that Thrift 1031 is a version that uses the Windows version of pthreads, but we need something that is unencumbered with LGPL licensing, so the total boost approach works well for us.

As I said in my JIRA comment of 7 October 2010, I'm not in a position where I can work on this. I did the original work because the company I work for needed it and I did the work during my normal work day. I really don't have time to work on this outside of work. Steven Knight worked on applying the work to the 0.4.0 code base, but wasn't able to finish. He uploaded a patch for what he had. Richard Swift was interested, but they must have gone some other way, because AFAICT, he disappeared after Oct. 2010.

I haver found a couple of bugs in my implementation over the past couple years. I thought I uploaded corrected files, but I don't see them in the JIRA. I could certainly fish them out of our local SVN repository.

> 
> One feature I did not see though, is the usage of thread pool for client connections: I guess it would not be too hard to implement, but I digress.

I implemented all of the clients and servers that existed in the C++ library at the time I did the work. And now it's been more than 2 years since I finished, so my memories of what's there have dimmed somewhat. I would think that if this was resurrected now, the same approach would apply. Just do a parallel implementation of everything the *nix library does.

Best regards,
Rush 

> 
> alex
> 
> -----Original Message-----
> From: Rush Manbert [mailto:rush@manbert.com] 
> Sent: Friday, December 02, 2011 6:07 PM
> To: user@thrift.apache.org
> Subject: Re: Pipe transport for Windows
> 
> Hi Peace,
> 
> No, I'm sorry to say that none of that code ever got brought into the trunk. We use it, and I know of a couple other commercial sites that use it as well, but that's all. (Although an interesting side effect is that I get occasional job offer feelers that are obviously motivated by someone knowing about that code.)
> 
> If you take a look at the 591 JIRA, you will see a file named "thrift-818530-patched.zip". That has the patch applied to the thrift source tree at svn rev 818530, which was current when I submitted it. So you can just download that and unzip it.
> 
> I don't know how well it meshes with the current sources, and if you have already done the work it's probably not that useful to you anyway, but it's written in the Thrift style, and is just another socket type that can be used with the other pieces. We use it all the time in our code.
> 
> One thing I'll mention that might be helpful to you. When I was doing my Windows port the most useful test I found was the stress test program. It can really hammer on the server side and it revealed quite a few bugs for me. My patched code includes a greatly (IMHO) improved version of the stress test that can use many different server and socket types, including the domain sockets and named pipe sockets. You'd have to make some changes, because I put the two types under (IIRC) TLocalSocket or some such, so the code that uses it can be cross platform. But it might be worth your while to see if it can help you. I found a lot of strange, undocumented named pipe behaviors that way.
> 
> Best regards,
> Rush
> 
> On Dec 2, 2011, at 12:32 PM, Peace wrote:
> 
>> Rush - Would you mind uploading your individual files (not in patch form) relevant to the pipes code? Did you incorporate it into the TSocket transport?  I appreciate your work in this area and apologize for overlooking 591. I may have viewed it a while ago and there has been so much activity on the Windows front that I assumed its contents had been incorporated by now.
>> 
>> 
>> Alex - Thanks for the example code and suggesting boost::asio (same to Rush). Is your approach intended to create a new server type?
>> 
>> 
>> 
>> Architecturally my preference is for an independent pipe transport that can be mixed & matched with any server. Well, any server that accepts a Thrift transport. With the Windows fix for 'regular' servers (THRIFT-1433), I am able to pass either TSocket / TServerSocket -or- TPipe / TServerPipe transports to the same TThreadPoolServer (TPipe is my unsubmitted named pipe transport). It just works by leveraging Thrift's layered architecture.
>> In the process of creating the pipe transport, I spent a good amount of time wading through the T[Server]Socket code trying to understand how the callbacks were processed. The TPipe transport is far less wordy by comparison. Cramming windows pipes into the existing TSocket transport would add to its complexity making it that much more difficult to maintain & debug.  I'm not intimately familiar with programming Unix domain sockets but at a high level it seems to mesh directly with sockets calls. It would make sense for that to stay there since it leverages so much of the TSocket code.  Windows named pipes are quite a different beast though and TSocket isn't the best fit.
>> 
>> 
>> I've been fortunate to be able to take the time to work on pipes but work priorities will change soon. I'd hate to see this implementation fall by the wayside as it seems to be working well and is cleanly partitioned from other modules.
>> 
>> 
>> -Peace
>> 
>> 
>> 
>> ________________________________
>> From: Rush Manbert <ru...@manbert.com>
>> To: user@thrift.apache.org 
>> Cc: 'Peace' <pc...@yahoo.com> 
>> Sent: Friday, December 2, 2011 1:04 PM
>> Subject: Re: Pipe transport for Windows
>> 
>> I don't want to be snarky, but you guys who are interested in having WIndows libraries are slowly reproducing the work I already did and submitted as part of https://issues.apache.org/jira/browse/THRIFT-591.
>> 
>> This includes a full ASIO based implementation of local sockets, implemented as Unix domain sockets on *nix, and Windows named pipes on Windows. It won't apply against the current sources, but the named pipe stuff was all new code anyway.
>> 
>> - Rush
>> 
>> On Dec 2, 2011, at 10:47 AM, Alex Parenteau wrote:
>> 
>>> Hi Peace,
>>> 
>>> I would use boost::asio, and use the ability of it to handle Windows/Posix file descriptors.
>>> 
>>> Below are some snippets of code that might help illustrate this (don't try to compile!)
>>> 
>>> I don't know much of the pipe transport in thrift, so this may not be applicable to your question.
>>> 
>>> As an orthogonal thought, I was wondering if anybody has put some thought around using boost::asio for async thrift servers (right now using libevent).
>>> 
>>> Regards,
>>> alex
>>> 
>>> #include <boost/asio.hpp> 
>>> #include <boost/system/windows_error.hpp>
>>> 
>>> #ifdef DVA_OS_WIN
>>>    using boost::asio::windows::stream_handle;
>>>    typedef stream_handle platform_stream;
>>>    typedef HANDLE platform_descriptor;
>>> #    define PIPE_EOF_ERROR_CODE boost::system::windows_error::broken_pipe
>>> #else
>>>    using boost::asio::posix::stream_descriptor;
>>>    typedef stream_descriptor platform_stream;
>>>    typedef int platform_descriptor;
>>> #    define PIPE_EOF_ERROR_CODE boost::asio::error::eof
>>> #endif
>>> 
>>>    boost::asio::io_service io_service_;
>>>    platform_stream pipe_;
>>>    std::vector<char> data_;
>>>    bool done_;
>>>    bool error_;
>>>    size_t total_size_;
>>>    boost::asio::strand strand_;
>>>    boost::thread thread_;
>>> 
>>> PipeSession(platform_descriptor fd) :
>>>        io_service_(), pipe_(io_service_, fd),
>>> {
>>> }
>>> 
>>> bool PipeSession ::start()
>>> {
>>> #ifdef LINUX
>>>    for (;;)
>>>    {
>>>        boost::asio::posix::descriptor_base::bytes_readable command(true);
>>>        pipe_.io_control(command);
>>>        std::size_t bytes_readable = command.get();
>>> 
>>>        if(bytes_readable) {
>>>            break;
>>>        }
>>>    }
>>> #endif
>>>    _thread = boost::thread(boost::bind(&PipeSession::run))
>>> 
>>>    return true;
>>> }
>>> 
>>> void PipeSession ::run() {
>>>    try {
>>>        pipe_.async_read_some(boost::asio::buffer(data_),
>>>            strand_.wrap(boost::bind(&PipeSession::handle_read,
>>>            this, boost::asio::placeholders::error,
>>>            boost::asio::placeholders::bytes_transferred)));
>>> 
>>>            std::size_t num = io_service_.run();
>>> 
>>>        } catch(const boost::system::system_error& e) {
>>>            done_ = true;
>>>            if(e.code() != PIPE_EOF_ERROR_CODE)
>>>                throw;
>>>        }
>>> 
>>>    static platform_descriptor CreatePipeFD(const std::string& pipeName, bool readFlag) {
>>> #ifdef WIN32
>>>        HANDLE fd = CreateNamedPipe( 
>>>            pipeName.c_str(),    // pipe name 
>>>            PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,       // read/write access TODO PIPE_ACCESS_INBOUND? PIPE_ACCESS_OUTBOUND?
>>>            PIPE_TYPE_BYTE |          // byte type pipe 
>>>            PIPE_READMODE_BYTE |      // byte-read mode 
>>>            PIPE_WAIT,                // blocking mode 
>>>            PIPE_UNLIMITED_INSTANCES, // max. instances  
>>>            BUFSIZE,                  // output buffer size 
>>>            BUFSIZE,                  // input buffer size 
>>>            0,                        // client time-out 
>>>            NULL);                    // default security attribute 
>>> 
>>>        if(fd == INVALID_HANDLE_VALUE) {
>>>            throw std::runtime_error("CreateNamedPipe failed");
>>>        }
>>> 
>>>        OVERLAPPED overlapped = {0};
>>>        overlapped.hEvent = CreateEvent(0,TRUE,FALSE,0);
>>>        if(ConnectNamedPipe(fd, &overlapped) != FALSE || GetLastError() != ERROR_IO_PENDING) {
>>>            CloseHandle(overlapped.hEvent);
>>>            CloseHandle(fd);
>>>            throw std::runtime_error("ConnectNamedPipe failed");
>>>        }
>>> #else
>>>        if(mkfifo(pipeName .c_str(), 0660) < 0) {
>>>            throw std::runtime_error("fifo failed");
>>>        }
>>> 
>>>        int fd = open(pipeName c_str(), (readFlag ? O_RDONLY : O_RDWR) | O_NONBLOCK);
>>>        if(fd <= 0) {
>>>            throw std::runtime_error("open failed");
>>>        }
>>> #endif
>>> 
>>> #ifdef WIN32
>>>        DWORD waitRes;
>>>        if((waitRes = WaitForSingleObject(overlapped.hEvent, LAUNCH_TIMEOUT * 1000)) != WAIT_OBJECT_0) {
>>>            CloseHandle(overlapped.hEvent);
>>>            CloseHandle(fd);
>>>            throw std::runtime_error("WaitForSingleObject failed");
>>>        }
>>>        CloseHandle(overlapped.hEvent);
>>> 
>>> #endif
>>> 
>>>        return fd;
>>>    }
>>> }
>>> 
>>> -----Original Message-----
>>> From: Peace [mailto:pc_5@yahoo.com] 
>>> Sent: Thursday, December 01, 2011 3:24 PM
>>> To: user@thrift.apache.org
>>> Subject: Pipe transport for Windows
>>> 
>>> Hello group,
>>> 
>>> I am implementing Named and Anonymous Pipes transport for Thrift on the Windows platform.  The motivation for this is to provide a lightweight local IPC transport for applications that run entirely on one system. Unix already has domain sockets support in the TSocket transport but that does not work on Windows.  I would have preferred a cross-platform solution but Windows pipes are much too different from the Unix implementations. What are your thoughts on submitting this for possible inclusion?  Would a Windows-only transport bother people?  Is there a better way to accomplish this?
>>> 
>>> 
>>> Regards,
>>> Peace


RE: Pipe transport for Windows

Posted by Alex Parenteau <ap...@adobe.com>.
I was looking at the patch, and it is fantastic! Very inlined with what I would have hoped for thrift (i.e. a boost::asio implementation)

Me wondering whether re-submitting the patch, on top of actual thrift trunk, would have more chances to go in this time. I did not read yet the arguments that lead to suspend it, but from what I see the boost::asio implementation is fairly large, and would benefit IMHO to:

- create a parallel structure, for easy integration, and comparison sake between libevent/threadpool.
- make it a linux/windows/mac story, not windows-only (or may be I'm misunderstanding the purpose for the patch)
- integrate/enhance the existing thrift test infrastructure with the stress program you created (as opposed to something else, not sure what I'm saying here)

Let me know if I could help somehow, I would love to work on a github fork on this matter (may be helping Peace?!), with the goal to present a case to Roger and al, and all the thrift developers.

One feature I did not see though, is the usage of thread pool for client connections: I guess it would not be too hard to implement, but I digress.

alex

-----Original Message-----
From: Rush Manbert [mailto:rush@manbert.com] 
Sent: Friday, December 02, 2011 6:07 PM
To: user@thrift.apache.org
Subject: Re: Pipe transport for Windows

Hi Peace,

No, I'm sorry to say that none of that code ever got brought into the trunk. We use it, and I know of a couple other commercial sites that use it as well, but that's all. (Although an interesting side effect is that I get occasional job offer feelers that are obviously motivated by someone knowing about that code.)

If you take a look at the 591 JIRA, you will see a file named "thrift-818530-patched.zip". That has the patch applied to the thrift source tree at svn rev 818530, which was current when I submitted it. So you can just download that and unzip it.

I don't know how well it meshes with the current sources, and if you have already done the work it's probably not that useful to you anyway, but it's written in the Thrift style, and is just another socket type that can be used with the other pieces. We use it all the time in our code.

One thing I'll mention that might be helpful to you. When I was doing my Windows port the most useful test I found was the stress test program. It can really hammer on the server side and it revealed quite a few bugs for me. My patched code includes a greatly (IMHO) improved version of the stress test that can use many different server and socket types, including the domain sockets and named pipe sockets. You'd have to make some changes, because I put the two types under (IIRC) TLocalSocket or some such, so the code that uses it can be cross platform. But it might be worth your while to see if it can help you. I found a lot of strange, undocumented named pipe behaviors that way.

Best regards,
Rush

On Dec 2, 2011, at 12:32 PM, Peace wrote:

> Rush - Would you mind uploading your individual files (not in patch form) relevant to the pipes code? Did you incorporate it into the TSocket transport?  I appreciate your work in this area and apologize for overlooking 591. I may have viewed it a while ago and there has been so much activity on the Windows front that I assumed its contents had been incorporated by now.
> 
> 
> Alex - Thanks for the example code and suggesting boost::asio (same to Rush). Is your approach intended to create a new server type?
> 
> 
> 
> Architecturally my preference is for an independent pipe transport that can be mixed & matched with any server. Well, any server that accepts a Thrift transport. With the Windows fix for 'regular' servers (THRIFT-1433), I am able to pass either TSocket / TServerSocket -or- TPipe / TServerPipe transports to the same TThreadPoolServer (TPipe is my unsubmitted named pipe transport). It just works by leveraging Thrift's layered architecture.
> In the process of creating the pipe transport, I spent a good amount of time wading through the T[Server]Socket code trying to understand how the callbacks were processed. The TPipe transport is far less wordy by comparison. Cramming windows pipes into the existing TSocket transport would add to its complexity making it that much more difficult to maintain & debug.  I'm not intimately familiar with programming Unix domain sockets but at a high level it seems to mesh directly with sockets calls. It would make sense for that to stay there since it leverages so much of the TSocket code.  Windows named pipes are quite a different beast though and TSocket isn't the best fit.
> 
> 
> I've been fortunate to be able to take the time to work on pipes but work priorities will change soon. I'd hate to see this implementation fall by the wayside as it seems to be working well and is cleanly partitioned from other modules.
> 
> 
> -Peace
> 
> 
> 
> ________________________________
> From: Rush Manbert <ru...@manbert.com>
> To: user@thrift.apache.org 
> Cc: 'Peace' <pc...@yahoo.com> 
> Sent: Friday, December 2, 2011 1:04 PM
> Subject: Re: Pipe transport for Windows
> 
> I don't want to be snarky, but you guys who are interested in having WIndows libraries are slowly reproducing the work I already did and submitted as part of https://issues.apache.org/jira/browse/THRIFT-591.
> 
> This includes a full ASIO based implementation of local sockets, implemented as Unix domain sockets on *nix, and Windows named pipes on Windows. It won't apply against the current sources, but the named pipe stuff was all new code anyway.
> 
> - Rush
> 
> On Dec 2, 2011, at 10:47 AM, Alex Parenteau wrote:
> 
>> Hi Peace,
>> 
>> I would use boost::asio, and use the ability of it to handle Windows/Posix file descriptors.
>> 
>> Below are some snippets of code that might help illustrate this (don't try to compile!)
>> 
>> I don't know much of the pipe transport in thrift, so this may not be applicable to your question.
>> 
>> As an orthogonal thought, I was wondering if anybody has put some thought around using boost::asio for async thrift servers (right now using libevent).
>> 
>> Regards,
>> alex
>> 
>> #include <boost/asio.hpp> 
>> #include <boost/system/windows_error.hpp>
>> 
>> #ifdef DVA_OS_WIN
>>     using boost::asio::windows::stream_handle;
>>     typedef stream_handle platform_stream;
>>     typedef HANDLE platform_descriptor;
>> #    define PIPE_EOF_ERROR_CODE boost::system::windows_error::broken_pipe
>> #else
>>     using boost::asio::posix::stream_descriptor;
>>     typedef stream_descriptor platform_stream;
>>     typedef int platform_descriptor;
>> #    define PIPE_EOF_ERROR_CODE boost::asio::error::eof
>> #endif
>> 
>>     boost::asio::io_service io_service_;
>>     platform_stream pipe_;
>>     std::vector<char> data_;
>>     bool done_;
>>     bool error_;
>>     size_t total_size_;
>>     boost::asio::strand strand_;
>>     boost::thread thread_;
>> 
>> PipeSession(platform_descriptor fd) :
>>         io_service_(), pipe_(io_service_, fd),
>> {
>> }
>> 
>> bool PipeSession ::start()
>> {
>> #ifdef LINUX
>>     for (;;)
>>     {
>>         boost::asio::posix::descriptor_base::bytes_readable command(true);
>>         pipe_.io_control(command);
>>         std::size_t bytes_readable = command.get();
>> 
>>         if(bytes_readable) {
>>             break;
>>         }
>>     }
>> #endif
>>     _thread = boost::thread(boost::bind(&PipeSession::run))
>> 
>>     return true;
>> }
>> 
>> void PipeSession ::run() {
>>     try {
>>         pipe_.async_read_some(boost::asio::buffer(data_),
>>             strand_.wrap(boost::bind(&PipeSession::handle_read,
>>             this, boost::asio::placeholders::error,
>>             boost::asio::placeholders::bytes_transferred)));
>> 
>>             std::size_t num = io_service_.run();
>> 
>>         } catch(const boost::system::system_error& e) {
>>             done_ = true;
>>             if(e.code() != PIPE_EOF_ERROR_CODE)
>>                 throw;
>>         }
>> 
>>     static platform_descriptor CreatePipeFD(const std::string& pipeName, bool readFlag) {
>> #ifdef WIN32
>>         HANDLE fd = CreateNamedPipe( 
>>             pipeName.c_str(),    // pipe name 
>>             PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,       // read/write access TODO PIPE_ACCESS_INBOUND? PIPE_ACCESS_OUTBOUND?
>>             PIPE_TYPE_BYTE |          // byte type pipe 
>>             PIPE_READMODE_BYTE |      // byte-read mode 
>>             PIPE_WAIT,                // blocking mode 
>>             PIPE_UNLIMITED_INSTANCES, // max. instances  
>>             BUFSIZE,                  // output buffer size 
>>             BUFSIZE,                  // input buffer size 
>>             0,                        // client time-out 
>>             NULL);                    // default security attribute 
>> 
>>         if(fd == INVALID_HANDLE_VALUE) {
>>             throw std::runtime_error("CreateNamedPipe failed");
>>         }
>> 
>>         OVERLAPPED overlapped = {0};
>>         overlapped.hEvent = CreateEvent(0,TRUE,FALSE,0);
>>         if(ConnectNamedPipe(fd, &overlapped) != FALSE || GetLastError() != ERROR_IO_PENDING) {
>>             CloseHandle(overlapped.hEvent);
>>             CloseHandle(fd);
>>             throw std::runtime_error("ConnectNamedPipe failed");
>>         }
>> #else
>>         if(mkfifo(pipeName .c_str(), 0660) < 0) {
>>             throw std::runtime_error("fifo failed");
>>         }
>> 
>>         int fd = open(pipeName c_str(), (readFlag ? O_RDONLY : O_RDWR) | O_NONBLOCK);
>>         if(fd <= 0) {
>>             throw std::runtime_error("open failed");
>>         }
>> #endif
>> 
>> #ifdef WIN32
>>         DWORD waitRes;
>>         if((waitRes = WaitForSingleObject(overlapped.hEvent, LAUNCH_TIMEOUT * 1000)) != WAIT_OBJECT_0) {
>>             CloseHandle(overlapped.hEvent);
>>             CloseHandle(fd);
>>             throw std::runtime_error("WaitForSingleObject failed");
>>         }
>>         CloseHandle(overlapped.hEvent);
>> 
>> #endif
>> 
>>         return fd;
>>     }
>> }
>> 
>> -----Original Message-----
>> From: Peace [mailto:pc_5@yahoo.com] 
>> Sent: Thursday, December 01, 2011 3:24 PM
>> To: user@thrift.apache.org
>> Subject: Pipe transport for Windows
>> 
>> Hello group,
>> 
>> I am implementing Named and Anonymous Pipes transport for Thrift on the Windows platform.  The motivation for this is to provide a lightweight local IPC transport for applications that run entirely on one system. Unix already has domain sockets support in the TSocket transport but that does not work on Windows.  I would have preferred a cross-platform solution but Windows pipes are much too different from the Unix implementations. What are your thoughts on submitting this for possible inclusion?  Would a Windows-only transport bother people?  Is there a better way to accomplish this?
>> 
>> 
>> Regards,
>> Peace


Re: Pipe transport for Windows

Posted by Rush Manbert <ru...@manbert.com>.
Hi Peace,

No, I'm sorry to say that none of that code ever got brought into the trunk. We use it, and I know of a couple other commercial sites that use it as well, but that's all. (Although an interesting side effect is that I get occasional job offer feelers that are obviously motivated by someone knowing about that code.)

If you take a look at the 591 JIRA, you will see a file named "thrift-818530-patched.zip". That has the patch applied to the thrift source tree at svn rev 818530, which was current when I submitted it. So you can just download that and unzip it.

I don't know how well it meshes with the current sources, and if you have already done the work it's probably not that useful to you anyway, but it's written in the Thrift style, and is just another socket type that can be used with the other pieces. We use it all the time in our code.

One thing I'll mention that might be helpful to you. When I was doing my Windows port the most useful test I found was the stress test program. It can really hammer on the server side and it revealed quite a few bugs for me. My patched code includes a greatly (IMHO) improved version of the stress test that can use many different server and socket types, including the domain sockets and named pipe sockets. You'd have to make some changes, because I put the two types under (IIRC) TLocalSocket or some such, so the code that uses it can be cross platform. But it might be worth your while to see if it can help you. I found a lot of strange, undocumented named pipe behaviors that way.

Best regards,
Rush

On Dec 2, 2011, at 12:32 PM, Peace wrote:

> Rush - Would you mind uploading your individual files (not in patch form) relevant to the pipes code? Did you incorporate it into the TSocket transport?  I appreciate your work in this area and apologize for overlooking 591. I may have viewed it a while ago and there has been so much activity on the Windows front that I assumed its contents had been incorporated by now.
> 
> 
> Alex - Thanks for the example code and suggesting boost::asio (same to Rush). Is your approach intended to create a new server type?
> 
> 
> 
> Architecturally my preference is for an independent pipe transport that can be mixed & matched with any server. Well, any server that accepts a Thrift transport. With the Windows fix for 'regular' servers (THRIFT-1433), I am able to pass either TSocket / TServerSocket -or- TPipe / TServerPipe transports to the same TThreadPoolServer (TPipe is my unsubmitted named pipe transport). It just works by leveraging Thrift's layered architecture.
> In the process of creating the pipe transport, I spent a good amount of time wading through the T[Server]Socket code trying to understand how the callbacks were processed. The TPipe transport is far less wordy by comparison. Cramming windows pipes into the existing TSocket transport would add to its complexity making it that much more difficult to maintain & debug.  I'm not intimately familiar with programming Unix domain sockets but at a high level it seems to mesh directly with sockets calls. It would make sense for that to stay there since it leverages so much of the TSocket code.  Windows named pipes are quite a different beast though and TSocket isn't the best fit.
> 
> 
> I've been fortunate to be able to take the time to work on pipes but work priorities will change soon. I'd hate to see this implementation fall by the wayside as it seems to be working well and is cleanly partitioned from other modules.
> 
> 
> -Peace
> 
> 
> 
> ________________________________
> From: Rush Manbert <ru...@manbert.com>
> To: user@thrift.apache.org 
> Cc: 'Peace' <pc...@yahoo.com> 
> Sent: Friday, December 2, 2011 1:04 PM
> Subject: Re: Pipe transport for Windows
> 
> I don't want to be snarky, but you guys who are interested in having WIndows libraries are slowly reproducing the work I already did and submitted as part of https://issues.apache.org/jira/browse/THRIFT-591.
> 
> This includes a full ASIO based implementation of local sockets, implemented as Unix domain sockets on *nix, and Windows named pipes on Windows. It won't apply against the current sources, but the named pipe stuff was all new code anyway.
> 
> - Rush
> 
> On Dec 2, 2011, at 10:47 AM, Alex Parenteau wrote:
> 
>> Hi Peace,
>> 
>> I would use boost::asio, and use the ability of it to handle Windows/Posix file descriptors.
>> 
>> Below are some snippets of code that might help illustrate this (don't try to compile!)
>> 
>> I don't know much of the pipe transport in thrift, so this may not be applicable to your question.
>> 
>> As an orthogonal thought, I was wondering if anybody has put some thought around using boost::asio for async thrift servers (right now using libevent).
>> 
>> Regards,
>> alex
>> 
>> #include <boost/asio.hpp> 
>> #include <boost/system/windows_error.hpp>
>> 
>> #ifdef DVA_OS_WIN
>>     using boost::asio::windows::stream_handle;
>>     typedef stream_handle platform_stream;
>>     typedef HANDLE platform_descriptor;
>> #    define PIPE_EOF_ERROR_CODE boost::system::windows_error::broken_pipe
>> #else
>>     using boost::asio::posix::stream_descriptor;
>>     typedef stream_descriptor platform_stream;
>>     typedef int platform_descriptor;
>> #    define PIPE_EOF_ERROR_CODE boost::asio::error::eof
>> #endif
>> 
>>     boost::asio::io_service io_service_;
>>     platform_stream pipe_;
>>     std::vector<char> data_;
>>     bool done_;
>>     bool error_;
>>     size_t total_size_;
>>     boost::asio::strand strand_;
>>     boost::thread thread_;
>> 
>> PipeSession(platform_descriptor fd) :
>>         io_service_(), pipe_(io_service_, fd),
>> {
>> }
>> 
>> bool PipeSession ::start()
>> {
>> #ifdef LINUX
>>     for (;;)
>>     {
>>         boost::asio::posix::descriptor_base::bytes_readable command(true);
>>         pipe_.io_control(command);
>>         std::size_t bytes_readable = command.get();
>> 
>>         if(bytes_readable) {
>>             break;
>>         }
>>     }
>> #endif
>>     _thread = boost::thread(boost::bind(&PipeSession::run))
>> 
>>     return true;
>> }
>> 
>> void PipeSession ::run() {
>>     try {
>>         pipe_.async_read_some(boost::asio::buffer(data_),
>>             strand_.wrap(boost::bind(&PipeSession::handle_read,
>>             this, boost::asio::placeholders::error,
>>             boost::asio::placeholders::bytes_transferred)));
>> 
>>             std::size_t num = io_service_.run();
>> 
>>         } catch(const boost::system::system_error& e) {
>>             done_ = true;
>>             if(e.code() != PIPE_EOF_ERROR_CODE)
>>                 throw;
>>         }
>> 
>>     static platform_descriptor CreatePipeFD(const std::string& pipeName, bool readFlag) {
>> #ifdef WIN32
>>         HANDLE fd = CreateNamedPipe( 
>>             pipeName.c_str(),    // pipe name 
>>             PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,       // read/write access TODO PIPE_ACCESS_INBOUND? PIPE_ACCESS_OUTBOUND?
>>             PIPE_TYPE_BYTE |          // byte type pipe 
>>             PIPE_READMODE_BYTE |      // byte-read mode 
>>             PIPE_WAIT,                // blocking mode 
>>             PIPE_UNLIMITED_INSTANCES, // max. instances  
>>             BUFSIZE,                  // output buffer size 
>>             BUFSIZE,                  // input buffer size 
>>             0,                        // client time-out 
>>             NULL);                    // default security attribute 
>> 
>>         if(fd == INVALID_HANDLE_VALUE) {
>>             throw std::runtime_error("CreateNamedPipe failed");
>>         }
>> 
>>         OVERLAPPED overlapped = {0};
>>         overlapped.hEvent = CreateEvent(0,TRUE,FALSE,0);
>>         if(ConnectNamedPipe(fd, &overlapped) != FALSE || GetLastError() != ERROR_IO_PENDING) {
>>             CloseHandle(overlapped.hEvent);
>>             CloseHandle(fd);
>>             throw std::runtime_error("ConnectNamedPipe failed");
>>         }
>> #else
>>         if(mkfifo(pipeName .c_str(), 0660) < 0) {
>>             throw std::runtime_error("fifo failed");
>>         }
>> 
>>         int fd = open(pipeName c_str(), (readFlag ? O_RDONLY : O_RDWR) | O_NONBLOCK);
>>         if(fd <= 0) {
>>             throw std::runtime_error("open failed");
>>         }
>> #endif
>> 
>> #ifdef WIN32
>>         DWORD waitRes;
>>         if((waitRes = WaitForSingleObject(overlapped.hEvent, LAUNCH_TIMEOUT * 1000)) != WAIT_OBJECT_0) {
>>             CloseHandle(overlapped.hEvent);
>>             CloseHandle(fd);
>>             throw std::runtime_error("WaitForSingleObject failed");
>>         }
>>         CloseHandle(overlapped.hEvent);
>> 
>> #endif
>> 
>>         return fd;
>>     }
>> }
>> 
>> -----Original Message-----
>> From: Peace [mailto:pc_5@yahoo.com] 
>> Sent: Thursday, December 01, 2011 3:24 PM
>> To: user@thrift.apache.org
>> Subject: Pipe transport for Windows
>> 
>> Hello group,
>> 
>> I am implementing Named and Anonymous Pipes transport for Thrift on the Windows platform.  The motivation for this is to provide a lightweight local IPC transport for applications that run entirely on one system. Unix already has domain sockets support in the TSocket transport but that does not work on Windows.  I would have preferred a cross-platform solution but Windows pipes are much too different from the Unix implementations. What are your thoughts on submitting this for possible inclusion?  Would a Windows-only transport bother people?  Is there a better way to accomplish this?
>> 
>> 
>> Regards,
>> Peace


Re: Pipe transport for Windows

Posted by Peace <pc...@yahoo.com>.
Rush - Would you mind uploading your individual files (not in patch form) relevant to the pipes code? Did you incorporate it into the TSocket transport?  I appreciate your work in this area and apologize for overlooking 591. I may have viewed it a while ago and there has been so much activity on the Windows front that I assumed its contents had been incorporated by now.


Alex - Thanks for the example code and suggesting boost::asio (same to Rush). Is your approach intended to create a new server type?



Architecturally my preference is for an independent pipe transport that can be mixed & matched with any server. Well, any server that accepts a Thrift transport. With the Windows fix for 'regular' servers (THRIFT-1433), I am able to pass either TSocket / TServerSocket -or- TPipe / TServerPipe transports to the same TThreadPoolServer (TPipe is my unsubmitted named pipe transport). It just works by leveraging Thrift's layered architecture.
In the process of creating the pipe transport, I spent a good amount of time wading through the T[Server]Socket code trying to understand how the callbacks were processed. The TPipe transport is far less wordy by comparison. Cramming windows pipes into the existing TSocket transport would add to its complexity making it that much more difficult to maintain & debug.  I'm not intimately familiar with programming Unix domain sockets but at a high level it seems to mesh directly with sockets calls. It would make sense for that to stay there since it leverages so much of the TSocket code.  Windows named pipes are quite a different beast though and TSocket isn't the best fit.


I've been fortunate to be able to take the time to work on pipes but work priorities will change soon. I'd hate to see this implementation fall by the wayside as it seems to be working well and is cleanly partitioned from other modules.


-Peace



________________________________
 From: Rush Manbert <ru...@manbert.com>
To: user@thrift.apache.org 
Cc: 'Peace' <pc...@yahoo.com> 
Sent: Friday, December 2, 2011 1:04 PM
Subject: Re: Pipe transport for Windows
 
I don't want to be snarky, but you guys who are interested in having WIndows libraries are slowly reproducing the work I already did and submitted as part of https://issues.apache.org/jira/browse/THRIFT-591.

This includes a full ASIO based implementation of local sockets, implemented as Unix domain sockets on *nix, and Windows named pipes on Windows. It won't apply against the current sources, but the named pipe stuff was all new code anyway.

- Rush

On Dec 2, 2011, at 10:47 AM, Alex Parenteau wrote:

> Hi Peace,
> 
> I would use boost::asio, and use the ability of it to handle Windows/Posix file descriptors.
> 
> Below are some snippets of code that might help illustrate this (don't try to compile!)
> 
> I don't know much of the pipe transport in thrift, so this may not be applicable to your question.
> 
> As an orthogonal thought, I was wondering if anybody has put some thought around using boost::asio for async thrift servers (right now using libevent).
> 
> Regards,
> alex
> 
> #include <boost/asio.hpp> 
> #include <boost/system/windows_error.hpp>
> 
> #ifdef DVA_OS_WIN
>     using boost::asio::windows::stream_handle;
>     typedef stream_handle platform_stream;
>     typedef HANDLE platform_descriptor;
> #    define PIPE_EOF_ERROR_CODE boost::system::windows_error::broken_pipe
> #else
>     using boost::asio::posix::stream_descriptor;
>     typedef stream_descriptor platform_stream;
>     typedef int platform_descriptor;
> #    define PIPE_EOF_ERROR_CODE boost::asio::error::eof
> #endif
> 
>     boost::asio::io_service io_service_;
>     platform_stream pipe_;
>     std::vector<char> data_;
>     bool done_;
>     bool error_;
>     size_t total_size_;
>     boost::asio::strand strand_;
>     boost::thread thread_;
> 
> PipeSession(platform_descriptor fd) :
>         io_service_(), pipe_(io_service_, fd),
> {
> }
> 
> bool PipeSession ::start()
> {
> #ifdef LINUX
>     for (;;)
>     {
>         boost::asio::posix::descriptor_base::bytes_readable command(true);
>         pipe_.io_control(command);
>         std::size_t bytes_readable = command.get();
> 
>         if(bytes_readable) {
>             break;
>         }
>     }
> #endif
>     _thread = boost::thread(boost::bind(&PipeSession::run))
> 
>     return true;
> }
> 
> void PipeSession ::run() {
>     try {
>         pipe_.async_read_some(boost::asio::buffer(data_),
>             strand_.wrap(boost::bind(&PipeSession::handle_read,
>             this, boost::asio::placeholders::error,
>             boost::asio::placeholders::bytes_transferred)));
> 
>             std::size_t num = io_service_.run();
> 
>         } catch(const boost::system::system_error& e) {
>             done_ = true;
>             if(e.code() != PIPE_EOF_ERROR_CODE)
>                 throw;
>         }
> 
>     static platform_descriptor CreatePipeFD(const std::string& pipeName, bool readFlag) {
> #ifdef WIN32
>         HANDLE fd = CreateNamedPipe( 
>             pipeName.c_str(),    // pipe name 
>             PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,       // read/write access TODO PIPE_ACCESS_INBOUND? PIPE_ACCESS_OUTBOUND?
>             PIPE_TYPE_BYTE |          // byte type pipe 
>             PIPE_READMODE_BYTE |      // byte-read mode 
>             PIPE_WAIT,                // blocking mode 
>             PIPE_UNLIMITED_INSTANCES, // max. instances  
>             BUFSIZE,                  // output buffer size 
>             BUFSIZE,                  // input buffer size 
>             0,                        // client time-out 
>             NULL);                    // default security attribute 
> 
>         if(fd == INVALID_HANDLE_VALUE) {
>             throw std::runtime_error("CreateNamedPipe failed");
>         }
> 
>         OVERLAPPED overlapped = {0};
>         overlapped.hEvent = CreateEvent(0,TRUE,FALSE,0);
>         if(ConnectNamedPipe(fd, &overlapped) != FALSE || GetLastError() != ERROR_IO_PENDING) {
>             CloseHandle(overlapped.hEvent);
>             CloseHandle(fd);
>             throw std::runtime_error("ConnectNamedPipe failed");
>         }
> #else
>         if(mkfifo(pipeName .c_str(), 0660) < 0) {
>             throw std::runtime_error("fifo failed");
>         }
> 
>         int fd = open(pipeName c_str(), (readFlag ? O_RDONLY : O_RDWR) | O_NONBLOCK);
>         if(fd <= 0) {
>             throw std::runtime_error("open failed");
>         }
> #endif
> 
> #ifdef WIN32
>         DWORD waitRes;
>         if((waitRes = WaitForSingleObject(overlapped.hEvent, LAUNCH_TIMEOUT * 1000)) != WAIT_OBJECT_0) {
>             CloseHandle(overlapped.hEvent);
>             CloseHandle(fd);
>             throw std::runtime_error("WaitForSingleObject failed");
>         }
>         CloseHandle(overlapped.hEvent);
> 
> #endif
> 
>         return fd;
>     }
> }
> 
> -----Original Message-----
> From: Peace [mailto:pc_5@yahoo.com] 
> Sent: Thursday, December 01, 2011 3:24 PM
> To: user@thrift.apache.org
> Subject: Pipe transport for Windows
> 
> Hello group,
> 
> I am implementing Named and Anonymous Pipes transport for Thrift on the Windows platform.  The motivation for this is to provide a lightweight local IPC transport for applications that run entirely on one system. Unix already has domain sockets support in the TSocket transport but that does not work on Windows.  I would have preferred a cross-platform solution but Windows pipes are much too different from the Unix implementations. What are your thoughts on submitting this for possible inclusion?  Would a Windows-only transport bother people?  Is there a better way to accomplish this?
> 
> 
> Regards,
> Peace

Re: Pipe transport for Windows

Posted by Rush Manbert <ru...@manbert.com>.
I don't want to be snarky, but you guys who are interested in having WIndows libraries are slowly reproducing the work I already did and submitted as part of https://issues.apache.org/jira/browse/THRIFT-591.

This includes a full ASIO based implementation of local sockets, implemented as Unix domain sockets on *nix, and Windows named pipes on Windows. It won't apply against the current sources, but the named pipe stuff was all new code anyway.

- Rush

On Dec 2, 2011, at 10:47 AM, Alex Parenteau wrote:

> Hi Peace,
> 
> I would use boost::asio, and use the ability of it to handle Windows/Posix file descriptors.
> 
> Below are some snippets of code that might help illustrate this (don't try to compile!)
> 
> I don't know much of the pipe transport in thrift, so this may not be applicable to your question.
> 
> As an orthogonal thought, I was wondering if anybody has put some thought around using boost::asio for async thrift servers (right now using libevent).
> 
> Regards,
> alex
> 
> #include <boost/asio.hpp> 
> #include <boost/system/windows_error.hpp>
> 
> #ifdef DVA_OS_WIN
> 	using boost::asio::windows::stream_handle;
> 	typedef stream_handle platform_stream;
> 	typedef HANDLE platform_descriptor;
> #	define PIPE_EOF_ERROR_CODE boost::system::windows_error::broken_pipe
> #else
> 	using boost::asio::posix::stream_descriptor;
> 	typedef stream_descriptor platform_stream;
> 	typedef int platform_descriptor;
> #	define PIPE_EOF_ERROR_CODE boost::asio::error::eof
> #endif
> 
> 	boost::asio::io_service io_service_;
> 	platform_stream pipe_;
> 	std::vector<char> data_;
> 	bool done_;
> 	bool error_;
> 	size_t total_size_;
> 	boost::asio::strand strand_;
> 	boost::thread thread_;
> 
> PipeSession(platform_descriptor fd) :
> 		io_service_(), pipe_(io_service_, fd),
> {
> }
> 
> bool PipeSession ::start()
> {
> #ifdef LINUX
> 	for (;;)
> 	{
> 		boost::asio::posix::descriptor_base::bytes_readable command(true);
> 		pipe_.io_control(command);
> 		std::size_t bytes_readable = command.get();
> 
> 		if(bytes_readable) {
> 			break;
> 		}
> 	}
> #endif
> 	_thread = boost::thread(boost::bind(&PipeSession::run))
> 
> 	return true;
> }
> 
> void PipeSession ::run() {
> 	try {
> 		pipe_.async_read_some(boost::asio::buffer(data_),
> 			strand_.wrap(boost::bind(&PipeSession::handle_read,
> 			this, boost::asio::placeholders::error,
> 			boost::asio::placeholders::bytes_transferred)));
> 
> 			std::size_t num = io_service_.run();
> 
> 		} catch(const boost::system::system_error& e) {
> 			done_ = true;
> 			if(e.code() != PIPE_EOF_ERROR_CODE)
> 				throw;
> 		}
> 
> 	static platform_descriptor CreatePipeFD(const std::string& pipeName, bool readFlag) {
> #ifdef WIN32
> 		HANDLE fd = CreateNamedPipe( 
> 			pipeName.c_str(),    // pipe name 
> 			PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,       // read/write access TODO PIPE_ACCESS_INBOUND? PIPE_ACCESS_OUTBOUND?
> 			PIPE_TYPE_BYTE |          // byte type pipe 
> 			PIPE_READMODE_BYTE |      // byte-read mode 
> 			PIPE_WAIT,                // blocking mode 
> 			PIPE_UNLIMITED_INSTANCES, // max. instances  
> 			BUFSIZE,                  // output buffer size 
> 			BUFSIZE,                  // input buffer size 
> 			0,                        // client time-out 
> 			NULL);                    // default security attribute 
> 
> 		if(fd == INVALID_HANDLE_VALUE) {
> 			throw std::runtime_error("CreateNamedPipe failed");
> 		}
> 
> 		OVERLAPPED overlapped = {0};
> 		overlapped.hEvent = CreateEvent(0,TRUE,FALSE,0);
> 		if(ConnectNamedPipe(fd, &overlapped) != FALSE || GetLastError() != ERROR_IO_PENDING) {
> 			CloseHandle(overlapped.hEvent);
> 			CloseHandle(fd);
> 			throw std::runtime_error("ConnectNamedPipe failed");
> 		}
> #else
> 		if(mkfifo(pipeName .c_str(), 0660) < 0) {
> 			throw std::runtime_error("fifo failed");
> 		}
> 
> 		int fd = open(pipeName c_str(), (readFlag ? O_RDONLY : O_RDWR) | O_NONBLOCK);
> 		if(fd <= 0) {
> 			throw std::runtime_error("open failed");
> 		}
> #endif
> 
> #ifdef WIN32
> 		DWORD waitRes;
> 		if((waitRes = WaitForSingleObject(overlapped.hEvent, LAUNCH_TIMEOUT * 1000)) != WAIT_OBJECT_0) {
> 			CloseHandle(overlapped.hEvent);
> 			CloseHandle(fd);
> 			throw std::runtime_error("WaitForSingleObject failed");
> 		}
> 		CloseHandle(overlapped.hEvent);
> 
> #endif
> 
> 		return fd;
> 	}
> }
> 
> -----Original Message-----
> From: Peace [mailto:pc_5@yahoo.com] 
> Sent: Thursday, December 01, 2011 3:24 PM
> To: user@thrift.apache.org
> Subject: Pipe transport for Windows
> 
> Hello group,
> 
> I am implementing Named and Anonymous Pipes transport for Thrift on the Windows platform.  The motivation for this is to provide a lightweight local IPC transport for applications that run entirely on one system. Unix already has domain sockets support in the TSocket transport but that does not work on Windows.  I would have preferred a cross-platform solution but Windows pipes are much too different from the Unix implementations. What are your thoughts on submitting this for possible inclusion?  Would a Windows-only transport bother people?  Is there a better way to accomplish this?
> 
> 
> Regards,
> Peace


RE: Pipe transport for Windows

Posted by Alex Parenteau <ap...@adobe.com>.
Hi Peace,

I would use boost::asio, and use the ability of it to handle Windows/Posix file descriptors.

Below are some snippets of code that might help illustrate this (don't try to compile!)

I don't know much of the pipe transport in thrift, so this may not be applicable to your question.

As an orthogonal thought, I was wondering if anybody has put some thought around using boost::asio for async thrift servers (right now using libevent).

Regards,
alex

#include <boost/asio.hpp> 
#include <boost/system/windows_error.hpp>

#ifdef DVA_OS_WIN
	using boost::asio::windows::stream_handle;
	typedef stream_handle platform_stream;
	typedef HANDLE platform_descriptor;
#	define PIPE_EOF_ERROR_CODE boost::system::windows_error::broken_pipe
#else
	using boost::asio::posix::stream_descriptor;
	typedef stream_descriptor platform_stream;
	typedef int platform_descriptor;
#	define PIPE_EOF_ERROR_CODE boost::asio::error::eof
#endif

	boost::asio::io_service io_service_;
	platform_stream pipe_;
	std::vector<char> data_;
	bool done_;
	bool error_;
	size_t total_size_;
	boost::asio::strand strand_;
	boost::thread thread_;

PipeSession(platform_descriptor fd) :
		io_service_(), pipe_(io_service_, fd),
{
}

bool PipeSession ::start()
{
#ifdef LINUX
	for (;;)
	{
		boost::asio::posix::descriptor_base::bytes_readable command(true);
		pipe_.io_control(command);
		std::size_t bytes_readable = command.get();

		if(bytes_readable) {
			break;
		}
	}
#endif
	_thread = boost::thread(boost::bind(&PipeSession::run))

	return true;
}

void PipeSession ::run() {
	try {
		pipe_.async_read_some(boost::asio::buffer(data_),
			strand_.wrap(boost::bind(&PipeSession::handle_read,
			this, boost::asio::placeholders::error,
			boost::asio::placeholders::bytes_transferred)));

			std::size_t num = io_service_.run();

		} catch(const boost::system::system_error& e) {
			done_ = true;
			if(e.code() != PIPE_EOF_ERROR_CODE)
				throw;
		}

	static platform_descriptor CreatePipeFD(const std::string& pipeName, bool readFlag) {
#ifdef WIN32
		HANDLE fd = CreateNamedPipe( 
			pipeName.c_str(),    // pipe name 
			PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,       // read/write access TODO PIPE_ACCESS_INBOUND? PIPE_ACCESS_OUTBOUND?
			PIPE_TYPE_BYTE |          // byte type pipe 
			PIPE_READMODE_BYTE |      // byte-read mode 
			PIPE_WAIT,                // blocking mode 
			PIPE_UNLIMITED_INSTANCES, // max. instances  
			BUFSIZE,                  // output buffer size 
			BUFSIZE,                  // input buffer size 
			0,                        // client time-out 
			NULL);                    // default security attribute 

		if(fd == INVALID_HANDLE_VALUE) {
			throw std::runtime_error("CreateNamedPipe failed");
		}

		OVERLAPPED overlapped = {0};
		overlapped.hEvent = CreateEvent(0,TRUE,FALSE,0);
		if(ConnectNamedPipe(fd, &overlapped) != FALSE || GetLastError() != ERROR_IO_PENDING) {
			CloseHandle(overlapped.hEvent);
			CloseHandle(fd);
			throw std::runtime_error("ConnectNamedPipe failed");
		}
#else
		if(mkfifo(pipeName .c_str(), 0660) < 0) {
			throw std::runtime_error("fifo failed");
		}

		int fd = open(pipeName c_str(), (readFlag ? O_RDONLY : O_RDWR) | O_NONBLOCK);
		if(fd <= 0) {
			throw std::runtime_error("open failed");
		}
#endif

#ifdef WIN32
		DWORD waitRes;
		if((waitRes = WaitForSingleObject(overlapped.hEvent, LAUNCH_TIMEOUT * 1000)) != WAIT_OBJECT_0) {
			CloseHandle(overlapped.hEvent);
			CloseHandle(fd);
			throw std::runtime_error("WaitForSingleObject failed");
		}
		CloseHandle(overlapped.hEvent);

#endif

		return fd;
	}
}

-----Original Message-----
From: Peace [mailto:pc_5@yahoo.com] 
Sent: Thursday, December 01, 2011 3:24 PM
To: user@thrift.apache.org
Subject: Pipe transport for Windows

Hello group,

I am implementing Named and Anonymous Pipes transport for Thrift on the Windows platform.  The motivation for this is to provide a lightweight local IPC transport for applications that run entirely on one system. Unix already has domain sockets support in the TSocket transport but that does not work on Windows.  I would have preferred a cross-platform solution but Windows pipes are much too different from the Unix implementations. What are your thoughts on submitting this for possible inclusion?  Would a Windows-only transport bother people?  Is there a better way to accomplish this?


Regards,
Peace