Re: Sockets Redirection problem
- From: "Bin Chen" <binary.chen@xxxxxxxxx>
- Date: 18 Feb 2007 17:15:34 -0800
On 2月19日, 上午6时05分, prad...@xxxxxxxxx wrote:
Hi guys,Instead with messing with system, there is an alternative that works
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...
easier, popen.
阅读更多 »
.
- References:
- Sockets Redirection problem
- From: pradqdo
- Sockets Redirection problem
- Prev by Date: Re: Sockets Redirection problem
- Next by Date: Re: Sockets Redirection problem
- Previous by thread: Re: Sockets Redirection problem
- Next by thread: Re: Sockets Redirection problem
- Index(es):
Relevant Pages
|