Firstly, i'm really new to all this bash/unix/c stuff so i will probably get some words meanings wrong here, but anyway:

Im trying to make a client pass simple shell commands to the server, which executes them. They communicate locally on the same machine through a socket.

I can make the server perform "ls -l" and "mkdir test" for example, but not "ls", e.g just one argument.

If i only send one command like "ls", the server will try "ls ¤"#"#%" <-- random data. So i think it's really a string problem. I've tried different ideas for a week now, but i am not closer to a solution, and my programming skills are not that good at all, so i thought i try asking for some help.

Server:

#include <unistd.h>

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>

#define SOCK_PATH "echo_socket"

int main(void)
{
    int s, s2, t, len;
    struct sockaddr_un local, remote;
    char str[100];
    char* arg_list[222];
    char str1[100], str2[100];

    if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
        perror("socket");
        exit(1);
    }

    local.sun_family = AF_UNIX;
    strcpy(local.sun_path, SOCK_PATH);
    unlink(local.sun_path);
    len = strlen(local.sun_path) + sizeof(local.sun_family);
    if (bind(s, (struct sockaddr *)&local, len) == -1) {
        perror("bind");
        exit(1);
    }

    if (listen(s, 5) == -1) {
        perror("listen");
        exit(1);
    }

    for(;;) {
        int active,done, sent, n;
        printf("Waiting for a connection...\n");
        t = sizeof(remote);
        if ((s2 = accept(s, (struct sockaddr *)&remote, &t)) == -1) {
            perror("accept");
            exit(1);
        }

        printf("Connected.\n");
        active = 0;
        done = 0;
        sent = 0;
        do {
            n = recv(s2, str, 100, 0);
            if (n <= 0) {
                if (n < 0) perror("recv");
                done = 1;
            }


            str[strcspn ( str, "\n" )] = '\0';
            strcpy(str1,str);

            int i=0,k=0;

            while (str1[i] != ' ')
                i++;

            while (str1[i] != '\0'){
                str2[k] = str1[i+1];
                k++;
                i++;
            }

            i=0;

            while (str1[i] != ' ')
                i++;

            str1[i] = '\0';


            int spawn (char* program, char** arg_list)
            {
                pid_t child_pid;
                child_pid = fork ();
                if (child_pid != 0)
                    return child_pid;

                else{
                    execvp (program, arg_list);
                }
                fprintf (stderr, "an error occurred in execvp\n");
                abort ();




                char* arg_list[222];
                char kommando[222];
                char * tmp;

                i=0;

                tmp = strtok (kommando," ");
                arg_list[0] = tmp;
                while (tmp != NULL)
                {
                    tmp = strtok (NULL, " ");
                    arg_list[i+1] = tmp;
                    i++;
                }

                char* arg[] = {
                        str1,
                        str2,
                        NULL
                };


                spawn (str1, arg);


                if (!done && sent == 0 && active == 0)
                    if (send(s2, str, n, 0) < 0) {
                        perror("send");
                        sent = 1;
                    }

                if (!done && sent == 0 && active == 1)
                    if (send(s2, str, n, 0) < 0) {
                        perror("send");
                        sent = 1;
                    }
                sent = 0;
            } while (!done);

            close(s2);
        }

        return 0;
    }

Client:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>

#define SOCK_PATH "echo_socket"

int main(void)
{
    int s, t, len;
    struct sockaddr_un remote;
    char str[100];

    if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
        perror("socket");
        exit(1);
    }

    printf("Trying to connect...\n");

    remote.sun_family = AF_UNIX;
    strcpy(remote.sun_path, SOCK_PATH);
    len = strlen(remote.sun_path) + sizeof(remote.sun_family);
    if (connect(s, (struct sockaddr *)&remote, len) == -1) {
        perror("connect");
        exit(1);
    }

    printf("Connected.\n");

    while(printf("> "), fgets(str, 100, stdin), !feof(stdin)) {
        if (send(s, str, strlen(str), 0) == -1) {
            perror("send");
            exit(1);
        }

        if ((t=recv(s, str, 100, 0)) > 0) {
            str[t] = '\0';
            printf("echo> %s", str);
        } else {
            if (t < 0) perror("recv");
            else printf("Server closed connection\n");
            exit(1);
        }
    }

    close(s);

    return 0;
}

Edited 3 Years Ago by pritaeas: Moved.

When you get extraneous garbage on a string, the problem is consistently a failure to terminate the string with '\0'. I didn't really look closely at your code, but I'm fairly confident that's the problem, so it should give you a starting point for troubleshooting. Just make sure that every time you have a string, it's terminated with '\0' at the correct place.

When you call send() in your client code, you're using the return value of strlen() as the number of bytes to send. Remember that strlen() does not include the terminating \0 in its count. So you'll have to add 1 to compensate for the terminating character. Make sure you're doing the same in your server code.

This article has been dead for over six months. Start a new discussion instead.