Search code examples
socketstcptcpclientserversocket

Socket TCP in linux - Client cannot insert username


I'm having troubles with implementing a signin/signup system with TCP/IP sockets.

So, whenever I want the user to signup, the client cannot insert the username, but he can insert the password. It looks like it is skipping one step.

Here is the code.

Client

void func(int sockfd)
{
    char username[MAX], password[MAX];
    int n, c;

    bzero(username, sizeof(username));
    printf("Enter the username : ");
    n = 0;
    while ((username[n++] = getchar()) != '\n')
        ;
    write(sockfd, username, sizeof(username));
    bzero(username, sizeof(username));

    bzero(password, sizeof(password));
    printf("Enter the password : ");
    c = 0;
    while ((password[c++] = getchar()) != '\n')
        ;
    write(sockfd, password, sizeof(password));
    bzero(username, sizeof(password));
}

...

int choice, ans;
    
func(sockfd);

bzero(buffer, 255);
n = read(sockfd, buffer, 255);
if(n < 0)
    error("Error reading from socket");
printf("Server - %s", buffer);
scanf("%d", &choice);
write(sockfd, &choice, sizeof(int));
    
if(choice == 1) {
    func(sockfd);
}


if(choice == 3) {
    printf("Session terminated\n");
    close(sockfd);
}

close(sockfd);
return 0;

Server

void func(int newsockfd)
{
    char username[MAX], password[MAX];
    int n;

    bzero(username, MAX);
    read(newsockfd, username, sizeof(username));
    printf("From client: %s\n", username);

    bzero(password, MAX);
    read(newsockfd, password, sizeof(password));
    printf("From client pass: %s\n", password);

    while ((username[n++] = getchar()) != '\n')
        ;

    write(newsockfd, username, sizeof(username));
}

int main(int argc, char *argv[]) {


    func(newsockfd);

    int num1, num2, ans, choice;

    n = write(newsockfd, "Benvenuto, inserisci una scelta: \n1. Registrazione\n2. Login\n3. Esci\n", strlen("Benvenuto, inserisci una scelta: \n1. Registrazione\n2. Login\n3. Esci\n"));
    if(n < 0) error("Error writing to socket");
    read(newsockfd, &choice, sizeof(int));

    switch(choice) {
        case 1:
            func(newsockfd);
            break;
        
        case 2:
            break;

        case 3:
            close(newsockfd);
            close(sockfd);
    }
    
    close(newsockfd);
    close(sockfd);
    return 0;
}

This is an example:

image


Solution

  • Ignoring the fact that the code provided is not complete code, the client and server are not even speaking the same protocol, so of course you are running into problems.

    The client is sending the username and password to the server before it has even received the server's initial prompt.

    The server is expecting the first input from the client to be the user's choice to the prompt, but the client is sending the username first, so the first few characters the server receives will be misinterpreted as an integer.

    When the server does expect to receive a username and password, it sends back the username, which the client does not read.

    You are also completely ignoring the return values of read() and write(). And you are not handling received strings properly, either.

    With that said, try something more like this instead:

    Shared

    int sendAll(int sockfd, void *buf, size_t len)
    {
        char *pbuf = (char*) buf;
        int n;
    
        while (len > 0) {
            n = send(sockfd, pbuf, len, 0);
            if (n < 0) return n;
            pbuf += n;
            len -= n;
        }
    
        return 0;
    }
    
    int recvAll(int sockfd, void *buf, size_t len)
    {
        char *pbuf = (char*) buf;
        int n;
    
        while (len > 0) {
            n = recv(sockfd, pbuf, len, 0);
            if (n <= 0) return n;
            pbuf += n;
            len -= n;
        }
    
        return 1;
    }
    
    int sendInt32(int sockfd, int32_t value)
    {
        value = htonl(value);
        return sendAll(sockfd, &value, sizeof(value));
    }
    
    int recvInt32(int sockfd, int32_t *value)
    {
        int n = recvAll(sockfd, value, sizeof(*value));
        if (n == 1) *value = ntohl(*value);
        return n;
    }
    
    int sendStr(int sockfd, const char *str)
    {
        int len = strlen(str);
        int n = sendInt32(sockfd, len);
        if (n == 0) n = sendAll(sockfd, str, len);
        return n;
    }
    
    int recvStr(int sockfd, char **str)
    {
        *str = NULL;
    
        int32_t len;
        int n = recvInt32(sockfd, &len);
        if (n <= 0) return n;
    
        *str = malloc(len + 1);
        if (*str == NULL) return -1;
    
        n = recvAll(sockfd, *str, len);
        if (n <= 0) {
            free(*str);
            *str = NULL;
            return n;
        }
    
        (*str)[len] = '\0';
        return 1;
    }
    

    Client

    void func(int sockfd)
    {
        char input[MAX+1];
        int n, c;
    
        printf("Enter the username : ");
        n = 0;
        while ((n < MAX) && ((c = getchar()) != EOF) && (c != '\n')) {
            input[n++] = (char) c;
        }
        input[n] = '\0';
    
        if (sendStr(sockfd, input) < 0)
            error("Error writing to socket");
    
        printf("Enter the password : ");
        n = 0;
        while ((n < MAX) && ((c = getchar()) != EOF) && (c != '\n')) {
            input[n++] = (char) c;
        }
        input[n] = '\0';
    
        if (sendStr(sockfd, input) < 0)
            error("Error writing to socket");
    
        char *ans;
        if (recvStr(sockfd, &ans) <= 0)
            error("Error reading from socket");
    
        printf("Server - %s: ", ans);
        free(ans);
    }
    
    int main() {
        int sockfd, choice;
        char *str;
        
        // connect to server...
        sockfd = ...;
    
        if (recvStr(sockfd, &str) <= 0)
            error("Error reading from socket");
    
        printf("Server - %s", str);
        free(str);
    
        scanf("%d", &choice);
    
        if (sendInt32(sockfd, choice) < 0)
            error("Error writing to socket");
        
        switch (choice) {
            case 1:
            case 2:
                func(sockfd);
                break;
    
            case 3:
                printf("Session terminated\n");
                break;
        }
    
        close(sockfd);
        return 0;
    }
    

    Server

    void func(int sockfd, int choice)
    {
        char *input;
    
        if (recvStr(sockfd, &input) <= 0)
            error("Error reading from socket");
    
        printf("From client user: %s\n", input);
        free(input);
    
        if (recvStr(sockfd, &input) <= 0)
            error("Error reading from socket");
    
        printf("From client pass: %s\n", input);
        free(input);
    
        char *ans = (choice == 1) ? "Registered" : "Logged in";
        if (sendStr(sockfd, ans) < 0)
            error("Error writing to socket");
    }
    
    int main() {
    
        int sockfd, clientsockfd, n;
        int32_t choice;
    
        // setup listening socket ...
        sockfd = ...;
    
        // accept client ...
        clientsockfd = ...;
    
        if (SendStr(clientsockfd, "Benvenuto, inserisci una scelta: \n1. Registrazione\n2. Login\n3. Esci\n") < 0)
            error("Error writing to socket");
    
        if (recvInt32(clientsockfd, &choice) < 0)
            error("Error reading from socket");
    
        switch (choice) {
            case 1:
            case 2:
                func(clientsockfd, choice);
                break;
    
            case 3:
                close(clientsockfd);
                break;
        }
        
        close(sockfd);
        return 0;
    }