C:HTTP webserver - the image "http://localhost.... cannot be displayed because it contains errors - html

It's my first time dabbling with socket programming and I stumbled upon this amazing code from https://dzone.com/articles/web-server-c.
WHAT WE NEED TO DO: implement a simple HTTP web server that uses the web browser(input from the user) as a client
Here it is:
/*
* WebServer.c
*
* Created on: Nov 3, 2012
* Author: pavithra
*
* A web server in C language using only the standard libraries.
* The port number is passed as an argument.
*
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/sendfile.h>
#define EOL "\r\n"
#define EOL_SIZE 2
typedef struct {
char *ext;
char *mediatype;
} extn;
//Possible media types
extn extensions[] ={
{"gif", "image/gif" },
{"txt", "text/plain" },
{"jpg", "image/jpg" },
{"jpeg","image/jpeg"},
{"png", "image/png" },
{"ico", "image/ico" },
{"zip", "image/zip" },
{"gz", "image/gz" },
{"tar", "image/tar" },
{"htm", "text/html" },
{"html","text/html" },
{"php", "text/html" },
{"pdf","application/pdf"},
{"zip","application/octet-stream"},
{"rar","application/octet-stream"},
{0,0} };
//find webroot, add design
/*
A helper function
*/
void error(const char *msg) {
perror(msg);
exit(1);
}
/*
A helper function
*/
int get_file_size(int fd) {
struct stat stat_struct;
if (fstat(fd, &stat_struct) == -1)
return (1);
return (int) stat_struct.st_size;
}
/*
A helper function
*/
void send_new(int fd, char *msg) {
int len = strlen(msg);
if (send(fd, msg, len, 0) == -1) {
printf("Error in send\n");
}
}
/*
This function recieves the buffer
until an "End of line(EOL)" byte is recieved
*/
int recv_new(int fd, char *buffer) {
char *p = buffer; // Use of a pointer to the buffer rather than dealing with the buffer directly
int eol_matched = 0; // Use to check whether the recieved byte is matched with the buffer byte or not
while (recv(fd, p, 1, 0) != 0) // Start receiving 1 byte at a time
{
if (*p == EOL[eol_matched]) // if the byte matches with the first eol byte that is '\r'
{
++eol_matched;
if (eol_matched == EOL_SIZE) // if both the bytes matches with the EOL
{
*(p + 1 - EOL_SIZE) = '\0'; // End the string
return (strlen(buffer)); // Return the bytes recieved
}
} else {
eol_matched = 0;
}
p++; // Increment the pointer to receive next byte
}
return (0);
}
/*
A helper function: Returns the
web root location.
*/
char* webroot() {
// open the file "kill.txt" for reading
FILE *in = fopen("kill.txt", "rt");
// read the first line from the file
char buff[1000];
fgets(buff, 1000, in);
// close the stream
fclose(in);
char* nl_ptr = strrchr(buff, '\n');
if (nl_ptr != NULL)
*nl_ptr = '\0';
return strdup(buff);
}
/*
Handles php requests
*/
void php_cgi(char* script_path, int fd) {
send_new(fd, "HTTP/1.1 200 OK\n Server: Web Server in C\n Connection: close\n");
dup2(fd, STDOUT_FILENO);
char script[500];
strcpy(script, "SCRIPT_FILENAME=");
strcat(script, script_path);
putenv("GATEWAY_INTERFACE=CGI/1.1");
putenv(script);
putenv("QUERY_STRING=");
putenv("REQUEST_METHOD=GET");
putenv("REDIRECT_STATUS=true");
putenv("SERVER_PROTOCOL=HTTP/1.1");
putenv("REMOTE_HOST=127.0.0.1");
execl("/usr/bin/php-cgi", "php-cgi", NULL);
}
/*
This function parses the HTTP requests,
arrange resource locations,
check for supported media types,
serves files in a web root,
sends the HTTP error codes.
*/
int connection(int fd) {
char request[500], resource[500], *ptr;
int fd1, length;
if (recv_new(fd, request) == 0) {
printf("Receive Failed\n");
}
printf("%s\n", request);
// Check for a valid browser request
ptr = strstr(request, " HTTP/");
if (ptr == NULL) {
printf("NOT HTTP !\n");
} else {
*ptr = 0;
ptr = NULL;
if (strncmp(request, "GET ", 4) == 0) {
ptr = request + 4;
}
if (ptr == NULL) {
printf("Unknown Request ! \n");
} else {
if (ptr[strlen(ptr) - 1] == '/') {
strcat(ptr, "test.html");
}
strcpy(resource, webroot());
strcat(resource, ptr);
char* s = strchr(ptr, '.');
int i;
for (i = 0; extensions[i].ext != NULL; i++) {
if (strcmp(s + 1, extensions[i].ext) == 0) {
fd1 = open(resource, O_RDONLY, 0);
printf("Opening \"%s\"\n", resource);
if (fd1 == -1) {
printf("404 File not found Error\n");
send_new(fd, "HTTP/1.1 404 Not Found\r\n");
send_new(fd, "Server : Web Server in C\r\n\r\n");
send_new(fd, "<html><head><title>404 Not Found</head></title>");
send_new(fd, "<body><p>404 Not Found: The requested resource could not be found!</p></body></html>\r\n");
//Handling php requests
} else if (strcmp(extensions[i].ext, "php") == 0) {
php_cgi(resource, fd);
sleep(1);
close(fd);
exit(1);
} else {
printf("200 OK, Content-Type: %s\n\n",
extensions[i].mediatype);
send_new(fd, "HTTP/1.1 200 OK\r\n");
send_new(fd, "Server : Web Server in C\r\n\r\n");
if (ptr == request + 4) // if it is a GET request
{
if ((length = get_file_size(fd1)) == -1)
printf("Error in getting size !\n");
size_t total_bytes_sent = 0;
ssize_t bytes_sent;
while (total_bytes_sent < length) {
//Zero copy optimization
if ((bytes_sent = sendfile(fd, fd1, 0,
length - total_bytes_sent)) <= 0) {
if (errno == EINTR || errno == EAGAIN) {
continue;
}
perror("sendfile");
return -1;
}
total_bytes_sent += bytes_sent;
}
//why is it not appearing up to 11:30
}
}
break;
}
int size = sizeof(extensions) / sizeof(extensions[0]);
if (i == size - 2) {
printf("415 Unsupported Media Type\n");
send_new(fd, "HTTP/1.1 415 Unsupported Media Type\r\n");
send_new(fd, "Server : Web Server in C\r\n\r\n");
send_new(fd, "<html><head><title>415 Unsupported Media Type</head></title>");
send_new(fd, "<body><p>415 Unsupported Media Type!</p></body></html>");
}
}
close(fd);
}
}
shutdown(fd, SHUT_RDWR);
}
int main(int argc, char *argv[]) {
int sockfd, newsockfd, portno, pid;
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
if (argc < 2) {
fprintf(stderr, "ERROR, no port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
error("ERROR on binding");
listen(sockfd, 5);
clilen = sizeof(cli_addr);
/*
Server runs forever, forking off a separate
process for each connection.
*/
while (1) {
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
error("ERROR on accept");
pid = fork();
if (pid < 0)
error("ERROR on fork");
if (pid == 0) {
close(sockfd);
connection(newsockfd);
exit(0);
} else
close(newsockfd);
} /* end of while */
close(sockfd);
return 0; /* we never get here */
}
NOTE: the kill.txt contains the directory of the server, the files(jpegs, gifs, etc.: /home/user/Desktop)
PROBLEM:
1. After I compile the program and execute it on my web browser as "localhost:port number/file" this is what appears on my web browser:
the image "http://localhost.... cannot be displayed because it contains errors.
And this is what appears on my terminal:
GET /sample5.gif HTTP/1.1
Opening "/home/user/Desktop/sample5.gif"
200 OK, Content-Type: image/gif
GET /favicon.ico HTTP/1.1
Opening "/home/user/Desktop/favicon.ico"
404 File not found Error
How do I fix this? Any help/comment would be greatly appreciated! Thanks.
Where is that favicon.ico bit coming from? /I looked this up and apparently having that favicon.ico bit is quite normal (can somebody please confirm this?)/

… I stumbled upon this amazing code from …
It is indeed amazing how bad it is.
At the end of the function int connection(int fd) there's:
close(fd);
}
}
shutdown(fd, SHUT_RDWR);
}
Browsers don't like the connection being reset by peer (due to close()) before it's tidily shut down. Move the close() after the shutdown().
The program neglects to reap child processes, thus a zombie process remains after each request. #include <signal.h> and add sigignore(SIGCHLD); at the start of main().
If the action for the SIGCHLD signal is set to SIG_IGN, child
processes of the calling processes will not be transformed into zombie
processes when they terminate.

Related

Server displaying text instead of HTML

I'm attempting to make a C server that will take inputs and be able to spit them back out to the user via html format where the server works as a user interface. My current issue I cant seem to figure out is why the C server spits out the HTML code as text at localhost:3838 instead of displaying it as a proper web page.
How can I solve this and have it be able to work to send user commands back to the server and spit out the proper response? Do I do this by using recieve and then putting the message into a buffer, parsing that message, and then putting that response into a buffer to send back using send?
CSERVER.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#define PORT "3838" //port being connected to
#define MAXLEN 800
#define BACKLOG 10 //number of pending connections to be held in queue
//format of html page
char header []=
"<!DOCTYPE html>\n"
"<html>\n"
"<head>\n"
"<title>Web-Based Remote Command Server</title>\n"
"</head>\n"
"<body>\n\n";
char input []=
"<form action= \"/run\" method= \"get\"> \n"
"Command: <input type=\"text\" size=\"100\" name=\"command\">\n"
"<input type=\"submit\" value=\"Run\">\n"
"</form>";
char output []= "<p>Command that was run:</p>\n"
"<pre>Your server will include the command that was just run here.</pre>\n\n"
"<p>Standard Output:</p>\n""<pre>Your server will include the stdout results here.</pre>\n\n"
"<p>Standard Error:</p>\n"
"<pre>Your server will include the stderr results here.</pre>\n\n"
"</body>\n""</html>";
char *buff = header;
void sigchld_handler(int s)
{
(void)s; // quiet unused variable warning
// waitpid() might overwrite errno, so we save and restore it:
int saved_errno = errno;
while(waitpid(-1, NULL, WNOHANG) > 0);
errno = saved_errno;
}
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main (void){
int sockfd;
int new_fd;
struct addrinfo hints;
struct addrinfo *serverinfo;
struct addrinfo *p;
struct sockaddr_storage client_addr;
socklen_t addrsize;
struct sigaction sa;
int yes = 1;
char s[INET6_ADDRSTRLEN];
int status;
memset(&hints, 0, sizeof hints); //makes struct empty
hints.ai_family = AF_UNSPEC; //IPv4 or v6
hints.ai_socktype = SOCK_STREAM; //TCP type need
hints.ai_flags = AI_PASSIVE; //Fill in IP for us
//if can't get address info print error
if((status = getaddrinfo(NULL, PORT, &hints, &serverinfo)) != 0){
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
return 1;
}
for(p = serverinfo; p != NULL; p = p->ai_next){
if((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1){
perror("server: socket");
continue;
}
if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1){
perror("setsockopt");
exit(1);
}
if(bind(sockfd, p->ai_addr, p->ai_addrlen) == -1){
close(sockfd);
perror("server: bind");
continue;
}
break;
}
freeaddrinfo(serverinfo);
if(p == NULL){
fprintf(stderr, "server: failed to bind\n");
exit(1);
}
if(listen(sockfd, BACKLOG) == -1){
perror("listen");
exit(1);
}
sa.sa_handler = sigchld_handler; // reap all dead processes
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
perror("sigaction");
exit(1);
}
printf("server: waiting for connections....\n");
while(1){
addrsize = sizeof client_addr;
new_fd = accept(sockfd, (struct sockaddr *)&client_addr, &addrsize);
if(new_fd == -1){
perror("Did not accept");
continue;
}
inet_ntop(client_addr.ss_family, get_in_addr((struct sockaddr *)&client_addr), s, sizeof s);
printf("server: got connection from %s\n", s);
if(!fork()){
close(sockfd);
int bufsize = 1024;
char *buffer = malloc(bufsize);
recv(new_fd, buffer, bufsize, 0);
write(new_fd, "HTTP/1.1 200 OK\n", 16);
write(new_fd, "Content-length: 46\n", 19);
write(new_fd, "Content-type: text/html\n\n", 25);
write(new_fd, "<html><head>\n<title>The Web Page</title>\n</head>\n</html>", 46);
if(send(new_fd, header, MAXLEN, 0) == -1)
perror("send");
close(new_fd);
exit(0);
}
close(new_fd);
}
return 0;
}
You need to add the response headers like this one :
for example the response header send by SO for this page is:
HTTP/2.0 200 OK
cache-control: private
content-type: text/html; charset=utf-8
content-encoding: gzip
x-frame-options: SAMEORIGIN
x-request-guid: 599a5768-3cc6-4b94-86e1-e1d1daa8acd5
strict-transport-security: max-age=15552000
content-security-policy: upgrade-insecure-requests
accept-ranges: bytes
date: Tue, 07 May 2019 13:17:15 GMT
via: 1.1 varnish
x-served-by: cache-lcy19237-LCY
x-cache: MISS
x-cache-hits: 0
x-timer: S1557235035.073229,VS0,VE89
vary: Accept-Encoding,Fastly-SSL
x-dns-prefetch-control: off
content-length: 35669
X-Firefox-Spdy: h2

Understanding how to use CGI programming with C and HTML

I'm attempting to use a local server made in C with an HTML page run on this server that will be able to interact with a program i made to be able to run bash commands which works perfectly outside of the html page but needs to be able to receive input from the user via text box on the web page, display the command entered as well as the output on the html page. Right now when i click the submit button on the html page it goes to localhost:PORT/pexec.cgi but shows absolutely no display at all, just white space. What am i doing wrong and how can i get this to work so that it will correctly display output?
WCServer.c
#include <sys/socket.h> // socket definitions
#include <sys/types.h> // socket types
#include <arpa/inet.h> // inet (3) funtions
#include <unistd.h> // misc. UNIX functions
#include <signal.h> // signal handling
#include <stdlib.h> // standard library
#include <stdio.h> // input/output library
#include <string.h> // string library
#include <errno.h> // error number library
#include <fcntl.h> // for O_* constants
#include <sys/mman.h> // mmap library
#include <sys/types.h> // various type definitions
#include <sys/stat.h> // more constants
// global constants
#define PORT 3838 // port to connect on
#define LISTENQ 10 // number of connections
int list_s; // listening socket
// structure to hold the return code and the filepath to serve to client.
typedef struct {
int returncode;
char *filename;
} httpRequest;
// Structure to hold variables that will be placed in shared memory
typedef struct {
pthread_mutex_t mutexlock;
int totalbytes;
} sharedVariables;
// headers to send to clients
char *header200 = "HTTP/1.0 200 OK\nServer: CS241Serv v0.1\nContent-Type: text/html\n\n";
char *header400 = "HTTP/1.0 400 Bad Request\nServer: CS241Serv v0.1\nContent-Type: text/html\n\n";
char *header404 = "HTTP/1.0 404 Not Found\nServer: CS241Serv v0.1\nContent-Type: text/html\n\n";
// get a message from the socket until a blank line is recieved
char *getMessage(int fd) {
// A file stream
FILE *sstream;
// Try to open the socket to the file stream and handle any failures
if( (sstream = fdopen(fd, "r")) == NULL)
{
fprintf(stderr, "Error opening file descriptor in getMessage()\n");
exit(EXIT_FAILURE);
}
// Size variable for passing to getline
size_t size = 1;
char *block;
// Allocate some memory for block and check it went ok
if( (block = malloc(sizeof(char) * size)) == NULL )
{
fprintf(stderr, "Error allocating memory to block in getMessage\n");
exit(EXIT_FAILURE);
}
// Set block to null
*block = '\0';
// Allocate some memory for tmp and check it went ok
char *tmp;
if( (tmp = malloc(sizeof(char) * size)) == NULL )
{
fprintf(stderr, "Error allocating memory to tmp in getMessage\n");
exit(EXIT_FAILURE);
}
// Set tmp to null
*tmp = '\0';
// Int to keep track of what getline returns
int end;
// Int to help use resize block
int oldsize = 1;
// While getline is still getting data
while( (end = getline( &tmp, &size, sstream)) > 0)
{
// If the line its read is a caridge return and a new line were at the end of the header so break
if( strcmp(tmp, "\r\n") == 0)
{
break;
}
// Resize block
block = realloc(block, size+oldsize);
// Set the value of oldsize to the current size of block
oldsize += size;
// Append the latest line we got to block
strcat(block, tmp);
}
// Free tmp a we no longer need it
free(tmp);
// Return the header
return block;
}
// send a message to a socket file descripter
int sendMessage(int fd, char *msg) {
return write(fd, msg, strlen(msg));
}
// Extracts the filename needed from a GET request and adds public_html to the front of it
char * getFileName(char* msg)
{
// Variable to store the filename in
char * file;
// Allocate some memory for the filename and check it went OK
if( (file = malloc(sizeof(char) * strlen(msg))) == NULL)
{
fprintf(stderr, "Error allocating memory to file in getFileName()\n");
exit(EXIT_FAILURE);
}
// Get the filename from the header
sscanf(msg, "GET %s HTTP/1.1", file);
// Allocate some memory not in read only space to store "public_html"
char *base;
if( (base = malloc(sizeof(char) * (strlen(file) + 18))) == NULL)
{
fprintf(stderr, "Error allocating memory to base in getFileName()\n");
exit(EXIT_FAILURE);
}
char* ph = "public_html";
// Copy public_html to the non read only memory
strcpy(base, ph);
// Append the filename after public_html
strcat(base, file);
// Free file as we now have the file name in base
free(file);
// Return public_html/filetheywant.html
return base;
}
// parse a HTTP request and return an object with return code and filename
httpRequest parseRequest(char *msg){
httpRequest ret;
// A variable to store the name of the file they want
char* filename;
// Allocate some memory to filename and check it goes OK
if( (filename = malloc(sizeof(char) * strlen(msg))) == NULL)
{
fprintf(stderr, "Error allocating memory to filename in parseRequest()\n");
exit(EXIT_FAILURE);
}
// Find out what page they want
filename = getFileName(msg);
// Check if its a directory traversal attack
char *badstring = "..";
char *test = strstr(filename, badstring);
// Check if they asked for / and give them input.html
int test2 = strcmp(filename, "public_html/");
// Check if the page they want exists
FILE *exists = fopen(filename, "r" );
// If the badstring is found in the filename
if( test != NULL )
{
// Return a 400 header and 400.html
ret.returncode = 400;
ret.filename = "400.html";
}
// If they asked for / return input.html
else if(test2 == 0)
{
ret.returncode = 200;
ret.filename = "public_html/input.html";
}
// If they asked for a specific page and it exists because we opened it sucessfully return it
else if( exists != NULL )
{
ret.returncode = 200;
ret.filename = filename;
// Close the file stream
fclose(exists);
}
// If we get here the file they want doesn't exist so return a 404
else
{
ret.returncode = 404;
ret.filename = "404.html";
}
// Return the structure containing the details
return ret;
}
// print a file out to a socket file descriptor
int printFile(int fd, char *filename) {
/* Open the file filename and echo the contents from it to the file descriptor fd */
// Attempt to open the file
FILE *read;
if( (read = fopen(filename, "r")) == NULL)
{
fprintf(stderr, "Error opening file in printFile()\n");
exit(EXIT_FAILURE);
}
// Get the size of this file for printing out later on
int totalsize;
struct stat st;
stat(filename, &st);
totalsize = st.st_size;
// Variable for getline to write the size of the line its currently printing to
size_t size = 1;
// Get some space to store each line of the file in temporarily
char *temp;
if( (temp = malloc(sizeof(char) * size)) == NULL )
{
fprintf(stderr, "Error allocating memory to temp in printFile()\n");
exit(EXIT_FAILURE);
}
// Int to keep track of what getline returns
int end;
// While getline is still getting data
while( (end = getline( &temp, &size, read)) > 0)
{
sendMessage(fd, temp);
}
// Final new line
sendMessage(fd, "\n");
// Free temp as we no longer need it
free(temp);
// Return how big the file we sent out was
return totalsize;
}
// clean up listening socket on ctrl-c
void cleanup(int sig) {
printf("Cleaning up connections and exiting.\n");
// try to close the listening socket
if (close(list_s) < 0) {
fprintf(stderr, "Error calling close()\n");
exit(EXIT_FAILURE);
}
// Close the shared memory we used
shm_unlink("/sharedmem");
// exit with success
exit(EXIT_SUCCESS);
}
int printHeader(int fd, int returncode)
{
// Print the header based on the return code
switch (returncode)
{
case 200:
sendMessage(fd, header200);
return strlen(header200);
break;
case 400:
sendMessage(fd, header400);
return strlen(header400);
break;
case 404:
sendMessage(fd, header404);
return strlen(header404);
break;
}
}
// Increment the global count of data sent out
int recordTotalBytes(int bytes_sent, sharedVariables *mempointer)
{
// Lock the mutex
pthread_mutex_lock(&(*mempointer).mutexlock);
// Increment bytes_sent
(*mempointer).totalbytes += bytes_sent;
// Unlock the mutex
pthread_mutex_unlock(&(*mempointer).mutexlock);
// Return the new byte count
return (*mempointer).totalbytes;
}
int main(int argc, char *argv[]) {
int conn_s; // connection socket
short int port = PORT; // port number
struct sockaddr_in servaddr; // socket address structure
// set up signal handler for ctrl-c
(void) signal(SIGINT, cleanup);
// create the listening socket
if ((list_s = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
fprintf(stderr, "Error creating listening socket.\n");
exit(EXIT_FAILURE);
}
// set all bytes in socket address structure to zero, and fill in the relevant data members
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(port);
// bind to the socket address
if (bind(list_s, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0 ) {
fprintf(stderr, "Error calling bind()\n");
exit(EXIT_FAILURE);
}
// Listen on socket list_s
if( (listen(list_s, 10)) == -1)
{
fprintf(stderr, "Error Listening\n");
exit(EXIT_FAILURE);
}
// Set up some shared memory to store our shared variables in
// Close the shared memory we use just to be safe
shm_unlink("/sharedmem");
int sharedmem;
// Open the memory
if( (sharedmem = shm_open("/sharedmem", O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)) == -1)
{
fprintf(stderr, "Error opening sharedmem in main() errno is: %s ", strerror(errno));
exit(EXIT_FAILURE);
}
// Set the size of the shared memory to the size of my structure
ftruncate(sharedmem, sizeof(sharedVariables) );
// Map the shared memory into our address space
sharedVariables *mempointer;
// Set mempointer to point at the shared memory
mempointer = mmap(NULL, sizeof(sharedVariables), PROT_READ | PROT_WRITE, MAP_SHARED, sharedmem, 0);
// Check the memory allocation went OK
if( mempointer == MAP_FAILED )
{
fprintf(stderr, "Error setting shared memory for sharedVariables in recordTotalBytes() error is %d \n ", errno);
exit(EXIT_FAILURE);
}
// Initalise the mutex
pthread_mutex_init(&(*mempointer).mutexlock, NULL);
// Set total bytes sent to 0
(*mempointer).totalbytes = 0;
// Size of the address
int addr_size = sizeof(servaddr);
// Sizes of data were sending out
int headersize;
int pagesize;
int totaldata;
// Number of child processes we have spawned
int children = 0;
// Variable to store the ID of the process we get when we spawn
pid_t pid;
// Loop infinitly serving requests
while(1)
{
// If we haven't already spawned 10 children fork
if( children <= 10)
{
pid = fork();
children++;
}
// If the pid is -1 the fork failed so handle that
if( pid == -1)
{
fprintf(stderr,"can't fork, error %d\n" , errno);
exit (1);
}
// Have the child process deal with the connection
if ( pid == 0)
{
// Have the child loop infinetly dealing with a connection then getting the next one in the queue
while(1)
{
// Accept a connection
conn_s = accept(list_s, (struct sockaddr *)&servaddr, &addr_size);
// If something went wrong with accepting the connection deal with it
if(conn_s == -1)
{
fprintf(stderr,"Error accepting connection \n");
exit (1);
}
// Get the message from the file descriptor
char * header = getMessage(conn_s);
// Parse the request
httpRequest details = parseRequest(header);
// Free header now were done with it
free(header);
// Print out the correct header
headersize = printHeader(conn_s, details.returncode);
// Print out the file they wanted
pagesize = printFile(conn_s, details.filename);
// Increment our count of total datasent by all processes and get back the new total
totaldata = recordTotalBytes(headersize+pagesize, mempointer);
// Print out which process handled the request and how much data was sent
printf("Process %d served a request of %d bytes. Total bytes sent %d \n", getpid(), headersize+pagesize, totaldata);
// Close the connection now were done
close(conn_s);
}
}
}
return EXIT_SUCCESS;
}
Pexec.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
static char* args[512];
pid_t pid;
int command_pipe[2];
#define READ 0
#define WRITE 1
static int command(int input, int first, int last)
{
int pipettes[2];
pipe( pipettes );
pid = fork();
if (pid == 0) {
if (first == 1 && last == 0 && input == 0) {
// First command
dup2( pipettes[WRITE], STDOUT_FILENO );
} else if (first == 0 && last == 0 && input != 0) {
// Middle command
dup2(input, STDIN_FILENO);
dup2(pipettes[WRITE], STDOUT_FILENO);
} else {
// Last command
dup2( input, STDIN_FILENO );
}
if (execvp( args[0], args) == -1)
_exit(EXIT_FAILURE);
}
if (input != 0)
close(input);
close(pipettes[WRITE]);
if (last == 1)
close(pipettes[READ]);
return pipettes[READ];
}
static void cleanup(int n)
{
int i;
for (i = 0; i < n; ++i)
wait(NULL);
}
static int run(char* cmd, int input, int first, int last);
static char line[1024];
static int n = 0; /* number of calls to 'command' */
int main(int argc, char *argv[])
{
while (1) {
// for(int i = 1; i < argc; i++){
// strcat(line, argv[i]);
// strcat(line, " ");
// }
/* Read a command line */
//if (!fgets(line, 1024, stdin))
//return 0;
int InputLength = atoi(getenv("INPUT_LENGTH"));
fread(line, InputLength, 1, stdin);
int input = 0;
int first = 1;
char* cmd = line;
char* next = strchr(cmd, '#'); /* Find first '|' */
while (next != NULL) {
/* 'next' points to '|' */
*next = '\0';
input = run(cmd, input, first, 0);
cmd = next + 1;
next = strchr(cmd, '#'); /* Find next '|' */
first = 0;
}
input = run(cmd, input, first, 1);
cleanup(n);
n = 0;
}
return 0;
}
static void split(char* cmd);
static int run(char* cmd, int input, int first, int last)
{
split(cmd);
if (args[0] != NULL) {
if (strcmp(args[0], "exit") == 0)
exit(0);
n += 1;
return command(input, first, last);
}
return 0;
}
static char* skipwhite(char* s)
{
while (isspace(*s)) ++s;
return s;
}
static void split(char* cmd)
{
cmd = skipwhite(cmd);
char* next = strchr(cmd, ' ');
int i = 0;
while(next != NULL) {
next[0] = '\0';
args[i] = cmd;
++i;
cmd = skipwhite(next + 1);
next = strchr(cmd, ' ');
}
if (cmd[0] != '\0') {
args[i] = cmd;
next = strchr(cmd, '\n');
next[0] = '\0';
++i;
}
args[i] = NULL;
}
input.html
<!DOCTYPE html>
<html>
<style>
input[type=text], select {
width: 100%;
padding: 12px 20px;
margin: 8px 0;
display: inline-block;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
}
input[type=submit] {
width: 100%;
background-color: #4CAF50;
color: white;
padding: 14px 20px;
margin: 8px 0;
border: none;
border-radius: 4px;
cursor: pointer;
}
input[type=submit]:hover {
background-color: #45a049;
}
div {
border-radius: 5px;
background-color: #f2f2f2;
padding: 20px;
}
</style>
<body>
<h3><center>The Html Page Title </center></h3>
<div>
<form method="POST" action="pexec.cgi">
<label for="cmmd">Command</label>
<input type="text" id="cmmd" name="firstname" placeholder="Enter your Command here and then hit Run! Below">
<label for="lname">Entered Command </label>
<input type="text" id="lname" name="lastname" placeholder="This is what you entered...">
<label for="lname">Standard Output </label>
<input type="text" id="lname" name="lastname" placeholder="Standard Output will be shown here...">
<label for="lname">Standard Error </label>
<input type="text" id="lname" name="lastname" placeholder="standard error will be shown here...">
<input type="submit" value="Run!">
</form>
</div>
</body>
</html>

How do I make cout stop outputting text after the page is full?

I've made a simple web browser using winsock2 and I have it cout the response from the server but it sends sum 21000 bytes and I need to be able to copy and paste the html, javascript, css, etc for testing the gui I made. It always fills up the terminal and I can't see where it starts I just end up in the middle of a lot of javascript. I want it to be like in the cmd where it stops and ask if you want to continue.
#include <windows.h>
#include <winsock2.h>
#include <conio.h>
#include <stdio.h>
#include <iostream>
using namespace std;
#define SCK_VERSION2 0x0202
#define DEFAULT_BUFLEN 21000
#define DEFAULT_PORT 27015
namespace Globals{
string input = "";
char recvbuf[DEFAULT_BUFLEN];
const char* carf = recvbuf;
}
using namespace Globals;
HWND staticText2 = CreateWindowEx(WS_EX_PALETTEWINDOW, TEXT("Static"), TEXT("Email"), /* email */
WS_CHILD | WS_VISIBLE, 122, 80, 44, 20,
/*hwnd*/NULL, NULL, NULL, NULL);
int sck() {
//----------------------
// Declare and initialize variables.
WSADATA wsaData;
int iResult;
SOCKET ConnectSocket = INVALID_SOCKET;
struct sockaddr_in clientService;
char name[500] = "";
char ipADDRESS[500] = "";
char sPORT[500] = "";
sockaddr_in sName;
int sNameSize = sizeof(sName);
char const* sendbuf = "GET /?gws_rd=ssl HTTP/1.1\r\n"
"Host: www.google.com:80\r\n"
"User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)\r\n"
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n"
"Accept-Language: en-us,en;q=0.5\r\n"
//"Accept-Encoding: gzip,deflate\r\n"
"Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n"
"Keep-Alive: 300\r\n"
"Connection: keep-alive\r\n"
"Pragma: no-cache\r\n"
"DNT: 1"
"Cookie:
"Cookie:
"Cache-Control: no-cache\r\n\r\n";
char recvbuf[DEFAULT_BUFLEN];
int recvbuflen = DEFAULT_BUFLEN; //23.214.132.132 GoDaddy.com
int WSAERROR = WSAGetLastError(); //190.93.243.15
//system("color 04"); //172.16.100.114 Mrs.Hall
//----------------------
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != NO_ERROR) {
printf("WSAStartup failed: %d\n", iResult);
return 1;
}
//----------------------
// Create a SOCKET for connecting to server
ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ConnectSocket == INVALID_SOCKET) {
printf("Error at socket(): %i\n", WSAGetLastError() );
WSACleanup();
return 1;
}
//----------------------
// The sockaddr_in structure specifies the address family,
// IP address, and port of the server to be connected to.
printf("IP ADDRESS: 74.125.196.191 is Google 216.58.208.37 is mail.google.com 129.66.24.10 is iNow\n");
cin >> ipADDRESS;
printf("PORT: \n");
cin >> sPORT;
//system("color 04");
u_short PORT = strtoul(sPORT, NULL, 0);
clientService.sin_family = AF_INET;
clientService.sin_addr.s_addr = inet_addr(ipADDRESS); //74.125.196.191
clientService.sin_port = htons(PORT); //135: msrpc, 445: microsoft-ds, 554: rtsp, 1025: NFS-or-IIS, 1026: LSA-or-nterm
//1027: IIS, 1028: uknown, 1029: ms-lsa, 139: weird behavior
//----------------------
// Connect to server.
iResult = connect( ConnectSocket, (SOCKADDR*) &clientService, sizeof(clientService) );
if ( iResult == SOCKET_ERROR) {
closesocket (ConnectSocket);
printf("Unable to connect to server: %i\n", WSAGetLastError());
WSACleanup();
return 1;
}
//----------------------
//Get local host name
iResult = gethostname(name, sizeof(name));
if (iResult == NO_ERROR) {
printf("Host Name: %s\n", name);
}
else if (iResult == SOCKET_ERROR) {
printf("Could not resolve host name: %i", WSAGetLastError());
}
//------------------------
//Get peer name
iResult = getpeername(ConnectSocket, (struct sockaddr*)&sName, &sNameSize);
if (iResult == NO_ERROR)
printf("Peer Name: %s\n", inet_ntoa(sName.sin_addr));
else if (iResult == SOCKET_ERROR)
printf("Could not get peer name: %i\n", WSAGetLastError());
//-------------------------
// Send an initial buffer
iResult = send( ConnectSocket, sendbuf, (int)strlen(sendbuf), 0 );
if (iResult == SOCKET_ERROR) {
printf("send failed: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 1;
}
else
printf("Bytes Sent: %i\n", iResult);
//-----------------------------
// shutdown the connection since no more data will be sent
iResult = shutdown(ConnectSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
printf("shutdown failed: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 1;
}
// Receive until the peer closes the connection
do {
iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
if ( iResult > 0 ) {
printf("Bytes received: %d\n", iResult);
cout << "From Server" << recvbuf << endl;//printf("From server: %s\n", recvbuf);
}
else if ( iResult == 0 )
printf("Connection closed\n");
else if (WSAERROR == WSAETIMEDOUT)
printf("recv failed: WSAETIMEDOUT\n");
} while( iResult > 0 );
// cleanup
closesocket(ConnectSocket);
WSACleanup();
system("PAUSE");
return 0;
}
int main() {
sck();
MessageBox(NULL, "Successful", "Result:", MB_OK);
}
That's my code
Just realized all I have to do is go to the webpage and change the cookie to what I made it in my program using the EditThisCookie plugin, then copy the source. XD

Browser display the image file sent from C server as a long string of characters

I have been working on creating a small C server to which browsers can connect and make "GET" requests for files. I ran the basic structure of the server using the typical "socket", "bind", "listen", and "accept". Then I used the file descriptor "accept" in order to invoke "write" or "send" calls to the client, which makes "GET" requests in the form of
http://ip_address:port/request
The first step I took was reading from the accept_fd (returned by accept) and get the first line of it, which was "GET /request HTTP/1.1\r\n". Then I use this to create a proper HTTP headers to send files over.
GET /image_file.gif HTTP/1.1\r\n
\r\n
HTTP/1.1 200 OK\r\n
Content-Type: image.gif\r\n
Content-Length: 9184\r\n
\r\n
The content length was fetched from the st_size of the file statistics and corresponds to the file I want to send over, so this tells me I am dealing with the right file. I use "fopen" with "r" for reading and store the content with "fread" into a big character array which I made. Then finally, I sent the buffer in which the content of the file is stored using "send" and the client browser receives it, but the contents displayed are some gibberish string of unrecognizable characters (possibly binary).
GIF89awÄ��ëQiò‹›òŒ›øÅÍìRiæ&Cýðòîn‚õ¨´éC\úÓÙè4Pûâæó™§í`uð}Žö¶Àõ©
Here is a snippet of what it looks like on the browser instead of an image file. I have been trying to solve this problem for four days and tried various things like sending each part of the HTTP headers individually instead of sending it all at once, sending the image file one byte at a time using "fgetc" and "write" but none of these attempts succeeded. Is there something wrong with what I am doing to send an image file over? (and the html files too. when I try to send it over, all the tags appear as though it was a text file instead of the browser interpreting and formatting the page.)
#include <arpa/inet.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#define STAT_200 " 200 OK\r\n"
#define STAT_404 " 404 Not Found\r\n"
#define STAT_501 " 501 Not Implemented\r\n"
#define F_DIR "Content-Type: text/directory\r\n"
#define F_GIF "Content-Type: image/gif\r\n"
#define F_HTML "Content-Type: text/html\r\n"
#define F_JPEG "Content-Type: image/jpeg\r\n"
#define F_JPG "Content-Type: image/jpg\r\n"
#define F_TXT "Content-Type: text/plain\r\n"
typedef enum {cgi, gif, html, jpeg, jpg, plain} ext;
ext get_ext(char *file) {
if (strstr(file, ".cgi") != NULL)
return cgi;
if (strstr(file, ".gif") != NULL)
return gif;
if (strstr(file, ".html") != NULL)
return html;
if (strstr(file, ".jpeg") != NULL)
return jpeg;
if (strstr(file, ".jpg") != NULL)
return jpg;
if (strstr(file, ".txt") != NULL)
return plain;
}
void parse(int accept_fd) {
char *response = (char *) malloc(sizeof(char) * 512);
char *content = (char *) malloc(sizeof(char) * 512);
if (read(accept_fd, content, 512) < 0) {
perror("read error");
exit(1);
}
char *part_end = strstr(content, "\n");
*(part_end + 1) = 0; // still has \r\n
strcat(response, content);
strcat(response, "\r\n");
// send(accept_fd, content, strlen(content), MSG_CONFIRM);
// send(accept_fd, "\r\n", 2, MSG_CONFIRM); // empty line
*(part_end - 1) = 0; // no more \r\n
char *type = (char *) malloc(sizeof(char) * 256); // "GET"
char *request = (char *) malloc(sizeof(char) * 256); // "/request"
char *version = (char *) malloc(sizeof(char) * 256); // "HTTP/x.x"
strcpy(type, content);
strcpy(request, strstr(content, "/"));
strcpy(version, strstr(content, "HTTP"));
part_end = strstr(type, "/");
*(part_end - 1) = 0;
part_end = strstr(request, "HTTP");
*(part_end - 1) = 0;
strcat(response, version);
// send(accept_fd, version, strlen(version), MSG_CONFIRM); // write the "HTTP/x.x"
if (strcmp(type, "GET") != 0) { // 501
strcat(response, STAT_501);
// send(accept_fd, STAT_501, strlen(STAT_501), MSG_CONFIRM);
}
struct stat f_stat;
int stat_fd;
char *cwd = (char *) malloc(sizeof(char) * 256);
char *f_name = (char *) malloc(sizeof(char) * 256);
if ((cwd = getcwd(cwd, 256)) == NULL) {
perror("getcwd error");
exit(1);
}
strcpy(f_name, cwd);
strcat(f_name, request);
if ((stat_fd = stat(f_name, &f_stat)) < 0) { // 404
strcat(response, STAT_404);
// send(accept_fd, STAT_404, strlen(STAT_404), MSG_CONFIRM);
}
if S_ISDIR(f_stat.st_mode) { // 200
strcat(response, STAT_200);
strcat(response, F_DIR);
strcat(response, "\r\n");
// send(accept_fd, STAT_200, strlen(STAT_200), MSG_CONFIRM); // # stat
// send(accept_fd, "Content-Type: text/directory\r\n", 30, MSG_CONFIRM);
// send(accept_fd, "\r\n", 2, MSG_CONFIRM);
write(accept_fd, response, strlen(response));
int red;
if ((red = dup2(accept_fd, STDOUT_FILENO)) < 0) {
perror("dup error");
exit(1);
}
if (execlp("ls", "ls", f_name, NULL) < 0) {
perror("exec error");
exit(1);
}
close(accept_fd);
exit(0);
} else if S_ISREG(f_stat.st_mode) { // 200
strcat(response, STAT_200);
// send(accept_fd, STAT_200, strlen(STAT_200), MSG_CONFIRM); // # stat
ext f_ext = get_ext(f_name);
if (f_ext == cgi) {
int red;
if ((red = dup2(accept_fd, STDOUT_FILENO)) < 0) {
perror("dup error");
exit(1);
}
if (execlp(f_name, f_name, NULL) < 0) {
perror("exec family error");
exit(1);
}
close(accept_fd);
exit(0);
} else if (f_ext == gif) {
strcat(response, F_GIF);
// send(accept_fd, F_GIF, strlen(F_GIF), MSG_CONFIRM);
FILE *f_open;
char *f_cont = (char *) malloc(sizeof(char) * 524288);
size_t f_size = f_stat.st_size;
char *con_len = (char *) malloc(sizeof(char) * 64);
sprintf(con_len, "Content-Length: %d\r\n\r\n", (int) f_size);
strcat(response, con_len);
write(accept_fd, response, strlen(response));
// send(accept_fd, con_len, strlen(con_len), MSG_CONFIRM); // Content-length: #\r\n
if ((f_open = fopen(f_name, "r")) == NULL) {
perror("fopen error");
exit(1);
}
// int i;
// char ch;
// for (i = 0; i < f_size; i++) {
// ch = fgetc(f_open);
// send(accept_fd, &ch, 1, MSG_CONFIRM);
// }
fread(f_cont, sizeof(char), f_size, f_open);
send(accept_fd, f_cont, f_size, MSG_CONFIRM);
close(accept_fd);
exit(0);
}
Here is the relevant part of the code, and I checked repeatedly whether I missed any \r or \n in the header by checking the string lengths, but no good. People who have experiences with this, can you note where the mistake is? Am I misusing any functions anywhere? I got rid of the part where it sends html files because it failed before so I was mainly working on transferring a gif file over.
It turns out the headers are supposed to start from the third line of what I thought was the correct header. So it should look like this:
HTTP/1.1 200 OK\r\n
Content-Type: text/html\r\n
\r\n
[file content]

C forking stops after 5 children

I am working on a C program which makes a connection to a database, grabs a list of devices, then forks the requests and creates an SSH connection to that device. The issue I am having is that, the query, which has 700 results, is always starting from the beginning after it hits 5 forks.
Essentially, I've looked into pthread and glibc to handle threading, but some of the examples I found did not work as desired, or added too much complexity.
The problem I am having is, it will stop at 5 children, and stop, instead of finishing the rest of the 700 devices.
Example code:
#include <libssh2.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/select.h>
#include <unistd.h>
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <ctype.h>
#include <limits.h>
#include <mysql.h>
/********************************
*
* gcc -o confmgr cfgmgr.c -Wall -lpthread -lz -lm -lrt -ldl -lssh2 $(mysql_config --cflags) $(mysql_config --libs) -std=gnu99
*
********************************/
static int waitsocket(int socket_fd, LIBSSH2_SESSION *session)
{
struct timeval timeout;
int rc;
fd_set fd;
fd_set *writefd = NULL;
fd_set *readfd = NULL;
int dir;
timeout.tv_sec = 10;
timeout.tv_usec = 0;
FD_ZERO(&fd);
FD_SET(socket_fd, &fd);
/* now make sure we wait in the correct direction */
dir = libssh2_session_block_directions(session);
if(dir & LIBSSH2_SESSION_BLOCK_INBOUND)
readfd = &fd;
if(dir & LIBSSH2_SESSION_BLOCK_OUTBOUND)
writefd = &fd;
rc = select(socket_fd + 1, readfd, writefd, NULL, &timeout);
return rc;
}
int *connect_to_device(MYSQL_RES** args){
printf("%s", args[2]);
const char *hostname = "1.1.1.1";
const char *commandline = "command_to_run ";
const char *username = "static_user";
const char *password = "static_pass";
unsigned long hostaddr;
int sock;
struct sockaddr_in sin;
const char *fingerprint;
LIBSSH2_SESSION *session;
LIBSSH2_CHANNEL *channel;
int rc;
int exitcode;
char *exitsignal=(char *)"none";
int bytecount = 0;
size_t len;
LIBSSH2_KNOWNHOSTS *nh;
int type;
rc = libssh2_init (0);
if (rc != 0) {
fprintf (stderr, "libssh2 initialization failed (%d)\n", rc);
return 1;
}
hostaddr = inet_addr(hostname);
/* Ultra basic "connect to port 22 on localhost"
* Your code is responsible for creating the socket establishing the
* connection
*/
sock = socket(AF_INET, SOCK_STREAM, 0);
sin.sin_family = AF_INET;
sin.sin_port = htons(22);
sin.sin_addr.s_addr = hostaddr;
if (connect(sock, (struct sockaddr*)(&sin),
sizeof(struct sockaddr_in)) != 0) {
fprintf(stderr, "failed to connect!\n");
return -1;
}
/* Create a session instance */
session = libssh2_session_init();
if (!session)
return -1;
/* tell libssh2 we want it all done non-blocking */
libssh2_session_set_blocking(session, 0);
/* ... start it up. This will trade welcome banners, exchange keys,
* and setup crypto, compression, and MAC layers
*/
while ((rc = libssh2_session_handshake(session, sock)) ==
LIBSSH2_ERROR_EAGAIN);
if (rc) {
fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
return -1;
}
/* We could authenticate via password */
while ((rc = libssh2_userauth_password(session, username, password)) == LIBSSH2_ERROR_EAGAIN);
if (rc) {
fprintf(stderr, "Authentication by password failed.\n");
goto shutdown;
}
libssh2_trace(session, LIBSSH2_TRACE_TRANS | LIBSSH2_TRACE_KEX | LIBSSH2_TRACE_AUTH | LIBSSH2_TRACE_CONN | LIBSSH2_TRACE_SCP | LIBSSH2_TRACE_SFTP | LIBSSH2_TRACE_ERROR | LIBSSH2_TRACE_PUBLICKEY );
/* Exec non-blocking on the remove host */
while( (channel = libssh2_channel_open_session(session)) == NULL &&
libssh2_session_last_error(session,NULL,NULL,0) == LIBSSH2_ERROR_EAGAIN )
{
waitsocket(sock, session);
}
if( channel == NULL )
{
fprintf(stderr,"Error\n");
exit( 1 );
}
while( (rc = libssh2_channel_exec(channel, commandline)) == LIBSSH2_ERROR_EAGAIN )
{
waitsocket(sock, session);
}
if( rc != 0 )
{
fprintf(stderr,"Error\n");
exit( 1 );
}
for( ;; )
{
// loop until we block
int rc;
do
{
char buffer[0x4000];
/* strange thing */
sleep( 1 );
rc = libssh2_channel_read( channel, buffer, sizeof(buffer) );
if( rc > 0 )
{
int i;
for( i=0; i < rc; ++i )
putchar( buffer[i] );
}
}
while( rc > 0 );
// this is due to blocking that would occur otherwise so we loop on this condition
if( rc == LIBSSH2_ERROR_EAGAIN )
{
waitsocket(sock, session);
}
else if( rc == 0 )
break;
}
while( (rc = libssh2_channel_close(channel)) == LIBSSH2_ERROR_EAGAIN )
;
if( rc == 0 )
{
//does-not-work if( libssh2_channel_wait_closed(channel) == 0 )
exitcode = libssh2_channel_get_exit_status( channel );
}
printf("\n%d\n", 221 );
libssh2_channel_free(channel);
channel = NULL;
/***********************/
shutdown:
libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing");
libssh2_session_free(session);
close(sock);
fprintf(stderr, "\n----------------------\nScript Finished\n\n");
libssh2_exit();
return 7;
}
/********************************
*
*
*
*
********************************/
int main(int argc, char *argv[]){
pid_t childPID;
int children = 0;
MYSQL *conn;
MYSQL_RES *res;
MYSQL_ROW row;
char *mySQLserver = "localhost";
char *mySQLuser = "root";
char *mySQLpassword = ""; /* set me first */
char *mySQLdatabase = "Devices";
conn = mysql_init(NULL);
/* Connect to database */
if (!mysql_real_connect(conn, mySQLserver,
mySQLuser, mySQLpassword, mySQLdatabase, 0, NULL, 0)) {
fprintf(stderr, "%s\n", mysql_error(conn));
exit(1);
}
/* send SQL query */
if (mysql_query(conn, "SELECT Hostname,Descr,IP,Username,Password FROM All_Active_Devices")) {
fprintf(stderr, "%s\n", mysql_error(conn));
exit(1);
}
res = mysql_use_result(conn);
/* output table name */
printf("MySQL Tables in mysql database:\n");
while ((row = mysql_fetch_row(res)) != NULL){
printf("%s \n", row[0]);
children++; // Last fork() was successful
while (children >= 5)
{
int status;
// Wait for one child to exit
if (wait(&status) == 7)
{
children--;
}
}
childPID = fork ();
if (childPID < 0) {
printf("Fork Error \n");
} else if (childPID == 0) {
printf("\tCreating Fork for %s: pid %d \n", row[0], childPID);
connect_to_device ( &row );
}
else{
printf("\tDid not create Fork for %s \n", row[0]);
}
}
/* close connection */
mysql_free_result(res);
mysql_close(conn);
return 0;
}
Your child processes are exitting - in particular not with exit status 7 - you have a return in your connect_to_device function, but that is ignored, and each child starts going round the loop, creating more children.
You probably want: return connect_to_device ( &row ); instead.
wait() returns the child PID that died, not its status - which is in WEXITSTATUS(status).
What happens after connect_to_device returns? It looks like that thread will also start in on the while loop as I don't see that child process exiting, sitting you in the while children >=5 loop. The 5 in your condition and 5 threads isn't a coincidence.
Some output from a run would be helpful, also paring down the code.
Try to get your scaffolding working, without the ssh code. Just getting the processes to stop and start shouldn't need ssh. Then add in the application logic once you're sure the underlying support works.
Perhaps ServerAliveCountMax is getting in the way:
EDIT FROM NETCODER BELOW
ServerAliveCountMax
Sets the number of server alive messages (see
below) which may be sent without ssh(1) receiving any messages back
from the server. If this threshold is reached while server alive
messages are being sent, ssh will disconnect from the server,
terminating the session. It is important to note that the use of
server alive messages is very different from TCPKeepAlive (below). The
server alive messages are sent through the encrypted channel and
therefore will not be spoofable. The TCP keepalive option enabled by
TCPKeepAlive is spoofable. The server alive mechanism is valuable when
the client or server depend on knowing when a connection has become
inactive.
The default value is 3. If, for example, ServerAliveInterval (see
below) is set to 15 and ServerAliveCountMax is left at the default, if
the server becomes unresponsive, ssh will disconnect after
approximately 45 seconds. This option applies to protocol version 2
only.
See the man page for ssh_config (man 5 ssh_config) for details.