Converted web_server to unix

This commit is contained in:
TriantaTV 2023-09-30 02:36:18 -05:00
parent 931de23a67
commit 3b3c421bae

View File

@ -1,306 +1,307 @@
//====================================================== file = weblite.c ===== //====================================================== file = weblite.c =====
//= A super light weight HTTP server = //= A super light weight HTTP server =
//============================================================================= //=============================================================================
//= Notes: = //= Notes: =
//= 1) Compiles for Winsock only since uses Windows threads. Generates = //= 1) Compiles for Winsock only since uses Windows threads. Generates =
//= one warning about unreachable code in main. Ignore this warning. = //= one warning about unreachable code in main. Ignore this warning. =
//= 2) Serves HTML and GIF only. = //= 2) Serves HTML and GIF only. =
//= 3) Sometimes the browser drops a connection when doing a refresh. = //= 3) Sometimes the browser drops a connection when doing a refresh. =
//= This is handled by checking the recv() return code in the function = //= This is handled by checking the recv() return code in the function =
//= that handles GETs. = //= that handles GETs. =
//= 4) The 404 HTML message does not always display in Explorer. = //= 4) The 404 HTML message does not always display in Explorer. =
//=---------------------------------------------------------------------------= //=---------------------------------------------------------------------------=
//= Execution notes: = //= Execution notes: =
//= 1) Execute this program in the directory which will be the root for = //= 1) Execute this program in the directory which will be the root for =
//= all file references (i.e., the directory that is considered at = //= all file references (i.e., the directory that is considered at =
//= "public.html"). = //= "public.html"). =
//= 2) Open a Web browser and surf to http://xxx.xxx.xxx.xxx/yyy where = //= 2) Open a Web browser and surf to http://xxx.xxx.xxx.xxx/yyy where =
//= xxx.xxx.xxx.xxx is the IP address or hostname of the machine that = //= xxx.xxx.xxx.xxx is the IP address or hostname of the machine that =
//= weblite is executing on and yyy is the requested object. = //= weblite is executing on and yyy is the requested object. =
//= 3) The only output (to stdout) from weblite is a message with the = //= 3) The only output (to stdout) from weblite is a message with the =
//= of the file currently being sent = //= of the file currently being sent =
//=---------------------------------------------------------------------------= //=---------------------------------------------------------------------------=
//= Build: bcc32 weblite.c, cl weblite.c wsock32.lib (or ws2_32.lib) = //= Build: bcc32 weblite.c, cl weblite.c wsock32.lib (or ws2_32.lib) =
//= gcc weblite.c -lsocket -lnsl for BSD = //= gcc weblite.c -lsocket -lnsl for BSD =
//=---------------------------------------------------------------------------= //=---------------------------------------------------------------------------=
//= Execute: weblite = //= Execute: weblite =
//=---------------------------------------------------------------------------= //=---------------------------------------------------------------------------=
//= History: KJC (12/29/00) - Genesis (from server.c) = //= History: KJC (12/29/00) - Genesis (from server.c) =
//= HF (01/25/01) - Ported to multi-platform environment = //= HF (01/25/01) - Ported to multi-platform environment =
//============================================================================= //=============================================================================
#define UNIX // WIN for Windows environment, UNIX for BSD or LINUX env. #define UNIX // WIN for Windows environment, UNIX for BSD or LINUX env.
//----- Include files --------------------------------------------------------- //----- Include files ---------------------------------------------------------
#include <stdio.h> // Needed for printf() #include <stdio.h> // Needed for printf()
#include <stdlib.h> // Needed for exit() #include <stdlib.h> // Needed for exit()
#include <string.h> // Needed for strcpy() and strlen() #include <string.h> // Needed for strcpy() and strlen()
#include <fcntl.h> // Needed for file i/o constants #include <fcntl.h> // Needed for file i/o constants
#include <sys/stat.h> // Needed for file i/o constants #include <sys/stat.h> // Needed for file i/o constants
#include <thread>
/* FOR BSD UNIX/LINUX ---------------------------------------------------- */
#ifdef UNIX /* FOR BSD UNIX/LINUX ---------------------------------------------------- */
#include <sys/types.h> // #ifdef UNIX
#include <netinet/in.h> // #include <sys/types.h> //
#include <sys/socket.h> // #include <netinet/in.h> //
#include <arpa/inet.h> // #include <sys/socket.h> //
#include <unistd.h> #include <arpa/inet.h> //
#endif #include <unistd.h>
/* ------------------------------------------------------------------------ */ #endif
/* ------------------------------------------------------------------------ */
/* FOR WIN ---------------------------------------------------------------- */
#ifdef WIN /* FOR WIN ---------------------------------------------------------------- */
#include <stddef.h> // Needed for _threadid #ifdef WIN
#include <process.h> // Needed for _beginthread() and _endthread() #include <stddef.h> // Needed for _threadid
#include <io.h> // Needed for open(), close(), and eof() #include <process.h> // Needed for _beginthread() and _endthread()
#include <windows.h> // Needed for all Winsock stuff #include <io.h> // Needed for open(), close(), and eof()
#endif #include <windows.h> // Needed for all Winsock stuff
/* ------------------------------------------------------------------------ */ #endif
/* ------------------------------------------------------------------------ */
//----- HTTP response messages ----------------------------------------------
#define OK_IMAGE "HTTP/1.0 200 OK\nContent-Type:image/gif\n\n" //----- HTTP response messages ----------------------------------------------
#define OK_TEXT "HTTP/1.0 200 OK\nContent-Type:text/html\n\n" #define OK_IMAGE "HTTP/1.0 200 OK\nContent-Type:image/gif\n\n"
#define NOTOK_404 "HTTP/1.0 404 Not Found\nContent-Type:text/html\n\n" #define OK_TEXT "HTTP/1.0 200 OK\nContent-Type:text/html\n\n"
#define MESS_404 "<html><body><h1>FILE NOT FOUND</h1></body></html>" #define NOTOK_404 "HTTP/1.0 404 Not Found\nContent-Type:text/html\n\n"
#define MESS_404 "<html><body><h1>FILE NOT FOUND</h1></body></html>"
//----- Defines -------------------------------------------------------------
#define BUF_SIZE 4096 // Buffer size (big enough for a GET) //----- Defines -------------------------------------------------------------
#define PORT_NUM 7080 // Port number for a Web server #define BUF_SIZE 4096 // Buffer size (big enough for a GET)
#define PORT_NUM 7080 // Port number for a Web server
//----- Function prototypes -------------------------------------------------
/* FOR WIN --------------------------------------------------------------- */ //----- Function prototypes -------------------------------------------------
#ifdef WIN /* FOR WIN --------------------------------------------------------------- */
void handle_get(void *in_arg); // Thread function to handle GET #ifdef WIN
#endif void handle_get(void *in_arg); // Thread function to handle GET
/* ----------------------------------------------------------------------- */ #endif
/* ----------------------------------------------------------------------- */
/* FOR UNIX/LINUX -------------------------------------------------------- */
#ifdef UNIX /* FOR UNIX/LINUX -------------------------------------------------------- */
void child_proc(int server_s, int client_s); // Fork function for GET #ifdef UNIX
#endif void child_proc(int server_s, int client_s); // Fork function for GET
/* ----------------------------------------------------------------------- */ #endif
/* ----------------------------------------------------------------------- */
//===== modeule main ========================================================
int main(void) //===== modeule main ========================================================
{ int main(void)
/* FOR WIN ------------------------------------------------------------- */ {
#ifdef WIN /* FOR WIN ------------------------------------------------------------- */
WORD wVersionRequested = MAKEWORD(1, 1); // Stuff for WSA functions #ifdef WIN
WSADATA wsaData; // Stuff for WSA functions WORD wVersionRequested = MAKEWORD(1, 1); // Stuff for WSA functions
#endif WSADATA wsaData; // Stuff for WSA functions
/* --------------------------------------------------------------------- */ #endif
/* --------------------------------------------------------------------- */
unsigned int server_s; // Server socket descriptor
struct sockaddr_in server_addr; // Server Internet address unsigned int server_s; // Server socket descriptor
unsigned int client_s; // Client socket descriptor struct sockaddr_in server_addr; // Server Internet address
struct sockaddr_in client_addr; // Client Internet address unsigned int client_s; // Client socket descriptor
struct in_addr client_ip_addr; // Client IP address struct sockaddr_in client_addr; // Client Internet address
socklen_t addr_len; // Internet address length struct in_addr client_ip_addr; // Client IP address
socklen_t addr_len; // Internet address length
/* FOR UNIX/LINUX ------------------------------------------------------ */
#ifdef UNIX /* FOR UNIX/LINUX ------------------------------------------------------ */
int nChild_proc_id; // New child process ID. #ifdef UNIX
#endif int nChild_proc_id; // New child process ID.
/* --------------------------------------------------------------------- */ #endif
/* --------------------------------------------------------------------- */
/* FOR WIN ------------------------------------------------------------- */
#ifdef WIN /* FOR WIN ------------------------------------------------------------- */
// Initialize winsock #ifdef WIN
WSAStartup(wVersionRequested, &wsaData); // Initialize winsock
#endif WSAStartup(wVersionRequested, &wsaData);
/* --------------------------------------------------------------------- */ #endif
/* --------------------------------------------------------------------- */
// Create a socket, fill-in address information, and then bind it
server_s = socket(AF_INET, SOCK_STREAM, 0); // Create a socket, fill-in address information, and then bind it
server_addr.sin_family = AF_INET; server_s = socket(AF_INET, SOCK_STREAM, 0);
server_addr.sin_port = htons(PORT_NUM); server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY); server_addr.sin_port = htons(PORT_NUM);
bind(server_s, (struct sockaddr *)&server_addr, sizeof(server_addr)); server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(server_s, (struct sockaddr *)&server_addr, sizeof(server_addr));
// Main loop to listen, accept, and then spin-off a thread to handle the GET
while (1) // Main loop to listen, accept, and then spin-off a thread to handle the GET
{ while (1)
// Listen for connections and then accept {
listen(server_s, 100); // Listen for connections and then accept
addr_len = sizeof(client_addr); listen(server_s, 100);
addr_len = sizeof(client_addr);
client_s = accept(server_s, (struct sockaddr *)&client_addr, &addr_len);
if (client_s == 0) client_s = accept(server_s, (struct sockaddr *)&client_addr, &addr_len);
{ if (client_s == 0)
printf("ERROR - Unable to create socket \n"); {
exit(1); printf("ERROR - Unable to create socket \n");
} exit(1);
}
/* FOR UNIX/LINUX ---------------------------------------------------- */
#ifdef UNIX /* FOR UNIX/LINUX ---------------------------------------------------- */
// Spin-off a child process by fork #ifdef UNIX
nChild_proc_id = fork(); // Spin-off a child process by fork
nChild_proc_id = fork();
// Separate the parent and child process here ...
if (nChild_proc_id == -1) // if I am a new child, go to the child module. // Separate the parent and child process here ...
{ if (nChild_proc_id == -1) // if I am a new child, go to the child module.
child_proc(server_s, client_s); {
} child_proc(server_s, client_s);
#endif }
/* ------------------------------------------------------------------- */ #endif
/* ------------------------------------------------------------------- */
/* FOR WIN ----------------------------------------------------------- */
#ifdef WIN /* FOR WIN ----------------------------------------------------------- */
// Spin-off a thread to handle this request (pass only client_s) #ifdef WIN
if (_beginthread(handle_get, 4096, (void *)client_s) < 0) // Spin-off a thread to handle this request (pass only client_s)
{ if (_beginthread(handle_get, 4096, (void *)client_s) < 0)
printf("ERROR - Unable to create thread \n"); {
exit(1); printf("ERROR - Unable to create thread \n");
} exit(1);
#endif }
/* ------------------------------------------------------------------- */ #endif
} /* ------------------------------------------------------------------- */
}
/* FOR UNIX/LINUX ------------------------------------------------------ */
#ifdef UNIX /* FOR UNIX/LINUX ------------------------------------------------------ */
// Close the server socket #ifdef UNIX
close(server_s); // Close the server socket
#endif close(server_s);
/* --------------------------------------------------------------------- */ #endif
/* --------------------------------------------------------------------- */
/* FOR WIN ------------------------------------------------------------- */
#ifdef WIN /* FOR WIN ------------------------------------------------------------- */
// Close the server socket and clean-up winsock #ifdef WIN
printf("this web server is shutting down .....\a\n"); // Close the server socket and clean-up winsock
printf("this web server is shutting down .....\a\n");
closesocket(server_s);
WSACleanup(); closesocket(server_s);
#endif WSACleanup();
/* --------------------------------------------------------------------- */ #endif
/* --------------------------------------------------------------------- */
// To make sure this "main" returns an integer.
return (1); // To make sure this "main" returns an integer.
} return (1);
}
/* FOR WIN --------------------------------------------------------------- */
#ifdef WIN /* FOR WIN --------------------------------------------------------------- */
//=========================================================================== #ifdef WIN
//= This is is the thread function to handle the GET = //===========================================================================
//= - It is assumed that the request is a GET = //= This is is the thread function to handle the GET =
//=========================================================================== //= - It is assumed that the request is a GET =
void handle_get(void *in_arg) //===========================================================================
{ void handle_get(void *in_arg)
unsigned int client_s; // Client socket descriptor {
char in_buf[BUF_SIZE]; // Input buffer for GET resquest unsigned int client_s; // Client socket descriptor
char out_buf[BUF_SIZE]; // Output buffer for HTML response char in_buf[BUF_SIZE]; // Input buffer for GET resquest
char *file_name; // File name char out_buf[BUF_SIZE]; // Output buffer for HTML response
unsigned int fh; // File handle char *file_name; // File name
unsigned int buf_len; // Buffer length for file reads unsigned int fh; // File handle
unsigned int retcode; // Return code unsigned int buf_len; // Buffer length for file reads
unsigned int retcode; // Return code
// Set client_s to in_arg
client_s = (unsigned int)in_arg; // Set client_s to in_arg
client_s = (unsigned int)in_arg;
// Receive the GET request from the Web browser
retcode = recv(client_s, in_buf, BUF_SIZE, 0); // Receive the GET request from the Web browser
retcode = recv(client_s, in_buf, BUF_SIZE, 0);
// Handle the GET if there is one (see note #3 in the header)
if (retcode != -1) // Handle the GET if there is one (see note #3 in the header)
{ if (retcode != -1)
// Parse out the filename from the GET request {
strtok(in_buf, " "); // Parse out the filename from the GET request
file_name = strtok(NULL, " "); strtok(in_buf, " ");
file_name = strtok(NULL, " ");
// Open the requested file
// - Start at 2nd char to get rid of leading "\" // Open the requested file
fh = open(&file_name[1], O_RDONLY | O_BINARY, S_IREAD | S_IWRITE); // - Start at 2nd char to get rid of leading "\"
fh = open(&file_name[1], O_RDONLY | O_BINARY, S_IREAD | S_IWRITE);
// Generate and send the response (404 if could not open the file)
if (fh == -1) // Generate and send the response (404 if could not open the file)
{ if (fh == -1)
printf("File %s not found - sending an HTTP 404 \n", &file_name[1]); {
strcpy(out_buf, NOTOK_404); printf("File %s not found - sending an HTTP 404 \n", &file_name[1]);
send(client_s, out_buf, strlen(out_buf), 0); strcpy(out_buf, NOTOK_404);
strcpy(out_buf, MESS_404); send(client_s, out_buf, strlen(out_buf), 0);
send(client_s, out_buf, strlen(out_buf), 0); strcpy(out_buf, MESS_404);
} send(client_s, out_buf, strlen(out_buf), 0);
else }
{ else
printf("File %s is being sent \n", &file_name[1]); {
if (strstr(file_name, ".gif") != NULL) printf("File %s is being sent \n", &file_name[1]);
strcpy(out_buf, OK_IMAGE); if (strstr(file_name, ".gif") != NULL)
else strcpy(out_buf, OK_IMAGE);
strcpy(out_buf, OK_TEXT); else
send(client_s, out_buf, strlen(out_buf), 0); strcpy(out_buf, OK_TEXT);
while (!eof(fh)) send(client_s, out_buf, strlen(out_buf), 0);
{ while (!eof(fh))
buf_len = read(fh, out_buf, BUF_SIZE); {
send(client_s, out_buf, buf_len, 0); buf_len = read(fh, out_buf, BUF_SIZE);
} send(client_s, out_buf, buf_len, 0);
close(fh); }
} close(fh);
} }
}
// Close the client socket and end the thread
closesocket(client_s); // Close the client socket and end the thread
_endthread(); closesocket(client_s);
} _endthread();
#endif }
/* ----------------------------------------------------------------------- */ #endif
/* ----------------------------------------------------------------------- */
/* FOR UNIX/LINUX -------------------------------------------------------- */
#ifdef UNIX /* FOR UNIX/LINUX -------------------------------------------------------- */
void child_proc(int server_s, int client_s) #ifdef UNIX
{ void child_proc(int server_s, int client_s)
char in_buf[BUF_SIZE]; // Input buffer for GET resquest {
char out_buf[BUF_SIZE]; // Output buffer for HTML response char in_buf[BUF_SIZE]; // Input buffer for GET resquest
char *file_name; // File name char out_buf[BUF_SIZE]; // Output buffer for HTML response
unsigned int fh; // File handle char *file_name; // File name
unsigned int buf_len; // Buffer length for file reads unsigned int fh; // File handle
ssize_t retcode; // Return code unsigned int buf_len; // Buffer length for file reads
ssize_t retcode; // Return code
// Shut down the parent pipe
close(server_s); // Shut down the parent pipe
close(server_s);
// Receive the GET request from the Web browser
retcode = recv(client_s, in_buf, BUF_SIZE, 0); // Receive the GET request from the Web browser
retcode = recv(client_s, in_buf, BUF_SIZE, 0);
// Handle the GET if there is one (see note #3 in the header)
if (retcode != -1) // Handle the GET if there is one (see note #3 in the header)
{ if (retcode != -1)
// Parse out the filename from the GET request {
strtok(in_buf, " "); // Parse out the filename from the GET request
file_name = strtok(NULL, " "); strtok(in_buf, " ");
file_name = strtok(NULL, " ");
// Open the requested file
// - Start at 2nd char to get rid of leading "\" // Open the requested file
// fh = open(&file_name[1], O_RDONLY | O_BINARY, S_IREAD | S_IWRITE); // - Start at 2nd char to get rid of leading "\"
fh = open(&file_name[1], O_RDONLY, S_IREAD | S_IWRITE); // fh = open(&file_name[1], O_RDONLY | O_BINARY, S_IREAD | S_IWRITE);
fh = open(&file_name[1], O_RDONLY, S_IREAD | S_IWRITE);
// Generate and send the response (404 if could not open the file)
if (fh == -1) // Generate and send the response (404 if could not open the file)
{ if (fh == -1)
printf("File %s not found - sending an HTTP 404 \n", &file_name[1]); {
strcpy(out_buf, NOTOK_404); printf("File %s not found - sending an HTTP 404 \n", &file_name[1]);
send(client_s, out_buf, strlen(out_buf), 0); strcpy(out_buf, NOTOK_404);
strcpy(out_buf, MESS_404); send(client_s, out_buf, strlen(out_buf), 0);
send(client_s, out_buf, strlen(out_buf), 0); strcpy(out_buf, MESS_404);
} send(client_s, out_buf, strlen(out_buf), 0);
else }
{ else
printf("File %s is being sent \n", &file_name[1]); {
if (strstr(file_name, ".gif") != NULL) printf("File %s is being sent \n", &file_name[1]);
strcpy(out_buf, OK_IMAGE); if (strstr(file_name, ".gif") != NULL)
else strcpy(out_buf, OK_IMAGE);
strcpy(out_buf, OK_TEXT); else
send(client_s, out_buf, strlen(out_buf), 0); strcpy(out_buf, OK_TEXT);
send(client_s, out_buf, strlen(out_buf), 0);
while (fh != EOF)
{ while (fh != EOF)
buf_len = read(fh, out_buf, BUF_SIZE); {
send(client_s, out_buf, buf_len, 0); buf_len = read(fh, out_buf, BUF_SIZE);
} send(client_s, out_buf, buf_len, 0);
close(fh); }
} close(fh);
} }
}
// Shut down my (the child) pipe
close(client_s); // Shut down my (the child) pipe
exit(1); close(client_s);
} exit(1);
#endif }
/* ----------------------------------------------------------------------- */ #endif
/* ----------------------------------------------------------------------- */