第十七章 進階程序間通信(部分):
#include <stropts.h>
int fattach(int filedes, const char * path);
if success return 0, else error return -1
#include <stropts.h>
int fdetach(const char * path);
if success return 0, else error return -1
#include <sys/socket.h>
int socketpair(int domain, int type, int protocol, int sockfd[2]);
if success return 0, else error return -1
struct sockaddr_un { /* Linux and Solaris */
sa_family_t sun_family; /* AF_UNIX */
char sun_path[108]; /* pathname */
};
struct sockaddr_un { /* FreeBSD and Mac OS X */
unsigned char sun_len; /* length includeing null */
sa_family_t sun_family; /* AF_UNIX */
char sun_path[104]; /* pathname */
};
示例:
#include <unistd.h>
int s_pipe(int fd[2])
{
return(pipe(fd));
}
#include <sys/socket.h>
/*
* returns a full-duplex "stream" pipe (a UNIX domain socket)
* with the two file descriptors returned in fd[0] and fd[1]
*/
int
s_pipe(int fd[2])
{
return(socketpair(AF_UNIX, SOCK_STREAM, 0, fd));
}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include "s_pipe_u.h"
/* #include "s_pipe_p.h" */
#define MAXLINE 1024
void
sig_pipe(int signo)
{
printf("SIGPIPE caught\n");
exit(1);
}
int
main(void)
{
int n;
int fd[2];
pid_t pid;
char line[MAXLINE];
if (signal(SIGPIPE, sig_pipe) == SIG_ERR) {
printf("signal error\n");
exit(1);
}
if (s_pipe(fd) < 0) { /* need only a single stream pipe */
printf("s_pipe error\n");
exit(1);
}
if ((pid = fork()) < 0) {
printf("fork error\n");
exit(1);
}
else if (pid > 0) {
close(fd[1]);
while (fgets(line, MAXLINE, stdin) != NULL) {
n = strlen(line);
if (write(fd[0], line, n) != n) {
printf("write error to pipe\n");
exit(1);
}
if ((n = read(fd[0], line, MAXLINE)) < 0) {
printf("read error from pipe\n");
exit(1);
}
if (n == 0) {
printf("child closed pipe\n");
break;
}
line[n] = 0;
if (fputs(line, stdout) == EOF) {
printf("fgets error\n");
exit(1);
}
}
if (ferror(stdin)) {
printf("fgets error on stdin\n");
exit(1);
}
exit(0);
}
else {
close(fd[0]);
if (fd[1] != STDIN_FILENO &&
dup2(fd[1], STDIN_FILENO) != STDIN_FILENO) {
printf("dup2 error to stdin\n");
exit(1);
}
if (fd[1] != STDOUT_FILENO &&
dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
printf("dup2 error to stdout\n");
exit(1);
}
if (execl("./add2", "add2", NULL) < 0) {
printf("execl error\n");
}
exit(1);
}
exit(0);
}
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stddef.h>
int
main(void)
{
int fd;
int size;
struct sockaddr_un un;
un.sun_family = AF_UNIX;
strcpy(un.sun_path, "foo.socket");
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
printf("socket error\n");
exit(1);
}
size = offsetof(struct sockaddr_un, sun_path) + strlen(un.sun_path);
if (bind(fd, (struct sockaddr *)&un, size) < 0) {
printf("bind failed\n");
exit(1);
}
printf("UNIX domain socket bound\n");
unlink("foo.socket");
exit(0);
}
#include <fcntl.h>
#include <stropts.h>
/* pipe permissions: user rw, group rw, others rw */
#define FIFO_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
/*
* establish an endpoint to listen for connect requests
* returns fd if all OK, <0 on error
*/
int
srv_listen(const char * name)
{
int tempfd;
int fd[2];
/*
* create a file: mount point for fattach()
*/
unlink(name);
if ((tempfd = creat(name, FIFO_MODE)) < 0) {
return(-1);
}
if (close(tempfd) < 0) {
return(-2);
}
if (pipe(fd) < 0) {
return(-3);
}
/*
* push connld & fattach() on fd[1]
*/
if (ioctl(fd[1], I_PUSH, "connld") < 0) {
close(fd[0]);
close(fd[1]);
return(-4);
}
if (fattach(fd[1], name) < 0) {
close(fd[0]);
close(fd[1]);
return(-5);
}
close(fd[1]); /* fattach holds this end open */
return(fd[0]); /* fd[0] is where client connections arrive */
}
#include <stdio.h>
#include <stropts.h>
/*
* wait for a client connection to arrive, and accept it
* we also obtain the client's user id
* returns new fd if all OK, <0 on error
*/
int
srv_accept(int listenfd, uid_t * uidptr)
{
struct strrecvfd recvfd;
if (ioctl(listenfd, I_RECVFD, &recvfd) < 0) {
return(-1); /* could be EINFT if signal caught */
}
if (uidptr != NULL) {
*uidptr = recvfd.uid; /* effective uid of caller */
}
return(recvfd.fd); /* return the new descriptor */
}
#include <fcntl.h>
#include <stropts.h>
/*
* create a client endpoint and connect to a server
* returns fd if all Ok, <0 on error
*/
int
clt_connect(const char * name)
{
int fd;
/* open the mounted stream */
if ((fd = open(name, O_RDWR)) < 0) {
return(-1);
}
if (isastream(fd) == 0) {
close(fd);
return(-2);
}
return(fd);
}
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#include <stddef.h>
#define QLEN 10
/*
* create a server endpoint of a connection
* returns fd if all OK, <0 on error
*/
int
srv_listen(const char * name)
{
int fd;
int len;
int err;
int rval;
struct sockaddr_un un;
/* create a UNIX domain stream socket */
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
return(-1);
}
unlink(name); /* in case it already exists */
/* fill in socket address structure */
memset(&un, 0, sizeof(un));
un.sun_family = AF_UNIX;
strcpy(un.sun_path, name);
len = offsetof(struct sockaddr_un, sun_path) + strlen(name);
/* bind the name to the descriptor */
if (bind(fd, (struct sockaddr *)&un, len) < 0) {
rval = -2;
goto errout;
}
if (listen(fd, QLEN) < 0) { /* tell kernel we are a server */
rval = -3;
goto errout;
}
return(fd);
errout:
err = errno;
close(fd);
errno = err;
return(rval);
}
#include <sys/socket.h>
#include <sys/un.h>
#include <time.h>
#include <time.h>
#include <errno.h>
#include <fcntl.h>
#include <stddef.h>
#define STALE 30 /* client's name cannot be older than this (sec) */
/*
* wait for a client connection to arrive, and accept it
* we alse obtain the client's user id from the pathname
* that is must bind before calling us
* returns new fd if all OK, <0 on error
*/
int
srv_accept(int listenfd, uid_t * uidptr)
{
int clifd;
int len;
int err;
int rval;
time_t staletime;
struct sockaddr_un un;
struct stat statbuf;
len = sizeof(un);
if ((clifd = accept(listenfd, (struct sockaddr *)&un, &len)) < 0) {
return(-1); /* 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 */
un.sun_path[len] = 0;
if (stat(un.sun_path, &statbuf) < 0) {
rval = -2;
goto errout;
}
#ifdef S_ISSOCK /* not defined for SVR4 */
if (S_ISSOCK(statbuf.st_mode) == 0) {
rval = -3; /* not a socket */
goto errout;
}
#endif
if ((statbuf.st_mode & (S_IRWXG | S_IRWXO)) ||
(statbuf.st_mode & S_IRWXU) != S_IRWXU) {
rval = -4; /* is not rwx------ */
goto errout;
}
staletime = time(NULL) - STALE;
if (statbuf.st_atime < staletime ||
statbuf.st_ctime < staletime ||
statbuf.st_mtime < staletime) {
rval = -5; /* i-node is too old */
goto errout;
}
if (uidptr != NULL) {
*uidptr = statbuf.st_uid; /* return uid of caller */
}
unlink(un.sun_path); /* we are done with pathname now */
return(clifd);
errout:
err = errno;
close(clifd);
errno = err;
return(rval);
}
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <stddef.h>
#define CLI_PATH "/var/tmp/" /* +5 for pid = 14 chars */
#define CLI_PERM S_IRWXU /* rwx for user only */
/*
* create a client endpoint and connect to a server
* returns fd if all OK, <0 on error
*/
int
clt_connect(const char * name)
{
int fd;
int len;
int err;
int rval;
struct sockaddr_un un;
/* create a UNIX domain stream socket */
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
return(-1);
}
/* fill socket address structure with our address */
memset(&un, 0, sizeof(un));
un.sun_family = AF_UNIX;
sprintf(un.sun_path, "%s%05d", CLI_PATH, getpid());
len = offsetof(struct sockaddr_un, sun_path) + strlen(un.sun_path);
unlink(un.sun_path); /* in case it already exists */
if (bind(fd, (struct sockaddr *)&un, len) < 0) {
rval = -2;
goto errout;
}
if (chmod(un.sun_path, CLI_PERM) < 0) {
rval = -3;
goto errout;
}
/* fill socket address structure with server's address */
memset(&un, 0, sizeof(un));
un.sun_family = AF_UNIX;
strcpy(un.sun_path, name);
len = offsetof(struct sockaddr_un, sun_path) + strlen(name);
if (connect(fd, (struct sockaddr *)&un, len) < 0) {
rval = -4;
goto errout;
}
return(fd);
errout:
err = errno;
close(fd);
errno = err;
return(rval);
}