2016-12-04 3 views
0

MISE À JOUR: Je viens d'initialiser la structure codée en dur dans la fonction problématique et j'ai toujours l'erreur!UDP sendto() donne l'erreur "adresse d'espace utilisateur invalide"

void sendjoin(unsigned int ipaddress, unsigned short port, unsigned short preferredID){ 
    printf("Sending join-request...\n"); 
    char msg[9]; 
    memset(msg, 0, 9); 
    msg[0] = JOIN_MASK | INTERN_MASK; 
    ipaddress = ipaddress; 
    port = port; 
    preferredID = htons(preferredID); 
    memcpy(&msg[1], &ipaddress, 4); 
    memcpy(&msg[5], &port, 2); 
    memcpy(&msg[7], &preferredID, 2); 

    errno = 0; 

    //printMSG((void *)&succAddr, sizeof(succAddr), 0); 
    socklen_t addrlen = sizeof(struct sockaddr_in); 
    struct sockaddr_in *temp = (struct sockaddr_in *) malloc(sizeof(struct sockaddr_in)); 
    temp->sin_family = AF_INET; 
    temp->sin_port = htons((short)8888); 
    temp->sin_addr.s_addr = htonl(16777343); 

    if(0 > sendto(sock, msg, 9, 0, (struct sockaddr *)temp, addrlen)){ 
     perror("Error while sending a packet.\n"); 
     switch(errno){ 
      case EFAULT: 
       printf("Invalid user space address.\n"); 
       break; 
      case EAGAIN: 
       printf("Something with blocking.\n"); 
       break; 
      case EBADF: 
       printf("Invalid descriptor.\n"); 
       break; 
      case EINVAL: 
       printf("Invalid argument.\n"); 
       break; 
      case EDESTADDRREQ: 
       printf("No Peer address.\n"); 
       break; 
      case EISCONN: 
       printf("Connection mode socket.\n"); 
       break; 
      case ENOTSOCK: 
       printf("The given socket is not a socket.\n"); 
       break; 
      case ENOTCONN: 
       printf("No Target.\n"); 
       break; 
      case ENOBUFS: 
       printf("Network output is full.\n"); 
       break; 
      default: 
       printf("No spezific error.\n"); 
     } 
     exit(1); 
    } 
    printf("Send to: %u %u\n", ntohl(succAddr.sin_addr.s_addr), ntohs(succAddr.sin_port)); 
} 

J'écris ce serveur distribué de table de hachage. C'est une version super simple. Je suis juste au début et j'ai un serveur qui écoute les paquets. Un autre essaie de rejoindre le réseau DHT du premier. Donc je remplis une structure globale sockaddr_in avec un numéro de port, la famille AF_INET, et une adresse IP. J'utilise la fonction inet_ntop() pour convertir ma chaîne "localhost" en ma structure. plus tard j'utilise sendto() pour commencer à communiquer avec le réseau DHT. Mais cela donne simplement l'erreur "adresse d'espace utilisateur invalide". Send12() reçoit un socket ouvert (own open serversocket!), Un buffer initialisé, sa longueur, l'adresse de struct sockaddr_in et sa longueur.

C'est du code. J'ai supprimé certaines fonctions inutilisées et essayé seulement d'inclure les fonctions où les variables sont utilisées. Dans le main() vous pouvez voir trois fonctions. L'un est checkarguments() ce qui n'est pas vraiment intéressant. Ensuite, vous avez la fonction setsocket() qui me donne un socket serveur à utiliser. A la fin de cette fonction, je remplis l'adresse IP, le port et l'id du serveur prédécesseur et successeur de celui-ci. Et puis vous avez la fonction letsgo() qui essaie de rejoindre un réseau DHT. Il remplit la structure globale sockaddr_in succAddr avec l'adresse du noeud dht connu, car l'appel à la fonction sendjoin() envoie toujours à succAddr. Et dans sendjoin() il essaie d'envoyer à succAddr mais échoue. Et je ne sais pas pourquoi. Mon succAddr est initialisé et ne devrait pas pointer vers un espace utilisateur invalide?!

Pls aide :)

Voici mon code:

//================================= 
//=Variablen======================= 
//================================= 

unsigned short myID = 0; 
char *myIP= NULL; 
char *myPORT = NULL; 
char *nodeIP = NULL; 
char *nodePORT = NULL; 

int sock = 0; 
struct sockaddr_in preAddr; 
unsigned short preID = 0; 
int preknown = 1; 
struct sockaddr_in succAddr; 
unsigned short succID = 0; 

char packet[PACKETSIZE]; 
struct sockaddr_storage sender; 
socklen_t sendersize = sizeof sender; 
int tablefunctionstarted = 0; 

char INTERN_MASK = 0b10000000; 
char STABILIZE_MASK = 0b00000100; 
char NOTIFY_MASK = 0b00000010; 
char JOIN_MASK = 0b00000001; 
char SNJ_MASK = 0b00000111; 

//================================= 
//=Functions======================= 
//================================= 


void setSocket(); 
int checkarguments(int argc, char **argv); 
int letsgo(); 
void printMSG(char *msg, int msglength, int plain); 
void handleintern(unsigned long msglength); 
void handleoutside(unsigned long msglength); 
void sendjoin(unsigned int ipaddress,unsigned short port, unsigned short preferredID); 
void sendnotify(unsigned int ipaddress,unsigned short port, unsigned short preferredID); 
void sendstabilize(); 

int main(int argc, char **argv){ 
    printf("Starting server...\n"); 
    int einklinken = checkarguments(argc, argv); 
    setSocket(); 
    if(einklinken) if(letsgo()){ perror("Problem while joining DHT network!\n"); exit(2);}; 

    /* 
    //Hauptpacketannahmeverarbeitungsschleife 
    long check = 0; 
    while(1){ 
     printf("Server is waiting for packets... \n"); 
     if(-1 == (check = recvfrom(sock, packet, PACKETSIZE, 0, (struct sockaddr *)&sender, &sendersize))){ 
      perror("Error with new packet!\n"); 
      exit(2); 
     } 
     printf("Found packet... \n"); 
     //printMSG(packet, check, 1); 

     if(0 != (packet[0] & INTERN_MASK)) handleintern(check); 
     else handleoutside(check); 
    } 
    */ 
} 


int checkarguments(int argc, char **argv){ 
    if(argc < 3){ fprintf(stderr,"Too few arguments! \nUsage: %s myip myport\nOptions:\n-id preferredID (Your preferred id in the DHT network.)\n-new ip port (IP address and port of a DHT network node.)", argv[0]); exit(1);} 
    if(argc > 8){ fprintf(stderr,"Too many arguments! \nUsage: %s myip myport\nOptions:\n-id preferredID (Your preferred id in the DHT network.)\n-new ip port (IP address and port of a DHT network node.)", argv[0]); exit(1);} 

    /* printf("Arguments:\n"); 
    for(int i = 0; i < argc; ++i){ 
     printf("%s\n", argv[i]); 
    } */ 
    printf("Parsing arguments...\n"); 
    myIP = argv[1]; 
    myPORT = argv[2]; 
    printf("My ip: %s\n", myIP); 
    printf("My port: %s\n", myPORT); 

    int newNode = 0; 
    int count = 3; 
    while(argc > count){ 
     if(argv[count][0]!='-'){fprintf(stderr,"Wrong usage! \nUsage: %s myip myport\nOptions:\n-id preferredID (Your preferred id in the DHT network.)\n-new ip port (IP address and port of a DHT network node.)", argv[0]); exit(1);} 
     if(argv[count][1]=='i'){ 
      ++count; 
      errno = 0; 
      long value = 0; 
      value = strtol(argv[count++], NULL, 10); 
      switch(errno){ 
       case ERANGE: 
        printf("The ID could not be represented.\n"); 
        exit(1); 
       case EINVAL: 
        printf("Unsupported base/radix.\n"); 
        exit(1); 
      } 
      if(value > 65536){ perror("Your desired ID is over the max value of 65536!\n"); exit(1);} 
      myID = (short) value; 
      printf("My id: %u\n", myID); 
     } 
     else if(argv[count][1]=='n'){ 
      ++count; 
      nodeIP = argv[count++]; 
      nodePORT = argv[count++]; 
      printf("The nodes ip: %s\n", nodeIP); 
      printf("The nodes port: %s\n", nodePORT); 
      newNode = 1; 
     } 
    } 

    printf("Finished parsing arguments.\n"); 
    return newNode; 
} 


void setSocket(){ 

    printf("Configuring the socket...\n"); 
    struct addrinfo hints, *locations, *p; 
    int yes=1; 

    memset(&hints, 0, sizeof hints); 
    hints.ai_family = AF_UNSPEC; 
    hints.ai_socktype = SOCK_DGRAM; 
    hints.ai_flags = AI_PASSIVE; 

    int rv = getaddrinfo(NULL, myPORT, &hints, &locations); 

    if(rv != 0){ 
     fprintf(stderr, "getaddrinfo threw an error! Maybe your port is used?\n"); 
     exit(1); 
    } 

    for(p = locations; p!=NULL; p=p->ai_next){ 

     sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol); 
     if(sock == -1){perror("SocketError");continue;} 

     if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1){perror("Can't clean socket!\n"); exit(1);} 

     if(bind(sock, p->ai_addr, p->ai_addrlen) == -1){perror("BindError");close(sock);continue;} 

     break; 
    } 

    if(p==NULL){ 
     perror("Failed to bind!\n"); 
     exit(2); 
    } 

    int check = 0; 
    if(-1 == (check = inet_pton(AF_INET, myIP, &(preAddr.sin_addr)))){ perror("Wrong ip format!\n"); exit(1);} 
    if(-1 == (check = inet_pton(AF_INET, myIP, &(succAddr.sin_addr)))){ perror("Wrong ip format!\n"); exit(1);} 
    memcpy(&(succAddr.sin_port), &(((struct sockaddr_in *)p->ai_addr)->sin_port), 2); 
    memcpy(&(preAddr.sin_port), &(((struct sockaddr_in *)p->ai_addr)->sin_port), 2); 
    memset(preAddr.sin_zero, 0, 8); 
    memset(succAddr.sin_zero, 0, 8); 
    preID = myID; 
    succID = myID; 

    printf("Finished configuring the socket.\n"); 

    freeaddrinfo(locations); 
} 


int letsgo(){ 
    printf("Trying to join an existent DHT network...\n"); 
    preknown = 0; 


    int check = 0; 
    succAddr.sin_family = AF_INET; 
    if(-1 == (check = inet_pton(AF_INET, nodeIP, &(succAddr.sin_addr)))){ perror("Wrong ip format!\n"); exit(1);} 
    errno = 0; 
    long value = 0; 
    value = strtol(nodePORT, NULL, 10); 
    switch(errno){ 
     case ERANGE: 
      printf("The node port could not be represented.\n"); 
      exit(1); 
     case EINVAL: 
      printf("Unsupported base/radix.\n"); 
      exit(1); 
    } 
    if(value > 65536){ perror("Your node port is over the max value of 65536!\n"); exit(1);} 
    succAddr.sin_port = htons((short) value); 

    unsigned int ipaddress = preAddr.sin_addr.s_addr; 
    unsigned short port = preAddr.sin_port; 
    unsigned short preferredID = 0; 

    sendjoin(ipaddress, port, myID); 

    while(1){ 
     printf("Wait for notify answer... \n"); 
     if(-1 == (check = recvfrom(sock, packet, PACKETSIZE, 0, (struct sockaddr *)&sender, &sendersize))){ 
      perror("Error with new packet!\n"); 
      exit(2); 
     } 
     printf("Got answer... \n"); 

     if(0 == (packet[0] & INTERN_MASK)){ printf("Can't understand the packet.\n"); continue;} 
     if(0 == (packet[0] & NOTIFY_MASK || check < 8)){ printf("Not a notify packet.\n"); continue;} 

     memcpy(&preferredID, &packet[7], 2); 
     preferredID = ntohs(preferredID); 
     if(preferredID > TABLE_LENGTH){ perror("Preferred id is too big!\n"); continue;} 
     memcpy(&ipaddress, &packet[1], 4); 
     memcpy(&port, &packet[5], 2); 

     succAddr.sin_addr.s_addr = ipaddress; 
     succAddr.sin_port = port; 
     succID = preferredID; 
     break; 
    } 


    return 0; 
} 


void sendjoin(unsigned int ipaddress, unsigned short port, unsigned short preferredID){ 
    printf("Sending join-request...\n"); 
    char msg[9]; 
    memset(&msg, 0, 9); 
    msg[0] = JOIN_MASK | INTERN_MASK; 
    ipaddress = ipaddress; 
    port = port; 
    preferredID = htons(preferredID); 
    memcpy(&msg[1], &ipaddress, 4); 
    memcpy(&msg[5], &port, 2); 
    memcpy(&msg[7], &preferredID, 2); 

    errno = 0; 

    //printMSG((void *)&succAddr, sizeof(succAddr), 0); 
    socklen_t addrlen = sizeof(struct sockaddr_in); 

    if(0 > sendto(sock, msg, 9, 0, (struct sockaddr *)&succAddr, addrlen)){ 
     perror("Error while sending a packet.\n"); 
     switch(errno){ 
      case EFAULT: 
       printf("Invalid user space address.\n"); 
       break; 
      case EAGAIN: 
       printf("Something with blocking.\n"); 
       break; 
      case EBADF: 
       printf("Invalid descriptor.\n"); 
       break; 
      case EINVAL: 
       printf("Invalid argument.\n"); 
       break; 
      case EDESTADDRREQ: 
       printf("No Peer address.\n"); 
       break; 
      case EISCONN: 
       printf("Connection mode socket.\n"); 
       break; 
      case ENOTSOCK: 
       printf("The given socket is not a socket.\n"); 
       break; 
      case ENOTCONN: 
       printf("No Target.\n"); 
       break; 
      case ENOBUFS: 
       printf("Network output is full.\n"); 
       break; 
      default: 
       printf("No spezific error.\n"); 
     } 
     exit(1); 
    } 
    printf("Send to: %u %u\n", ntohl(succAddr.sin_addr.s_addr), ntohs(succAddr.sin_port)); 
} 
+0

'perror()' déjà imprime le texte correct pour l'erreur. Pas besoin de cette énorme déclaration de commutateur du tout, surtout quand il imprime le * mauvais * texte. Ne pas 'traduire' les codes d'erreur du système ou les messages. Sinon, vous risquez de donner les mauvaises informations, et vous seul pouvez déboguer le code. – EJP

+0

Avez-vous essayé d'utiliser 'strace' pour confirmer que les arguments de' sendto() 'sont corrects? –

+0

@EJP J'ai seulement obtenu une "mauvaise adresse" comme description d'erreur de 'perror()' et les pages de manuel errno trouvées sur internet l'ont spécifié avec "adresse d'espace utilisateur invalide". Mais ouais je vais arrêter de faire ça à l'avenir :). Je ne sais toujours pas ce qu'est l'erreur. Mais aujourd'hui, j'ai testé mon programme sur Ubuntu 14 et il n'a pas donné une seule erreur. Cela a quelque chose à voir avec mon cygwin sur Windows. – Hyrikan

Répondre

0

Cette ligne:

socklen_t addrlen = sizeof(struct sockaddr); 

doit être:

socklen_t addrlen = sizeof(struct sockaddr_in); 
+0

Ah désolé. Cette ligne est de plusieurs heures de trouver cette petite erreur que j'ai faite quelque part. Mais ça ne change pas le résultat :( – Hyrikan

+0

Ouais, je viens de remarquer que 'sizeof (sockaddr_in) == sizeof (sockaddr) == 16' sur Linux, donc ce n'est pas ça. – selbie