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 = %dn", addr2.sun_path, len);

          exit(0);
}
socketpair Function

• Create two sockets that are then connected
  together(only available in unix domain
  socket)
#include<sys/socket.h>
int socketpair(int family, int type, int protocol, int sockfd[2]);
                          return: nonzero if OK, -1 on error

• family must be AF_LOCAL
• protocol must be 0
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
mycat                                        openfile

                          fork

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

                           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

Npc14

  • 1.
  • 2.
    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
  • 3.
    Introduction • Unix domainprotocol – perform client-server communication on a single host using same API that is used for client-server model on the different hosts.
  • 4.
    unix domain socketaddress 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
  • 5.
    #include "unp.h" int main(intargc, 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 = %dn", addr2.sun_path, len); exit(0); }
  • 6.
    socketpair Function • Createtwo sockets that are then connected together(only available in unix domain socket) #include<sys/socket.h> int socketpair(int family, int type, int protocol, int sockfd[2]); return: nonzero if OK, -1 on error • family must be AF_LOCAL • protocol must be 0
  • 7.
    socket function(restriction) • Defaultfile 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
  • 8.
    unix domain streamclient-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);
  • 9.
    unix domain streamclient-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 */ } }
  • 10.
    unix domain datagramclient-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 */
  • 11.
    unix domain datagramclient-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 */
  • 12.
    unix domain datagramclient-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 */
  • 13.
    passing descriptors • Currentunix system provide a way to pass any open descriptor from one process to any other process.(using sendmsg)
  • 14.
    passing descriptors(2) 1)Create aunix 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)
  • 15.
    Descriptor passing example mycat [0] [1] Figure 14.7) mycat program after create stream pipe using socketpair
  • 16.
    mycat openfile fork Exec(command-line args) [0] [1] descriptor Figure 14.8) mycat program after invoking openfile program
  • 17.
    #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)
  • 18.
    #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
  • 19.
    /* 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
  • 20.
    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 */
  • 21.
    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