Chinaunix首页 | 论坛 | 博客
  • 博客访问: 334310
  • 博文数量: 214
  • 博客积分: 4258
  • 博客等级: 上校
  • 技术积分: 2021
  • 用 户 组: 普通用户
  • 注册时间: 2010-12-02 09:16
个人简介

http://blog.csdn.net/ly21st http://ly21st.blog.chinaunix.net

文章分类

全部博文(214)

文章存档

2018年(16)

2015年(1)

2014年(2)

2012年(22)

2011年(173)

分类: LINUX

2011-09-27 13:38:58

14.1 概述

       Unix域提供了两种类型的套接口:字节流套接口(与tcp类似)和数据报套接口(与udp类似)

14.2 Unix域套接口地址结构

14.7 描述字传递

当考虑从一个进程向另一个进程传递所打开的描述字时,我们通常会想到:

1)fork调用后,子进程共享父进程的所有打开的描述字;

2)在调用exec时所有描述字仍保持打开。

 

在两个进程间传递描述字的步骤是:

1)创建一个字节流的或数据报的Unix域套接口。如果目标是fork一个子进程,让子进程打开描述字并将它传回给父进程,那么父进程可以用socketpair创建一个流管道,用它来传递描述字。如果进程间没有亲缘关系,那么服务器必须创建一个Unix域字节流套接口,bind一个路径名,让客户connect到这个套接口,然后客户可以向服务器发送一个请求以打开某个描述字,服务器将描述字通过Unix域套接口传回。

2)进程可以用任何返回描述字的Unix函数打开一个描述字;

3)发送进程建立一个msghdr结构,其中包含要传递的描述字。发送进程调用sendmsg通过第一步得到的Unix域套接口发送描述字。这时我们说这个描述字是“飞行中”的。即使在发送进程调用sendmsg后,但在仅售进程调用recvmsg之前将描述字关闭,它仍会为接收进程保持打开状态。描述字哦的发送导致它的访问计数加1

4)接收进程调用recvmsgunix域套接口上接收描述字。通常接收进程收到的描述字编号和发送进程中的描述字的编号不同,但这没有问题。传递描述字不是传递描述字的编号,而是在接收进程中创建一个新的描述字,指向内核的文件表中与发送进程发送的描述字相同的项。

 

客户和服务器之间必须有某种应用协议,使接收方知道何时接收描述字。如果接收方调用recvmsg但没有分配接收描述字的空间,而且有一个描述字哦已被传递并正待读出,这个已传递的描述字就会关闭。在用recvmsg接收描述字时还要避免使用MSG_PEEK标志,否则后果不可预测。

 

通过执行另一个程序来打开文件的好处是,另一个程序可以是一个setuidroot的程序,能打开原来没有权限打开的文件。这个程序能够扩展通常的Unix权限(用户、用户组和其他用户)到它想要的任何形式的访问检查。

 

进程间传递打开的描述最的一个例子

# mycat.c

 

#include  "unp.h"

 

int     my_open(const char *, int);

 

int

main(int argc, char **argv)

{

   int     fd, n;

   char buff[BUFFSIZE];

 

   if (argc != 2)

     err_quit("usage: mycat ");

 

   if ( (fd = my_open(argv[1], O_RDONLY)) < 0)

     err_sys("cannot open %s", argv[1]);

 

   while ( (n = Read(fd, buff, BUFFSIZE)) > 0)

     Write(STDOUT_FILENO, buff, n);

 

   exit(0);

}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

# myopen.c

 

#include  "unp.h"

 

int

my_open(const char *pathname, int mode)

{

   int       fd, sockfd[2], status;

   pid_t     childpid;

   char    c, argsockfd[10], argmode[10];

 

   Socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd);

 

   if ( (childpid = Fork()) == 0) {    /* child process */

     Close(sockfd[0]);

     snprintf(argsockfd, sizeof(argsockfd), "%d", sockfd[1]);

     snprintf(argmode, sizeof(argmode), "%d", mode);

     execl("./openfile", "openfile", argsockfd, pathname, argmode,

          (char *) NULL);

     err_sys("execl error");

   }

 

   /* parent process - wait for the child to terminate */

   Close(sockfd[1]);      /* close the end we don't use */

 

   Waitpid(childpid, &status, 0);

   if (WIFEXITED(status) == 0)

     err_quit("child did not terminate");

   if ( (status = WEXITSTATUS(status)) == 0)

     Read_fd(sockfd[0], &c, 1, &fd);

   else {

     errno = status;   /* set errno value from child's status */

     fd = -1;

   }

 

   Close(sockfd[0]);

   return(fd);

}

 

 

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

# read_fd.c

/* include read_fd */

#include  "unp.h"

 

ssize_t

read_fd(int fd, void *ptr, size_t nbytes, int *recvfd)

{

   struct msghdr  msg;

   struct iovec iov[1];

   ssize_t      n;

 

#ifdef  HAVE_MSGHDR_MSG_CONTROL

   union {

     struct cmsghdr  cm;

     char          control[CMSG_SPACE(sizeof(int))];

   } control_un;

   struct cmsghdr *cmptr;

 

   msg.msg_control = control_un.control;

   msg.msg_controllen = sizeof(control_un.control);

#else

   int          newfd;

 

   msg.msg_accrights = (caddr_t) &newfd;

   msg.msg_accrightslen = sizeof(int);

#endif

 

   msg.msg_name = NULL;

   msg.msg_namelen = 0;

 

   iov[0].iov_base = ptr;

   iov[0].iov_len = nbytes;

   msg.msg_iov = iov;

   msg.msg_iovlen = 1;

 

   if ( (n = recvmsg(fd, &msg, 0)) <= 0)

     return(n);

 

#ifdef  HAVE_MSGHDR_MSG_CONTROL

   if ( (cmptr = CMSG_FIRSTHDR(&msg)) != NULL &&

       cmptr->cmsg_len == CMSG_LEN(sizeof(int))) {

     if (cmptr->cmsg_level != SOL_SOCKET)

        err_quit("control level != SOL_SOCKET");

     if (cmptr->cmsg_type != SCM_RIGHTS)

        err_quit("control type != SCM_RIGHTS");

     *recvfd = *((int *) CMSG_DATA(cmptr));

   } else

     *recvfd = -1;     /* descriptor was not passed */

#else

/* *INDENT-OFF* */

   if (msg.msg_accrightslen == sizeof(int))

     *recvfd = newfd;

   else

     *recvfd = -1;     /* descriptor was not passed */

/* *INDENT-ON* */

#endif

 

   return(n);

}

/* end read_fd */

 

ssize_t

Read_fd(int fd, void *ptr, size_t nbytes, int *recvfd)

{

   ssize_t   n;

 

   if ( (n = read_fd(fd, ptr, nbytes, recvfd)) < 0)

     err_sys("read_fd error");

 

   return(n);

}

 

 

__________________________________________________________________________________

openfile.c

#include  "unp.h"

 

int

main(int argc, char **argv)

{

   int     fd;

 

   if (argc != 4)

     err_quit("openfile ");

 

   if ( (fd = open(argv[2], atoi(argv[3]))) < 0)

     exit( (errno > 0) ? errno : 255 );

 

   if (write_fd(atoi(argv[1]), "", 1, fd) < 0)

     exit( (errno > 0) ? errno : 255 );

 

   exit(0);

}

 

write_fd.c

#include  "unp.h"

 

int

main(int argc, char **argv)

{

   int     fd;

 

   if (argc != 4)

     err_quit("openfile ");

 

   if ( (fd = open(argv[2], atoi(argv[3]))) < 0)

     exit( (errno > 0) ? errno : 255 );

 

   if (write_fd(atoi(argv[1]), "", 1, fd) < 0)

     exit( (errno > 0) ? errno : 255 );

 

   exit(0);

}

 

14.8 接收发送者的凭证  

阅读(300) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~