/*
** server.c -- a stream socket server demo
Basic Server code from 
Beej's Guide to Network Programming:
http://beej.us/guide/bgnet/output/htmlsingle/bgnet.html#simpleserver

It was changed to be more modular and the stage functions were added.
-Stanislav Nurilov
*/

// and /* */ are used to indicate text not looked at by the compiler, which turns the code in to a binary

//header files, code and variable definitions in the files listed below(each preceeded by a #) are treated as if they were 
//explicitly stated in this file
//try /usr/include
 
#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 <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
// the files surrounded by <> are looked for in the global include directories indicated in the environment variables when 
// the compiler is run or by command line options passed to the compiler
// the file below, surrounded by quotes, is searched for in relation to the current working directory of the compiler 
// (the compiler will be gcc or if you swing that way VC++ or borland or some other weird shit but if you are using 
// anything too outlandish you can safely ignore the rest of this commentary as it is meant for those self learning.) 
#include "send_flag.h"

//defines are used to specify in a global and absolute way (see ifndef) variables and functions that are important to have 
//be absolute. The capital letters are an important formality for mnemetic sake.
#define MYPORT 50000    // the port users will be connecting to
#define BACKLOG 20     // how many pending connections queue will hold
//if not defined (if no one has said...) SEND_MACRO, define it! and thats all I want to do (endif)
#ifndef SEND_MACRO
#define SEND_MACRO(f, s) if(send(f, s, strlen(s),0)==-1) perror("send")
#endif

//these declare what functions will be used and what variable types they can take and how many variables
//the functions below return nothing, indicated by void, start_server_listen further below returns a variable of type int, which i
//is defined in the system include files, for my system an int is 4 bytes, I found this in /usr/include/mips/int_types.h which was 
//included from /usr/include/machine/int_types.h which was included from /usr/include/sys/types.h

//client_function is the name of the function, it takes a single int as an argument

void client_function(int fd);

//the * indicates that variable is a pointer, pointers point to a place in memory, understanding pointers and memory layout is essential to programming

void server_function(struct sockaddr_in *their_addr);
void sigchld_handler(int s)

//this is an actual function, this particular function opens a port and returns an int, this int is a file descriptor pointing to the open port
//I am not going to go in to any detail about this function, part of programming is that sometimes you just trust something works. If you cant stand not being 
//told what every little bit of this function does then RTFM (read the fucking manual) and if you see a variable used that is not defined somewhere in this 
//file then it is defined by one of the .h files listed at the top of the source code

int start_server_listen(int port, int backlog){
	int sockfd, new_fd;  // listen on sock_fd, new connection on new_fd
	struct sockaddr_in my_addr;    // my address information
	struct sockaddr_in their_addr; // connector's address information
	socklen_t sin_size;
	struct sigaction sa;
	int yes=1;

	if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
		perror("socket");
		exit(1);
	}

	if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
		perror("setsockopt");
		exit(1);
    }

	my_addr.sin_family = AF_INET;         // host byte order
	my_addr.sin_port = htons(port);     // short, network byte order
	my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP
	memset(&(my_addr.sin_zero), '\0', 8); // zero the rest of the struct

//request a port to be ours and point to it with sockfd, the port is indicated by my_addr, the & before my_addr indicates this is a pointer but I want to see 
//what location the pointer is stored in memory, so if int i = 5 then int p* = &i would make i point to p so *p would be 5, p would be the location that 5 is 
//stored at, and &p would be the location in memory the address of that 5 is stored at, or rather where the pointer is. structs are used also, this is a 
//larger topic, you can write functional C without using structs but I would suggest googling 
	if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr))== -1) {
		perror("bind");
		exit(1);
	}
//set the port to listen for connection
	if (listen(sockfd, backlog) == -1) {
		perror("listen");
		exit(1);
	}
	return sockfd;
}

//the MAIN function is where the program starts
int main(void)
{
	int sockfd, new_fd;  // listen on sock_fd, new connection on new_fd
	struct sockaddr_in my_addr;    // my address information
	struct sockaddr_in their_addr; // connector's address information
	socklen_t sin_size;
	struct sigaction sa;
	
	sockfd = start_server_listen(MYPORT, BACKLOG );

	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);
	}

	while(1) {  // main accept() loop
        	sin_size = sizeof(struct sockaddr_in);
//if a connection was not requested and accepted by the accept function (man accept)
		if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1) {
			perror("accept");
//just keep right on continuing (enter the while again)
			continue;
		}
//record that a connection was made
		server_function(&their_addr);
//this if() creates a child process via fork and simultaneously checks if we are said process
		if (!fork()) { // this is the child process
			close(sockfd); // child doesn't need the listener
			client_function(new_fd);
			exit(0);
		}
//the { is the beginning of what happens if the if is true, the } is the end
		close(new_fd);  // parent doesn't need this
	}
//this } is for the while(1) { above
//the return below ends execution and returns a 0 for the program as a whole, indicating success, anything else would indicate a failure state
	return 0;
}
//this { is for main, this is the end of the program, but not the source code!

void client_function(int new_fd){
	SEND_MACRO(new_fd, "foster.stonedcoder.org/~druid/hkm.c, ripped off from brooklyn polytechnic\n");
    close(new_fd);
}

void server_function(struct sockaddr_in *their_addr){
//this opens a file for appending, indicated by the "a"
	FILE * f = fopen("/var/log/CHALL1LOG", "a");
	if(f == NULL){
//printf prints to the screen, fprintf prints to a file, indicated by f
		printf("hint server: got connection from %s\n", inet_ntoa(their_addr->sin_addr));
	}else{
		fprintf(f, "hint server: got connection from %s\n", inet_ntoa(their_addr->sin_addr));
		fclose(f);
	}
}

// this is the last function! it checks the status of a child process spawned by this process, -1 indicates that all children should be checked. while is a 
// standard C function that loops while the condition is met, in this case if the child has had any changes, so as soon as the child has not had a state change this 
// while will be false and the function will return.

void sigchld_handler(int s)
{
    while(waitpid(-1, NULL, WNOHANG) > 0);
}

