0

UPDATE: I just initialized the struct hardcoded in the problematic function and i still got the error!

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));
}

i am writing this distributed hash table server. It's a super simple version. I am just at the beginning and got a server who is just listening for packages. Another one tries to join the first one's dht network. So i am filling a global struct sockaddr_in with a port number, family AF_INET, and an ip address.

I use the function inet_ntop() to convert my "localhost" - string into my struct. later i am using sendto() to start communicating with the dht network. But it just gives the "invalid user space address" error.

sendto() gets an open socket (own open serversocket!), an initialized buffer, his length, the sockaddr_in struct as address and his length.

It is quite some code. I deleted some unused functions and tried only to include the functions where the variables are used. In the main() you can see three functions. One is checkarguments() which is not really interesting. Then you have the setsocket() function which gets me a server socket to use. At the end of this function i am filling in the ip address, port and id for the predecessor and successor server of this one. And then you have the letsgo() function which tries to join a dht network. It fills the global struct sockaddr_in succAddr with the address of the known dht node, because the call to the sendjoin() function is always sending to succAddr. And in sendjoin() it tries to send to succAddr but fails. And i have no idea why. My succAddr is initialized and shouldnt point to an invalid user space ?!

Pls help :)

Here is my 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));
}
Hyrikan
  • 59
  • 7
  • 1
    `perror()` already prints the correct text for the error. No need for that huge switch statement at all, especially when it prints the *wrong* text. Don't 'translate' system error codes or messages. Otherise you risk giving the wrong information, and only you can debug the code. – user207421 Dec 04 '16 at 21:22
  • Have you tried using `strace` to confirm that the arguments to `sendto()` are correct? – Joel C Dec 05 '16 at 16:00
  • 1
    @EJP I only got "bad address" as error describtion from 'perror()' and the errno man pages i found on the internet specified it with "invalid user space address". But yeah i will stop doing that in the future :). I still don't know what the mistake is. But today i tested my program on ubuntu 14 and it gave not a single error. It has something to do with my cygwin on windows. – Hyrikan Dec 09 '16 at 13:44

1 Answers1

0

This line:

socklen_t addrlen = sizeof(struct sockaddr);

Needs to be:

socklen_t addrlen = sizeof(struct sockaddr_in);
selbie
  • 100,020
  • 15
  • 103
  • 173
  • Ah sorry. That line is from several hours of finding that little mistake i made somewhere. But it does not change the outcome :( – Hyrikan Dec 04 '16 at 18:56
  • Yeah, I just noticed that `sizeof(sockaddr_in) == sizeof(sockaddr) == 16` on Linux. So that's not it. – selbie Dec 04 '16 at 19:02