Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Proper way to close a blocking UDP socket

Tags:

c++

sockets

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)

like image 385
Müllmusik Avatar asked Jun 10 '11 11:06

Müllmusik


2 Answers

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().

like image 115
blaze Avatar answered Oct 17 '22 08:10

blaze


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.

like image 26
cnicutar Avatar answered Oct 17 '22 10:10

cnicutar