Sometimes it is useful to issue commands on another host. I once was in a situation where I had 20 or more other hosts and I wanted to issue commands to these other hosts from one host. There are Unix commands called rsh (remote shell), and rex (remote execute). Even with this standard options, it still turned out useful for me to create an environment where I could with one command start up a system of 20 hosts or shut id down. I don't plan to spend much time explaining any of this, but I did want to make it available since it only uses concepts that we have already covered.
cproxyMain.c is a small piece of code that demonstrates how the client side works. To build the client piece, issue
gcc cproxyMain.c cproxy.c -o cproxy
The server side is created with
gcc sproxy.c -o sproxy
To start up the server, issue the command:
./sproxy portnumber
#include "cproxy.h"
#include <stdio.h>
main()
{
char * szHost = "gettysburg.wccnet.org";
int nPort = 7778;
char * argv[] = {"tail", "-f", "msg.log"};
// Synchronous start
nRunCmd(szHost, nPort, stdout, "ls -l", NULL);
nRunCmd(szHost, nPort, stdout, "ps -af", NULL);
// Send file cproxy.c to the remote file cproxy.c.remote
nStoreFile(szHost, nPort, stdout, "cproxy.c", "cproxy.c.remote");
// Asynchronous start
nStartCmd(szHost, nPort, stdout, 3, argv);
}
#include <stdio.h>
#define END_OF_STORE "End of Store Cmd\n"
#define END_OF_START "End of Start Cmd\n"
#define LAST_INPUT_LINE "@@@@@@@@@@"
#define RUN_CMD "run"
#define START_CMD "start"
#define STORE_CMD "store"
#define SEND_BUFF_SIZE 3000
#define CPROXY_CONN_ERR -1
int nStoreFile(char *szHost, int nPort, FILE *fp,
char *szFileToSend, char *szRemoteFileName);
int nRunCmd(char *szHost, int nPort, FILE *fp,
char *szCmdToRun, char *szFileToReceiveResults);
int nStartCmd(char *szHost, int nPort, FILE *fp,
int nArgs, char *szArg[]);
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include "cproxy.h"
#define BUFF_SIZE 2000
int nConnect(int nPort, char *szHostname, char **pszErr);
void SendFile(char *szFile, int fd1);
void WaitForResponse (int nfd1, FILE *fp);
void WaitForOutput (int nfd1, FILE *fp, char *szFileOut);
int nRunCmd(char *szHost, int nPort, FILE *fp,
char *szCmdToRun, char *szFileToReceiveResults)
{
int fd1 = -1;
char cbuff[500];
char *szErrMsg;
fd1 = nConnect(nPort, szHost, &szErrMsg);
if (fd1 < 0)
{
if (fp != NULL)
fprintf(fp,"Unable to connect to Host(%s) port(%d) Err(%s)\n",
szHost, nPort, strerror(errno));
return CPROXY_CONN_ERR;
}
sprintf(cbuff,"%s;%s;\n", RUN_CMD, szCmdToRun);
write(fd1, cbuff, strlen(cbuff));
WaitForOutput(fd1,fp, szFileToReceiveResults);
close(fd1);
}
int nStoreFile(char *szHost, int nPort, FILE *fp,
char *szFileToSend, char *szRemoteFileName)
{
int fd1 = -1;
char cbuff[500];
char *szErrMsg;
struct linger lingOpt;
struct timeval tmvTimeout;
fd1 = nConnect(nPort, szHost, &szErrMsg);
if (fd1 < 0)
{
if (fp != NULL)
fprintf(fp,"Unable to connect to Host(%s) port(%d) Err(%s)\n",
szHost, nPort, strerror(errno));
return CPROXY_CONN_ERR;
}
/* Set the LINGER Option here. ? */
lingOpt.l_onoff = 1;
lingOpt.l_linger = 0;
if (setsockopt(fd1, SOL_SOCKET, SO_LINGER, (const void *) &lingOpt,
sizeof(lingOpt)) < 0)
{
fprintf(fp, "Unable to setsockopt errno: %d(%s)", errno,
strerror(errno));
}
sprintf(cbuff,"%s;%s;\n", STORE_CMD, szRemoteFileName);
write(fd1, cbuff, strlen(cbuff));
SendFile(szFileToSend, fd1);
/* We do a shutdown here to send kind of EOF for the cat at the other end.
*/
if (shutdown(fd1, 1) < 0)
{
fprintf(fp, "Unable to Shutdown the send part, err:%d(%s)", errno,
strerror(errno));
}
/* Wait for a Done. from the sproxy here. */
WaitForResponse(fd1, NULL);
close(fd1);
}
int nStartCmd(char *szHost, int nPort, FILE *fp,
int nArgs, char *szArg[])
{
int fd1 = -1;
int i;
char cbuff[500];
char *szErrMsg;
fd1 = nConnect(nPort, szHost, &szErrMsg);
if (fd1 < 0)
{
if (fp != NULL)
fprintf(fp,"Unable to connect to Host(%s) port(%d) Err(%s)\n",
szHost, nPort, strerror(errno));
return CPROXY_CONN_ERR;
}
sprintf(cbuff,"%s;", START_CMD);
for (i = 0; i < nArgs; i++)
{
strcat(cbuff,szArg[i]);
strcat(cbuff,";");
}
strcat(cbuff,"\n");
write(fd1, cbuff, strlen(cbuff));
WaitForResponse(fd1,fp);
close(fd1);
}
void WaitForResponse (int fd1, FILE *fp)
{
char buffer[BUFF_SIZE];
struct timeval stv;
long lBytes;
int iMaxFd, iNumInputs, nContinue = 1;
fd_set fdCheck;
/* Wait for output */
stv.tv_sec = 60;
stv.tv_usec = 0;
FD_ZERO(&fdCheck);
iMaxFd = fd1;
iMaxFd += 1;
FD_SET(fd1, &fdCheck);
iNumInputs = select(iMaxFd, &fdCheck, 0, 0, NULL /* &stv*/);
if (iNumInputs == -1)
{
/* Error*/
if (fp != NULL)
fprintf(fp,
"\n Select Err(%d):%s\n==> die\n", errno, strerror(errno));
nContinue = 0;
}
else if (iNumInputs == 0)
{
/* Timeout */
if (fp != NULL)
fprintf(fp,"\n Timeout from select\n");
}
else if (FD_ISSET(fd1, &fdCheck))
{
lBytes = read(fd1, buffer, BUFF_SIZE);
if (fp !=NULL)
fprintf(fp,"\nRead %d bytes from fd1\n", lBytes);
if (lBytes > 0)
{
buffer[lBytes] = 0;
if (fp !=NULL)
{
fprintf(fp,"%s\n", buffer);
fflush(fp);
}
}
else
{
if (fp != NULL)
fprintf(fp,"\nfd1 read(%d bytes) err(%d):%s\n ==> die\n",
lBytes, errno, strerror(errno));
}
}
close(fd1);
}
void WaitForOutput (int fd1, FILE *fp, char *szFileOut)
{
char buffer[BUFF_SIZE];
struct timeval stv;
long lBytes;
int iMaxFd, iNumInputs, nContinue;
fd_set fdCheck;
FILE *fout=NULL;
/* Wait for output */
if (szFileOut == NULL)
fout = fp;
else
{
fout = fopen(szFileOut,"w");
if (fout == NULL)
{
if (fp != NULL)
{
fprintf(fp,"Unable to open(%s) Err(%s)\n",
szFileOut, strerror(errno));
fflush(fp);
}
}
}
for (nContinue = 1; nContinue;)
{
stv.tv_sec = 600;
stv.tv_usec = 0;
FD_ZERO(&fdCheck);
iMaxFd = fd1;
iMaxFd += 1;
FD_SET(fd1, &fdCheck);
iNumInputs = select(iMaxFd, &fdCheck, 0, 0, NULL /* &stv*/);
if (iNumInputs == -1)
{
/* Error*/
if (fp != NULL)
fprintf(fp, "\n Select Err(%d):%s\n==> die\n",
errno, strerror(errno));
nContinue = 0;
}
else if (iNumInputs == 0)
{
nContinue = 0;
/* Timeout */
if (fp != NULL)
fprintf(fp,"\n Timeout from select\n");
}
else if (FD_ISSET(fd1, &fdCheck))
{
lBytes = read(fd1, buffer, BUFF_SIZE);
if (fp !=NULL)
fprintf(fp,"\nRead %d bytes from fd1\n", lBytes);
if (lBytes > 0)
{
if (fout !=NULL)
{
fwrite(buffer,1, lBytes, fout);
fflush(fout);
}
}
else
{
nContinue = 0;
if (fp != NULL)
fprintf(fp,"\nfd1 read(%d bytes) err(%d):%s\n ==> die\n",
lBytes, errno, strerror(errno));
}
}
}/* End of for nContinue */
close(fd1);
if ((fout != NULL) && (fp != fout))
fclose(fout);
}
int nConnect(int nPort, char *szHostname, char **pszErr)
{
int nFidRet=-1;
struct sockaddr_in sin;
struct hostent *hp;
static char cErrMsg[200];
cErrMsg[0] = 0;
*pszErr = cErrMsg;
hp = gethostbyname(szHostname);
if (hp == NULL)
{
sprintf(cErrMsg,"%s: unknown host.", szHostname);
}
else
{
if ((nFidRet = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
sprintf(cErrMsg,"socket err(%d):%s", errno, strerror(errno));
}
else
{
sin.sin_family = AF_INET;
sin.sin_port = htons(nPort);
memcpy(&sin.sin_addr, hp->h_addr, hp->h_length);
if (connect(nFidRet, (struct sockaddr *)&sin, sizeof(sin)) < 0)
{
sprintf(cErrMsg,"connect err(%d):%s", errno, strerror(errno));
close(nFidRet);
nFidRet = -1;
}
}
}
return nFidRet;
}
void SendFile(char *szFile, int fd1)
{
int nRead;
int nWrite, nTemp;
FILE *fp;
char cbuff[SEND_BUFF_SIZE];
fp = fopen(szFile, "r");
if (fp == NULL)
{
printf("Can't open file(%s) Err(%s)\n", szFile, strerror(errno));
fflush(stdout);
return;
}
while((nRead=fread(cbuff, 1, SEND_BUFF_SIZE, fp)) > 0)
{
#ifdef DEBUG
printf("Read %d bytes.\n", nRead);
fflush(stdout);
#endif
nWrite = 0;
while (nWrite < nRead)
{
nTemp = write(fd1, cbuff+nWrite, nRead-nWrite);
if (nTemp == -1)
{
printf("Error Writing to socket [%d] err: (%s)\n",
fd1, strerror(errno));
break;
}
nWrite += nTemp;
}
#ifdef DEBUG
printf("Write %d bytes.\n", nWrite);
fflush(stdout);
#endif
}
fclose(fp);
}
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/time.h>
#include "cproxy.h"
#define MAX_ARGS 10
#define BIG_BUFF_SIZE 8000
void myChild(int fd1, int aPort);
void SpawnCmd(int nArg, char *arg[]);
void mysig(int nsig)
{
int nStatus, nPid;
nPid = waitpid(-1, &nStatus, WNOHANG);
printf("\nSignal(%d) received\n", nsig);
signal(SIGCHLD, mysig);
}
main (int argc, char **argv)
{
char c;
long pid;
int rc, fromlen, aPort;
char hostname[64];
int i, s;
int nOpt=1;
int fd1, fd2;
struct sockaddr_in sin, fsin;
if (argc < 2)
{
printf("usage:%s <porta> \n", argv[0]);
exit(1);
}
aPort = atoi(argv[1]);
gethostname(hostname, sizeof(hostname));
printf("\n I will be your Proxy Server on port %d \n", aPort);
signal(SIGCHLD, mysig);
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("server: socket()");
exit(1);
}
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(aPort);
sin.sin_addr.s_addr = htonl(INADDR_ANY);
// The following makes it quicker to reclaim a port when you
// restart your application -- normally ports can't be reused for a time
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &nOpt, sizeof(int));
if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
{
perror("server: bind()");
exit(1);
}
if (listen(s, 5) < 0)
{
perror("server: listen()");
exit(1);
}
fromlen = sizeof(fsin);
for (;;)
{
if ((fd1 = accept(s, (struct sockaddr *)&fsin, &fromlen)) < 0)
{
perror("server:accept()");
continue; /* hope this is normally due to a child death*/
}
if ((pid = fork()) > 0)
{
/* Parent */
close(fd1);
continue;
}
if (pid == 0)
{
/* Must be the child */
myChild(fd1, aPort); /* Never returns */
}
}
close(s);
exit(0);
}
void myChild(int fd1, int aPort)
{
char bigbuff[BIG_BUFF_SIZE];
FILE *fp, *fp2;
char cbuff[1000], cFile[200];
struct timeval stv;
long lBytes;
int i, nRead, nWrite, nTemp;
int iMaxFd, iNumInputs, nContinue = 1, nArg;
fd_set fdCheck;
char *szInputLine, *szTemp, *szCmd, *szFile, *szArg[MAX_ARGS];
printf("\n New Child: fd1(%d)\n", fd1);
fp=fdopen(fd1,"r+b");
if (fp==NULL)
{
printf("Can't Make a file descriptor out of the stream\n");
fflush(stdout);
close(fd1);
_exit(0);
}
if ( (szInputLine = fgets(bigbuff,BIG_BUFF_SIZE, fp)) != NULL)
{
printf("Parsing<%s>\n", szInputLine);
if ((szTemp = strchr(szInputLine, ';')) == NULL)
printf("Missing a ; for command parsing\n");
else
{
*szTemp = 0;
if (strcmp(szInputLine, RUN_CMD) == 0)
{
szCmd = szTemp+1;
szTemp = strchr(szCmd, ';');
*szTemp = 0;
sprintf(cbuff, "%s ", szCmd);
printf("run: <%s>\n", cbuff);
fflush(stdout);
if (dup2(fd1,STDOUT_FILENO) <0)
perror("dup2 STDOUT failed");
if(dup2(fd1,STDIN_FILENO) < 0)
{
perror("dup2 STDIN failed");
fflush(stderr);
}
system(cbuff);
}
/* This used for receiving files across. */
else if (strcmp(szInputLine, STORE_CMD) == 0)
{
szFile = szTemp+1;
szTemp = strchr(szFile, ';');
*szTemp = 0;
sprintf(cbuff, "%s", szFile);
printf("store: <%s>\n", cbuff);
fflush(stdout);
fp2 = fopen(szFile, "w");
if (fp2 == NULL)
{
printf("Can't open file(%s) Err(%s)\n", szFile,
strerror(errno));
fflush(stdout);
return;
}
while((nRead = fread(bigbuff, 1, SEND_BUFF_SIZE, fp)) > 0)
{
nWrite = 0;
while (nWrite < nRead)
{
nTemp = fwrite(bigbuff+nWrite, 1, nRead - nWrite, fp2);
if (nTemp == -1)
{
printf("Error Writing to file [%s] err: (%s)\n",
szFile, strerror(errno));
break;
}
nWrite += nTemp;
}
fflush(fp2);
fflush(stdout);
}
/* Close the file. */
fclose(fp2);
sprintf(cbuff, "Done.");
write(fd1, cbuff, strlen(cbuff)+1);
}
else if (strcmp(szInputLine, START_CMD) == 0)
{
nArg = 0;
do
{
szArg[nArg] = szTemp+1;
szTemp = strchr(szTemp+1,';');
if (szTemp != NULL)
{
*szTemp = 0;
nArg += 1;
}
}while ((szTemp != NULL) && (nArg <MAX_ARGS) );
printf("start: <");
for (i = 0; i < nArg; i++)
printf("arg(%d)=%s ", i,szArg[i]);
printf(">\n");
SpawnCmd(nArg, szArg);
write(fd1, END_OF_START, strlen(END_OF_START));
}
else
{
printf ("Didn't recognize command <%s>\n", szInputLine);
}
}
}
fclose(fp);
close (fd1);
_exit(0);
}
void SpawnCmd(int nArg, char *arg[])
{
int nPid, i;
if ((nPid=fork()) < 0)
{
/* Big trouble if we can't fork */
printf("Fork error for prog(%s)\n",
arg[0]);
fflush(stdout);
}
else if (nPid == 0)
{
printf("Child Spawned with arguments:\n ");
for (i= 0; i < nArg; i++)
printf("arg(%d)=%s ", i, arg[i]);
printf("\n");
fflush(stdout);
/* Must be child */
execvp(arg[0], arg); _exit(-1);
}
else
{
/* Must be parent */
}
}