/* 
 * Copyright (C) Telefonica 2015
 * All rights reserved.
 *
 * Telefonica Proprietary Information.
 *
 * Contains proprietary/trade secret information which is the property of 
 * Telefonica and must not be made available to, or copied or used by
 * anyone outside Telefonica without its written authorization.
 *
 * Authors: 
 *   Matteo Varvello <matteo.varvello@telefonica.com> et al. 
 *
 * Description: 
 * An SSL/SPP server. 
 */


#include "common.h"
#include <stdbool.h>            
#define KEYFILE "server.pem"
#define PASSWORD "password"
#define DHFILE "dh1024.pem"
#include <openssl/e_os2.h>
#define DEBUG
#define MAX_PACKET 16384 

static char *strategy = "uni";

// Listen TCP socket
int tcp_listen(){
    
	int sock;
	struct sockaddr_in sin;
	int val = 1;

	// Create socket, allocate memory and set sock options
	if((sock=socket(AF_INET,SOCK_STREAM,0)) < 0){
		err_exit("Couldn't make socket");
	}
    memset(&sin, 0, sizeof(sin));
    sin.sin_addr.s_addr = INADDR_ANY;
    sin.sin_family = AF_INET;
    sin.sin_port = htons(PORT);
    setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val,sizeof(val));

	// Bind to socket    
	if(bind(sock,(struct sockaddr *)&sin, sizeof(sin))<0){
		berr_exit("Couldn't bind");
	}

	// Listen to socket
    listen(sock,5);  

	// Return socket descriptor
    return(sock);
}

// Load parameters from "dh1024.pem"
void load_dh_params(SSL_CTX *ctx, char *file){
	DH *ret=0;
	BIO *bio;

    if ((bio=BIO_new_file(file,"r")) == NULL){
      berr_exit("Couldn't open DH file");
	}

	ret = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
	BIO_free(bio);
	if(SSL_CTX_set_tmp_dh(ctx,ret) < 0){
		berr_exit("Couldn't set DH parameters");
	}
}

// Generate ephemeral RSA key (check DH) 
void generate_eph_rsa_key(ctx)
  SSL_CTX *ctx;
  {
    RSA *rsa;

    rsa = RSA_generate_key(512, RSA_F4, NULL, NULL);
    
    if (!SSL_CTX_set_tmp_rsa(ctx,rsa))
      berr_exit("Couldn't set RSA key");

    RSA_free(rsa);
  }
    
// Compute the size of a file to be served
int calculate_file_size(char *filename){ 

	FILE *fp; 	
	int sz = 0; 

	// Open file 
 	fp = fopen(filename,"r");
 
	// Check for errors while opening file
	if(fp == NULL){
		printf("Error while opening file %s.\r\n", filename);
		exit(-1);
	}
	
	// Seek  to the end of the file and ask for position 
	fseek(fp, 0L, SEEK_END);
	sz = ftell(fp);
	//fseek(fp, 0L, SEEK_SET);

	// Close file 
	fclose (fp);
	
	// Return file size 
	#ifdef DEBUG
	printf ("[DEBUG] File requested is <<%s>> with size <<%d bytes>>\n", filename, sz); 
	#endif 
	return sz; 
}

// Function to print a prox list
void print_proxy_list(SPP_PROXY **proxies, int N){
	int i; 

	#ifdef DEBUG
	printf("[DEBUG] Print proxy list (There are %d available proxies)\r\n", N);
	#endif

	// Iterate through list 
	for (i = 0; i < N; i++){
		printf("Proxy %d -- %s\r\n", i, proxies[i]->address);
	}
}


// Check for SSL_write error (just write at this point) -- TO DO: check behavior per slice 
void check_SSL_write_error(SSL *ssl, int r, int request_len){

    switch(SSL_get_error(ssl, r)){
        case SSL_ERROR_NONE:
            if(request_len != r){
                err_exit("Incomplete write!");
            }
            break;

        default:
            berr_exit("SSL write problem");
    }
}

// splitting 
void splitting (SSL *ssl, char *request, int request_len){
	int beginIndex = 0; 
	int i; 
	int inc = request_len / (ssl->slices_len - 1); 
		
	// Slicing happens here  
	for (i = 1; i < ssl->slices_len; i++){
		
		char* dest = (char*) malloc(inc); 
		#ifdef DEBUG
		printf("[DEBUG] Write sub-record with slice [%d ; %s]. [S1 is for handshake ; S2 is for the client]\n"\
			"[DEBUG] Sub-record size is %d (beginIndex=%d -- endIndex=%d)\n", \
			ssl->slices[i]->slice_id, ssl->slices[i]->purpose, inc, beginIndex, (beginIndex + inc)); 
		#endif
    	memset(dest, 0, inc);
		memcpy(dest, request + beginIndex,  inc); 
		printf("%s\n", dest); 
		int r = SPP_write_record(ssl, dest, inc, ssl->slices[i]);
		check_SSL_write_error(ssl, r, inc);
		
		// Move pointers
		beginIndex += inc;

		// Increase pointer for last slice  
		if ( i == (ssl->slices_len - 2)){
			inc = request_len - beginIndex; 
		} else if (strcmp(strategy, "exp") == 0){
			inc = 2 * inc; 
		}
	
		// free memory 
		free (dest); 
	}
}

// Send some data (SSL and SPP) 
void sendData(SSL *ssl, char *request, char *proto, int request_len){

	int r; 

	//mmmm  
	//request_len--; 

	// logging
	#ifdef DEBUG
	printf("[DEBUG] sendData with length %d\n", request_len); 
	#endif 
	
	// SPP
	if (strcmp(proto, "spp") == 0){
		// TO DO implement further splitting here 
		splitting(ssl, request, request_len); 
	}
		
	// SSL
	if (strcmp(proto, "ssl") == 0){
		r = SSL_write(ssl, request, request_len); 
		check_SSL_write_error(ssl, r, request_len);
	}
}

// Simple test for SPP handshake 
static int http_simple_response(SSL *ssl, int s, char *proto){

	int N_proxies, N_slices, i; 

	#ifdef DEBUG
	printf("[DEBUG] HTTP test simple response\n"); 
	#endif 	
	
	#ifdef DEBUG
	printf("[DEBUG] Verify proxies and slices were correctly received\n"); 

	if (strcmp(proto, "spp") == 0){
		// Print proxies
		N_proxies = ssl->proxies_len; 
		for (i = 0; i < N_proxies; i++){
			printf("\t[DEBUG] Proxy: %s\n", ssl->proxies[i]->address); 
		}

		// print slices
		N_slices = ssl->slices_len; 
		for (i = 0; i < N_slices; i++){
			printf("\t[DEBUG] Slice with ID %d and purpose %s\n", ssl->slices[i]->slice_id, ssl->slices[i]->purpose); 
		}
	}
	#endif 

	// put 200 OK on the wire 
	char *data = "HTTP/1.0 200 OK\r\n"; 
	int request_len = strlen(data);
	sendData(ssl, data, proto, request_len); 

	// Shutdown SSL - TO DO (check what happens here) 
	int r = SSL_shutdown(ssl);
	if( !r ){
		shutdown(s, 1);
		r = SSL_shutdown(ssl);
    }

	// Verify that shutdown was good 
	switch(r){  
		case 1:
       		break; // Success
		case 0:
		case -1:
		default: // Error 
			#ifdef DEBUG 
			printf ("Shutdown failed with code %d\n", r); 
			#endif 
			berr_exit("Shutdown failed");
	}
	
	// free SSL 
    SSL_free(ssl);
	
	// All good	
	return 0; 
}


// Parse HTTP GET request to get filename 
char* parse_http_get(char *buf){ 

	char *delim="\r\n"; 
	char *token = strtok(buf , delim);   
	delim=" "; 
	char *fn = strtok(token, delim);   
	fn = strtok(NULL, delim);   
	return fn; 
}

// Serve a given amount of data 
int serveData(SSL *ssl, int data_size, char *proto){ 
	
	// Logging
	#ifdef DEBUG
	printf ("[DEBUG] Requested data with size %d\n", data_size); 
	#endif 
	// Send data via SPP/SSL
	int still_to_send = data_size; 
	for (;;){
		// Derive min between how much to send and max buffer size 
		int toSend = BUFSIZZ; 
		if (still_to_send < toSend){
			toSend = still_to_send; 
		}

		//Allocate buffer with size to sens and fill with zeros
		char *buf = (char*) malloc(sizeof(char) * toSend);
		memset(buf, '!', sizeof(char) * toSend);	
		printf ("[DEBUG] Buffer=\n%s\n", buf); 
		
		// Send <<buf>> on SPP/SSL connection 
		if (strcmp(proto, "spp") == 0){
			sendData(ssl, buf, proto, sizeof(char) * toSend); 
		}
		if (strcmp(proto, "ssl") == 0){
			int r = SSL_write(ssl, buf, toSend);
			check_SSL_write_error(ssl, r, toSend);
		}
		
		// Update how much content is still to send 
		still_to_send -= toSend;
		if (still_to_send == 0){
			printf ("[DEBUG] No more data to send\n"); 
			break; 	
		}

		// Free buffer
		free(buf); 
	}

	// All good
	return 0; 
}	

// Serve a file -- solution extracted from original s_client 
// NOTES: (1) modified not to use BIO ; (2) re-negotiation currently not used
int serveFile(SSL *ssl, char *filename, char *proto){ 
	
 	FILE *fp;				// file descriptot 
	int file_size = 0;		// size of file being sent 
 
	// Open requested file for reading
 	if ((fp = fopen(filename,"r")) == NULL){
		#ifdef DEBUG
		printf ("File <<%s>> do not exist\n", filename); 
		#endif 
		char *data = "Error opening file\r\n"; 
		int request_len = strlen(data);
		sendData(ssl, data, proto, request_len); 
		fclose(fp); 
		return -1; 
	}else{
		// Calculate file size 
		// Seek  to the end of the file and ask for position 
		fseek(fp, 0L, SEEK_END);
		file_size = ftell(fp);
		// Seek to the beginning of the file 
		fseek(fp, 0L, SEEK_SET);
		
		#ifdef DEBUG
		printf ("[DEBUG] File requested is <<%s>> with size <<%d bytes>>\n", filename, file_size); 
		#endif 
	}

	// Allocate buffer for data to send 
	char* buf = (char*) malloc (file_size); 
	
	// Read "toSend" content from file 
	int i = fread(buf, file_size, 1, fp);

	// Check for end of file
	if (i <= 0){
		#ifdef DEBUG
		printf("[DEBUG] Done reading file %s\n", filename); 	
		#endif
	}else{
		#ifdef DEBUG
		printf("[DEBUG] Still some data to read? (read result = %d)\n", i); 	
		#endif
	}

	// Send <<buf>> on SPP/SSL connection 
	sendData(ssl, buf, proto, file_size); 
		
	// Close file
	fclose(fp); 

	// All good
	return 0; 
}	



// Serve a file -- solution extracted from original s_client 
// NOTES: (1) modified not to use BIO ; (2) re-negotiation currently not used
int serveFile_old(SSL *ssl, char *filename, char *proto){ 
	
 	FILE *fp;				// file descriptot 
	char buf[BUFSIZZ];		// buffer for data to send
	int file_size = 0;		// size of file being sent 
	int still_to_send; 		// amount of data from file still to be sent 
 
	// Open requested file for reading
 	if ((fp = fopen(filename,"r")) == NULL){
		#ifdef DEBUG
		printf ("File <<%s>> do not exist\n", filename); 
		#endif 
		char *data = "Error opening file\r\n"; 
		int request_len = strlen(data);
		sendData(ssl, data, proto, request_len); 
		fclose(fp); 
		return -1; 
	}else{
		// Calculate file size 
		// Seek  to the end of the file and ask for position 
		fseek(fp, 0L, SEEK_END);
		file_size = ftell(fp);
		// Seek to the beginning of the file 
		fseek(fp, 0L, SEEK_SET);
		
		#ifdef DEBUG
		printf ("[DEBUG] File requested is <<%s>> with size <<%d bytes>>\n", filename, file_size); 
		#endif 
	}

	// Transfer file via SPP/SSL
	still_to_send = file_size; 
	for (;;){
		
		// Derive min between how much to send and max buffer size 
		int toSend = BUFSIZZ; 
		if (still_to_send < toSend){
			toSend = still_to_send; 
		}

		// Read "toSend" content from file 
		int i = fread(buf, toSend, 1, fp);

		// Check for end of file
		if (i <= 0){
			#ifdef DEBUG
			printf("[DEBUG] Done reading file %s\n", filename); 	
			#endif
			break; 
		}else{
			#ifdef DEBUG
			printf("[DEBUG] Read %d bytes from file\n", toSend); 	
			#endif
		}

		// Update how much content is still to send 
		still_to_send -= (i * toSend);
		
		// Send <<buf>> on SPP/SSL connection 
		if (strcmp(proto, "spp") == 0){
			int request_len = strlen(buf);
			sendData(ssl, buf, proto, request_len); 
		}
		if (strcmp(proto, "ssl") == 0){
			int r = SSL_write(ssl, buf, toSend);
			check_SSL_write_error(ssl, r, toSend);
		}
	}

	// Close file
	fclose(fp); 

		/* CODE FOR RENOGOTIATION 
		// Check if too many losses 
		if (total_bytes > (3 * file_size)){
			total_bytes = 0;
			fprintf(stderr,"RENEGOTIATE\n");
			SSL_renegotiate(ssl); 
		}
		
		// Renegotiation if too many lossed
		for (j = 0; j < i; ){
			// After 13 attempts, re-negotate at SSL level 
			static int count = 0; 
			if (++count == 13) { 
				SSL_renegotiate(ssl); 
			} 

			int r = SSL_write(ssl, buf, BUFSIZZ);
			check_SSL_write_error(ssl, r, BUFSIZZ);
			//int k = BIO_write(io, &(buf[j]), i-j);
			if (k <= 0){
				if (! BIO_should_retry(io)){
					goto write_error; 
				}else {
					BIO_printf(io, "rewrite W BLOCK\n");
					}
				}else{
					j += k;
				}
			write_error:
				BIO_free(file);
				break; 
			}

		if((r = BIO_flush(io))<0){
			err_exit("Error flushing BIO");
		}
    } // end for loop 
	*/
	
	// All good
	return 0; 
}	


// 1) work with both SSL and SPP
// 2) no usage of BIO APIs
static int http_serve_request(SSL *ssl, int s, char *proto, bool shut, int action){
  
    int r; 
	char buf[BUFSIZZ];
	char *filename = ""; 
	int ret_value = 0; 

	// Read HTTP GET (assuming a single read is enough)
	while(1){
		if (strcmp(proto, "spp") == 0){
			SPP_SLICE *slice;       
			SPP_CTX *ctx;           
			r = SPP_read_record(ssl, buf, BUFSIZZ, &slice, &ctx);
		}
	
		if (strcmp(proto, "ssl") == 0){
			r = SSL_read(ssl, buf, BUFSIZZ);
		}

		if (SSL_get_error(ssl, r) == SSL_ERROR_NONE){
		} else {
			berr_exit("SSL read problem");
		}
		
		#ifdef DEBUG
		printf("Request received:\n"); 
		printf("%s\n", buf); 
		#endif

		//Look for the blank line that signals the end of the HTTP header
		if(strstr(buf, "\r\n") || strstr(buf, "\n")){
			break; 
		}
	}

	// Q: do we still want to put Put 200 OK on the wire?
	/*
	char *data = "HTTP/1.0 200 OK\r\n"; 
	sendData(ssl, data, proto); 
	*/

	// Parse filename from HTTP GET
	filename = parse_http_get(buf); 
	int fSize = atoi(filename);
	if (fSize != 0 || filename[0] == '0'){
		#ifdef DEBUG
		printf("[DEBUG] File requested by size <<%d>>\n", fSize);
		#endif
	} else {
		#ifdef DEBUG
		printf("[DEBUG] File requested by name <<%s>>\n", filename); 
		#endif
	}

	// Simple trick to end 
	if (strcmp(filename, "-1") == 0){
		#ifdef DEBUG
		printf("[DEBUG] Client requested to end session\n");
		#endif 
		ret_value = -1; 
		shut = true;  	
	}else{
		// Serve requested file either by name or by size  
		if (action == 3){
			if (fSize == 0){
				serveFile(ssl, filename, proto); 
			} else {
				serveData(ssl, fSize, proto); 
			}
		}
		if (action == 4){
			// convert filename into data size 
			int data_size; 
			sscanf(filename, "%d", &data_size); 

			// serve data with size above 
			serveData(ssl, data_size, proto); 
		}
	}

	// Do not shutdown TLS for browser-like behavior unless requested
	if (shut){
		#ifdef DEBUG
		printf("[DEBUG] Shutdown SSL connection\n");
		#endif 
		// Shutdown SSL - TO DO (check what happens here) 
		r = SSL_shutdown(ssl);
		if( !r ){
			shutdown(s, 1);
			r = SSL_shutdown(ssl);
	    }

		// Verify that all went good 
		switch(r){  
			case 1:
    	   		break; // Success
			case 0:
			case -1:
			default: // Error 
				#ifdef DEBUG 
				printf ("Shutdown failed with code %d\n", r); 
				#endif 
				berr_exit("Shutdown failed");
		}

		// free SSL 
    	SSL_free(ssl);
	
		// Close socket
    	close(s);
	}else{
		#ifdef DEBUG
		printf("[DEBUG] No shutdown since SSL connection might still be used\n");
		#endif
	}
	// All good 
    return ret_value; 
}


// SSL http serve (almost original function) 
static int http_serve_SSL(SSL *ssl, int s){
  
	char buf[BUFSIZZ];
	int r; //len; //len seems useless...
	BIO *io,*ssl_bio;
    
	io = BIO_new(BIO_f_buffer());	
	ssl_bio = BIO_new(BIO_f_ssl());
	BIO_set_ssl(ssl_bio, ssl, BIO_CLOSE);
	BIO_push(io, ssl_bio);
    	
	while(1){
		r = BIO_gets(io, buf, BUFSIZZ-1);
	
		
		if (SSL_get_error(ssl, r) == SSL_ERROR_NONE){
		} else {
			berr_exit("SSL read problem");
		}
		
		//Look for the blank line that signals the end of the HTTP headers //
		if(!strcmp(buf, "\r\n") || !strcmp(buf, "\n")){
			break; 
		}
	}
    
	// Put 200 OK on the wire 
	if((r = BIO_puts (io, "HTTP/1.0 200 OK\r\n")) <= 0){
		err_exit("Write error");
	}

	// Put server name on the wire 
    if((r = BIO_puts (io,"Server: Svarvel\r\n\r\n")) <= 0){
		err_exit("Write error");
	}
	
	if((r=BIO_puts (io,"Server test page\r\n"))<=0){
		err_exit("Write error");
	}
  	
	// Send file index.html -- TO DO, extend to a requested name
	BIO *file;
	static int bufsize = BUFSIZZ;
	int total_bytes = 0, j = 0, file_size = 0; 

	// Determine file size -- TO DO: integration with BIO stuff 
	file_size = calculate_file_size("index.html"); 
	
	// Open requested file 
	if ((file = BIO_new_file("index.html","r")) == NULL){                
		BIO_puts(io, "Error opening file"); // what is text? ERROR
        BIO_printf(io,"Error opening index.html\r\n");
		goto write_error;
	}

	// Put file on the wire 
	for (;;){
		// Read bufsize from requested file 
		int i = BIO_read(file, buf, bufsize);
		if (i <= 0){
			break; 
		}

		// Keep count of bytes sent on the wire 
		total_bytes += i;
		
		// Check if too many losses 
		if (total_bytes > (3 * file_size)){
			total_bytes = 0;
			fprintf(stderr,"RENEGOTIATE\n");
			SSL_renegotiate(ssl); 
		}
		
		// ??
		for (j = 0; j < i; ){
			// After 13 attempts, re-negotate at SSL level 
			static int count = 0; 
			if (++count == 13) { 
				SSL_renegotiate(ssl); 
			} 

			int k = BIO_write(io, &(buf[j]), i-j);
			if (k <= 0){
				if (! BIO_should_retry(io)){
					goto write_error; 
				}else {
					BIO_printf(io, "rewrite W BLOCK\n");
					}
				}else{
					j += k;
				}
			write_error:
				BIO_free(file);
				break; 
			}

		if((r = BIO_flush(io))<0){
			err_exit("Error flushing BIO");
		}
		
		r = SSL_shutdown(ssl);
		if( !r ){
      /* If we called SSL_shutdown() first then
         we always get return value of '0'. In
         this case, try again, but first send a
         TCP FIN to trigger the other side's
         close_notify*/
			shutdown(s,1);
			r = SSL_shutdown(ssl);
    	}
		switch(r){  
			case 1:
        		break; /* Success */
			case 0:
			case -1:
			default:
				#ifdef DEBUG 
				printf ("Shutdown failed with code %d\n", r); 
				#endif 
				berr_exit("Shutdown failed");
		}
    } // end for loop 

    SSL_free(ssl);
    close(s);

    return(0);
  }

// Usage function 
void usage(void){
	printf("usage: wserver -c -o -s\n");
	printf("-c:   protocol requested: ssl, spp.\n");
	printf("-o:   {1=test handshake ; 2=200 OK ; 3=file transfer ; 4=browser-like behavior}\n");
	printf("-s:   content slicing strategy {uni; exp}\n");
	exit(-1);
}


// Main function  
int main(int argc, char **argv){
	int sock, s;
	BIO *sbio;
	SSL_CTX *ctx;
	SSL *ssl;
	int r;
	pid_t pid;
	char *proto;                        // protocol type 
	extern char *optarg;                // user input parameters
	int c;                              // user iput from getopt
	int action = 0;                     // specify client/server behavior (handshake, 200OK, serve file, browser-like) 

	// Handle user input parameters
	while((c = getopt(argc, argv, "c:o:s:")) != -1){
		switch(c){
			// Protocol 
			case 'c':
				if(! (proto = strdup(optarg) )){
					err_exit("Out of memory");
				}
				break; 

			// Client/Server behavior 
			case 'o':
				action = atoi(optarg); 
				break; 

			// Control slicing strategy
			case 's':
				if(! (strategy = strdup(optarg) )){
					err_exit("Out of memory");
				}
				break;
			}
	}

	// Check that input parameters are correct 
	if (argc == 1){
		usage();
	}
	if (action < 1 || action > 4){
		usage(); 
	}
	
	// Logging input parameters 
	#ifdef DEBUG
	printf("[DEBUG] Parameters count: %d\n", argc);
	char *temp_str = "undefined"; 
	if (action == 1)
		temp_str = "handshake_only";  
	if (action == 2)
		temp_str = "200_OK";  
	if (action == 3)
		temp_str = "serve_file";  
	printf("[DEBUG] proto=%s; action=%d (%s)\n", proto, action, temp_str); 
	#endif 

	// Build SSL context
	ctx = initialize_ctx(KEYFILE, PASSWORD, proto);
	load_dh_params(ctx,DHFILE);
   
	// Socket in listen state
	sock = tcp_listen();

	// Wait for client request 
	while(1){
		#ifdef DEBUG
		printf("[DEBUG] Waiting on accept...\n"); 
		#endif
		if((s = accept(sock, 0, 0)) < 0){
			err_exit("Problem socket accept\n");
		}else{
			#ifdef DEBUG
			printf("[DEBUG] Accepted new connection %d\n", sock); 
			#endif
		}
		// fork a new proces 
		if((pid = fork())){
			#ifdef DEBUG
			printf("[DEBUG] Parent process close socket (PID=%d)\n", pid); 
			#endif
			close(s);
			exit(0);
		} else {
			sbio = BIO_new_socket(s, BIO_NOCLOSE);
			ssl = SSL_new(ctx);
			SSL_set_bio(ssl, sbio, sbio);

			// SSL Accept 
			if((r = SSL_accept(ssl) <= 0)){
				berr_exit("SSL accept error");
			} else {
				#ifdef DEBUG
				if (strcmp(proto, "ssl") == 0){ 		
					printf("[DEBUG] SSL accept OK\n"); 
				}else{
					printf("[DEBUG] SPP accept OK\n"); 
				}
				#endif
			}
   			
			// Switch across possible client-server behavior 
			// NOTE: here we can add more complex strategies
			switch(action){

				// Handshake only 
				case 1: 
					break; 

				// Respond with 200 OK
				case 2: 
					http_simple_response(ssl, s, proto);
					break; 

				// Serve some content 
				case 3: 
					http_serve_request(ssl, s, proto, true, action);
					break;
				
				// Serve a browser like behavior 
				case 4:
					/* NOTE
					* This can only serve one connection at a time. 
					* Here we would need to fire a new thread 
					* (or re-think the code) to support multiple SSL connections 
					*/
					while(1){
						if (http_serve_request(ssl, s, proto, false, action) < 0){
							break; 
						}
					}
					break;
 
				// Unknown option 
				default: 
					usage();
					break; 
			} 

		/* exit from process forked -- THIS CAUSE PREMATURE CLOSE ON CLIENT SIDE? 
		#ifdef DEBUG
		printf("[DEBUG] Exit from forked process\n"); 
		#endif
		exit(0);
		*/
		}
	}
	
// Clean context
destroy_ctx(ctx);
	
// Exit
exit(0);
}
