360 likes | 553 Views
Passing Credentials And File Description PL 실험실 석사 1 학기 박병태. 목 차. Ancillary Data 소개 I/O Vector 소개 sendmsg(2) 와 recvmsg(2) 함수 Ancillary Data 구조체와 매크로 Ancillary Data 사용 예 Socket Server 의 테스트. Ancillary Data 소개. 특징 credential 은 보조데이타의 부분으로 수락 보조데이터는 보통의 자료를 수반
E N D
Passing Credentials And File Description PL 실험실 석사 1학기 박병태
목 차 • Ancillary Data 소개 • I/O Vector 소개 • sendmsg(2)와 recvmsg(2) 함수 • Ancillary Data 구조체와 매크로 • Ancillary Data 사용 예 • Socket Server의 테스트
Ancillary Data 소개 • 특징 • credential은 보조데이타의 부분으로 수락 • 보조데이터는 보통의 자료를 수반 • 보조데이터는 여러 개의 보조 항목을 포함
I/O Vector 소개(1) • I/O Vector(struct iovec) struct iovec ptr_t iov_base; /*시작 주소*/ size_t iov_len; /*바이트 길이*/ Struct iovec은 하나의 백터 원리로 정의된다 보통 이구조체는 여러 개의 요소에서 배열처럼 사용 readv(2)와 writev(2)의 함수에서 사용
I/O Vector 소개(2) • readv(2)와 writev[2] 함수 • 함수의 원형 #include <sys/uio.h> int readv(int fd, const struct iovec *vector, int count) int writev(int fd, const struct iovec *vector, int count) • 3가지 인수의 대한 설명 int fd : 파일 기술자 const struct iovec *vector : 읽고 쓰기 위해 사용되는 I/O vector Int count: 사용하는 백터 요소의 수
I/O Vector 소개(3) • writev(2)를 사용하는 예제 17.1 • 순서도 함수선언/초기화 Iovec iov[] 정의 I/O vector 할당 스트링 길이 결정 Writev(2) 시스템 콜
I/O Vector 소개(4) • 소스분석(예제 17.1) 9 : static char part2[] = “ THIS IS FROM WRITEV”; 10: static char part3[] = “]\n”; 11: static char part1[] = “[“; 물리적으로 분리된 스트링 세개를 정의 12: struct iovec iov[3]; I/O vector iov[3] 이 정의 14: iov[0].iov_base = part1; 15: iov[0].iov_len = strlen(part1); 14라인에서 첫번째 스트링의 포인터를 I/O Vector에 할당 15라인에서 첫번째 스트링의 길이가 결정 23: writev(1, iov, 3); 23라인에서 writev 시스템 콜이 실행된다. 인수의 1은 표준출력에 사용되고 I/Ovector 배열 iov이 제공되고 3은 세개의 값을가진 3개의 인자로 정의 된다.
I/O Vector 소개(5) • 실행 • 실행결과 $ make writev gcc -g -c -D_GNU_SOURCE -Wall -Wreturn -type writev.c gcc writev -O -o writev $ ./writev [THIS IS FROM WRITEV] $
sendmsg(2)와 recvmsg(2) 함수(1) • sendmsg(2) 함수 • sendmsg 함수의 원형 # include <sys/types.h> # include <sys/socket.h> int sendmsg(int s, const struct msghdr *msg, unsigned int flags); • Sendmsg에 대한 설명 • 보내는 메시지 소켓 S • 구조체 포인터 msg메시지 헤더는 이 함수호출의 연산자를 제어. • 선택적 플래그 비트 인수. 이것은 send(2)와 sendto(2)의 함수호출에 유효한 같은 플래그 임. • 이 함수의 리턴값은 보낸 바이트 수
sendmsg(2)와 recvmsg(2) 함수(2) • recvmsg(2) 함수 • 함수의 원형 # include <sys/type.h> # include <sys/socket.h> int recvmsg(int s, struct msghdr *msg, unsigned int flags); • recvmsg에 대한 설명 • 메시지를 받는 소켓 s • 구조체 포인터 msg 메시지 헤더는 함수호출의 연산자 제어 • 선택적 플래그 비트 인수. 이것은 recv(2)와 recvfrom(2)함수호출에 유용한 같은 플래그 • 이함수의 리턴값은 받은 바이트의 수
sendmsg(2)와 recvmsg(2) 함수(3) • Struct msghdr의 이해 • 구조체의 정의 Struct msghdr{ void *msg_name; socklen_t msg_namelen; struct iovec msg_iov; size_t *msg_iovlen; void msg_control; size_t msg_controllen; int msg_flags; } 이 구조체 맴버는 4개의 그룹으로 나눌수 있다. • 소켓 주소 맴버 msg_name과 msg_namelen • 참조 I/O vector msg_iov 와 msg_iovlen • 보조자료 버퍼 맴버 msg_control와 msg_controllen • 받아진 메시지 플레그 비트 msg_flags.
Ancillary Data 구조체와 매크로(1) • struct cmsghdr 구조체 소개 • 구조체의 정의 struct cmsghdr{ socklen_t cmsg_len; int cmsg_level; int cmsg_type; /* u_char cmsg_data[];*/ }; • 구조체 맴버에 대한 설명 • cmsg_len은 구조상의 헤더의 크기를 포함하는 보조 자료의 바이트 총계 이 값은 CMSG_LEN()매크로에 의해 계산 • cmsg_level이 값는 시작되고 있는 프로토콜 수준 • cmsg_type 이 값 제어 통제 메시지 형 • cmsg_data 이 멤버는 실제로는 존재하지 않는다. 그것은 설명에서 추가 보조 자료가 물리적으로 위치하는지 설명하는 것을 나타내어진다
ancillary object number 1 ancillary object number 2 Ancillary Data 구조체와 매크로(2) • Ancillary data 구조체의 구성 Msg_controlen CMSG_SPACE() CMSG_SPACE() CMSG_LEN() CMSG_LEN() cmsghdr cmsghdr cmsg_data[] cmsg_data[] padding cmsg_type() padding cmsg_type() cmsg_len() cmsg_len() cmsg_level() cmsg_level() Figure 17.1
Ancillary Data 구조체와 매크로(3) • cmsg(3) 매크로 소개 • cmsg(3) 구성 # include <sys/socket.h> struct cmsghdr *CMSG_FIRSTHDR(struct msghdr *msgh); size_t CMSG_ALIGN(size_t length); size_t CMSG_SPACE(size_t length); size_t CMSG_LEN(size_t length); void *CMSG_DATA(struct cmsghdr *cmsg); - 몇개의 매크로는 다른 유닉스에서는 사용가능하지 않는다 (예를 들어, FreeBSD 유닉스에는 CMSG_AIGN(), CMSG_SPACE(), CMSG_SPACE() 매크로가 없다.)
Ancillary Data 구조체와 매크로(4) • 보조데이타 루프 예제 struct msghdr msgh; /*Message Hdr*/ struct cmsghdr *cmsg /* Ptr to ancillary hdr*/ int *fd_ptr; /* Ptr fo file descript*/ int received_fd; /*the file descriptor*/ for (cmsg=CMSG_FIRSTHDR(&msgh); cmsg!=NULL; cmsg=CMSG_NXTHDR(&msgh,cmsg)){ if(cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS){ fd_ptr = (int*) CMSG_DATA(cmsg); received_fd = *fd_ptr; break; } } if(cmsg == NULL) { /* Error : No file descriptor recv`d */ }
Ancillary Data 구조체와 매크로(5) • 보조데이타 생성 sturuct msghdr msg; /*Message header*/ struct cmsghdr cmsg; /*Ptr to ancillary hdr*/ int fd; /*File descriptor to send*/ char buf[CMSG_SPACE(sizeof fd)]; /*Anc. Buf */ int fd_ptr; /*Ptr to file descriptor*/ msg.msg_control = buf; msg.msg_controllen = sizeof buf; cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; cmsg->cmsg_len = CMSG_LEN(sizeof fd); /*Initialize the payload:*/ fd_ptr = (int *) CMSG_DATA(cmsg); *fd_ptr = fd; /* Sum of the length of all control messages in the buffer: */ msg.msg_controllen = cmsg -> cmsg_len;
Ancillary Data 예제 • recvcred.c(예제 17.4) • 순서도 초 기 화 구조체 msghdr 초기화 Recv_fd() 호출 메시지 수신 사용자 인증
Ancillary Data 예제 • 초기화[32-49] 32: int s, /*Socket*/ 33: struct ucred *credp, /*Credential buffer*/ 34: void *buf, /*receiving Data buffer*/ 35: unsigned bufsiz, /* Recv. Data buf size*/ 36: void *addr, /*Received Peer address*/ 37: socklen_t *alen) /* Ptr to addr length*/ 38: 39: int z; 40: struct msghdr msgh; /* Message header */ 41: struct iovec iov[1]; /* I/O vector */ 42: struct cmsghdr *cmsgp=NULL; 43: char mbuf[CMSG_SPACE(sizeof * credp)]; 44: 45: /* 46: *Zero out message areas: 47: */ 48: memset(&msgh,0,sizeof msgh); 49: memset(&mbuf,0,sizeof mbuf);
Ancillary Data 예제 • 구조체 msghdr 초기화 54: msgh.msg_name=addr; 55: msgh.msg_namelen=alen?*alen : 0; 60: msgh.msg_iov=iov; 61: msgh.msg_iovlen=1; 66: iov[0].iov_base=buf; 67: iov[0].iov_len=bufsiz; 72: msgh.msg_control=mbuf; 73: msgh.msg_controllen=sizeof mbuf;
Ancillary Data 예제 • 메시지 수신 78: do 79: z=recvmsg(s,&msgh,0); 80: while (z==-1 && errno == EINTR); 81: 82: if(z==1) 83: return -1; /*Failed:check errno*/ 84: 85: /* 86: * If ptr alen is non-NULL, return the 87: * returned address length (datagrams): 88; */ 89: if(alen) 90: *alen=msgh.msg_namelen; 91: 92: /* 93: *Walk the list of control messages: 94: /* 95: for(cmsgp=CMSG_FIRSTHDR(&msgh); 96: cmsgp != NULL; 97: cmsgp=CMSG_NXTHDR(&msgh,cmsgp) ) 98: 99: if(cmsgp->cmsg_lever == SOL_SOCKET 100: && cmsgp->cmsg_type==SCM_CREDENTIALS)
Ancillary Data 예제 • 사용자 인증 95: for(cmsgp=CMSG_FIRSTHDR(&msgh); 96: cmsgp != NULL; 97: cmsgp=CMSG_NXTHDR(&msgh,cmsgp) ) 98: 99: if(cmsgp->cmsg_lever == SOL_SOCKET 100: && cmsgp->cmsg_type==SCM_CREDENTIALS) 101: 102: /* 103: *Pass back credentials struct: 104: */ 105: *credp=* 106: (struct ucred *) CMSG_DATA(cmsgp); 107: 108: return z; /* 3 of data byes read */ 117: errno=ENOENT; 118: return -1;
Ancillary Data 예제 • 간단한 웹 서버(예제 17.5) • 순서도 c=accept(s,(struct sockaddr *) &a_cln,*alen); 함수선언/초기화 rx=fdopen(c,"r"); tx=fdopen(dup(c),"w"); 소켓 생성/바인드 Socket(); bind(); fgets(getbuf,sizeof getbuf,rx); . Reqport(80) 호출 fput(); Listen(2) 호출 fclose() ;
Ancillary Data 예제 • reqport() 함수 • 순서도(예제 17.6) 소켓 생성 connect(2) 호출 reqport() 호출 write(2) 호출 recv-fd() 호출 close() 호출
Ancillary Data 예제 • recv_fd 함수 • 순서도(예제 17.7) 선 언 msghdr 구조체 초기화 memset(); Recv_fd() 호출 구조체 msghdr 초기화 메시지 수신 종 료
Ancillary Data 예제 • 소스분석 • 구조체 msghdr 초기화 43: msgh.msg_iov = iov; 44: msgh.msg_iovlen = 1; 50: iov[0].iov_base = dbuf; 51: iov[0].iov_len = sizeof dbuf; 56: msgh.msg_control = buf; 57: msgh.msg_controllen = sizeof buf;
Ancillary Data 예제 • 메시지 수신 62: do 63: z=recvmsg(s,&ms호,0); 64: while (z== -1 && reeno == EINTR); 65: 66: if (z==-1) 67: return -1; /* Failed: see errno*/ 73: for ( cmsgp = CMSG_FIRSTHDR(&msgh); 74: cmsgp !=NULL; 75: cmsgp = CMSG_NXTHDR(&msgh, cmsgp) 76: 77: if (cmsgp->cmsg_level == SOL_SOCKET 78: && cmsgp -> cmsg_type == SCM_RIGHTS) 82: return *(int *) CMSG_DATA(cmsgp); 92: if (z== sizeof (int) ) 93: errno = *(int *)dbuf; /* Rcvd errno*/ 94: else 95: errno = ENOENT; /*Default errno*/ 96: 97: return -1; /* Return failure indication */
Ancillary Data 예제 • sockserv 서버 프로그램 • 순서도(예제 17.8) 함 수 선언 listen(2); 호출 초 기 화 연결을 기다림 accept(); UserID 생성 Fputs(); 종 료 socket(); 호출
Ancillary Data 예제 • Send_fd() 함수 • 소켓 서버는 요구한 처리 결과를 보내주기 위하여 send_fd()를 사용한다. • 순서도(예제 17.9) 함 수 선언 Client process 송신 sendmsg(); 메시지 clear memset(); 구조체 msghdr 초기화
Ancillary Data 예제 • 구조체 msghdr 초기화 33: memset(&msgh,0,sizeof msgh); 34: memset(buf,0,sizeof buf); 39: msgh.msg_name = addr; 40: msgh.msg_namelen = alen; 45: msgh.msg_iov = iov; 46: msgh.msg_iovlen = 1; 54: iov[0].iov_base = &er; 55: iov[0].iov_len = sizeof er; 60: msgh.msg_control = buf; 61: msgh.msg_controllen = sizeof buf;
Ancillary Data 예제 • 메시지 clear 67: cmsgp = CMSG_FIRSTHDR(&msgh); 68: cmsgp->cmsg_level = SOL_SOCKET; 69: cmsgp->cmsg_type = SCM_RIGHTS; 70: cmsgp->cmsg_len = CMSG_LEN(sizeof fd); 75: *((int *)CMSG_DATA(cmsgp)) = fd; 76: msgh.msg_controllen = cmsgp->cmsg_len; • client process 송신 81: do { 82: z = sendmsg(s,&msgh,0); 83: } while ( z == -1 && errno == EINTR ); 84: 85: return z == -1 ? -1 : 0;
Socket Server의 테스트 • 결과 $ ./web80 stand_alone Permission denied: binding port 80 $
Socket Server의 테스트 • Sockserv 테스트 • 예제 1 • 예제 2 $ su root Pssword: # ./sockserv fred & [1] 1077 # $ ./web80 & [1] 1079 $
Socket Server의 테스트 • 예제 3 $ telnet 127.0.0.1 80 Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'. GET/something <HTML> <HEAD> <TITLE> Test Page for this little web80 server</TITLE> </HEAD> <BODY> <H1>web80 Worked!</H1> <H2>From PID 1079 @Sat Nov 20 12:39:26 1999 </H2> </BODY> </HTML> Connection closed by foreign host. $
참고자료 • 쓰기 함수 • SCM_RIGHTS와 SCM_CREDENTIALS
참고자료 • struct msghdr msg_flags values