[asio] asio::socket -> native handle ->asio::socket not working on windows

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

[asio] asio::socket -> native handle ->asio::socket not working on windows

Boost - Users mailing list

Hello,

 

I am using boost asio in a cross platform project. The project consists of two libraries, having a C call API in between.

 

Until now, each of those two libraries uses boost::asio internally. Each of these libraries have their own instance of boost::asio::io_service.

 

I now need to implement a change, that requires to pass a connected socket from one library to the other one via the C call API:

 

This is what I want to do it.

 

* Lib1 calls new method connect() in lib2

* lib2::connect() creates a boost::asio::ip::tcp::socket

* lib2::connect() connects to a service

* lib2::connect() does some async communication with that service.

* when the service is initialized, lib2::connect() shall

   pass the native handle back to its caller (Lib1).

* Lib1 then creates a boost::asio::ip::tcp::socket from the native handle

 

I have learned, that there is no way to destroy a boost::asio::ip::tcp::socket without closing the native handle.

 

So, I have to dup() it. No problem on POSIX systems, on Windows I can use a combination of WSADuplicateSocket () and WSASocket () to achieve the same.

 

Everything works fine on Linux, but on Windows, the parts do not work together J

 

The individual parts are working find.

* I can use the boost::asio::ip::tcp::socket to communicate with the service.

* I can use WSADuplicateSocket () and WSASocket () to get a 2nd, native handle to the socket

* I can use the   2nd, native handle to communicate to the service, even after destroying the boost::asio::ip::tcp::socket instance.

* I also can create a working boost::asio::ip::tcp::socket from a native socket handle, created with socket() and connected to a service with connect().

 

BUT: If I try to create a boost::asio::ip::tcp::socket on the socket created by the WSADuplicateSocket () and WSASocket () sequence, I get an exception.

 

The call to CreateIoCompletionPort() in win_iocp_io_service.ipp, win_iocp_io_service::register_handle() fails with error 87 (Invalid Parameter).

 

I have no idea, why CreateIoCompletionPort() is failing and how to avoid this.

 

Here is a sample program demonstrating my problem. If BUG is #defined, the code fails with std::exception “assign: Falscher Parameter” (invalid parameter).

 

#ifdef _WIN32

#include <winsock2.h>

#include <ws2tcpip.h>

#else

#include <sys/socket.h>

#endif

 

#include <boost/asio.hpp>

 

#define ADDR "127.0.0.1"

#define PORT "7"    /* echo */

 

#include <stdio.h>

 

#ifndef _WIN32

inline int WSAGetLastError() { return errno; }

#endif

 

int main()

{

       char Request[]="Hello";

       char Buffer[256];

       int n;

 

       try

       {

#ifdef _WIN32

             SOCKET s1 = INVALID_SOCKET;

#else

             int s1=-1;

#endif

#ifdef BUG

             {

                    printf("The programm does not work with this code on windows :-(\n");

                    boost::asio::io_service IoService;

                    boost::asio::ip::tcp::resolver Resolver(IoService);

                    boost::asio::ip::tcp::resolver::query Query(ADDR, PORT);

                    boost::asio::ip::tcp::socket s(IoService);

                    s.connect(*Resolver.resolve(Query));

                    printf("connected\n");

 

#ifdef _WIN32

                    WSAPROTOCOL_INFO ProtocolInfo;

                    DWORD MyProcId = GetCurrentProcessId();

                    int x = WSADuplicateSocket((SOCKET)s.native_handle(), MyProcId, &ProtocolInfo);

                    if (x)

                           throw boost::system::error_code(WSAGetLastError(), boost::system::system_category());

 

                    s1 = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, &ProtocolInfo, 0, WSA_FLAG_OVERLAPPED);

#else /* !_WIN32 */

                    s1=dup(s.native_handle());

#endif /* !_WIN32 */

                    if (s1<0)

                           throw boost::system::error_code(WSAGetLastError(), boost::system::system_category());

             }

#else

             s1 = socket(PF_INET, SOCK_STREAM, 0);

             if (s1 < 0)

                    throw boost::system::error_code(WSAGetLastError(), boost::system::system_category());

             struct sockaddr_in Addr;

             Addr.sin_family = AF_INET;

             Addr.sin_port = htons(atoi(PORT));

             inet_pton(AF_INET, ADDR, &Addr.sin_addr);

             if (connect(s1, (struct sockaddr*)&Addr, sizeof(Addr)) < 0)

                    throw boost::system::error_code(WSAGetLastError(), boost::system::system_category());

#endif

             printf("s1=%d\n", s1);

             {

                    boost::asio::io_service IoService;

                    boost::asio::ip::tcp::socket s(IoService, boost::asio::ip::tcp::v4(), (boost::asio::ip::tcp::socket::native_handle_type)s1);

                    n = s.write_some(boost::asio::buffer(&Request, sizeof(Request)));

                    printf("write_some() returned %d\n", n);

                    n = s.read_some(boost::asio::buffer(Buffer, sizeof(Buffer)));

                    printf("read_some() returned %d\n", n);

 

             }

             return 0;

       }

       catch (boost::system::error_code &ec)

       {

             fprintf(stderr, "boost::system::error_code: %s\n", ec.message().c_str());

             return -1;

       }

       catch (std::exception &e)

       {

             fprintf(stderr, "std::exception: %s\n", e.what());

             return -1;

       }

}

 

Thanks in advance,

 

Mario

--

Mario Klebsch                      Actia I+ME GmbH

[hidden email]         Dresdenstrasse 17/18
Fon: +49 531 38 701 716            38124 Braunschweig
Fax: +49 531 38 701 88
            German

 


_______________________________________________
Boost-users mailing list
[hidden email]
https://lists.boost.org/mailman/listinfo.cgi/boost-users
Reply | Threaded
Open this post in threaded view
|

Re: [asio] asio::socket -> native handle ->asio::socket not working on windows

Boost - Users mailing list
The socket interface has the release() method which disassociates the native handle from the asio socket object.

There is a constructor overload which takes a native handle.

No need for dup() or equivalent.

R

On Fri, 20 Dec 2019 at 11:36, Klebsch, Mario via Boost-users <[hidden email]> wrote:

Hello,

 

I am using boost asio in a cross platform project. The project consists of two libraries, having a C call API in between.

 

Until now, each of those two libraries uses boost::asio internally. Each of these libraries have their own instance of boost::asio::io_service.

 

I now need to implement a change, that requires to pass a connected socket from one library to the other one via the C call API:

 

This is what I want to do it.

 

* Lib1 calls new method connect() in lib2

* lib2::connect() creates a boost::asio::ip::tcp::socket

* lib2::connect() connects to a service

* lib2::connect() does some async communication with that service.

* when the service is initialized, lib2::connect() shall

   pass the native handle back to its caller (Lib1).

* Lib1 then creates a boost::asio::ip::tcp::socket from the native handle

 

I have learned, that there is no way to destroy a boost::asio::ip::tcp::socket without closing the native handle.

 

So, I have to dup() it. No problem on POSIX systems, on Windows I can use a combination of WSADuplicateSocket () and WSASocket () to achieve the same.

 

Everything works fine on Linux, but on Windows, the parts do not work together J

 

The individual parts are working find.

* I can use the boost::asio::ip::tcp::socket to communicate with the service.

* I can use WSADuplicateSocket () and WSASocket () to get a 2nd, native handle to the socket

* I can use the   2nd, native handle to communicate to the service, even after destroying the boost::asio::ip::tcp::socket instance.

* I also can create a working boost::asio::ip::tcp::socket from a native socket handle, created with socket() and connected to a service with connect().

 

BUT: If I try to create a boost::asio::ip::tcp::socket on the socket created by the WSADuplicateSocket () and WSASocket () sequence, I get an exception.

 

The call to CreateIoCompletionPort() in win_iocp_io_service.ipp, win_iocp_io_service::register_handle() fails with error 87 (Invalid Parameter).

 

I have no idea, why CreateIoCompletionPort() is failing and how to avoid this.

 

Here is a sample program demonstrating my problem. If BUG is #defined, the code fails with std::exception “assign: Falscher Parameter” (invalid parameter).

 

#ifdef _WIN32

#include <winsock2.h>

#include <ws2tcpip.h>

#else

#include <sys/socket.h>

#endif

 

#include <boost/asio.hpp>

 

#define ADDR "127.0.0.1"

#define PORT "7"    /* echo */

 

#include <stdio.h>

 

#ifndef _WIN32

inline int WSAGetLastError() { return errno; }

#endif

 

int main()

{

       char Request[]="Hello";

       char Buffer[256];

       int n;

 

       try

       {

#ifdef _WIN32

             SOCKET s1 = INVALID_SOCKET;

#else

             int s1=-1;

#endif

#ifdef BUG

             {

                    printf("The programm does not work with this code on windows :-(\n");

                    boost::asio::io_service IoService;

                    boost::asio::ip::tcp::resolver Resolver(IoService);

                    boost::asio::ip::tcp::resolver::query Query(ADDR, PORT);

                    boost::asio::ip::tcp::socket s(IoService);

                    s.connect(*Resolver.resolve(Query));

                    printf("connected\n");

 

#ifdef _WIN32

                    WSAPROTOCOL_INFO ProtocolInfo;

                    DWORD MyProcId = GetCurrentProcessId();

                    int x = WSADuplicateSocket((SOCKET)s.native_handle(), MyProcId, &ProtocolInfo);

                    if (x)

                           throw boost::system::error_code(WSAGetLastError(), boost::system::system_category());

 

                    s1 = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, &ProtocolInfo, 0, WSA_FLAG_OVERLAPPED);

#else /* !_WIN32 */

                    s1=dup(s.native_handle());

#endif /* !_WIN32 */

                    if (s1<0)

                           throw boost::system::error_code(WSAGetLastError(), boost::system::system_category());

             }

#else

             s1 = socket(PF_INET, SOCK_STREAM, 0);

             if (s1 < 0)

                    throw boost::system::error_code(WSAGetLastError(), boost::system::system_category());

             struct sockaddr_in Addr;

             Addr.sin_family = AF_INET;

             Addr.sin_port = htons(atoi(PORT));

             inet_pton(AF_INET, ADDR, &Addr.sin_addr);

             if (connect(s1, (struct sockaddr*)&Addr, sizeof(Addr)) < 0)

                    throw boost::system::error_code(WSAGetLastError(), boost::system::system_category());

#endif

             printf("s1=%d\n", s1);

             {

                    boost::asio::io_service IoService;

                    boost::asio::ip::tcp::socket s(IoService, boost::asio::ip::tcp::v4(), (boost::asio::ip::tcp::socket::native_handle_type)s1);

                    n = s.write_some(boost::asio::buffer(&Request, sizeof(Request)));

                    printf("write_some() returned %d\n", n);

                    n = s.read_some(boost::asio::buffer(Buffer, sizeof(Buffer)));

                    printf("read_some() returned %d\n", n);

 

             }

             return 0;

       }

       catch (boost::system::error_code &ec)

       {

             fprintf(stderr, "boost::system::error_code: %s\n", ec.message().c_str());

             return -1;

       }

       catch (std::exception &e)

       {

             fprintf(stderr, "std::exception: %s\n", e.what());

             return -1;

       }

}

 

Thanks in advance,

 

Mario

--

Mario Klebsch                      Actia I+ME GmbH

[hidden email]         Dresdenstrasse 17/18
Fon: +49 531 38 701 716            38124 Braunschweig
Fax: +49 531 38 701 88
            German

 

_______________________________________________
Boost-users mailing list
[hidden email]
https://lists.boost.org/mailman/listinfo.cgi/boost-users
--
Richard Hodges
office: +442032898513
home: +376841522
mobile: +376380212


_______________________________________________
Boost-users mailing list
[hidden email]
https://lists.boost.org/mailman/listinfo.cgi/boost-users