Re: Sockets Redirection problem



On 2月19日, 上午6时05分, prad...@xxxxxxxxx wrote:
Hi guys,
I am trying to build a simple server that can execute local commands
and return the output of the execution to the client. For example
executing ls, cd, find and all of the normal unix utility programs.
Here is my program's server source:

serv.c:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/wait.h>

#define MYPORT 1111

#define BACKLOG 10

#define MAXDATASIZE 100
#define COMMANDBUFFER 100000

void sigchld_handler(int s)
{
while (waitpid(-1, NULL, WNOHANG) > 0);}

int check_token(char *buf, FILE *fp, char *match); // check for valid
usernames and passwords
int execute(int sockfd);

int main (void)
{

int sockfd, new_fd;
struct sockaddr_in my_addr;
struct sockaddr_in their_addr;
socklen_t sin_size;
struct sigaction sa;
int yes = 1, numbytes;
char buf[MAXDATASIZE];
FILE *user;
char match[50]; // used to check usernames or passwords

if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(EXIT_FAILURE);
}

if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int))
== -1) {
perror("setsockopt");
exit(EXIT_FAILURE);
}
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(MYPORT);
my_addr.sin_addr.s_addr = INADDR_ANY;
memset(&(my_addr.sin_zero), '\0', 8);

if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct
sockaddr)) == -1) {
perror("bind");
exit(EXIT_FAILURE);
}
if (listen(sockfd, BACKLOG) == -1) {
perror("listen");
exit(EXIT_FAILURE);
}

sa.sa_handler = sigchld_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
perror("sigaction");
exit(EXIT_FAILURE);
}

while (1)
{
sin_size = sizeof(struct sockaddr_in);
if ( (new_fd = accept(sockfd, (struct sockaddr *)&their_addr,
&sin_size)) == -1 ) {
perror("accept");
continue;
}
printf("Server got connection from: %s\n",
inet_ntoa(their_addr.sin_addr));

if (!fork())
{
close(sockfd);
if (send(new_fd, "Stan's Server v0.1", 18, 0) == -1)
perror("send banner");

if ( (numbytes = recv(new_fd, buf, MAXDATASIZE - 1, 0)) == -1)
perror("recv username");
buf[numbytes - 1] = '\0'; // get rid of the \n
if ( (user = fopen("users", "r")) == NULL) {
fprintf(stderr, "Error opening username file\n");

if (send(new_fd, "2", 1, 0) == -1)
perror("send response");
}

if (check_token(buf, user, NULL) == 1)
{
printf("%s provided valid username.\n",
inet_ntoa(their_addr.sin_addr));
if (send(new_fd, "1", 1, 0) == -1)
perror("send response");

strcpy(match, buf); // store the valid user name to be compared
with a valid
// password for that username

if ( (numbytes = recv(new_fd, buf, MAXDATASIZE - 1, 0)) == -1)
perror("recv passwrd");
buf[numbytes - 1] = '\0'; // get rid of \n

if(check_token(buf, user, match) == 1)
{
printf("%s provided valid password.\nAuthentication of %s
successful!\n", inet_ntoa(their_addr.sin_addr),
inet_ntoa(their_addr.sin_addr));
if (send(new_fd, "1", 1, 0) == -1)
perror("send response");
execute(new_fd); // authentication successful so we start
executing commands
}
else
if (send(sockfd, "0", 1, 0) == -1)
perror("send resopnse");
}
else
if (send(new_fd, "0", 1, 0) == -1)
perror("send bad_username");

close(new_fd);
exit(0);
}
close(new_fd);
}
return 0;

}

int check_token(char *buf, FILE *fp, char *match)
{
char temp[128];
char *tok;

rewind(fp);
while (!feof(fp))
{
fgets(temp, 128, fp);
tok = strtok(temp, ":");

if (match == NULL) {
if (!strcmp(tok, buf))
return 1;
else
continue;
}
else // we have already a username that was checked for
correction so we have
// to check the password
{
if (!strcmp(tok, match))
{
tok = strtok(NULL, ":");
tok[strlen(tok) - 1] = '\0'; // remove newline character \n
if (!strcmp(tok, buf))
return 1;
}
}
}
return 0;}

int execute(int sockfd)
{
int redir_stdout[2]; // pipe used for redirection of commands :)
char pipe_transffer[4096];
char buf[MAXDATASIZE * 5];
int numbytes;
char *command[MAXDATASIZE];
char *temp;
int counter = 0;
int status; // close child

pipe(redir_stdout);
while (1)
{
counter = 0;
if ( (numbytes = recv(sockfd, buf, MAXDATASIZE * 5 - 1, 0)) ==
-1) {
perror("recv command");
return -1;
}
buf[numbytes] = '\0';
/* sPLITTING THE COMMAND */
temp = strtok(buf, " \n");
if (!strcmp(temp, "quit"))
break;
while (temp)
{
command[counter] = (char *)malloc(sizeof(char) * strlen(temp));
strcpy(command[counter++], temp);
temp = strtok(NULL, " \n");
}
command[counter] = NULL;

printf("Executing: ");
counter = 0;
while(command[counter])
printf("%s ", command[counter++]);

if (!fork()) // child
{
close(1);
close(redir_stdout[0]);
dup2(redir_stdout[1], fileno(stdout));
execvp (command[0], command);
exit (EXIT_SUCCESS);
}
// parent
while(1)
{
numbytes = read(redir_stdout[0], pipe_transffer,
strlen(pipe_transffer));
if (send(sockfd, pipe_transffer, strlen(pipe_transffer), 0) == -1)
{
perror("send pipe_redirection");
return -1;
}
printf("Numbytes sent: %d\n", numbytes);

// See if there is more data to be sent or there is none so we can
escape blocking
// in case there is nothing in the pipe and we try to read
if (numbytes < )
{
if (send(sockfd, "0", 1, 0) == -1)
perror("send end_of_data");
break;
}
else
{
if (send(sockfd, "1", 1, 0) == -1)
perror("send more_data");
continue;
}
}
wait(&status);
}

return 1;

}

Here is my client source:

cli.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <errno.h>
#include <netdb.h>
#include <netinet/in.h>

#define PORT 1111

#define MAXDATASIZE 100
void bye (char *buf);
int command(int sockfd);

int main (int argc, char **argv)
{
int sockfd, numbytes;
char buf[MAXDATASIZE];
struct hostent *he;
struct sockaddr_in their_addr;
struct timeval timeout;

if (argc != 2) {
fprintf(stderr, "Usage: %s server_hostname\n", argv[0]);
exit(EXIT_FAILURE);
}

if ( (he = gethostbyname(argv[1])) == NULL) {
herror("gethostbyname");
exit(EXIT_FAILURE);
}

if ( (sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
bye("socket");

//Set timeout
bzero (&timeout, sizeof(timeout));
timeout.tv_sec = 2;
if (setsockopt (sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeout,
sizeof(timeout))) {
fprintf(stderr, "Error setting timeout option!\n");
exit(EXIT_FAILURE);
}

their_addr.sin_family = AF_INET;
their_addr.sin_port = htons(PORT);
their_addr.sin_addr = *((struct in_addr *)he->h_addr);
memset(&(their_addr.sin_zero), '\0', 8);

if (connect(sockfd, (struct sockaddr *)&their_addr, sizeof(struct
sockaddr)) == -1)
bye("connect");

/* Get banner */
if ( (numbytes = recv(sockfd, buf, MAXDATASIZE - 1, 0)) == -1)
perror("recv banner");
buf[numbytes] = '\0';
printf("%s\n", buf);
/*-------------------------*/

/* Authenticate */
printf("Enter username: ");
fgets(buf, MAXDATASIZE, stdin);

if (send(sockfd, buf, strlen(buf), 0) == -1)
perror("send username");

/* Recieve response */
if ( (numbytes = recv(sockfd, buf, MAXDATASIZE - 1, 0)) == -1)
bye("recv response");
buf[numbytes] = '\0';
if (atoi(buf) == 1) // username is valid
{
/* Send password */
printf("Enter password: ");
fgets(buf, MAXDATASIZE, stdin);
if (send(sockfd, buf, strlen(buf), 0) == -1)
bye("send password");

/* Receive response */
if ( (numbytes = recv(sockfd, buf, MAXDATASIZE - 1, 0)) == -1)
bye("recv response");
buf[numbytes] = '\0';
if (atoi(buf) == 1)
{
printf("Password accepted! Enjoy your stay!\n");

command(sockfd);
}
else
printf("Wrong password!\n");
}
else if (atoi(buf) == 2)
printf("Username/Password Database error!\n");
else
printf("Wrong username!\n");

close(sockfd);

return 0;

}

void bye (char *buf)
{
perror(buf);
exit(EXIT_FAILURE);

}

int command(int sockfd)
{
char buf[MAXDATASIZE * 50];
int numbytes;

while(1)
{
printf("Command: ");
fgets(buf, MAXDATASIZE * 5, stdin);

if (buf[0] == '\n')
continue;

if (!strcmp(strtok(buf, "\n"), "quit"))
break;

printf("Sending command: %s\n", buf);
if ((numbytes = send(sockfd, buf, strlen(buf), 0)) == -1) {
perror("send command");
return -1;
}
while (1)
{
if ((numbytes = recv(sockfd, buf, MAXDATASIZE * 50 - 1, 0)) == -1)
{ // PIPE SIZE ON THE SERVER
perror("recv response");
return -1;
}
buf[numbytes] = '\0';
printf("%s", buf);

// Get information if there is more data to follow
if ( (numbytes = recv(sockfd, buf, 101, 0)) == -1)
perror("recv response for continuity");
printf("Continue: %s\n", buf);
if (atoi(buf) == 0)
break;
}
}

return 1;

}

As you can see I am trying to do something very simple but I have a
couple of questions:

1. When I redirect the standard output to a pipe from the fork in the
child process on the server side and then when I try to read after
that in the parent in order to send the output of the command that was
executed how can I know in advance how much data it is needed to be
sent to the client because I know that pipes have a limitation of 4096
and if I do a ls /usr/bin it will produce much larger stream of data
so I have to resend the...
Instead with messing with system, there is an alternative that works
easier, popen.

阅读更多 »


.



Relevant Pages

  • Sockets Redirection problem
    ... I am trying to build a simple server that can execute local commands ... executing ls, cd, find and all of the normal unix utility programs. ... int execute; ...
    (comp.os.linux.development.apps)
  • Re: [9fans] Small program "PlanKey" (paraphrase of DOSKey)
    ... commands that take up more than one line won't be stored in the history properly, so each line will get its own entry. ... int len; ... char buf; ... // Array of BackSpaces ...
    (comp.os.plan9)
  • Re: why display is ffffff82 instead of 82 ??
    ... > but after i use the following commands, the last byte 82 is displayed as ... char is a signed integer type. ... Casting to int retains this ... signedness and extends the sign-bit into all available "negativity" ...
    (comp.lang.cpp)
  • Re: [MFC REQUEST] Filename completion in sh(1)
    ... * This code is derived from software contributed to The NetBSD Foundation ... +static const char * ... +static int ... void ckfree; ...
    (freebsd-current)
  • Re: [MFC REQUEST] Filename completion in sh(1)
    ... pointer ckrealloc; ... void stunalloc; ... int unaliascmd(int, char **); ... -extern struct output output; ...
    (freebsd-current)