Is it possible to detach a native socket from Boost.ASIO's socket class? If so, how can it be done? I can't seem to find anything obvious in the documentation.
As a quick overview of what I'm trying to accomplish: I have a class that makes a connection and does some negotiation using Boost.ASIO, then passes back a native Windows SOCKET on success or 0 on failure.
Unless I'm mistaken, the native socket will be closed and deallocated when my boost::asio::basic_socket is destructed.
Answering my own question.
Windows has a WSADuplicateSocket function, which can be used to duplicate the native socket. The underlying socket will remain open until all descriptors for this socket are deallocated.
http://msdn.microsoft.com/en-us/library/ms741565(VS.85).aspx
For Mac OS X do the following (for Linux it isn't hard to modify, just notice the very idea):
Wrap socket in a shared_ptr, so that it won't close when passing into different routines and keep it alive (at least one reference should always exist);
Get a native descriptor with socket.native();
Remove it from kqueue:
struct kevent event;
EV_SET(&event, descriptor, EVFILT_READ, EV_DELETE, 0, 0, 0); //or EVFILT_WRITE
And make it blocking if needed:
fcntl(descriptor, F_SETFL, fcntl(descriptor, F_GETFL, 0) & ~O_NONBLOCK);
Related
In boost.asio, there is a class called an acceptor. The acceptor is used to listen for connection requests on a specific endpoint and open a socket in response to a request.
There are three acceptor constructors I am interested in.
construct an acceptor without opening or binding
explicit basic_socket_acceptor(
const executor_type & ex);
construct an acceptor and open it
basic_socket_acceptor(
const executor_type & ex,
const protocol_type & protocol);
construct an acceptor, open it, and bind it to an endpoint
basic_socket_acceptor(
const executor_type & ex,
const endpoint_type & endpoint,
bool reuse_addr = true);
1 and 3 both make sense. 1 constructs the acceptor in the C++ sense: allocate memory on the stack, maybe initialize some variables, etc. 3 specifies the endpoint that the acceptor should listen on. Incoming connection requests addressed to the endpoint will be accepted and a connection will be created on a new socket. 2, however, appears to be a middle ground that allows you to set a "protocol type."
I want to say that that "2 allows you to specify more member variables (the protocol) than 1 and less member variables (e.g., IP address and port number) than 3." However, I don't know if it does anything "extra" over setting some member variables (does it engage with the OS or the NIC?).
What does it mean to open an acceptor?
It opens the socket, indeed.
I chose to talk about the constructor to differentiate between 1, 2, and 3. A question about the member function open would probably have the same answer as this question.
The question then becomes just what does ::socket do (https://pubs.opengroup.org/onlinepubs/009604499/functions/socket.html):
The socket() function shall create an unbound socket in a communications domain, and return a file descriptor that can be used in later function calls that operate on sockets
So for your practical understanding, it allocates and initializes in-kernel resources[1].
Note
Technically there is no difference between an "acceptor" socket and a "connection" socket. Asio distinguishes them conceptually so it's easier to use them right. The reverse question might offer enlightenment: Design rationale behind that separate acceptor class exists in ASIO
[1] on most operating systems, userland TCP stacks exists though
Do you know the underlying logic of accepting incoming networking connections with BSD sockets?
The steps, if you write them manually, are:
open a socket with socket()
just like opening a file, and you get an integer descriptor you can use with read(), write(), close() etc.
bind the socket to a network address with bind()
unlike a file, the socket descriptor is not associated with anything outside your process until you do this
tell the OS you want to listen for connections on this socket, with listen()
until this point, it could still be used as an outgoing connection, although it's unusual to bind the source address explicitly
start accepting incoming connection requests by calling accept()
So when you open an acceptor, you're asking the OS for a socket and saving the descriptor to a member variable.
When you bind an acceptor, you're just asking the OS to link that socket to an address (but there may be a member variable tracking its state as well, so the acceptor remembers this has been done).
Note that the "middle ground" passes a protocol type, which is needed to open a socket (it corresponds exactly to the arguments to socket()), but it doesn't have an address (or endpoint), so it can't bind that socket yet.
I want to be able to call recv() without having to block, so I want to make it non-blocking, but I do not want it to be non blocking when sending data. So can a socket be made non-blocking only for the recv() function, or does the blocking/non-blocking mode affects all of the socket functions?
For windows, you can use ioctlsocket() to set the socket in non-blocking mode. Unfortunately these settings apply to all operations on the socket. So for your case you'll have to switch it between the receivings and the sendings.
For the records:
For linux, you could have used the MSG_DONTWAIT flag in the recv() call arguments. The single call will then be non blocking.
There is no way to make the socket non-blocking just for the recv() function.
However there is something close to that (but flawed), which is by using ioctlsocket() with the FIONREAD flag. For example:
unsigned long l;
ioctlsocket(s, FIONREAD, &l);
This function will return (immediately without blocking) how many bytes is available to be read, although not quite accurate (but we don't care about that, because we are using it to know if there is data to be read and not to know exactly how many bytes are there).
As I have mentioned earlier, this approach is flawed, because it doesn't tell you when the other end has disconnected, because recv() returns 0 on disconnect, and this function will return 0 if no data is available!
From posts like this, I know on linux the recv/send functions are thread safe and user is allowed to operate on the same socket from different threads simultaneously.
Though this is not a good design, in following situation I wonder what shall we do from user level code in order to keep data consistency and healthy running state: There are threads operating on the same sockets, the first one for creating and closing socket, the second for reading socket and the last one for sending sockets. See the pseudo code
struct SocketInfo
{
int SockFd;
int SockType;
queue<Packet*> RecvPacks;
};
map<int, SocketInfo*> gSocketInfoMap;
pthread_mutex_t gSocketsLock;
//Thread1
pthread_mutex_lock(&gSocketsLock);
// get information for sock
SocketInfo* info = gSocketInfoMap[sock];
pthread_mutex_unlock(&gSocketsLock);
close(sock); // line-1
.....
//thread-2
pthread_mutex_lock(&gSocketsLock);
SocketInfo* info = gSocketInfoMap[sock];
pthread_mutex_unlock(&gSocketsLock);
recv(sock, buffer, sizeof(buffer)); // line-2
.....
//thread-3
pthread_mutex_lock(&gSocketsLock);
SocketInfo* info = gSocketInfoMap[sock];
pthread_mutex_unlock(&gSocketsLock);
send(sock, buffer, sizeof buffer); // line-3
.....
I wonder if I need to move the Line-1, Line-2 and Line-3 into the protection scope of gSocketsLock? Why?
As the linked question states, socket operations are threadsafe. In any event, receiving and sending data are independent operations which do not interfere with each other.
Obviously, it is not a great idea to close a socket which is actively being read from and written to, but putting the close() inside a critical section does not do anything to prevent that bug. Whatever mechanism ensures that active sockets are not closed or that closed sockets are not accessed is at a higher level than the critical sections shown in the OP.
If one thread closes a socket that another thread is trying to use for I/O, the worst that can happen is that the recv/send call will return an error.
In short: no, it would not be a good idea to put the socket operations inside the critical section. It has not benefit, and it unnecessarily increases the likelihood of lock contention.
I have a C++ object that creates a thread to read from a blocking UDP socket:
mRunning.store(true);
while (mRunning.load(boost::memory_order_consume)) {
...
int size = recvfrom(mSocket, buf, kTextBufSize , 0,
(struct sockaddr *) &packet->mReplyAddr.mSockAddr, (socklen_t*)&packet->mReplyAddr.mSockAddrLen);
if (size > 0) {
//do stuff
}
}
return 0;
(mRunning is a boost::atomic)
The object's destructor is called from another thread and does this:
mRunning.store(false);
#ifdef WIN32
if (mSocket != -1) closesocket(mSocket);
#else
if (mSocket != -1) close(mSocket);
#endif
pthread_join(mThread, NULL);
This seems to work, but one of my colleagues suggested that there might be a problem if recv is interrupted in the middle of reading something. Is this thread safe? What's the correct way of closing a blocking UDP socket? (Needs to be cross-platform OSX/Linux/Windows)
There could be a lot of different problems. Moving my application from one FreeBSD version to another I found that such close() worked normally on older kernel and just hung close() until something returned from recv() on newer. And OSX is FreeBSD based :)
Portable way of closing sockets from different thread is to create pipe and block not in recv(), but in select(). When you need to close socket, write something to pipe, select() will unblock and you can safely do close().
Well recvfrom in itself is thread-safe. IIRC all socket functions are. The question is:
What's going to happen if you pull the descriptor from under recvfrom while it's copying data to your buffer ?
It's a good question but I doubt the standard says anything about this (I also doubt the specific manual of an implementation says anything about it). So any implementation is free to:
Complete the operation (perhaps because it doesn't need the descriptor anymore, or because it's doing some cool reference counting or something else)
Make the recvfrom fail and return a -1 (ENOTSOCK, EINVAL ?)
Crash spectacularly because buffers and internal data structures are freed by the close.
Obviously this is just speculation (I have been wrong before, many times), but unless you find something in the standard to support the idea that you can close the socket while receiving through it, you're not safe.
So, what can you do ? THe safest: use a synchronization mechanism to ensure that you only close the socket after the recvfrom is done (semaphores, mutexes, whatever).
Personally I would do an UP on a semaphore after the recvfrom and a DOWN before the close.
Your colleague is right, boost sockets are not thread safe.
Your options;
Use ASIO (do this one)
Timeout on blocking call. This isn't really portable though it might work.
I've two classes (Negotiator, Client), both has their own boost::asio::ip::tcp::socket. Is there a way to transfer socket object to Client after negotiation is finished. I'm looking forward to do something like that:
boost::asio::ip::tcp::socket sock1(io);
//...
boost::asio::ip::tcp::socket sock2;
sock2.assign(sock1);
This operation must guarantee that the connection won't be closed when sock1 is destroyed.
I think that you could:
obtain sock1's native handle with the native() member function
dup() (or WSADuplicateSocket()) sock1's native handle
pass the dup()-ed handle to sock2 with the assing() member function
However:
I'm not sure as I never tried that
If you want to transfer (instead of sharing) the socket from Negotiator to Client, Dan's suggestion of using dynamic allocation is probably simpler, using unique_ptr (or auto_ptr)
Create the socket on the heap (new), and pass the pointer from the negotiator to the client.
As of the current version of Boost, you would now get the handle with
boost::asio::ip::tcp::socket::my_socket;
auto my_handle = my_socket.native_handle();
instead of the old native() member function.