366 lines
12 KiB
C
366 lines
12 KiB
C
/*
|
|
SlideScript - minimalistic top-down scripting language.
|
|
(C) Copyright 2014-2021 Chris Dorman - some rights reserved (GPLv2)
|
|
|
|
View README file supplied with this software for more details
|
|
*/
|
|
|
|
#include "deps.h"
|
|
#include "network.h"
|
|
#include "util.h"
|
|
|
|
// Structure of file types for nethttp
|
|
// mimetype struct, searched through when checking mimetype
|
|
struct {
|
|
char *ext;
|
|
char *filetype;
|
|
} file_extensions [] = {
|
|
{"gif", "image/gif" },
|
|
{"jpg", "image/jpeg" },
|
|
{"jpeg","image/jpeg" },
|
|
{"png", "image/png" },
|
|
{"zip", "application/zip" },
|
|
{"gz", "application/gzip" },
|
|
{"tar", "application/x-tar" },
|
|
{"htm", "text/html" },
|
|
{"html","text/html" },
|
|
{"cgi", "text/cgi" },
|
|
{"asp","text/asp" },
|
|
{"xml", "text/xml" },
|
|
{"js", "text/js" },
|
|
{"css", "text/css" },
|
|
{"c", "text/plain" },
|
|
{"h", "text/plain" },
|
|
{"md", "text/plain" },
|
|
{"txt", "text/plain" },
|
|
{"ss", "text/plain" },
|
|
{"sh", "text/plain" },
|
|
{"ogg", "audio/ogg" },
|
|
{"mp3", "audio/mpeg" },
|
|
{0,0}
|
|
};
|
|
|
|
/* Serve process function, on connection catch buffer from socket */
|
|
void snet_process_connection(int sockfd, char *srch, char *resp)
|
|
{
|
|
char buff[MAX_STRING_BUFSIZE+1];
|
|
int rr, wr;
|
|
//bzero(buff, MAX_STRING_BUFSIZE);
|
|
// read the message from client and copy it in buffer
|
|
rr = read(sockfd, buff, sizeof(buff));
|
|
|
|
if(rr == -1) syn_error("ss:net:client read error");
|
|
|
|
// print buffer which contains the client contents
|
|
printf("ss:net: %s\n", buff);
|
|
bzero(buff, MAX_STRING_BUFSIZE);
|
|
// if msg contains "Exit" then server exit and chat ended.
|
|
if (strncmp("exit", buff, 4) == 0)
|
|
{
|
|
syn_error("ss:net:call to exit");
|
|
}
|
|
|
|
if (strncmp(srch, buff, strlen(srch)) == 0)
|
|
{
|
|
wr = write(sockfd, resp, sizeof(resp));
|
|
if(wr == -1) syn_error("ss:error:network write error!");
|
|
}
|
|
else
|
|
{
|
|
wr = write(sockfd, resp, sizeof(resp));
|
|
if(wr == -1) syn_error("ss:error:network write error!");
|
|
}
|
|
}
|
|
|
|
/* Main netlisten function */
|
|
void snet_listen(int port, char *srch, char *resp)
|
|
{
|
|
int sockfd, connfd, length;
|
|
struct sockaddr_in servaddr;
|
|
struct sockaddr_in cliaddr;
|
|
|
|
// socket create and verification
|
|
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
|
if (sockfd == -1)
|
|
{
|
|
syn_error("ss:error:network socket creation failed");
|
|
}
|
|
|
|
bzero(&servaddr, sizeof(servaddr));
|
|
|
|
// assign IP, PORT
|
|
servaddr.sin_family = AF_INET;
|
|
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
servaddr.sin_port = htons(port);
|
|
|
|
// Binding newly created socket to given IP and verification
|
|
if ((bind(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr))) != 0)
|
|
{
|
|
syn_error("ss:error:network bind failed");
|
|
}
|
|
|
|
// Now server is ready to listen and verification
|
|
if ((listen(sockfd, 64)) != 0)
|
|
{
|
|
syn_error("ss:error:network listen failed");
|
|
}
|
|
else
|
|
{
|
|
printf("ss:net:listening on '%d'\n", port);
|
|
}
|
|
|
|
for( ; ; ) {
|
|
length = sizeof(cliaddr);
|
|
// Accept the data packet from client and verification
|
|
if((connfd = accept(sockfd, (struct sockaddr*)&cliaddr, (socklen_t*) &length)) < 0)
|
|
{
|
|
syn_error("ss:error:network accept failed");
|
|
}
|
|
|
|
snet_process_connection(connfd, srch, resp);
|
|
}
|
|
|
|
// After chatting close the socket
|
|
close(sockfd);
|
|
}
|
|
|
|
// Main nettoss function
|
|
void snet_toss(char *address, int port, char *string)
|
|
{
|
|
int sockfd;
|
|
struct sockaddr_in servaddr;
|
|
|
|
// socket create and varification
|
|
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
|
if (sockfd == -1)
|
|
{
|
|
syn_error("ss:error:network failed to create socket");
|
|
}
|
|
|
|
bzero(&servaddr, sizeof(servaddr));
|
|
|
|
// assign IP, PORT
|
|
servaddr.sin_family = AF_INET;
|
|
servaddr.sin_addr.s_addr = inet_addr(address);
|
|
servaddr.sin_port = htons(port);
|
|
|
|
// connect the client socket to server socket
|
|
if (connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) != 0)
|
|
{
|
|
syn_error("ss:error:network failled to connect");
|
|
}
|
|
else
|
|
{
|
|
printf("ss:net:connect: %s:%d\n", address, port);
|
|
}
|
|
|
|
// If write reports -1, exit on error.
|
|
if(write(sockfd, string, strlen(string)) < 0) syn_error("ss:net:socket write error!");
|
|
|
|
// close the socket after pushing content
|
|
close(sockfd);
|
|
}
|
|
|
|
// Process connection of nethttp
|
|
void snet_http_process(int fd, int forkval)
|
|
{
|
|
int j, file_fd, buflen, len;
|
|
long i, filesize;
|
|
char *fstr = NULL;
|
|
static char buffer[HTTP_BUFSIZE+1];
|
|
|
|
// Check to see if file is corrupted
|
|
filesize = read(fd,buffer,HTTP_BUFSIZE);
|
|
if(filesize == 0 || filesize == -1) {
|
|
sprintf(buffer,"HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n");
|
|
if(write(fd,buffer,strlen(buffer)) < 0) syn_error("ss:net:http socket write error");
|
|
sprintf(buffer,"<html><head><title>ss:http:missed header</title></head><body><h2>301: Missed header call</h2>" \
|
|
"<p>Could not locate file</p><br /><br /><center>ss:http:%s</center></body></html>", VERSION);
|
|
if(write(fd,buffer,strlen(buffer)) < 0) syn_error("ss:net:http socket write error");
|
|
exit(1);
|
|
}
|
|
|
|
if(filesize > 0 && filesize < HTTP_BUFSIZE) {
|
|
buffer[filesize]=0;
|
|
} else {
|
|
buffer[0]=0;
|
|
}
|
|
|
|
for(i=0;i<filesize;i++) {
|
|
if(buffer[i] == '\r' || buffer[i] == '\n') {
|
|
buffer[i]='*';
|
|
}
|
|
}
|
|
|
|
if(strncmp(buffer,"GET ",4) && strncmp(buffer,"get ",4)) {
|
|
sprintf(buffer,"HTTP/1.0 501 Not Implemented\r\nContent-Type: text/html\r\n\r\n");
|
|
if(write(fd,buffer,strlen(buffer)) < 0) syn_error("ss:net:http socket write error");
|
|
sprintf(buffer,"<html><head><title>ss:http: server not implemented</title></head><body>" \
|
|
"<h2>501: Not Implemented</h2><p>ss:http only supports simple GET requests via HTTP/1.0</p>" \
|
|
"<br /><br /><center>ss:http:%s</center></body></html>", VERSION);
|
|
if(write(fd,buffer,strlen(buffer)) < 0) syn_error("ss:net:http socket write error");
|
|
exit(1);
|
|
}
|
|
|
|
|
|
// This gets the file name from "GET /..."
|
|
for(i=4;i<HTTP_BUFSIZE;i++) {
|
|
if(buffer[i] == ' ') {
|
|
buffer[i] = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Check if connection is trying to view in directories behind webserver root
|
|
for(j=0;j<i-1;j++) {
|
|
if(buffer[j] == '.' && buffer[j+1] == '.') {
|
|
sprintf(buffer,"HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n");
|
|
if(write(fd,buffer,strlen(buffer)) < 0) syn_error("ss:net:http socket write error");
|
|
sprintf(buffer,"<html><head><title>ss:http: parent directory not available</title></head><body><h2>FORBIDDEN: parent directory</h2>" \
|
|
"<p>You do not have access to view ../. Blocked.</p><br /><br /><center>ss:http:%s</center></body></html>", VERSION);
|
|
if(write(fd,buffer,strlen(buffer)) < 0) syn_error("ss:net:http socket write error");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
// If client is connecting with GET / (root of website) then send index
|
|
if( !strncmp(&buffer[0],"GET /\0",6) || !strncmp(&buffer[0],"get /\0",6) ) {
|
|
if(file_exists("index.html")) {
|
|
strcpy(buffer,"GET /index.html");
|
|
} else {
|
|
sprintf(buffer,"HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n");
|
|
if(write(fd,buffer,strlen(buffer)) < 0) syn_error("ss:net:http socket write error");
|
|
sprintf(buffer,"<html><head><title>ss:http: file not found</title></head><body><h2>File not found</h2>" \
|
|
"<p>Could not locate index.html</p><br /><br /><center>ss:http:%s</center></body></html>", VERSION);
|
|
if(write(fd,buffer,strlen(buffer)) < 0) syn_error("ss:net:http socket write error");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
// Get file mimetype
|
|
buflen=strlen(buffer);
|
|
for(i=0;file_extensions[i].ext != 0;i++) {
|
|
len = strlen(file_extensions[i].ext);
|
|
if(!strncmp(&buffer[buflen-len], file_extensions[i].ext, len)) {
|
|
fstr = file_extensions[i].filetype;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(fstr == NULL)
|
|
{
|
|
fstr = "application/octet-stream";
|
|
}
|
|
|
|
if(forkval == 0)
|
|
printf("ss:net:http request %s, %s\n", &buffer[5], fstr);
|
|
|
|
if(is_dir(&buffer[5]) == 1)
|
|
{
|
|
sprintf(buffer,"HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n");
|
|
if(write(fd,buffer,strlen(buffer)) < 0) syn_error("ss:net:http socket write error");
|
|
sprintf(buffer,"<html><head><title>ss:http: directory</title></head><body><h2>Directory</h2>" \
|
|
"<p>No directory listings at this time...</p><br /><br /><center>ss:http:%s</center></body></html>", VERSION);
|
|
if(write(fd,buffer,strlen(buffer)) < 0) syn_error("ss:net:http socket write error");
|
|
exit(1);
|
|
}
|
|
|
|
// See if the web server can open requested file from browser
|
|
if(( file_fd = open(&buffer[5],O_RDONLY)) == -1) {
|
|
sprintf(buffer,"HTTP/1.0 404 Not Found\r\nContent-Type: text/html\r\n\r\n");
|
|
if(write(fd,buffer,strlen(buffer)) < 0) syn_error("ss:net:http socket write error");
|
|
sprintf(buffer,"<html><head><title>ss:http:file not found</title></head><body><h2>404: File not found</h2>" \
|
|
"<p>Could not locate file</p><br /><br /><center>ss:http:%s</center></body></html>", VERSION);
|
|
if(write(fd,buffer,strlen(buffer)) < 0) syn_error("ss:net:http socket write error");
|
|
exit(1);
|
|
}
|
|
|
|
sprintf(buffer,"HTTP/1.0 200 OK\r\nContent-Type: %s\r\n\r\n", fstr);
|
|
if(write(fd,buffer,strlen(buffer)) < 0) syn_error("ss:net:http socket write error");
|
|
|
|
while ((filesize = read(file_fd, buffer, HTTP_BUFSIZE)) > 0) {
|
|
if(write(fd,buffer,filesize) < 0) syn_error("ss:net:http socket write error");
|
|
}
|
|
|
|
|
|
#ifdef LINUX
|
|
sleep(1);
|
|
#endif
|
|
exit(0);
|
|
}
|
|
|
|
// Main function for nethttp //
|
|
void snet_http(int port, int forkval)
|
|
{
|
|
// Intergers for ports, sockets, etc
|
|
int i, pid, listenfd, socketfd, hit;
|
|
socklen_t length;
|
|
// structs for socket addresses, these are always needed!
|
|
static struct sockaddr_in cli_addr;
|
|
static struct sockaddr_in serv_addr;
|
|
|
|
// This forks the httpd process into the background, if forkval > 0
|
|
if(forkval > 0)
|
|
{
|
|
if(fork() != 0)
|
|
syn_error("ss:net:http forked");
|
|
|
|
#ifndef BSD
|
|
signal(SIGCLD, SIG_IGN);
|
|
#endif
|
|
signal(SIGHUP, SIG_IGN);
|
|
for(i=0;i<32;i++) {
|
|
close(i);
|
|
}
|
|
}
|
|
|
|
setpgid(0, 0);
|
|
if(forkval < 1)
|
|
printf("Starting httpd...\n");
|
|
|
|
// Check if socket succeeded to open
|
|
if((listenfd = socket(AF_INET, SOCK_STREAM,0)) <0) {
|
|
printf("Failed to open socket\n");
|
|
exit(1);
|
|
}
|
|
|
|
// check if valid port number
|
|
if(port < 0 || port >65534) {
|
|
syn_error("ss:net:http incorrect port range (vaild 1 - 65534)");
|
|
}
|
|
|
|
// binds the socket to a specific port and address
|
|
// in this case, 0.0.0.0 and the port you choose
|
|
serv_addr.sin_family = AF_INET;
|
|
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
serv_addr.sin_port = htons(port);
|
|
if(bind(listenfd, (struct sockaddr *)&serv_addr,sizeof(serv_addr)) <0) {
|
|
syn_error("ss:net:http failed to bind to socket");
|
|
}
|
|
if( listen(listenfd,64) <0) {
|
|
syn_error("ss:net:http failed to listen to socket");
|
|
}
|
|
|
|
for(hit=1; ;hit++) {
|
|
length = sizeof(cli_addr);
|
|
|
|
// Check if server succeeded to accept connection
|
|
if((socketfd = accept(listenfd, (struct sockaddr *)&cli_addr, &length)) < 0) {
|
|
syn_error("ss:net:http failed to accept connection");
|
|
}
|
|
|
|
// Fork, and die if server fails to fork process
|
|
if((pid = fork()) < 0) {
|
|
syn_error("ss:net:http failed to fork connection");
|
|
}
|
|
else {
|
|
if(pid == 0) {
|
|
close(listenfd);
|
|
snet_http_process(socketfd, forkval);
|
|
} else {
|
|
close(socketfd);
|
|
}
|
|
}
|
|
}
|
|
}
|