Npc14

21
Chapter 14 Unix domain protocol

Transcript of Npc14

Page 1: Npc14

Chapter 14

Unix domain protocol

Page 2: Npc14

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

Page 3: Npc14

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.

Page 4: Npc14

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

Page 5: Npc14

#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);}

Page 6: Npc14

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

Page 7: Npc14

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

Page 8: Npc14

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);

Page 9: Npc14

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 */

}}

Page 10: Npc14

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 */

Page 11: Npc14

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 */

Page 12: Npc14

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 */

Page 13: Npc14

passing descriptors

• Current unix system provide a way to pass any open descriptor from one process to any other process.(using sendmsg)

Page 14: Npc14

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)

Page 15: Npc14

Descriptor passing example

[0] [1]

mycat

Figure 14.7) mycat program after create stream pipe using socketpair

Page 16: Npc14

fork

[1][0]Exec(command-line args)

mycat openfile

descriptor

Figure 14.8) mycat program after invoking openfile program

Page 17: Npc14

#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)

Page 18: Npc14

#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

Page 19: Npc14

/* 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

Page 20: Npc14

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 */

Page 21: Npc14

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