2016-03-28 11 views
0

Yapmaya çalıştığım şey HTTP (S) bağlantılarını ele alan bir forking vekilidir: GET (SSL olmadan) istekleri başarılı bir şekilde yürütüldüğünde ve içeriği istemciye teslim edildiğinde CONNECT yöntemine geliyor, işler iyi gitmiyor, çünkü uzak sunucuya connect() girmesi hemen başaramayabilir: aslında, nevers başarılı olur.HTTPS proxy'si başarıyla bağlanmayı başarıyor

Ben uzak sunucuya bağlı olmayan bir engelleme soket için çalıştı, bu yüzden connect() hemen gider ya biraz zaman alır diye görebiliyorum

: Uzak sunucu göndermeye hazır olduğunda ikinci durumda, ben görmek select() derim bana veriler: henüz, connect() asla bağlanmadı.

ClientManager::ClientManager() { 
    sockfd_client = -1; // socket connected to client 
    new_sockfd_client = -1; // socket accepting connection from client 
    sockfd_server = -1; // socket connected to remote server 
} 

// error controls omitted 
bool ClientManager::startListeningForClient(int port) { 
    struct sockaddr_in serv_addr; 
    bzero((char*)&serv_addr,sizeof(serv_addr)); 

    serv_addr.sin_family=AF_INET; 
    serv_addr.sin_port=htons(port); 
    serv_addr.sin_addr.s_addr=INADDR_ANY; 

    sockfd_client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
    bind(sockfd_client,(struct sockaddr*)&serv_addr, sizeof(serv_addr)); 
    listen(sockfd_client, 50); 
    return true; 
} 

// error controls omitted 
int ClientManager::acceptConnectionFromClient(void) { 
    struct sockaddr_in cli_addr; 
    unsigned int clilen; 
    bzero((char*)&cli_addr, sizeof(cli_addr)); 
    clilen = sizeof(cli_addr); 
    new_sockfd_client = accept(sockfd_client, (struct sockaddr*)&cli_addr, &clilen); 
    return new_sockfd_client; 
} 

int ClientManager::forkAndManageClient() { 
    // getRequestFromClient: the method below receives requests from 
    // clients and parses the infos I need (i.e. what method, 
    // hostname of remote server to be resolved, its port, ...) 
    getRequestFromClient(); 
    // managing the HTTP(S) request by the child process 
    int pid = fork(); 
    if (pid < 0) { 
     perror("ERROR on fork"); 
    } 
    else if (pid > 0) { 
     // parent process 
     // do nothing 
    } 
    else { 
     // close immediately the client socket used for accepting new connections from the parent process 
     close (sockfd_client); 
     if (!manageRequest()) { 
      perror("Error managing request from client"); 
     } 
     // close the connection from the client 
     close (new_sockfd_client); 
     new_sockfd_client = -1; 
     // the child process will terminate now 
     _exit(EXIT_SUCCESS); 
    } 
    return pid; 
} 

// now the problematic method... 
bool ClientManager::manageRequest(void) { 
    // if this is a CONNECT request 
    if (rm.isCONNECT()) { 
     struct sockaddr_in remote_server; 
     int conn_res; 
     remote_server.sin_family = AF_INET; 
     remote_server.sin_addr.s_addr = rm.getServerAddr(); 
     remote_server.sin_port = rm.getServerPort(); 
     fd_set fdset; 
     struct timeval tv; 

     sockfd_server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
     // make socket not blocking 
     int flags = fcntl(sockfd_server, F_GETFL, 0); 
     flags = flags | O_NONBLOCK; 
     if (fcntl(sockfd_server, F_SETFL, flags) == -1) { 
      perror("FCNTL:"); 
     } 
     printf("CONNECT set socket to non-blocking mode\n"); 

     conn_res = connect(sockfd_server, (struct sockaddr *)&remote_server, sizeof(struct sockaddr_in)); 

     printf("AFTER CONNECT()\n"); 
     if (conn_res < 0) { 
      if (errno != EINPROGRESS) { 
       printf("CONNECT: connect() failed, quitting\n"); 
       return false; 
      } 
     } 
     printf("CONNECT connection is taking place...\n"); 

     // connected immediately 
     if (conn_res == 0) { 
      printf("CONNECT connected OK!\n"); 
      goto CONNECTED; 
     } 

     FD_ZERO(&fdset); 
     FD_SET(sockfd_server, &fdset); 
     tv.tv_sec = 5; // tried 5, 20, 60 seconds, but it always times out 
     tv.tv_usec = 0; 

     printf("CONNECT attempting select()\n"); 
     if (select(sockfd_server+1, NULL, &fdset, NULL, &tv) == 0) { 
      errno = ETIMEDOUT; 
      close(sockfd_server); 
      sockfd_server = -1; 
      return false; 
     } 

     if (FD_ISSET(sockfd_server, &fdset)) { 
      int so_error; 
      socklen_t len = sizeof so_error; 
      if (getsockopt(sockfd_server, SOL_SOCKET, SO_ERROR, &so_error, &len) < 0) { 
       return false; 
      } 
     } else { 
      printf("sockfd_server not set\n"); 
     } 

     CONNECTED: 
     fcntl(sockfd_server, F_SETFL, flags &~ O_NONBLOCK); 
     // yeah, now I will start to deal the HTTPS flow in both directions 
     return true; 
    } 
} 

Bu ayarı yönetmek: kimi omissis olan fonksiyonlar üzerinde main() denir Sorunumla, ClientManager.cpp ile ilgili değil sahip

int main(int argc, char *argv[]) { 
    // ClientManager.cpp is described below 
    ClientManager cm; 
    //listening on port given by argv 
    if (cm.startListeningForClient(listening_port)) { 
     while(true) { 
      int new_client_socket = cm.acceptConnectionFromClient(); 
      if (new_client_socket >= 0) { 
       cm.forkAndManageClient(); 
      } 
      else { 
       perror("accept error"); 
      } 
     } 
    } else { 
     perror("Error on start listening"); 
    } 
    return EXIT_SUCCESS; 
} 

Şimdi şu:

İşte benim vekil main() kod engelleme moduna sokma ve CONNECT connection is taking place...'u yazdırmak için, ancak her zaman Error managing request from client: Connection timed out'u döndürür.

LOC milleri gönderdiği için özür dilerim, ama bu günlerden beri beni çıldırtıyor ve mesajlar, eğitim ve kılavuzları okuduktan sonra gerçekten ne yapacağımı bilmiyorum.

cevap

0

Artık bir HTTPS bağlantısı gerektiren her siteye bağlanıyor! Soket tanımlayıcılarının kapatılması ve kapatılmasıyla ilgili doğru hata eksik.

bool ClientManager::manageRequest(void) { 

if (rm.isCONNECT()) { 
    struct sockaddr_in remote_server, local_bind; 
    int conn_res, select_res; 

    memset(&remote_server, 0, sizeof(remote_server)); 
    remote_server.sin_family = AF_INET; 
    remote_server.sin_addr.s_addr = rm.getServerAddr(); 
    remote_server.sin_port = rm.getServerPort(); 

    memset(&local_bind, 0, sizeof(local_bind)); 
    local_bind.sin_family = AF_INET; 
    local_bind.sin_addr.s_addr = htonl(INADDR_ANY); 
    local_bind.sin_port = htons(0); 

    fd_set rdset, wrset; 
    struct timeval tv; 

    sockfd_server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
    if (sockfd_server < 0) { 
     perror("socket: "); 
    } 

    if(!setNonBlocking(sockfd_server)) 
     perror("fcntl"); 
    debug_green("CONNECT set socket to non-blocking mode\n"); 

    bind(sockfd_server, (struct sockaddr*) &local_bind, sizeof(local_bind)); 

    conn_res = connect(sockfd_server, (struct sockaddr *)&remote_server, sizeof(struct sockaddr_in)); 
    // The socket is nonblocking and the connection cannot be completed immediately 
    // check for EINPROGRESS 
    if ((conn_res == -1) && (errno != EINPROGRESS)) { 

     FD_ZERO(&rdset); 
     FD_SET(sockfd_server, &rdset); 
     wrset = rdset; 
     tv.tv_sec = 0; 
     tv.tv_usec = 0; 

     debug_yellow("CONNECT attempting select()\n"); 
     do { 
      select_res = select(sockfd_server+1, &rdset, &wrset, NULL, &tv); 
     } while ((select_res == -1) && (errno == EINTR)); 

     if ((!FD_ISSET(sockfd_server, &rdset)) && ((!FD_ISSET(sockfd_server, &wrset)))) { 
      debug_red("SELECT sockfds not responding\n"); 
      close(sockfd_server); 
      sockfd_server = -1; 
      return false; 
     } 

     conn_res = connect(sockfd_server, (struct sockaddr *)&remote_server, sizeof(struct sockaddr_in)); 
     if (conn_res == -1) { 
      if(errno == EISCONN) 
       printf ("connect(): connections already existing, OK\n"); 
      else { 
       printf("connect() for safety check: connection NOT successfull\n"); 
       close(sockfd_server); 
       sockfd_server = -1; 
       return false; 
      } 
     } 
     printf("connection OK\n"); 
     fflush(stdout); 
    } else { 
     debug_green("Connection immediately OK\n"); 
     fflush(stdout); 
    } 
    if (!setBlocking(sockfd_server)) { 
     perror("FCNTL:"); 
    } 
    debug_green("CONNECT set socket back to blocking mode\n");fflush(stdout); 
} 

return true; 
} 

Fonksiyonlar ayar engelleme veya olmayan engelleme soket:

bool ClientManager::setNonBlocking(int sockfd) { 
    printf("setting non block socket\n"); fflush(stdout); 
    int flags; 
    if ((flags = fcntl(sockfd, F_GETFL, 0)) < 0) 
     return false; 
    flags |= O_NONBLOCK; 
    if (fcntl(sockfd, F_SETFL, flags) < 0) 
     return false; 
    return true; 
} 

bool ClientManager::setBlocking(int sockfd) { 
    printf("setting block socket\n"); fflush(stdout); 
    int flags; 
    if ((flags = fcntl(sockfd, F_GETFL, 0)) < 0) 
     return false; 
    flags &= (~O_NONBLOCK); 
    if (fcntl(sockfd, F_SETFL, flags) < 0) 
     return false; 
    return true; 
} 

ayıklama fonksiyonları:

#define DEFAULTCOLOR "\033[0m" 
#define RED    "\033[22;31m" 
#define YELLOW   "\033[1;33m" 
#define GREEN   "\033[0;0;32m" 

#define debug_red(...) std::cout << RED << __VA_ARGS__ << DEFAULTCOLOR; fflush(stdout); 
#define debug_yellow(...) std::cout << YELLOW << __VA_ARGS__ << DEFAULTCOLOR; fflush(stdout); 
#define debug_green(...) std::cout << GREEN << __VA_ARGS__ << DEFAULTCOLOR; fflush(stdout); 
İşte benim kod