?? proxy.c
字號:
/*代理服務器源代碼proxy.c*/
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <netdb.h>
#define TCP_PROTO "tcp"
int proxy_port; /*全局變量,指定代理服務器的端口*/
struct sockaddr_in hostaddr; /*全局變量,遠端主機地址*/
extern int errno;
extern char *sys_myerrlist[];
void parse_args (int argc, char **argv); /*參數轉換函數*/
void daemonize (int servfd); /*創建守護進程函數*/
void do_proxy (int usersockfd); /*代理處理函數*/
void errorout (char msg); /*錯誤輸出函數*/
/*********************************************************
主函數
**********************************************************/
main (argc,argv)
int argc;
char **argv;
{
int clilen;
int childpid;
int sockfd, newsockfd;
struct sockaddr_in servaddr, cliaddr;
/*把命令行參數轉存到全局變量中*/
parse_args(argc,argv);
/*為偵聽客戶請求準備一個地址*/
bzero((char *) &servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = proxy_port;
/*得到一個端口的文件描述符*/
if ((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0) {
fputs("failed to create server socket\r\n",stderr);
exit(1);
}
/*綁定到前面的地址上*/
if (bind(sockfd,(struct sockaddr_in *) &servaddr,sizeof(servaddr)) < 0) {
fputs("faild to bind server socket to specified port\r\n",stderr);
exit(1);
}
/*準備接收*/
listen(sockfd,5);
/*把自身變為守護進程*/
daemonize(sockfd);
/*進入一個循環,并發處理連接請求*/
while (1) {
/*接受連接請求*/
clilen = sizeof(cliaddr);
newsockfd = accept(sockfd, (struct sockaddr_in *) &cliaddr, &clilen);
if (newsockfd < 0 && errno == EINTR)
continue;
else if (newsockfd < 0)
/*出錯,kill服務器*/
errorout("failed to accept connection");
/*產生一個子進程,進行連接處理*/
if ((childpid = fork()) == 0) {
close(sockfd);
do_proxy(newsockfd); /*真正的處理過程*/
exit(0);
}
/*如果產生子進程失敗,連接將被丟掉*/
close(newsockfd);
}
}
/****************************************************************
進行參數轉換,把從命令行得到的參數值賦給全局變量
****************************************************************/
void parse_args (argc,argv)
int argc;
char **argv;
{
int i;
struct hostent *hostp;
struct servent *servp;
unsigned long inaddr;
struct {
char proxy_port [16];
char isolated_host [64];
char service_name [32];
} pargs;
/*輸入不合規范*/
if (argc < 4) {
printf("usage: %s <proxy-port> <host> <service-name|port-number>\r\n", argv[0]);
exit(1);
}
/*(將什么)將輸入參數先放到自定義的數據結構中*/
strcpy(pargs.proxy_port,argv[1]);
strcpy(pargs.isolated_host,argv[2]);
strcpy(pargs.service_name,argv[3]);
/*檢查端口號是否是數字,再賦給proxy_port*/
for (i = 0; i < strlen(pargs.proxy_port); i++)
if (!isdigit(*(pargs.proxy_port + i)))
break;
if (i == strlen(pargs.proxy_port))
proxy_port = htons(atoi(pargs.proxy_port));
else {
printf("%s: invalid proxy port\r\n",pargs.proxy_port);
exit(0);
}
/*把遠端服務器地址賦給hostaddr*/
bzero(&hostaddr,sizeof(hostaddr));
hostaddr.sin_family = AF_INET;
/*不管是主機名還是IP地址,都把它轉換為hostaddr 的地址*/
if ((inaddr = inet_addr(pargs.isolated_host)) != INADDR_NONE)
bcopy(&inaddr,&hostaddr.sin_addr,sizeof(inaddr));
else if ((hostp = gethostbyname(pargs.isolated_host)) != NULL)
bcopy(hostp->h_addr,&hostaddr.sin_addr,hostp->h_length);
else {
printf("%s: unknown host\r\n",pargs.isolated_host);
exit(1);
}
/*不管是用數字表示端口還是用服務表示的端口,都把它轉換后賦給hostaddr.sin_port*/
if ((servp = getservbyname(pargs.service_name,TCP_PROTO)) != NULL)
hostaddr.sin_port = servp->s_port;
else if (atoi(pargs.service_name) > 0)
hostaddr.sin_port = htons(atoi(pargs.service_name));
else {
printf("%s: invalid/unknown service name or port number\r\n", pargs.service_name);
exit(1);
}
}
/****************************************************************
創建守護進程函數
****************************************************************/
void daemonize (servfd)
int servfd;
{
int childpid, fd, fdtablesize;
/*忽略終端I/O讀、寫和stop 信號*/
signal(SIGTTOU,SIG_IGN);
signal(SIGTTIN,SIG_IGN);
signal(SIGTSTP,SIG_IGN);
/*通過fork子進程,kill父進程,把自身轉入后臺*/
if ((childpid = fork()) < 0) {
fputs("failed to fork first child\r\n",stderr);
exit(1);
}
else if (childpid > 0)
exit(0); /*若是父進程,結束*/
/*設為會話組長,擺脫原終端*/
setsid(0) ;
/*釋放控制終端*/
if ((fd = open("/dev/tty",O_RDWR)) >= 0) {
ioctl(fd,TIOCNOTTY,NULL);
close(fd);
}
/*關閉除 servfd 外的所有文件描述符*/
for (fd = 0, fdtablesize = getdtablesize(); fd < fdtablesize; fd++)
if (fd != servfd)
close(fd);
/*改變工作目錄到根目錄*/
chdir("/");
/*重設文件掩碼*/
umask(0);
}
/***************************************************
代理處理函數
****************************************************************/
void do_proxy (usersockfd)
int usersockfd;
{
int isosockfd;
fd_set rdfdset;
int connstat;
int iolen;
char buf[2048];
/*作為一個客戶端,新開一個端口以連接遠端服務器*/
if ((isosockfd = socket(AF_INET,SOCK_STREAM,0)) < 0)
errorout("failed to create socket to host");
/*發連接請求*/
connstat = connect(isosockfd,(struct sockaddr *) &hostaddr, sizeof(
hostaddr));
/*出錯處理*/
switch (connstat) {
case 0:
break;
case ETIMEDOUT:
case ECONNREFUSED:
case ENETUNREACH:
strcpy(buf,sys_myerrlist[errno]);
strcat(buf,"\r\n");
write(usersockfd,buf,strlen(buf));
close(usersockfd);
exit(1);
break;
default:
errorout("failed to connect to host");
}
/*現在已經建立了連接,進入代理的數據反饋循環*/
while (1) {
/* 使用select進行并發處理 */
FD_ZERO(&rdfdset);
FD_SET(usersockfd,&rdfdset);
FD_SET(isosockfd,&rdfdset);
if (select(FD_SETSIZE,&rdfdset,NULL,NULL,NULL) < 0)
errorout("select failed");
/*客戶端有數據發過來嗎*/
if (FD_ISSET(usersockfd,&rdfdset)) {
/*小于或等于0意味著客戶端已斷*/
if ((iolen = recv(usersockfd,buf,sizeof(buf)),0) <= 0)
break;
send(isosockfd,buf,iolen,0);
/*把數據拷貝一份發給服務器端*/
}
/*遠端服務器有數據發過來嗎*/
if (FD_ISSET(isosockfd,&rdfdset)) {
f ((iolen = recv(isosockfd,buf,sizeof(buf))) <= 0)
break; /*接收數據長度小于或等于0標明連接已斷*/
send(usersockfd,buf,iolen);
/*把數據拷貝一份發給客戶端*/
}
}
close(isosockfd);
close(usersockfd);
}
/****************************************************************
出錯處理函數
****************************************************************/
void errorout (msg)
char *msg;
{
FILE *console;
console = fopen("/dev/console","a");
fprintf(console,"proxyd: %s\r\n",msg);
fclose(console);
exit(1);
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -