Monday, July 19, 2021

Connection refused: Why is my UNIX socket client giving me this?

Language:  C++

Environment: Ubuntu 20

Application:  Creating a UNIX Socket server


If you go out onto the Internet looking for help with this, you'll find oodles and oodles of articles, forum posts, blog posts, tutorials and everything in between explaining how TCP sockets work and how to create them, use them, debug them, take them out to the park and run around with them...

...but UNIX sockets get very little love, and that's not so good when you run into a problem with one.

(The easiest way to tell the difference is to look at the code presented by one of these sites.  Look at the socket() system call.  If the first parameter is AF_INET, you're working with an Internet socket.  If it says PF_UNIX, you're where you want to be.)

A UNIX socket is essentially a special file.  That's it.  That means all the stuff that you could run into when working with files can also impact you when working with UNIX sockets.  The beauty of this is that if you have any experience working with files from your C++ program, then you already have the experience you need to debug problems with your UNIX sockets.

Suppose your "Connection refused" error comes right after a line that looks something like this:

connect(server_,(const struct sockaddr *)&server_addr,sizeof(server_addr))

Inside sockaddr (which is a struct of type sockaddr_un) is a field that holds the path name.  Yes, that means file path.  So what might cause a connection refused?  Well, what sorts of things cause a failure when you try to open a file?  Maybe the file doesn't exist.  Maybe the process doesn't have access privileges on that file.  (See where I'm going with this?)

When the connect() function tries to open that UNIX socket, the socket needs to:

  • Exist.  Don't try to manually create it yourself using mkdir or touch.  That socket gets created when you run a UNIX socket server.  
  • Be a socket.  This is why you don't create it yourself.  When the socket server creates the socket and calls the bind() system call, the socket can now be connected to by a socket client.  Yes, that implies that you have to start your socket server before your client.
  • Be accessible.  Whatever user your process is running as needs to have permissions on that socket in whatever file directory it exists in.  
This is what a socket looks like on the file system when you do ls -l:

srwxrwxr-x  1 arcticfox arcticfox    0 Jul 19 21:13 my_sock

This one is in the /tmp directory, which is a nice, safe, out of the way place.  Notice the first letter for the file type is 's' as opposed to 'd' which it would be if it were a directory.  That's how we know it's a UNIX socket.   

So if you've done everything correctly but your client is refusing to connect, check these three things.


No comments:

Post a Comment