210 likes | 328 Views
Chapter 14. Unix domain protocol. contents. Introduction unix domain socket address structure socketpair socket function unix domain stream client-server unix domain datagram client-server passing descriptors receiving sender credentials. Introduction. Unix domain protocol
E N D
Chapter 14 Unix domain protocol
contents • Introduction • unix domain socket address structure • socketpair • socket function • unix domain stream client-server • unix domain datagram client-server • passing descriptors • receiving sender credentials
Introduction • Unix domain protocol • perform client-server communication on a single host using same API that is used for client-server model on the different hosts.
unix domain socket address structure • <sys/un.h> struct sockaddr_un{ uint8_t sun_len; sa_family_t sun_family; /*AF_LOCAL*/ char sun_path[104]; /*null terminated pathname*/ }; • sun_path => must null terminated
#include "unp.h" int main(int argc, char **argv) { int sockfd; socklen_t len; struct sockaddr_un addr1, addr2; if (argc != 2) err_quit("usage: unixbind <pathname>"); sockfd = Socket(AF_LOCAL, SOCK_STREAM, 0); unlink(argv[1]); /* OK if this fails */ bzero(&addr1, sizeof(addr1)); addr1.sun_family = AF_LOCAL; strncpy(addr1.sun_path, argv[1], sizeof(addr1.sun_path)-1); Bind(sockfd, (SA *) &addr1, SUN_LEN(&addr1)); len = sizeof(addr2); Getsockname(sockfd, (SA *) &addr2, &len); printf("bound name = %s, returned len = %d\n", addr2.sun_path, len); exit(0); }
socketpair Function • Create two sockets that are then connected together(only available in unix domain socket) • family must be AF_LOCAL • protocol must be 0 #include<sys/socket.h> int socketpair(int family, int type, int protocol, int sockfd[2]); return: nonzero if OK, -1 on error
socket function(restriction) • Default file access permition created by bind shiuld be 0777, modified by the current umask value • path name must be absolute pathname not a relative path name • the path name in the connect must be a pathname that is currently bound to an open unix domain socket of the same type. • Unix domain stream socket are similar to TCP socket • unix domain datagram are similar to UDP socket • unlike UDP socket, sending a datagram on an unbound unix domain datagram does not bind a pathname to the socket
unix domain stream client-server #include "unp.h" int main(int argc, char **argv) { int listenfd, connfd; pid_t childpid; socklen_t clilen; struct sockaddr_un cliaddr, servaddr; void sig_chld(int); listenfd = Socket(AF_LOCAL, SOCK_STREAM, 0); unlink(UNIXSTR_PATH); bzero(&servaddr, sizeof(servaddr)); servaddr.sun_family = AF_LOCAL; strcpy(servaddr.sun_path, UNIXSTR_PATH); Bind(listenfd, (SA *) &servaddr, sizeof(servaddr)); Listen(listenfd, LISTENQ); Signal(SIGCHLD, sig_chld);
unix domain stream client-server(2) for ( ; ; ) { clilen = sizeof(cliaddr); if ( (connfd = accept(listenfd, (SA *) &cliaddr, &clilen)) < 0) { if (errno == EINTR) continue; /* back to for() */ else err_sys("accept error"); } if ( (childpid = Fork()) == 0) { /* child process */ Close(listenfd); /* close listening socket */ str_echo(connfd); /* process the request */ exit(0); } Close(connfd); /* parent closes connected socket */ } }
unix domain datagram client-server #include "unp.h" int main(int argc, char **argv) { int sockfd; struct sockaddr_un servaddr; sockfd = Socket(AF_LOCAL, SOCK_STREAM, 0); bzero(&servaddr, sizeof(servaddr)); servaddr.sun_family = AF_LOCAL; strcpy(servaddr.sun_path, UNIXSTR_PATH); Connect(sockfd, (SA *) &servaddr, sizeof(servaddr)); str_cli(stdin, sockfd); /* do it all */ exit(0); } /* unix domain stream protocol echo client */
unix domain datagram client-server(2) #include "unp.h" int main(int argc, char **argv) { int sockfd; struct sockaddr_un servaddr, cliaddr; sockfd = Socket(AF_LOCAL, SOCK_DGRAM, 0); unlink(UNIXDG_PATH); bzero(&servaddr, sizeof(servaddr)); servaddr.sun_family = AF_LOCAL; strcpy(servaddr.sun_path, UNIXDG_PATH); Bind(sockfd, (SA *) &servaddr, sizeof(servaddr)); dg_echo(sockfd, (SA *) &cliaddr, sizeof(cliaddr)); }/* unix domain datagram protocol echo server */
unix domain datagram client-server(3) #include "unp.h" int main(int argc, char **argv) { int sockfd; struct sockaddr_un cliaddr, servaddr; sockfd = Socket(AF_LOCAL, SOCK_DGRAM, 0); bzero(&cliaddr, sizeof(cliaddr)); /* bind an address for us */ cliaddr.sun_family = AF_LOCAL; strcpy(cliaddr.sun_path, tmpnam(NULL)); Bind(sockfd, (SA *) &cliaddr, sizeof(cliaddr)); bzero(&servaddr, sizeof(servaddr)); /* fill in server's address */ servaddr.sun_family = AF_LOCAL; strcpy(servaddr.sun_path, UNIXDG_PATH); dg_cli(stdin, sockfd, (SA *) &servaddr, sizeof(servaddr)); exit(0); } /* unix domain datagram protocol echo client */
passing descriptors • Current unix system provide a way to pass any open descriptor from one process to any other process.(using sendmsg)
passing descriptors(2) 1)Create a unix domain socket(stream or datagram) 2)one process opens a descriptor by calling any of the unix function that returns a descriptor 3)the sending process build a msghdr structure containing the descriptor to be passed 4)the receiving process calls recvmsg to receive the descriptor on the unix domain socket from step 1)
Descriptor passing example mycat [0] [1] Figure 14.7) mycat program after create stream pipe using socketpair
fork mycat openfile [0] [1] Exec(command-line args) descriptor Figure 14.8) mycat program after invoking openfile program
#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 <pathname>"); 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); } mycat program show in Figure 14.7)
#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"); } myopen function(1) : open a file and return a descriptor
/* 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); } myopen function(2) : open a file and return a descriptor
receiving sender credentials • User credentials via fcred structure Struct fcred{ uid_t fc_ruid; /*real user ID*/ gid_t fc_rgid; /*real group ID*/ char fc_login[MAXLOGNAME];/*setlogin() name*/ uid_t fc_uid; /*effectivr user ID*/ short fc_ngroups; /*number of groups*/ gid_t fc_groups[NGROUPS]; /*supplemenary group IDs*/ }; #define fc_gid fc_groups[0] /* effective group ID */
receiving sender credentials(2) • Usally MAXLOGNAME is 16 • NGROUP is 16 • fc_ngroups is at least 1 • the credentials are sent as ancillary data when data is sent on unix domain socket.(only if receiver of data has enabled the LOCAL_CREDS socket option) • on a datagram socket , the credentials accompany every datagram. • Credentials cannot be sent along with a descriptor • user are not able to forge credentials