システム・プログラムI
電子・情報工学系
新城 靖
<yas@is.tsukuba.ac.jp>
このページは、次の URL にあります。
http://www.hlla.is.tsukuba.ac.jp/~yas/coins/syspro1-1997/1997-06-10
あるいは、次のページから手繰っていくこともできます。
http://www.hlla.is.tsukuba.ac.jp/~yas/coins/
http://www.hlla.is.tsukuba.ac.jp/~yas/index-j.html
-------------------------------------------------------------------- % telnet localhost echoTrying... Connected to localhost. Escape character is '^]'. hello
hello exit
exit quit
quit aaa
aaa ^] telnet> quit
Connection closed. %
--------------------------------------------------------------------
pipe() の代りに、TCP/IP のストリームを使って、異なる計算機上のプロセス を接続して、フィルタの処理を行わせてみなさい。
(34) で、3つ以上のプロセスを接続できるようにしなさい。
----------------------------------------------------------------------
1:
2: /*
3: echo-server-fork.c -- 受け取った文字列をそのまま返すサーバ(fork版)
4: /usr/local/LECTURES/syspro-1997-shinjo/ipc/echo-server-fork.c
5: $Header: echo-server-fork.c,v 1.5 97/06/09 21:28:27 yas Exp $
6: Start: 1997/06/09 19:46:40
7: */
8: #include <stdio.h>
9: #include <sys/socket.h> /* socket() */
10: #include <netinet/in.h> /* struct sockaddr_in */
11: #include <netdb.h> /* gethostbyname() */
12: #include <time.h> /* gettimeofday(), struct timeval */
13:
14: main( argc,argv )
15: int argc ;
16: char *argv[] ;
17: {
18: int portno ;
19: if( argc >= 3 )
20: {
21: fprintf( stdout,"Usage: %s host port\n",argv[0] );
22: exit( -1 );
23: }
24: if( argc == 2 )
25: portno = atoi( argv[1] );
26: else
27: portno = getuid();
28: echo_server( portno );
29: }
30:
31: echo_server( portno )
32: int portno ;
33: {
34: int acc,com ;
35: pid_t child_pid ;
36: acc = tcp_acc_port( portno );
37: if( acc<0 )
38: exit( -1 );
39: print_host_port( portno );
40: while( 1 )
41: {
42: if( (com = accept( acc,0,0 )) < 0 )
43: {
44: perror("accept");
45: exit( -1 );
46: }
47: tcp_peeraddr_print( com );
48: if( (child_pid=fork()) > 0 ) /* parent */
49: {
50: close( com );
51: }
52: else if( child_pid == 0 )
53: {
54: close( acc );
55: echo_reply( com );
56: printf("[%d,%d] connection closed.\n",getpid(),com );
57: close( com );
58: exit( 0 );
59: }
60: }
61: }
62:
63: #define BUFFSIZE 1024
64:
65: echo_reply( com )
66: int com ;
67: {
68: char buff[BUFFSIZE] ;
69: int rcount ;
70: int wcount ;
71:
72: while( (rcount=read(com,buff,BUFFSIZE)) > 0 )
73: {
74: if( (wcount=writen(com,buff,rcount))!= rcount )
75: {
76: perror("write");
77: exit( 1 );
78: }
79: printf("[%d,%d] ",getpid(),com );
80: fflush( stdout );
81: write( 1, buff, rcount );
82: }
83: }
84:
85: tcp_peeraddr_print( com )
86: int com ;
87: {
88: struct sockaddr_in addr ;
89: int addr_len ;
90: union {
91: int i ;
92: unsigned char byte[4] ;
93: } x ;
94: addr_len = sizeof( addr );
95: if( getpeername( com, &addr, &addr_len )<0 )
96: {
97: perror("print_peeraddr");
98: }
99: x.i = addr.sin_addr.s_addr ;
100: printf("[%d,%d] connection from %d.%d.%d.%d:%d\n",getpid(),com,
101: x.byte[0],x.byte[1],x.byte[2],x.byte[3],
102: ntohs( addr.sin_port ));
103: }
<以下省略>
----------------------------------------------------------------------
実行例。
サーバ側。サーバは、終了しないので、最後に、^C か Del を押して、割り込みを掛けて終了させる。
クライアント側(その1)。---------------------------------------------------------------------- % ./echo-server-forkecho orchid 1231 [9930,4] connection from 130.158.86.225:1849 [9956,4] 012 [9930,4] connection from 127.0.0.1:1859 [9963,4] abc [9963,4] def [9963,4] connection closed. [9956,4] 345 [9956,4] connection closed. ^C %
----------------------------------------------------------------------
クライアント側(その2)。localhost (127.0.0.1) は、自分自信を意味する。---------------------------------------------------------------------- % telnet orchid 1231Trying... Connected to orchid. Escape character is '^]'. 012
012 345
345 ^] telnet> quit
Connection closed. %
----------------------------------------------------------------------
---------------------------------------------------------------------- % telnet localhost 1231Trying... Connected to localhost. Escape character is '^]'. abc
abc def
def ^] telnet> quit
Connection closed. %
----------------------------------------------------------------------
上の tcp_peeraddr_print() は、IP アドレスを数字で表示していた。 これを、ホスト名で表示するようにしなさい。 それには、gethostbyaddr()を利用するとよい。
普通は、ホスト名からIPアドレスを調べる手続き gethostbyname() が使われ る。gethostbyaddr() は、その逆を行う手続きである。
ここで紹介しているサーバのプログラムは、どのホストからの要求も受け付け ている。特定のホストからの要求しか受け付けないように、変更しなさい。 たとえば、次のようなことを実現しなさい。
ヒント:上のプログラムで、tcp_peeraddr_print() は、接続相手のIPアドレ スとポート番号を表示している。同じようにな手続きを書き、表示ではなくて、 接続を許すか許さないかをチェックするようにするとよい。
echo-server-fork.c では、クライアントから接続要求を受け付ける
たびに、新しいプロセスを作っていた。echo-server-select.cでは、
1つのプロセスで実行している。
----------------------------------------------------------------------
1:
2: /*
3: echo-server-select.c -- 受け取った文字列をそのまま返すサーバ(select版)
4: /usr/local/LECTURES/syspro-1997-shinjo/ipc/echo-server-select.c
5: $Header: echo-server-select.c,v 1.1 97/06/09 21:47:47 yas Exp $
6: Start: 1997/06/09 19:53:33
7: */
8: #include <stdio.h>
9: #include <sys/socket.h> /* socket() */
10: #include <netinet/in.h> /* struct sockaddr_in */
11: #include <netdb.h> /* gethostbyname() */
12: #include <time.h> /* gettimeofday(), struct timeval */
13: #include <sys/types.h> /* fd_set */
14:
15: main( argc,argv )
16: int argc ;
17: char *argv[] ;
18: {
19: int portno ;
20: if( argc >= 3 )
21: {
22: fprintf( stdout,"Usage: %s host port\n",argv[0] );
23: exit( -1 );
24: }
25: if( argc == 2 )
26: portno = atoi( argv[1] );
27: else
28: portno = getuid();
29: echo_server( portno );
30: }
31:
32: echo_server( portno )
33: int portno ;
34: {
35: int acc,com ;
36: fd_set readfds,readfds_save ;
37: int i,n ;
38:
39: acc = tcp_acc_port( portno );
40: if( acc<0 )
41: exit( -1 );
42: print_host_port( portno );
43:
44: FD_ZERO( &readfds_save );
45: FD_SET( acc,&readfds_save );
46: while( 1 )
47: {
48: readfds = readfds_save ;
49: n = select( FD_SETSIZE,&readfds,0,0,0 );
50: if( n <= 0 )
51: {
52: perror("select");
53: exit( 1 );
54: }
55: if( FD_ISSET(acc,&readfds) )
56: {
57: FD_CLR( acc,&readfds );
58: if( (com = accept( acc,0,0 )) < 0 )
59: {
60: perror("accept");
61: exit( -1 );
62: }
63: FD_SET( com, &readfds_save );
64: tcp_peeraddr_print( com );
65: }
66: for( i=0 ; i<FD_SETSIZE ; i++ )
67: {
68: if( FD_ISSET(i,&readfds) )
69: {
70: if( echo_reply_once( i )<=0 )
71: {
72: printf("[%d,%d] connection closed.\n",getpid(),i );
73: close( i );
74: FD_CLR( i,&readfds_save );
75: }
76: }
77: }
78: }
79: }
80:
81: #define BUFFSIZE 1024
82:
83: echo_reply_once( com )
84: int com ;
85: {
86: char buff[BUFFSIZE] ;
87: int rcount ;
88: int wcount ;
89:
90: if( (rcount=read(com,buff,BUFFSIZE)) > 0 )
91: {
92: if( (wcount=writen(com,buff,rcount))!= rcount )
93: {
94: perror("write");
95: exit( 1 );
96: }
97: printf("[%d,%d] ",getpid(),com );
98: fflush( stdout );
99: write( 1, buff, rcount );
100: }
101: return( rcount );
102: }
<以下省略>
----------------------------------------------------------------------
実行例。
サーバ側。サーバは、終了しないので、最後に、^C か Del を押して、割り込みを掛けて終了させる。
クライアント側(その1)。---------------------------------------------------------------------- % ./echo-server-selectecho orchid 1231 [9792,4] connection from 127.0.0.1:1704 [9792,4] abc [9792,5] connection from 130.158.86.225:1720 [9792,5] 012 [9792,5] 345 [9792,5] connection closed. [9792,4] efg [9792,4] connection closed. ^C %
----------------------------------------------------------------------
クライアント側(その2)。localhost (127.0.0.1) は、自分自信を意味する。---------------------------------------------------------------------- % telnet orchid 1231Trying... Connected to orchid. Escape character is '^]'. 012 012 345 345 ^] telnet> quit
Connection closed. %
----------------------------------------------------------------------
---------------------------------------------------------------------- % telnet localhost 1231Trying... Connected to localhost. Escape character is ^]'. abc
abc efg
efg ^] telnet> quit
Connection closed. %
---------------------------------------------------------------------- '
finger サーバを作成しなさい。これは、受け取った文字列を引数にして、 finger コマンドを実行するとよい。そして、実行結果を、接続先に返すよう にするとよい。
finger コマンドと finger サーバの間は、パイプで接続しなさい。今までの 例題で利用した方法を組み合わせることで実現することができるはずである (pipe(),fork(),dup(),close(),execve()など)。popen() ライブラリ関数を 利用してもよい。
http サーバを作成しなさい。これは、受け取ったファイル名のファイルを開 いて、内容を読み込み、それを接続先に返すようにするとよい。
この課題では、特にセキュリティに気をつけなさい。必ず次の条件を満たすよ うなサーバを作りなさい。
~/public_html)以下のファイル
しかアクセスできないようにすること。
.. が含まれていたら、アクセスを拒否すること。
---------------------- Content-Type: 拡張子 ---------------------- text/html .html text/plain .txt image/gif .gif image/jpeg .jpeg ----------------------
インターネットのセキュリティを高めるための道具として、TCP Wrapper があ る。TCP Wrapper は、クライアントの IP アドレスを調べて、接続を許可した り拒否したりする機能がある。そのような機能を持っていないプログラムに、 そのような機能を外付けで付け加えることができる。
次の場所にソースを置いておく。
/usr/local/LECTURES/syspro-1997-shinjo/tcp_wrappers_7.6/
TCP/IP のプログラムを書く時には、sized_io ライブラリを利用すると便利である。 stream.c は、短いので目を通しておくとよい。
次の場所にソースを置いておく。
/usr/local/LECTURES/syspro-1997-shinjo/sized_io/