2016-12-30 4 views
0

Я пытаюсь использовать программу C для аутентификации OAuth 2 с сервера Google (в виде запроса HTTP GET). Если я пытаюсь читать с помощью recv(), он выдает ошибку, Конечная точка транспорта не подключена. Это происходит только после того, как я получу неотрицательное целое число после вызова accept(). Я пробовал то же самое с помощью утилиты Java и Netcat, оба работают отлично для меня.Сокет закрыт до recv без вызова close

Вот код.

#include<stdio.h> 
#include<string.h> 
#include<arpa/inet.h> 
#include<unistd.h> 
#include<stdlib.h> 
#include<pthread.h> 
#include<sys/select.h> 
#include<fcntl.h> 
#include<errno.h> 

void *send_authcode_request(void *sockaddr_ptr); 

int main() { 
    char *bind_addr = "127.0.0.1"; 
    char *errmsg = (char *) malloc(1024); 
    short int port = 0; 

    setvbuf(stdout, NULL, _IONBF, 0); 

    struct sockaddr_in local_addr; 
    struct sockaddr_in client_addr; 
    local_addr.sin_family = AF_INET; 
    local_addr.sin_port = port; 
    inet_aton(bind_addr, &(local_addr.sin_addr)); 
    memset(&(local_addr.sin_zero), '\0', 8); 

    int sock_id = socket(AF_INET, SOCK_STREAM, 0); 
    /*fcntl(sock_id, F_SETFL, O_NONBLOCK);*/ 

    if (bind(sock_id, (struct sockaddr*) &local_addr, sizeof(struct sockaddr)) == -1) { 
     sprintf(errmsg, "Cannot bind socket to the port #%d", port); 
     perror(errmsg); 
     return -1; 
    } 
    if (listen(sock_id, 20) == -1) { 
     sprintf(errmsg, "Cannot listen to connections on the socket"); 
     perror(errmsg); 
     return -1; 
    } 
    int sin_size = sizeof(struct sockaddr_in); 
    if(getsockname(sock_id, (struct sockaddr *) &local_addr, &sin_size) == -1) { 
     sprintf(errmsg, "Unable to get the current address of the socket"); 
     perror(errmsg); 
     return -1; 
    } 
    printf("\n Port no after binding #%d\n", ntohs(local_addr.sin_port)); 

    pthread_t authcode_req_thread; 
    pthread_create(&authcode_req_thread, NULL, send_authcode_request, (void *) &local_addr); 

    fd_set read_fs; 
    FD_ZERO(&read_fs); 
    FD_SET(sock_id, &read_fs); 

    long accept_timeout = 60*10; 

    struct timeval tv; 
    tv.tv_sec = accept_timeout; 
    tv.tv_usec = 0; 

    char auth_code_info[1024]; 

    if (select(sock_id+1, &read_fs, NULL, NULL, &tv) > 0) { 
     /*if(accept4(sock_id, (struct sockaddr *) &client_addr, &sin_size, SOCK_NONBLOCK) == -1) {*/ 
     if(accept(sock_id, (struct sockaddr *) &client_addr, &sin_size) >= 0) { 
      /* Accept auth code */ 
      int bytesread; 
      if ((bytesread = recv(sock_id, auth_code_info, 1023, 0)) == -1) { 
       perror(errmsg); 
       return -1; 
      } 
      printf("\n%s\n", auth_code_info); 
      char *reply = "Done! You can now close the window"; 
      send(sock_id, reply, strlen(reply), 0); 
     } else { 
      sprintf(errmsg, "No client connected within timeout of %ld seconds", accept_timeout); 
      perror(errmsg); 
      return -1; 
     } 
    } else { 
     sprintf(errmsg, "No client connected within timeout of %ld seconds", accept_timeout); 
     perror(errmsg); 
     return -1; 
    } 
    close(sock_id); 
    printf("\n"); 
    return 0; 
} 

void *send_authcode_request(void *ptr) { 
    char *scope = "https://www.googleapis.com/auth/drive"; 
    char *client_id = "1098482466406-c3h15ld90l03s0pl4rm7qq54fcb49t78.apps.googleusercontent.com"; 
    const char *temp_authcode_uri = "xdg-open \"https://accounts.google.com/o/oauth2/v2/auth?scope=%s&redirect_uri=http://127.0.0.1:%d&response_type=code&client_id=%s\""; 

    struct sockaddr_in *socket_address = (struct sockaddr_in *) ptr; 

    int max_authcode_uri_len = strlen(temp_authcode_uri) + strlen(client_id) + strlen(scope); 
    char *authcode_uri = (char *) malloc(max_authcode_uri_len); 
    sprintf(authcode_uri, temp_authcode_uri, scope, ntohs(socket_address->sin_port), client_id); 
    printf("\n%s\n", authcode_uri); 
    system(authcode_uri); 
} 

Однако, когда я слушаю тот же порт, используя Netcat, он отображает запрос HTTP из браузера. Поэтому я отслеживал трафик TCP для порта, используя Wireshark, и обнаружил, что один трафик отличается от того, что я получаю при использовании netcat.

Для моей программы

No.  Time   Source    Destination   Protocol Length Info 
     1 0.000000000 127.0.0.1    127.0.0.1    TCP  74  48234 → 49927 [SYN] Seq=0 Win=43690 Len=0 MSS=65495 SACK_PERM=1 TSval=7268636 TSecr=0 WS=128 
     2 0.000010715 127.0.0.1    127.0.0.1    TCP  74  49927 → 48234 [SYN, ACK] Seq=0 Ack=1 Win=43690 Len=0 MSS=65495 SACK_PERM=1 TSval=7268636 TSecr=7268636 WS=128 
     3 0.000020978 127.0.0.1    127.0.0.1    TCP  66  48234 → 49927 [ACK] Seq=1 Ack=1 Win=43776 Len=0 TSval=7268636 TSecr=7268636 
     4 0.000059901 127.0.0.1    127.0.0.1    TCP  74  48236 → 49927 [SYN] Seq=0 Win=43690 Len=0 MSS=65495 SACK_PERM=1 TSval=7268636 TSecr=0 WS=128 
     5 0.000064624 127.0.0.1    127.0.0.1    TCP  74  49927 → 48236 [SYN, ACK] Seq=0 Ack=1 Win=43690 Len=0 MSS=65495 SACK_PERM=1 TSval=7268636 TSecr=7268636 WS=128 
     6 0.000070536 127.0.0.1    127.0.0.1    TCP  66  48236 → 49927 [ACK] Seq=1 Ack=1 Win=43776 Len=0 TSval=7268636 TSecr=7268636 
     7 0.000384302 127.0.0.1    127.0.0.1    TCP  66  49927 → 48234 [FIN, ACK] Seq=1 Ack=1 Win=43776 Len=0 TSval=7268636 TSecr=7268636 
     8 0.000412860 127.0.0.1    127.0.0.1    TCP  66  49927 → 48236 [RST, ACK] Seq=1 Ack=1 Win=43776 Len=0 TSval=7268636 TSecr=7268636 
     9 0.000997709 127.0.0.1    127.0.0.1    TCP  66  48234 → 49927 [FIN, ACK] Seq=1 Ack=2 Win=43776 Len=0 TSval=7268637 TSecr=7268636 
    10 0.000974316 127.0.0.1    127.0.0.1    TCP  66  [TCP Keep-Alive] 48234 → 49927 [ACK] Seq=1 Ack=2 Win=43776 Len=0 TSval=7268637 TSecr=7268636 
    11 0.001005630 127.0.0.1    127.0.0.1    TCP  66  49927 → 48234 [ACK] Seq=2 Ack=2 Win=43776 Len=0 TSval=7268637 TSecr=7268637 
    12 0.001047174 127.0.0.1    127.0.0.1    TCP  74  48238 → 49927 [SYN] Seq=0 Win=43690 Len=0 MSS=65495 SACK_PERM=1 TSval=7268637 TSecr=0 WS=128 
    13 0.001051855 127.0.0.1    127.0.0.1    TCP  54  49927 → 48238 [RST, ACK] Seq=1 Ack=1 Win=0 Len=0 
    14 0.237652758 127.0.0.1    127.0.0.1    TCP  74  48240 → 49927 [SYN] Seq=0 Win=43690 Len=0 MSS=65495 SACK_PERM=1 TSval=7268696 TSecr=0 WS=128 
    15 0.237664760 127.0.0.1    127.0.0.1    TCP  54  49927 → 48240 [RST, ACK] Seq=1 Ack=1 Win=0 Len=0 
    16 5.243733213 127.0.0.1    127.0.0.1    TCP  74  48242 → 49927 [SYN] Seq=0 Win=43690 Len=0 MSS=65495 SACK_PERM=1 TSval=7269947 TSecr=0 WS=128 
    17 5.243751969 127.0.0.1    127.0.0.1    TCP  54  49927 → 48242 [RST, ACK] Seq=1 Ack=1 Win=0 Len=0 

при использовании Netcat

Использование Netcat, я получаю нужный HTTP GET запрос, содержащий маркер аутентификации.

No.  Time   Source    Destination   Protocol Length Info 
     1 0.000000000 127.0.0.1    127.0.0.1    TCP  74  45064 → 2807 [SYN] Seq=0 Win=43690 Len=0 MSS=65495 SACK_PERM=1 TSval=7233868 TSecr=0 WS=128 
     2 0.000008155 127.0.0.1    127.0.0.1    TCP  74  2807 → 45064 [SYN, ACK] Seq=0 Ack=1 Win=43690 Len=0 MSS=65495 SACK_PERM=1 TSval=7233868 TSecr=7233868 WS=128 
     3 0.000015895 127.0.0.1    127.0.0.1    TCP  66  45064 → 2807 [ACK] Seq=1 Ack=1 Win=43776 Len=0 TSval=7233868 TSecr=7233868 
     4 0.000043941 127.0.0.1    127.0.0.1    TCP  74  45066 → 2807 [SYN] Seq=0 Win=43690 Len=0 MSS=65495 SACK_PERM=1 TSval=7233868 TSecr=0 WS=128 
     5 0.000047566 127.0.0.1    127.0.0.1    TCP  74  2807 → 45066 [SYN, ACK] Seq=0 Ack=1 Win=43690 Len=0 MSS=65495 SACK_PERM=1 TSval=7233868 TSecr=7233868 WS=128 
     6 0.000050911 127.0.0.1    127.0.0.1    TCP  66  45066 → 2807 [ACK] Seq=1 Ack=1 Win=43776 Len=0 TSval=7233868 TSecr=7233868 
     7 0.000074583 127.0.0.1    127.0.0.1    TCP  66  2807 → 45066 [RST, ACK] Seq=1 Ack=1 Win=43776 Len=0 TSval=7233868 TSecr=7233868 
     8 0.000833585 127.0.0.1    127.0.0.1    HTTP  654 GET /?code=4/zuPKCQlOvIcJq5gAvPRGLQdkiICNzOmAQUAx9apK5go HTTP/1.1 
     9 0.000841060 127.0.0.1    127.0.0.1    TCP  66  2807 → 45064 [ACK] Seq=1 Ack=589 Win=44928 Len=0 TSval=7233868 TSecr=7233868 
    10 45.005118503 127.0.0.1    127.0.0.1    TCP  66  [TCP Keep-Alive] 45064 → 2807 [ACK] Seq=588 Ack=1 Win=43776 Len=0 TSval=7245120 TSecr=7233868 
    11 45.005166221 127.0.0.1    127.0.0.1    TCP  66  [TCP Keep-Alive ACK] 2807 → 45064 [ACK] Seq=1 Ack=589 Win=44928 Len=0 TSval=7245120 TSecr=7233868 

Как вы можете видеть, моя программа отправляет флаг FIN, которого нет в netcat. Где я здесь не так?

+1

Не размещайте изображения текста! – Olaf

+0

@Olaf Я бы точно не назвал Wireshark скриншотом изображение текста. Вы не можете просто скопировать/вставить список пакетов, не так просто. – dbush

+0

@dbush: вы можете выгрузить его в текстовый файл (не уверен, что даже можно сбросить в буфер обмена). – Olaf

ответ

0

Вы читаете неправильный разъем.

Сокет, который вы передаете listen, является только гнездом для прослушивания. Он не представляет собой подключенный сокет. Он идентифицируется только локальным IP-адресом и портом.

Когда вы вызываете accept, эта функция возвращает дескриптор файла подключенного сокета. Эти сокеты идентифицируются локальным IP-адресом и портом, а также удаленным IP-адресом и портом. Поэтому эту функцию можно вызывать несколько раз для нескольких входящих соединений, каждая со своим собственным сокетом. Таким образом, вы можете иметь дело с соединениями из нескольких конечных точек.

Сохраните возвращаемое значение accept в качестве нового разъема и используйте его для send и recv. Обязательно сделайте это close, когда закончите.

Смежные вопросы