For my master thesis project I am building an API in C that works with Unix sockets. To make it short, I have two sockets identified by their two fds, on which I have called a O_NONBLOCK
connect()
. At this point, I am calling select()
to check which one connects first and is ready for writing.
The problems start now, as the application which is using this API is aware of only one of those sockets, let's say the one identified by fd1. If the socket identified by fd2 is the first to connect, the application has no way to know it can write to that socket.
I think my best options are using dup()
and/or dup2()
, but according to the their man page, dup()
creates a copy of the fd passed to the function, but which refers to the same open file description, meaning that the two can be used interchangeably, and dup2()
closes the new fd which replaces the old fd.
So my assumptions on what would happen are (in pseudo code)
int fd1, fd2, fd3;
fd1 = socket(x); // what the app is aware of
fd2 = socket(y); // first to connect
fd3 = dup(fd1); // fd1 and fd3 identify the same description
dup2(fd2, fd1); // The description identified by fd2 is now identified by fd1, the description previously identified by fd1 (and fd3) is closed
dup2(fd3, fd2); // The description identified by fd3 (copy of fd1, closed in the line above) is identified by fd2 (which can be closed and reassigned to fd3) since now the the description that was being identified by fd2 is being identified by fd1.
Which looks fine, except for the fact that the first dup2()
closes fd1, which closes also fd3 since they are identifying the same file description. The second dup2()
works fine but it's replacing the fd of a connection which has been closed by the first one, while I want it to keep trying to connect.
Can anyone with a better understanding of Unix file descriptors help me out?
EDIT: I want to elaborate a little bit more on what the API does and why the application only sees one fd.
The API provides to the application the means to call a very "fancy" version of connect()
select()
and close()
.
When the application calls api_connect()
, it passes to the function a pointer to an int (together with all the necessary addresses and protocols etc). api_connect()
will call socket()
, bind()
and connect()
, the important part is that it will write the return value of socket()
in the memory parsed through the pointer. This is what I mean by "The socket is only aware of one fd". The application will then call FD_SET(fd1, write_set)
, call a api_select() and then check if the fd is writable by calling FD_ISSET(fd1, write_set)
. api_select()
works more or less like select()
, but has a timer which can trigger a timeout if the connection takes more than a set amount of time to connect (since it's O_NONBLOCK
). If this happens, api_select()
creates a new connection on a different interface (calling all the necessary socket()
, bind()
and connect()
). This connection is identified by a new fd -fd2- the application doesn't know about, and which is tracked in the API.
Now, if the application calls api_select()
with FD_SET(fd1, write_set)
and the API realises that is the second connection that has completed, thus making fd2 writable, I want the application to use fd2. The problem is that the application will only call FD_ISSET(fd1, write_set)
and write(fd1)
afterwards, that's why I need to replace fd2 with fd1.
At this point I'm really confused on whether I really need to dup or just do an integer swap (my understanding of Unix file descriptors is just a little bit more than basic).