The book defines 3 customized functions:
int serv_listen(const char *name);
//Returns: file descriptor to listen on if OK, negative value on error
int serv_accept(int listenfd, uid_t *uidptr);
//Returns: new file descriptor if OK, negative value on error
int cli_conn(const char *name);
//Returns: file descriptor if OK, negative value on error
The
serv_accept
function (Figure 17.9) is used by a server to wait for a client’s connect request to arrive. When one arrives, the system automatically creates a new UNIX domain socket, connects it to the client’s socket, and returns the new socket to the server. Additionally, the effective user ID of the client is stored in the memory to whichuidptr
points.
serv_accept
function code and description:
#include "apue.h"
#include <sys/socket.h>
#include <sys/un.h>
#include <time.h>
#include <errno.h>
#define STALE 30 /* client's name can't be older than this (sec) */
/*
* Wait for a client connection to arrive, and accept it.
* We also obtain the client's user ID from the pathname
* that it must bind before calling us.
* Returns new fd if all OK, <0 on error
*/
int
serv_accept(int listenfd, uid_t *uidptr)
{
int clifd, err, rval;
socklen_t len;
time_t staletime;
struct sockaddr_un un;
struct stat statbuf;
char *name;
/* allocate enough space for longest name plus terminating null */
if ((name = malloc(sizeof(un.sun_path + 1))) == NULL)
return(-1);
len = sizeof(un);
if ((clifd = accept(listenfd, (struct sockaddr *)&un, &len)) < 0) {
free(name);
return(-2); /* often errno=EINTR, if signal caught */
}
/* obtain the client's uid from its calling address */
len -= offsetof(struct sockaddr_un, sun_path); /* len of pathname */
memcpy(name, un.sun_path, len);
name[len] = 0; /* null terminate */
if (stat(name, &statbuf) < 0) {
rval = -3;
goto errout;
}
#ifdef S_ISSOCK /* not defined for SVR4 */
if (S_ISSOCK(statbuf.st_mode) == 0) {
rval = -4; /* not a socket */
goto errout;
}
#endif
if ((statbuf.st_mode & (S_IRWXG | S_IRWXO)) ||
(statbuf.st_mode & S_IRWXU) != S_IRWXU) {
rval = -5; /* is not rwx------ */
goto errout;
}
staletime = time(NULL) - STALE;
if (statbuf.st_atime < staletime ||
statbuf.st_ctime < staletime ||
statbuf.st_mtime < staletime) {
rval = -6; /* i-node is too old */
goto errout;
}
if (uidptr != NULL)
*uidptr = statbuf.st_uid; /* return uid of caller */
unlink(name); /* we're done with pathname now */
free(name);
return(clifd);
errout:
err = errno;
close(clifd);
free(name);
errno = err;
return(rval);
}
... Then we call
stat
to verify that the pathname is indeed a socket and that the permissions allow only user-read, user-write, and user-execute. We also verify that the three times associated with the socket are no older than 30 seconds.If all these checks are OK, we assume that the identity of the client (its effective user ID) is the owner of the socket.
Why does the server code unlink(name)
the file attached to the client's socket?
Other 2 functions code are provided via a link: