I am trying to write a simple server and client that will act as a shell, in C.
The server receives data from the client in the form of system commands, executes them and redirects the output to the socket. The client then reads the socket, and prints it to stdout. It works well when I input existing system commands like ls
or df
, and it works with arguments as well. So ls -l
works just fine.
However, when I enter a command that isn't recognized, either the server or client (I don't know which one) slips and the output is somehow delayed. I'll show you what I mean.
This is my server.c
:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#define SOCK_PATH "echo_socket"
int main(void)
{
int s, s2, t, len;
struct sockaddr_un local, remote;
char str[1024];
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 done, 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");
done = 0;
do {
memset(str,0,strlen(str));
n = recv(s2, str, 1024, 0);
if (n <= 0) {
if (n < 0) perror("recv");
done = 1;
}
int cpid = fork();
int e;
if (cpid == 0)
{
printf("executing: %s\n", str);
dup2(s2, STDOUT_FILENO);
dup2(s2, STDERR_FILENO);
//system(str);
execl("/bin/sh", "sh", "-c", str, (char *) 0)
str[0] = 0;
exit(0);
}
wait();
} while (!done);
close(s2);
}
return 0;
}
And this is my client.c
:
#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[1024];
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(str[0] = '\0', printf("Server shell> "), fgets(str, 1024, stdin), !feof(stdin)) {
if (str[0] == '\n') continue;
str[strlen(str) - 1] = '\0';
if (send(s, str, strlen(str), 0) == -1) {
perror("send");
exit(1);
}
str[0] = '\0';
if ((t=recv(s, str, 1024, 0)) > 0) {
str[t] = '\0';
printf("%s\n", str);
} else {
if (t < 0) perror("recv");
else printf("Server closed connection\n");
exit(1);
}
}
close(s);
return 0;
}
Here is an example of usage and output:
Trying to connect...
Connected.
Server shell> ls
client
client.c
echo_socket
server
server.c
Server shell> m
sh: 1:
Server shell> df
m: not found
Server shell> df
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda1 3596128 2655360 738376 79% /
udev 10240 0 10240 0% /dev
tmpfs 204880 4872 200008 3% /run
tmpfs 512196 39624 472572 8% /dev/shm
tmpfs 5120 4 5116 1% /run/lock
tmpfs 512196 0 512196 0% /sys/fs/cgroup
/dev/sda8 3750424 215924 3324276 7% /home
/dev/sda7 365639 65527 276714 20% /tmp
/dev/sda5 1791524 296880 1385588 18% /var
tmpfs 102440 4 102436 1% /run/user/116
tmpfs 102440 8 102432 1% /run/user/1000
/dev/sr0 57632 57632 0 100% /media/cdrom0
Operativsystem 1953512444 1804472304 149040140 93% /media/sf_Operativsystem
As you can see, it works fine until I input m
, which isn't recognized.
Could someone help me out? If you need more information, please let me know.