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 :)
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
#include
#else
#include
#endif
#include
#define ADDR "127.0.0.1"
#define PORT "7" /* echo */
#include
#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
Mario.klebsch@ime-actia.demailto:Mario.klebsch@ime-actia.de Dresdenstrasse 17/18
Fon: +49 531 38 701 716 38124 Braunschweig
Fax: +49 531 38 701 88 German