I'm studying an OS programming book, in particular network sockets. I have two questions(2nd one is down at the bottom). There is something I don't quite understand. What if this piece of code, which sets sigpipe's default action to ignore and opens a socket:
Code:
if ((u_ignore_sigpipe() != 0) || ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1))
return -1;
is replaced by this
Code:
if (((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) || (u_ignore_sigpipe() != 0) )
return -1;
The books says that this problem would arise: "if u_ignore_sigpipe() fails, u_connect returns with an open file descriptor in sock. Since the calling program does not have the value of sock, this file descriptor could not be closed."
What I don't understand is that socket gets run first and returns a file descriptor to sock, then u_ignore_sigpipe() gets evaluated. So if u_ignore_sigpipe() fails then sock doesn't get assigned? It would make sense if in the if statement, order of precedence goes from right to left so that if u_ignore_sigpipe() fails, then the if statement would just break and socket() would not even run. Is this the case?
Here's the complete program
Code:
#include <ctype.h>
#include <errno.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/types.h>
#include "uiciname.h"
#include "uici.h"
int u_ignore_sigpipe(void);
int u_connect(u_port_t port, char *hostn) {
int error;
int retval;
struct sockaddr_in server;
int sock;
fd_set sockset;
if (name2addr(hostn,&(server.sin_addr.s_addr)) == -1) {
errno = EINVAL;
return -1;
}
server.sin_port = htons((short)port);
server.sin_family = AF_INET;
if ((u_ignore_sigpipe() == -1) ||
((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1))
return -1;
if (((retval =
connect(sock, (struct sockaddr *)&server, sizeof(server))) == -1) &&
((errno == EINTR) || (errno == EALREADY))) { /* asynchronous */
FD_ZERO(&sockset);
FD_SET(sock, &sockset);
while (((retval = select(sock+1, NULL, &sockset, NULL, NULL)) == -1)
&& (errno == EINTR)) {
FD_ZERO(&sockset);
FD_SET(sock, &sockset);
}
}
if (retval == -1) {
error = errno;
while ((close(sock) == -1) && (errno == EINTR));
errno = error;
return -1;
}
return sock;
}
I'm also confused about what happens if the connect() function fails with either EINTR or EALREADY. EINTR is just when the connect() function gets interrupted by a signal. EALREADY is when the connection request is already in progress on a socket. So if either one is true,
1. What does FD_ZERO(&sockset) and FD_SET(sock, &socket) do?
Do they zero out the file descriptor and then sets it back to value of sock?
2. Then it runs select(), what does that do exactly? The book only says that it calls select to detect that the file descriptor is ready for writing. So basically the TCP 3 way handshake is complete, and select() makes sure that the socket is open for write?