A simple proxy server code

发表于:2007-07-04来源:作者:点击数: 标签:
Implement without following RFC1928.Only for interest. Implement without following RFC1928.Only for interest. 共有五个函数,main,parse_args,init_daemon,do_proxy,error_quit. parse_args : 处理命令行参数,初始化一些变量,即代理 服务器 本身端
Implement without following RFC1928.Only for interest.

          

  Implement without following RFC1928.Only for interest.

  共有五个函数,main,parse_args,init_daemon,do_proxy,error_quit.

parse_args : 处理命令行参数,初始化一些变量,即代理服务器本身端口proxy_port,
代理的远端主机sockaddr结构变量hostaddr.

init_daemon : 使用fork变成守护进程。

error_quit : 由于守护进程把stdin,stdout,stderr都关了,so need a function
to display error message on the console.

do_proxy : 代理处理。客户与代理服务器建立连接(usersockfd),代理服务器与客户
请求的服务器建立连接(remote_sockfd),所以此函数把一个socket的输出送到另一个
socket的输入,相反亦是如此。

     1    /*
     2       A simple proxy server
     3       Copyright (C) 2005  by kf_701
     4    
     5       This program is free software; you can redistribute it and/or modify
     6       it under the terms of the GNU General Public License as published by
     7       the Free Software Foundation; either version 2 of the License, or
     8       (at your option) any later version.
     9    
    10       This program is distributed in the hope that it will be useful,
    11       but WITHOUT ANY WARRANTY; without even the implied warranty of
    12       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13       GNU General Public License for more details.
    14    
    15       You should have received a copy of the GNU General Public License
    16       along with this program; if not, write to the Free Software
    17       Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
    18    
    19       The author can be reached as follows:
    20        E_mail:        kf_701@21cn.com
    21        Address:    hefei of china
    22        Phone:        0551-2150103
    23    */
    24    #include <stdio.h>
    25    #include <string.h>
    26    #include <stdlib.h>
    27    #include <ctype.h>
    28    #include <errno.h>
    29    #include <signal.h>
    30    #include <unistd.h>
    31    #include <sys/stat.h>
    32    #include <sys/param.h>
    33    #include <sys/types.h>
    34    #include <sys/socket.h>
    35    #include <sys/ioctl.h>
    36    #include <.netinet/in.h>
    37    #include <arpa/inet.h>
    38    #include <sys/wait.h>
    39    #include <netdb.h>
    40    
    41    #define TCP_PROTO    "tcp"
    42    #define MAXFD        64
    43    
    44    unsigned short proxy_port;
    45    struct sockaddr_in hostaddr;    /* remote host addr */
    46    
    47    void parse_args(int argc,char **argv);    /* deal with arguments */
    48    void init_daemon(void);            /* become daemon */
    49    void do_proxy(int usersockfd);        /* main proxy process */
    50    void error_quit(char *msg);        /* print error message for daemon */
    51    
    52    int main(int argc,char **argv)
    53    {
    54        int clilen;
    55        int childpid;
    56        int sockfd,newsockfd;
    57        struct sockaddr_in servaddr,cliaddr;
    58    
    59        parse_args(argc,argv);
    60        init_daemon();
    61    
    62        /* prepare servaddr for listening client */
    63        bzero((char*)&servaddr,sizeof(servaddr));
    64        servaddr.sin_family = AF_INET;
    65        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    66        servaddr.sin_port = proxy_port;
    67    
    68        /* socket,bind,listen */
    69        if((sockfd = socket(AF_INET,SOCK_STREAM,0))<0)
    70            error_quit("failed to create server socket");
    71        if(bind(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr))<0)
    72            error_quit("failed to bind server socket");
    73        listen(sockfd,5);
    74    
    75        while(1){
    76            clilen = sizeof(cliaddr);
    77            newsockfd = aclearcase/" target="_blank" >ccept(sockfd,(struct sockaddr *)&cliaddr,&clilen);
    78            if(newsockfd<0 && errno == EINTR)
    79                continue;
    80            else if(newsockfd < 0)
    81                error_quit("failed to accept connection");
    82    
    83            if((childpid = fork()) == 0){
    84                close(sockfd);
    85                do_proxy(newsockfd); /* proxy main process */
    86                exit(0);
    87            }
    88            /* if fork failed,close connection */
    89            close(newsockfd);
    90        }
    91    }
    92    
    93    void parse_args(int argc,char **argv)
    94    {
    95        int i;
    96        struct hostent *hostp;
    97        struct servent *servp;
    98        unsigned long inaddr;
    99        struct{
   100            char proxy_port[16];
   101            char isolated_host[64];
   102            char service_name[32];
   103        }pargs;
   104    
   105        /* invalid arguments */
   106        if(argc<4){
   107            printf("usage: %s <proxy_port><host><service_name|port_number>\n",argv[0]);
   108            exit(1);
   109        }
   110    
   111        /* save arguments to pargs struct */
   112        strcpy(pargs.proxy_port,argv[1]);
   113        strcpy(pargs.isolated_host,argv[2]);
   114        strcpy(pargs.service_name,argv[3]);
   115    
   116        /* check argv[1] and set global proxy_port */
   117        for(i=0;i<strlen(pargs.proxy_port);i++)
   118            if(!isdigit(*(pargs.proxy_port+i)))
   119                break;
   120        if(i == strlen(pargs.proxy_port))
   121            proxy_port = htons(atoi(pargs.proxy_port));
   122        else{
   123            printf("%s: invalid proxy port\n",pargs.proxy_port);
   124            exit(1);
   125        }
   126    
   127        /* set global hostaddr */
   128        bzero(&hostaddr,sizeof(hostaddr));
   129        hostaddr.sin_family = AF_INET;
   130        /* set sin_addr for hostaddr */
   131        if((inaddr = inet_addr(pargs.isolated_host)) != INADDR_NONE)
   132            bcopy(&inaddr,&hostaddr.sin_addr,sizeof(inaddr));
   133        else if((hostp = gethostbyname(pargs.isolated_host)) != NULL)
   134            bcopy(hostp->h_addr,&hostaddr.sin_addr,hostp->h_length);
   135        else{
   136            printf("%s:unknown host\n",pargs.isolated_host);
   137            exit(1);
   138        }
   139        /* set sin_port for hostaddr */
   140        if((servp = getservbyname(pargs.service_name,TCP_PROTO)) != NULL)
   141            hostaddr.sin_port = servp->s_port;
   142        else if(atoi(pargs.service_name) > 0)
   143            hostaddr.sin_port = htons(atoi(pargs.service_name));
   144        else{
   145            printf("%s:invalid/unknown service name or port number\n",pargs.service_name);
   146            exit(1);
   147        }
   148    }
   149    
   150    void init_daemon(void)
   151    {
   152        pid_t pid;
   153        int i;
   154        
   155        if((pid = fork()))    /*exit terminal*/
   156            exit(0);
   157        else if(pid<0)
   158            exit(1);
   159        
   160        setsid();        /*become session leader*/
   161    
   162        /* when session leader terminate,all
   163          process of session will receive SIGHUP */
   164        if(signal(SIGHUP,SIG_IGN) == SIG_ERR)
   165            exit(1);
   166        
   167        if((pid=fork()))      /*prevent daemon opening terminal*/
   168            exit(0);
   169        else if(pid<0)
   170            exit(1);
   171        
   172        for(i=0;i<MAXFD;++i)    /*close fds opened by parent*/
   173        {
   174            close(i);
   175        }
   176        
   177        chdir("/");        /*leave working dir*/
   178    
   179        umask(0);        /*create file mask*/
   180    
   181        return;
   182    }
   183    
   184    void do_proxy(int usersockfd)
   185    {
   186        int remote_sockfd;
   187        fd_set rdfdset;
   188        int conn;
   189        int iolen;
   190        char buf[2048];
   191    
   192        /* connect remote server for the client */
   193        if((remote_sockfd = socket(AF_INET,SOCK_STREAM,0))<0)
   194            error_quit("failed to create socket to host");
   195        conn = connect(remote_sockfd,(struct sockaddr *)&hostaddr,sizeof(hostaddr));
   196        switch(conn){
   197            case 0:        /* successed */
   198                break;
   199            case -1:    /* bad luck */
   200                strcpy(buf,strerror(errno));
   201                strcat(buf,"\r\n");
   202                write(usersockfd,buf,strlen(buf));
   203                close(usersockfd);
   204                exit(1);
   205                break;
   206            default:
   207                error_quit("failed to connect to host");
   208        }
   209    
   210        /* all right,start real work now */
   211        while(1){
   212            FD_ZERO(&rdfdset);
   213            FD_SET(usersockfd,&rdfdset);
   214            FD_SET(remote_sockfd,&rdfdset);
   215    
   216            if(select(FD_SETSIZE,&rdfdset,NULL,NULL,NULL)<0)
   217                error_quit("select failed");
   218    
   219            /* detect data from client and send it to server */
   220            if(FD_ISSET(usersockfd,&rdfdset)){
   221                if((iolen = recv(usersockfd,buf,sizeof(buf),0))<=0)
   222                    break;
   223                send(remote_sockfd,buf,iolen,0);
   224            }
   225    
   226            /* detect data from server and send it to client */
   227            if(FD_ISSET(remote_sockfd,&rdfdset)){
   228                if((iolen = recv(remote_sockfd,buf,sizeof(buf),0))<=0)
   229                    break;
   230                send(usersockfd,buf,iolen,0);
   231            }
   232        }
   233    
   234        close(remote_sockfd);
   235        close(usersockfd);
   236    }
   237    
   238    void error_quit(char *msg)
   239    {
   240        FILE *console;
   241        console = fopen("/dev/console","a");
   242        fprintf(console,"proxyd:%s\r\n",msg);
   243        fclose(console);
   244        exit(1);
   245    }

原文转自:http://www.ltesting.net