luku 15 – unix domain socket

27
TEKNIIKAN JA TALOUDEN YLIOPISTO www.lut.fi

Upload: arissa

Post on 19-Jan-2016

60 views

Category:

Documents


0 download

DESCRIPTION

LUKU 15 – Unix Domain Socket. Unix Domain Socket Descriptorien välittäminen prosessien välillä Asiakkaan tietojen välittäminen (client credentials). UNIX Domain Socket. Socket rajapintaa käyttävä IPC mekanismi Stream ja Datagram protokollat ovat tuettuja, (RAW) ei. Osoitestruktuuri. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: LUKU 15 – Unix Domain Socket

TEKNIIKAN JA TALOUDEN YLIOPISTO

www.lut.fi

Page 2: LUKU 15 – Unix Domain Socket

LUKU 15 – Unix Domain Socket

Unix Domain Socket Descriptorien välittäminen

prosessien välillä Asiakkaan tietojen välittäminen

(client credentials)

Page 3: LUKU 15 – Unix Domain Socket

UNIX Domain Socket

Socket rajapintaa käyttävä IPC mekanismi Stream ja Datagram protokollat ovat tuettuja,

(RAW) ei

Page 4: LUKU 15 – Unix Domain Socket

Osoitestruktuuri

#include sys/un.h

struct sockaddr_un {

sa_family_t sun_family;

char sun_path[108];

};

sun_path[0] = ”INADDR_ANY”;

Page 5: LUKU 15 – Unix Domain Socket

unixdomain/unixbind.cintmain(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: LUKU 15 – Unix Domain Socket

Huomioita

Bind ei onnistu, jos tiedoston nimi on jo olemassa

→unlink()

Tarkasta polun mahtuminen osoitekenttään

Page 7: LUKU 15 – Unix Domain Socket

socketpair

#include <sys/types.h>

#include <sys/socket.h>

int socketpair(int family, int type, int protocol, int sv[2]);

Osoite perheen pitää olla AF_LOCAL

tyyppi voi olla SOCK_STREAM tai SOCK_DGRAM

Vertaa pipe() funktioon!

Page 8: LUKU 15 – Unix Domain Socket

Huomioita

Annetun polun tulisi olla absoluuttinen. Suhteellisten polkujen käyttäminen voi antaa epäluotettavia tuloksia.

Connect():lle annetun polun tulee olla avoin domain socket ja oikeaa protokolla tyyppiä

Tiedosto-oikeuksien tarkastus connect():in yhteydessä vastaa open() kutsua kirjoitustilaan.

Stream ja datagrammi protokollat Connect palauttaa ECONNREFUSED, mikäli kuuntelevan

socketin jono on täynnä. Ei uudelleen lähetystä! Jos bind():iä ei ole kutsuttu, datagrammin mukana ei välity

lähettäjän tietoja. Vastaanottaja ei voi siis lähettää vastausta.

Page 9: LUKU 15 – Unix Domain Socket

unixdomain/unixstrserv01.cint 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 ( ; ; ) {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 request */exit(0);

}Close(connfd); /* parent closes connected socket */

}}

Page 10: LUKU 15 – Unix Domain Socket

unixdomain/unixstrcli01.c

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

Page 11: LUKU 15 – Unix Domain Socket

unixdomain/unixdgserv01.c

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

Page 12: LUKU 15 – Unix Domain Socket

unixdomain/unixdgcli01.c

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

Page 13: LUKU 15 – Unix Domain Socket

tmpnam

#include <stdio.h>

char *tmpnam(char *s);

- Jos s == NULL, palauttaa sisäisen staattisen puskurin osoitteen

- s:n pitää olla L_tempnam pituinen

Page 14: LUKU 15 – Unix Domain Socket

Descriptorin välittäminen

Luodaan domain socket tai käytetään socketpair-funktiota forkataan, mikäli on tarkoitus, että lapsi avaa descriptorin, joka

välitetään vanhemmalle Joku prosessi avaa välitettävän descriptorin (open, pipe, mkfifo,

socket, accept) Lähettävä prosessi rakentaa msghdr struktuurin, jossa descriptori

lähetetään Lähettävä prosessi lähettää dataa ja msghdr-struktuurin sendmsg-

funktiolla Vastaanottava prosessi kutsuu recvmsg funktiota

Descriptori ja descriptorin numero prosessissa ovat eri asiat!!!

Page 15: LUKU 15 – Unix Domain Socket

Esimerkki

mycat openfile

descriptori

fork

exit( exit status )

Page 16: LUKU 15 – Unix Domain Socket

unixdomain/mycat.c

int my_open(const char *, int);

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

Page 17: LUKU 15 – Unix Domain Socket

unixdomain/myopen.c

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 18: LUKU 15 – Unix Domain Socket

msghdr

struct msghdr { void * msg_name; /* optional address */ socklen_t msg_namelen; /* size of address */ struct iovec * msg_iov; /* scatter/gather array */ size_t msg_iovlen; /* # elements in msg_iov */ void * msg_control; /* ancillary data, see below */ socklen_t msg_controllen; /* ancillary data buffer len */ int msg_flags; /* flags on received message */ };

Page 19: LUKU 15 – Unix Domain Socket

msgcontrol

struct cmsghdr {

socklen_t cmsg_len; /* data byte count, including hdr */

int cmsg_level; /* originating protocol */

int cmsg_type; /* protocol-specific type */

/* followed by u_char cmsg_data[]; */

};

Page 20: LUKU 15 – Unix Domain Socket

Makrot msgcontrol struktuurien käsittelyyn

#include <sys/socket.h>

struct cmsghdr *CMSG_FIRSTHDR(struct msghdr *msgh);struct cmsghdr *CMSG_NXTHDR(struct msghdr *msgh,

struct cmsghdr *cmsg);size_t CMSG_ALIGN(size_t length);size_t CMSG_SPACE(size_t length);size_t CMSG_LEN(size_t length);

Page 21: LUKU 15 – Unix Domain Socket

lib/read_fd

ssize_t read_fd(int fd, void *ptr, size_t nbytes, int *recvfd){

struct msghdr msg;struct iovec iov[1];ssize_t n;

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

#elseint newfd;

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

#endif

msg.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;

Page 22: LUKU 15 – Unix Domain Socket

if ( (n = recvmsg(fd, &msg, 0)) <= 0)return(n);

#ifdefHAVE_MSGHDR_MSG_CONTROLif ( (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 */#else/* *INDENT-OFF* */

if (msg.msg_accrightslen == sizeof(int))*recvfd = newfd;

else*recvfd = -1; /* descriptor was not passed */

/* *INDENT-ON* */#endif

return(n);}/* end read_fd */

ssize_tRead_fd(int fd, void *ptr, size_t nbytes, int *recvfd){

ssize_t n;

if ( (n = read_fd(fd, ptr, nbytes, recvfd)) < 0)err_sys("read_fd error");

return(n);}

Page 23: LUKU 15 – Unix Domain Socket

unixdomain/openfile.cintmain(int argc, char **argv){

int fd;

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

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

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

exit(0);}

Page 24: LUKU 15 – Unix Domain Socket

lib/write_fd.c

ssize_twrite_fd(int fd, void *ptr, size_t nbytes, int sendfd){

struct msghdr msg;struct iovec iov[1];

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

cmptr = CMSG_FIRSTHDR(&msg);cmptr->cmsg_len = CMSG_LEN(sizeof(int));cmptr->cmsg_level = SOL_SOCKET;cmptr->cmsg_type = SCM_RIGHTS;*((int *) CMSG_DATA(cmptr)) = sendfd;

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

#endif

msg.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;

return(sendmsg(fd, &msg, 0));}

Page 25: LUKU 15 – Unix Domain Socket

cmsgcred

struct cmscred {

pid_t cmcred_pid; // PID of sender

uid_t cmcred_uid; // Real UID of sender

uid_t cmcred_euid; // Effective UID

gid_t cmcred_gid; // Real GID of process

gid_t cmcred_groups[CMGROUP_MAX];

};

Page 26: LUKU 15 – Unix Domain Socket

unixdomain/readcred.c

#define CONTROL_LEN (sizeof(struct cmsghdr) + sizeof(struct cmsgcred))

ssize_tread_cred(int fd, void *ptr, size_t nbytes, struct cmsgcred *cmsgcredptr){

struct msghdr msg;struct iovec iov[1];char control[CONTROL_LEN];int n;

msg.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;msg.msg_control = control;msg.msg_controllen = sizeof(control);msg.msg_flags = 0;

if ( (n = recvmsg(fd, &msg, 0)) < 0)return(n);

cmsgcredptr->cmcred_ngroups = 0; /* indicates no credentials returned */if (cmsgcredptr && msg.msg_controllen > 0) {

struct cmsghdr *cmptr = (struct cmsghdr *) control;

if (cmptr->cmsg_len < CONTROL_LEN)err_quit("control length = %d", cmptr->cmsg_len);

if (cmptr->cmsg_level != SOL_SOCKET)err_quit("control level != SOL_SOCKET");

if (cmptr->cmsg_type != SCM_CREDS)err_quit("control type != SCM_CREDS");

memcpy(cmsgcredptr, CMSG_DATA(cmptr), sizeof(struct cmsgcred));}

return(n);

Page 27: LUKU 15 – Unix Domain Socket

unixdomain/strecho.c

ssize_t read_cred(int, void *, size_t, struct cmsgcred *);

voidstr_echo(int sockfd){

ssize_t n;int i;char buf[MAXLINE];struct cmsgcred cred;

again:while ( (n = read_cred(sockfd, buf, MAXLINE, &cred)) > 0) {

if (cred.cmcred_ngroups == 0) {printf("(no credentials returned)\n");

} else {printf("PID of sender = %d\n", cred.cmcred_pid);printf("real user ID = %d\n", cred.cmcred_uid);printf("real group ID = %d\n", cred.cmcred_gid);printf("effective user ID = %d\n", cred.cmcred_euid);printf("%d groups:", cred.cmcred_ngroups - 1);for (i = 1; i < cred.cmcred_ngroups; i++)

printf(" %d", cred.cmcred_groups[i]);printf("\n");

}Writen(sockfd, buf, n);

}

if (n < 0 && errno == EINTR)goto again;

else if (n < 0)err_sys("str_echo: read error");

}