2012-11-28 3 views
1
이 코드를 가지고 내가 내 프로젝트의 일환으로 사용하기 위해 노력하고있어

않습니다. 프로젝트의 세부 사항은 현재로서는 중요하지 않지만 브라우저와 로컬 http 서버간에 프록시로이 포트 전달 프록시를 사용하려고합니다.C :는 epoll 포트 포워딩 프록시는 전달하지 모든 데이터

그래서 브라우저에 http : //127.0.0.1:8999/을 입력하면 127.0.0.1:8888에서 웹 페이지를 다시 가져오고 싶습니다. 이것은 작은 웹 페이지 (이미지, 작은 html 파일, ...)에 대해서만 작동합니다. 몇 가지 이미지가있는 웹 페이지에서이 작업을 수행하려고하면 이미지가 전송되지 않거나 부분적으로 만 전송됩니다.

필자는 telnet과 웹 사이트에서 큰 html 파일을 테스트했습니다. 프록시에 연결하고 HEAD 메서드 요청을 보냅니다. 예상대로 모든 메타 데이터를 얻었습니다. 내가 GET 메서드를 시도했을 때 웹 페이지의 html 파일의 일부만 얻었습니다.

는 사람이 올바른 방향으로 날 지점 수 있을까요? 내가 뭘 잘못하고 있는지 정말로 모르겠다. 당신이 당신의 epoll 이벤트 모두에 EPOLLET (에지 트리거) 플래그를 사용하는 것처럼

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netdb.h> 
#include <unistd.h> 
#include <fcntl.h> 
#include <sys/epoll.h> 
#include <errno.h> 
#include <signal.h> 
#include <assert.h> 

#define FALSE  0 
#define TRUE  1 
#define EPOLL_QUEUE_LEN 256 
#define SERVER_PORT 7000 
#define LISTEN_PORT 8667  // Proxy Server Listens for this port 
#define FORWARD_PORT 8888  // Proxy Server forwards all port LISTEN_PORT data to this port 
#define BUFLEN 1024 
//Globals 
int fd_server; 
int sent = 0; // for how many requests were processed to client 
int forwardSockets[EPOLL_QUEUE_LEN]; 
int internalSockets[EPOLL_QUEUE_LEN]; 
// Function prototypes 
static void SystemFatal (const char* message); 
static int forwardData (int fd); 
void close_fd (int); 

// This is the main function which handles the epoll loop and 
// accepts connections 
// Also handles the data processing back to the client. 
int main (int argc, char* argv[]) 
{ 
    int i, arg, src_port, forwardSD, dest_port; 
    int num_fds, fd_new, epoll_fd; 
    int linenum=0; 
    static struct epoll_event events[EPOLL_QUEUE_LEN], event; 
    struct sockaddr_in addr, remote_addr; 
    socklen_t addr_size = sizeof(struct sockaddr_in); 
    struct sigaction act; 
    struct hostent *hp; 
    struct sockaddr_in server_fwd; 
    char *host; 
     char line[256], ip[256]; 
    FILE *fp; 

    fp=fopen("port_forward_config", "r"); 
    //src_port = LISTEN_PORT;   // Use the default listen port 


     while(fgets(line, 256, fp) != NULL) 
     { 
       linenum++; 
       if(line[0] == '#') continue; 

       sscanf(line, "%s %d %d", &ip, &src_port, &dest_port); 
     { 
        fprintf(stderr, "Syntax error, line %d\n", linenum); 
       continue; 
     } 
    } 
    printf("Reading Config File...\n"); 
    printf("IP %s LPORT %d DPORT %d\n", ip, src_port, dest_port); 
    host = ip; 

    // set up the signal handler to close the server socket when CTRL-c is received 
    act.sa_handler = close_fd; 
    act.sa_flags = 0; 
    if ((sigemptyset (&act.sa_mask) == -1 || sigaction (SIGINT, &act, NULL) == -1)) 
    { 
      perror ("Failed to set SIGINT handler"); 
      exit (EXIT_FAILURE); 
    } 
//-------------------------------------------------------------------------------------------- 
    // Create the listening socket 
    fd_server = socket (AF_INET, SOCK_STREAM, 0); 
    if (fd_server == -1) 
    { 
     SystemFatal("socket"); 
    } 
    // set SO_REUSEADDR so port can be resused imemediately after exit, i.e., after CTRL-c 
    arg = 1; 
    if (setsockopt (fd_server, SOL_SOCKET, SO_REUSEADDR, &arg, sizeof(arg)) == -1) 
    { 
     SystemFatal("setsockopt"); 
    } 
    // Make the server listening socket non-blocking 
    if (fcntl (fd_server, F_SETFL, O_NONBLOCK | fcntl (fd_server, F_GETFL, 0)) == -1) 
    { 
     SystemFatal("fcntl"); 
    } 
    // Bind to the specified listening port 
    memset (&addr, 0, sizeof (struct sockaddr_in)); 
    addr.sin_family = AF_INET; 
    addr.sin_addr.s_addr = htonl(INADDR_ANY); 
    addr.sin_port = htons(src_port); 
    if (bind (fd_server, (struct sockaddr*) &addr, sizeof(addr)) == -1) 
    { 
     SystemFatal("bind"); 
    } 
    // Listen for fd_news; SOMAXCONN is 128 by default 
    if (listen (fd_server, SOMAXCONN) == -1) 
    { 
     SystemFatal("listen"); 
    } 
//--------------------------------------------------------------------------------------------- 
    // Create the epoll file descriptor 
    epoll_fd = epoll_create(EPOLL_QUEUE_LEN); 
    if (epoll_fd == -1) 
    { 
     SystemFatal("epoll_create"); 
    } 
    // Add the server socket to the epoll event loop 
    event.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLET; 
    event.data.fd = fd_server; 
    if (epoll_ctl (epoll_fd, EPOLL_CTL_ADD, fd_server, &event) == -1) 
    { 
     SystemFatal("epoll_ctl"); 
    } 
    // Execute the epoll event loop 
    while (TRUE) 
    { 
     //struct epoll_event events[MAX_EVENTS]; 
     num_fds = epoll_wait (epoll_fd, events, EPOLL_QUEUE_LEN, -1); 
     if (num_fds < 0) 
     { 
      SystemFatal ("Error in epoll_wait!"); 
     } 
     for (i = 0; i < num_fds; i++) 
     { 
       // Case 1: Error condition 
       if (events[i].events & (EPOLLHUP | EPOLLERR)) 
      { 
        fputs("epoll: EPOLLERR", stderr); 
        //close(events[i].data.fd); 
        continue; 
       } 
       assert (events[i].events & EPOLLIN); 
//----------------------------------------------------------------------------------------- 
       // Case 2: Server is receiving a connection request 
       if (events[i].data.fd == fd_server) 
      { 
       //socklen_t addr_size = sizeof(remote_addr); 
       fd_new = accept (fd_server, (struct sockaddr*) &remote_addr, &addr_size); 
       if (fd_new == -1) 
       { 
         if (errno != EAGAIN && errno != EWOULDBLOCK) 
        { 
         perror("accept"); 
         } 
         continue; 
       } 
//------------------------------------------------------------------------------------------------ 
       // Make the fd_new non-blocking 
       if (fcntl (fd_new, F_SETFL, O_NONBLOCK | fcntl(fd_new, F_GETFL, 0)) == -1) 
       { 
        SystemFatal("fcntl"); 
       } 

       // Add the new socket descriptor to the epoll loop 
       event.data.fd = fd_new; 
       if (epoll_ctl (epoll_fd, EPOLL_CTL_ADD, fd_new, &event) == -1) 
       { 
        SystemFatal ("epoll_ctl"); 
       } 
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
       printf(" Remote Address: %s\n", inet_ntoa(remote_addr.sin_addr)); 
       //close(fd_new); 
       dest_port = FORWARD_PORT;  // Used the default forward port 
       // create internal connection 
       printf("Trying to create forward socket\n");   
       if ((forwardSD = socket(AF_INET, SOCK_STREAM, 0)) == -1) { 
        perror("Cannot create forward socket."); 
        exit(1); 
       } 

       printf("Binding...\n"); 
       bzero((char *)&server_fwd, sizeof(struct sockaddr_in)); 
       server_fwd.sin_family = AF_INET; 
       server_fwd.sin_port = htons(dest_port); 
       //host = "192.168.0.10";  
       if ((hp = gethostbyname(host)) == NULL) { 
        printf("Failed to get host name"); 
       } 

       bcopy(hp->h_addr, (char *)&server_fwd.sin_addr, hp->h_length); 

       printf("Connecting to interal machine.\n"); 
       printf("Server Forward Port: %d\n", ntohs(server_fwd.sin_port)); 
       printf("Server Forward IP: %s\n", inet_ntoa(server_fwd.sin_addr)); 

       // Connecting to interal machine 
       if (connect (forwardSD, (struct sockaddr *)&server_fwd, sizeof(server_fwd)) == -1) { 
        perror("connect failed"); 
        exit(1); 
       } 

       // Add the new socket descriptor to the epoll loop 
       event.data.fd = forwardSD; 
       if (epoll_ctl (epoll_fd, EPOLL_CTL_ADD, forwardSD, &event) == -1) 
       { 
        SystemFatal ("epoll_ctl"); 
       } 
       printf ("Connected: Server: %s\n", hp->h_name); 
       forwardSockets[fd_new] = forwardSD; 
       internalSockets[forwardSD] = fd_new; 
      // end internal connection 
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
       continue; 
       } 
       // Case 3: One of the sockets has read data 
       if (!forwardData(events[i].data.fd)) 
      { 
       // epoll will remove the fd from its set 
       // automatically when the fd is closed 
       close (events[i].data.fd);  
      } 
     } 
    } 
    close(fd_server); 
    exit (EXIT_SUCCESS); 
} 

/* 
    This function clears a socket if it has data waiting to be processed. 
    It takes the string sent from the client and parses it. After it has 
    done that it will send back to the client the amount of data it requested 
    for however many requests it defined as well. 
*/ 
static int forwardData (int fd) 
{ 
    int n, bytes_to_read; 
    char *bp, buf[BUFLEN]; 
    int  forwardData; 
    printf ("Forwarding :\n"); 

    //check if internal or external connection to send data back to. 
    if(forwardSockets[fd] != 0){ 
     forwardData = forwardSockets[fd]; 
    } 
    if(internalSockets[fd] != 0){ 
     forwardData = internalSockets[fd]; 
    } 

    bp = buf; 
     bytes_to_read = BUFLEN; 
     while ((n = recv (fd, bp, bytes_to_read, 0)) > 0) { 
       bp += n; 
       bytes_to_read -= n; 
     send (forwardData, buf, n, 0); 
     return TRUE; 
     } 
    return TRUE; 

} 

// Prints the error stored in errno and aborts the program. 
static void SystemFatal(const char* message) 
{ 
    perror (message); 
    exit (EXIT_FAILURE); 
} 
// close fd 
void close_fd (int signo) 
{ 
     close(fd_server); 
    exit (EXIT_SUCCESS); 
} 
+2

'send (forwardData, buf, n, 0);'반환 값을 테스트하고, 아마도 루프를 반환하고 -1 반환 할 때 버퍼를 반환해야합니다./EWOULDBLOCK – wildplasser

답변

2

보인다. 이 플래그는 파일 디스크립터가 사용 불가능에서 사용 가능으로 바뀔 때 epoll 만 이벤트를 반환하도록합니다.

또한 forwardData 함수에서 BUFLEN 바이트를받은 다음 TRUE을 반환합니다. 사용 가능한 바이트 수가 더 많은 경우 이벤트가 에지 트리거되고 다시 전송되지 않으므로 전달하지 않습니다.

forwardData을 수정 (아마도 루프에서 return TRUE 제거)하여 모든 읽을 수있는 데이터가 반환되기 전에 전달되도록하십시오.

+0

감사합니다. forwardData 함수를 변경하여 모든 데이터를 읽을 때까지 읽도록했습니다. 이제 작동합니다. :) – jureso