Upload
vamsitricks
View
271
Download
4
Tags:
Embed Size (px)
Citation preview
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() */
elseerr_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"
intmain(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
[0] [1]
mycat
Figure 14.7) mycat program after create stream pipe using socketpair
fork
[1][0]Exec(command-line args)
mycat openfile
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"
intmy_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