1 unix domain sockets computer network programming

25
1 Unix Domain Sockets Computer Network Programming

Upload: donald-horton

Post on 17-Dec-2015

235 views

Category:

Documents


6 download

TRANSCRIPT

Page 1: 1 Unix Domain Sockets Computer Network Programming

1

Unix Domain Sockets

Computer Network Programming

Page 2: 1 Unix Domain Sockets Computer Network Programming

2

Outline

• Motivation

• What are Unix domain sockets• address structure

• How to use unix domain sockets

• Example client-server apps using UDSs.

• Example use of UDSs.• Passing descriptors

• Passing credentials

Page 3: 1 Unix Domain Sockets Computer Network Programming

3

Motivation– We need a way of interprocess communication

between process running in the same host• faster than TCP/IP

– But we want to use the same socket API• hence our programs for TCP and UDP sockets will work

with little modifications for processes running on the same host.

– (TCP and UDP sockets can also be used for communicatşon between process on the same host but it is slower

Use Unix Domain Sockets

Page 4: 1 Unix Domain Sockets Computer Network Programming

4

Unix Domain Sockets

• Not an actual protocol suite like TCP/IP

• For Unix only

• A way of performing IPC between processes running on the same host using the same socket API.

• Two types of UD sockets• stream sockets (similar to TCP)

• datagram sockets (similar to UDP)

Page 5: 1 Unix Domain Sockets Computer Network Programming

5

Uses of UD sockets

– They are faster than TCP and UDP sockets• at least twice

• for example X Window System uses UD sockets of client is on the same host as the server

» client checks the DISPLAY environment variable

– Used for passing file (socket) descriptors• any descriptor can be passed

– Used to pass client’s credentials (user ID etc) to the server (can be used for security check).

Page 6: 1 Unix Domain Sockets Computer Network Programming

6

Protocol Addresses– Pathnames are used as protocol addresses

• instead of IP address, port number pair

struct sockaddr_un {uint8_t sun_len;/* 1 byte */

sa_familiy_t sun_family;/* 1 byte */char sun_path[104];

}

– The pathnames must be null-terminated. – If pathname is null-string, it corresponds to

INADDR_ANY constant.

Page 7: 1 Unix Domain Sockets Computer Network Programming

7

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

How to bind a protocol address (pathname) to a UD socket

If pathname exists already, bind will fail. Therefore we remove the pathname first using unlink function

When bind() is called it createsa file(path) corresponding to the pathname (protocol address) provided as argument

Page 8: 1 Unix Domain Sockets Computer Network Programming

8

Notes about use Socket Function with UD sockets

– The pathname created should have file permissions as 0777

– can read, write and execute by user, group or others

– The pathname should be absolute pathname. – so that client and server does not have to be run in the

same directory

– For a client to be able to issue a connect()– there has to be pathname in the file system

– there has to be an open socket on that pathname

– the socket and pathname should be of the same type

» stream or datagram

Page 9: 1 Unix Domain Sockets Computer Network Programming

9

Notes about use Socket Function with UD sockets

– Unix domain stream sockets are similar to TCP sockets: byte stream oriented, no record boundaries

– Unix domain datagram sockets are similar to UDP sockets: unreliable and preserves record boundaries.

– Unlike UDP, sending a datagram out of a socket does not bind a pathname to the socket.

» Hence receiver can not send a reply back unless the sender binds a pathname to its UD socket.

» Similarly issuing connect does not bind a pathname to the socket

Page 10: 1 Unix Domain Sockets Computer Network Programming

10

Sockpair function

• This function creates two sockets that are then connected together. (only for Unix domain sockets)

int socketpair(int family, int type, int protocol, int sockfd[2]);» family is AF_LOCAL

» protocol is 0

» type is SOCK_DGRAM or SOCK_STREAM

» sockfd[0] and sockfd[1] are two socket descriptors

• created sockets are unnamed

• they are full-duplex (data can go in each direction)

• also called stream pipes if type is SOCK_STREAM

Page 11: 1 Unix Domain Sockets Computer Network Programming

11

#define UNIXSTR_PATH "/tmp/unix.str"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); for ( ; ; ) {

/* Rest is same with a TCP server: accept() called fork() called child process serves the requests*/

} }

Example of Unix Domain Sockets: Stream Server

Page 12: 1 Unix Domain Sockets Computer Network Programming

12

#define UNIXSTR_PATH "/tmp/unix.str”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);}

Example of Unix Domain Sockets: Stream Client

Same with a TCP clientexcept we need to filla sockaddr_un structure withthe information about the serverprotocol address

Page 13: 1 Unix Domain Sockets Computer Network Programming

13

#define UNIXDG_PATH "/tmp/unix.dg"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));}

Example of Unix Domain Sockets: Datagram Server

Same with a UDP serverexcept we need to filla sockaddr_un structure withthe information about the serverprotocol addressand bind it to theserver socket

Page 14: 1 Unix Domain Sockets Computer Network Programming

14

#define UNIXDG_PATH "/tmp/unix.dg"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);}

Example of Unix Domain Sockets: Datagram Client

Similar to a UDP clientexcept we need to binda protocol addressto the socket

tmpnam() generatesa temporary file name.

Page 15: 1 Unix Domain Sockets Computer Network Programming

15

Passing Descriptors• A descriptor is an integer value that corresponds to a

socket or file or terminal device etc.

• We learned how to pass open descriptors from patent to child.

– Similarly we can pass descriptors as the arguments of exec while executing an other program from the child process

– Files and sockets corresponding to descriptors that are passed from parent to child remain open.

• We want also pass descriptors:– from a child to a parent

– between two unrelated processes

• We can achieve this by using Unix domain sockets

Page 16: 1 Unix Domain Sockets Computer Network Programming

16

Steps involved in passing descriptors between two processes

• Create a Unix domain socket (stream or datagram)– if the processes are parent and child then we can use socketpair

function– if processes are unrelated then one should be server and bind a

well known pathname to the socket and the client should talk/connect to this socket.

• One process (sending process)– open a descriptor

» for example open a file (using open, socket, accept, pipe…)– builds a msghdr structure containg the descriptor to be passed

and then calls sendmsg

• Receiving process calls recvmsg to obtain the descriptor and then uses it.

Page 17: 1 Unix Domain Sockets Computer Network Programming

17

Example: mycat programWe want to execute the following scenerio

parent child

file

fd

fd

Unix domainstream communication

fd

(1)

(2)

(3)

stdout(screen)

(4)

(1) Child open a file and obtains descriptor fd(2) Child sends the descriptor to parent(3) Parent reads from the received descriptor - namely reads from the file(4) Parent prints the content of the fileto the screen

mycatprogram

By this method, a process may be executing as root and opening

important files for other clients.

openfile

program

Page 18: 1 Unix Domain Sockets Computer Network Programming

18

mycat programfist create a socket pair (stream pipe)

[0] [1]

[0] [1]

mycat openfile

fork

exec(pathname, mode, sockfd)

descriptor

exit (exit status)

then fork and exec a new program

mycat

Page 19: 1 Unix Domain Sockets Computer Network Programming

19

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

Page 20: 1 Unix Domain Sockets Computer Network Programming

20

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

Page 21: 1 Unix Domain Sockets Computer Network Programming

21

/* * Message header for recvmsg and sendmsg calls. */#if !defined(_XPG4_2)struct msghdr { caddr_t msg_name; /* optional address */ int msg_namelen; /* size of address */ struct iovec *msg_iov; /* scatter/gather array */ int msg_iovlen; /* # elements in msg_iov */ caddr_t msg_accrights; /* access rights sent/received */ int msg_accrightslen;};#elsestruct msghdr { void *msg_name; /* optional address */ size_t msg_namelen; /* size of address */ struct iovec *msg_iov; /* scatter/gather array */ int msg_iovlen; /* # elements in msg_iov */ void *msg_control; /* ancillary data */ size_t msg_controllen; /* ancillary data buffer len */ int msg_flags; /* flags on received message */};#endif /* !defined(_XPG4_2) */

Definition of msghdr structure in /usr/include/sys/socket.h

Page 22: 1 Unix Domain Sockets Computer Network Programming

22

ssize_t read_fd(int fd, void *ptr, size_t nbytes, int *recvfd){ struct msghdr msg; struct iovec iov[1]; ssize_t n; int newfd;

#ifdef HAVE_MSGHDR_MSG_CONTROLunion { 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);

#elsemsg.msg_accrights = (caddr_t) &newfd;msg.msg_accrightslen = sizeof(int);

#endifmsg.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); /* continued in the next page */

read_fd() function

Page 23: 1 Unix Domain Sockets Computer Network Programming

23

/* conitinued from previous page */#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 */

#elseif (msg.msg_accrightslen == sizeof(int))

*recvfd = newfd;else

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

return(n);}

read_fd() function continued

Page 24: 1 Unix Domain Sockets Computer Network Programming

24

openfile programintmain(int argc, char **argv){ int fd; ssize_t n;

if (argc != 4) err_quit("openfile <sockfd#> <filename> <mode>");

if ( (fd = open(argv[2], atoi(argv[3]))) < 0) exit( (errno > 0) ? errno : 255 );

if ( (n = write_fd(atoi(argv[1]), "", 1, fd)) < 0) exit( (errno > 0) ? errno : 255 ); exit(0);}

write_fd similar to read_fd. It prepares a msghdr structure withcontrol data (descriptor) in it and sends it to the mycat programusing sendmsg() function over Unix Datagram Stream Socket.

Page 25: 1 Unix Domain Sockets Computer Network Programming

25

Sending Credentials

– Similar to sending descriptors, user credentials can be sent over a Unix datagram socket using sendmsg() and recvmsg() again as control (ancillary) data

• credentials include: – read user ID (from password file for user)

– read group ID (from password file for user)

– effective user ID

– login name

– supplementary group id’s etc.