632 lines
16 KiB
C
632 lines
16 KiB
C
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <getopt.h>
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <openssl/ssl.h>
|
|
#include <errno.h>
|
|
#include <wait.h>
|
|
|
|
// Local Includes
|
|
#include "httpStruct.h"
|
|
#include "socketHelp.h"
|
|
#include "returnRequest.h"
|
|
#include "server.h"
|
|
#include "utils.h"
|
|
|
|
#define WEB_ROOT "/var/www/html/"
|
|
//#define WEB_ROOT "content/"
|
|
#define BUFF_READ 1024
|
|
|
|
static int verbose_flag = 0;
|
|
bool enableHTTPS = 0;
|
|
|
|
static int timeout = 0;
|
|
|
|
int printDebug(char message[]) {
|
|
if (verbose_flag == 1) {
|
|
printf("[Debug] %s\n", message);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
char *php_cgi(char *sPath, struct HTTPRequest *r) {
|
|
int phpPipe[2];
|
|
char *buf = NULL;
|
|
size_t bufLen = 1024;
|
|
|
|
buf = malloc(bufLen);
|
|
pipe(phpPipe);
|
|
|
|
pid_t pid;
|
|
int status = 0;
|
|
pid = fork();
|
|
|
|
if (pid == 0) { // Child fork
|
|
char script[500];
|
|
char *queryString = NULL;
|
|
close(phpPipe[0]);
|
|
dup2(phpPipe[1], STDOUT_FILENO);
|
|
strcpy(script, "SCRIPT_FILENAME=");
|
|
strcat(script, WEB_ROOT);
|
|
strcat(script, sPath);
|
|
putenv("GATEWAY_INTERFACE=CGI/1.1");
|
|
putenv(script);
|
|
putenv("REDIRECT_STATUS=true");
|
|
putenv("SERVER_PROTOCOL=HTTP/1.1");
|
|
putenv("REMOTE_HOST=127.0.0.1");
|
|
if (!strcmp(r->requestType, "POST")) {
|
|
putenv("REQUEST_METHOD=POST");
|
|
char conLenString[256];
|
|
sprintf(conLenString, "CONTENT_LENGTH=%zu", r->requestBodyLen);
|
|
putenv(conLenString);
|
|
putenv("CONTENT_TYPE=application/x-www-form-urlencoded");
|
|
queryString = malloc(r->requestBodyLen + 24);
|
|
sprintf(queryString, "QUERY_STRING=%s", r->requestBody);
|
|
putenv(queryString);
|
|
|
|
// Starting fork to pipe stdin into php-cgi
|
|
int phpPipe2[2];
|
|
pipe(phpPipe2);
|
|
pid_t pid2;
|
|
pid2 = fork();
|
|
|
|
if (pid2 == 0) { // Child fork
|
|
close(phpPipe2[0]);
|
|
dup2(phpPipe2[1], STDOUT_FILENO);
|
|
printf("%s", r->requestBody);
|
|
close(phpPipe2[1]);
|
|
exit(EXIT_SUCCESS);
|
|
} else if (pid < 0) { // Error forking
|
|
printDebug("Error in stdin php frok");
|
|
} else { // Parent fork
|
|
close(phpPipe[1]);
|
|
dup2(phpPipe2[0], STDIN_FILENO);
|
|
execlp("/usr/bin/php-cgi", "php-cgi", NULL);
|
|
}
|
|
} else {
|
|
queryString = malloc(strlen(r->requestVars) + 24);
|
|
sprintf(queryString, "QUERY_STRING=%s", r->requestVars);
|
|
putenv(queryString);
|
|
putenv("REQUEST_METHOD=GET");
|
|
execl("/usr/bin/php-cgi", "php-cgi", NULL);
|
|
}
|
|
} else if (pid < 0) { // Error forking
|
|
printDebug("Error forking php exec");
|
|
} else { // Parent fork
|
|
size_t buffCount;
|
|
close(phpPipe[1]);
|
|
do {
|
|
buffCount = read(phpPipe[0], buf, BUFF_READ);
|
|
if (strlen(buf) == bufLen) {
|
|
bufLen *= 2;
|
|
buf = realloc(buf, bufLen);
|
|
}
|
|
} while (buffCount == 0);
|
|
do {
|
|
waitpid(pid, &status, WUNTRACED);
|
|
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
|
|
}
|
|
|
|
close(phpPipe[0]);
|
|
if (status != 0) {
|
|
return NULL;
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
int parseHTTPRequest(unsigned char *buffer, struct HTTPRequest *r) {
|
|
char temp[1]; // Used to check newlines
|
|
char *token = calloc(8, sizeof(char));
|
|
int line = 0;
|
|
int contentCheck = 0;
|
|
unsigned char *checkLine = calloc(1000, sizeof(unsigned char));
|
|
unsigned char *logLine = malloc(sizeof(unsigned char));
|
|
char * varCheck;
|
|
|
|
// Creating empty requestBody
|
|
r->requestBody = calloc(8, sizeof(char));
|
|
r->requestBodyLen = 0;
|
|
|
|
for (int i = 0; i <= strlen((char *)buffer); i++) {
|
|
temp[0] = buffer[i];
|
|
// Checking for newline character OR end of string
|
|
if (((!strcmp(temp, "\n")) && (i != 0)) || (i == strlen((char *)buffer))) {
|
|
// Config Check
|
|
if (line == 0) { // Grabbing first line for type parsing
|
|
logLine = calloc(strlen((char *)checkLine), sizeof(char));
|
|
strcpy((char *)logLine, (char *)checkLine);
|
|
token = strtok((char *)checkLine, " ");
|
|
// HTTP Request Type
|
|
if ((!strcmp(token, "GET")) || (!strcmp(token, "POST")) ||
|
|
(!strcmp(token, "PUT")) || (!strcmp(token, "DELETE")) ||
|
|
(!strcmp(token, "CONNECT")) || (!strcmp(token, "HEAD"))) {
|
|
// Grabbing HTTP Request Type
|
|
r->requestType = malloc(strlen(token));
|
|
strcpy(r->requestType, token);
|
|
// Grabbing HTTP Request Dir
|
|
token = strtok(NULL, " ");
|
|
varCheck = strchr(token, '?');
|
|
if (varCheck != NULL) {
|
|
*varCheck = ' ';
|
|
}
|
|
sscanf(token, "%ms %ms", &r->requestDir, &r->requestVars);
|
|
// Grabbing HTTP Request Version
|
|
token = strtok(NULL, "");
|
|
token[strlen(token) - 1] = '\0'; // Fixing version end char
|
|
r->requestVersion = malloc(strlen(token));
|
|
strcpy(r->requestVersion, token);
|
|
} else { // First line contains unsupported request
|
|
free(logLine);
|
|
free(checkLine);
|
|
return 2;
|
|
}
|
|
// Log Request
|
|
PrintLog(logLine);
|
|
} else { // Gather information on >first line
|
|
if (contentCheck) { // Once content check is set to one everything after is part of the body
|
|
r->requestBody = realloc(r->requestBody,
|
|
(strlen((char *)checkLine) + strlen((char *)r->requestBody) + 1));
|
|
strcat((char *)r->requestBody, (char *)checkLine);
|
|
// Adding newline to requestBody
|
|
strcat((char *)r->requestBody, "\n");
|
|
r->requestBodyLen += strlen((char *)checkLine);
|
|
} else { // Information parsing !content
|
|
if (strlen((char *)checkLine) == 1) { // Looking for blank empty line to end header info
|
|
contentCheck = 1;
|
|
}
|
|
token = strtok((char *)checkLine, ":");
|
|
// Host Check
|
|
if (!strcmp(token, "Host")) {
|
|
token = strtok(NULL, "");
|
|
r->requestHost = malloc(strlen(token));
|
|
strcpy(r->requestHost, token);
|
|
} else if (!strcmp(token, "Content-Type")) {
|
|
token = strtok(NULL, ":");
|
|
r->requestConType = malloc(strlen(token));
|
|
strcpy(r->requestConType, token);
|
|
} else if (!strcmp(token, "Content-Length")) {
|
|
token = strtok(NULL, ":");
|
|
if (token == NULL) {
|
|
printDebug("Content-length parsing error");
|
|
return -1;
|
|
}
|
|
r->requestConLen = malloc(strlen(token));
|
|
strcpy(r->requestConLen, token);
|
|
}
|
|
}
|
|
}
|
|
if (strlen((char *)checkLine) > 0) {
|
|
// Clear checkLine
|
|
memset(checkLine,0,strlen((char *)checkLine));
|
|
}
|
|
line++;
|
|
} else {
|
|
strcat((char *)checkLine, temp);
|
|
}
|
|
}
|
|
|
|
if (strlen(r->requestType) == 0) {
|
|
free(logLine);
|
|
free(checkLine);
|
|
return -1;
|
|
}
|
|
|
|
free(logLine);
|
|
free(checkLine);
|
|
return 0;
|
|
}
|
|
|
|
int handleGetRequest(int socket, struct HTTPRequest *r, SSL *ssl) {
|
|
char errResponse[256];
|
|
char ch;
|
|
size_t size = 8;
|
|
int i = 0;
|
|
unsigned char *fileContent = calloc(size, sizeof(unsigned char));
|
|
FILE *fp;
|
|
char *workingReqDir;
|
|
|
|
char *phpReturn = NULL;
|
|
char phpEnd[5] = ".php";
|
|
bool endsWithPhp = false;
|
|
if (strlen(phpEnd) <= strlen(r->requestDir)) {
|
|
for (int i = 0; i < strlen(phpEnd); i++) {
|
|
if (r->requestDir[i + strlen(r->requestDir) - strlen(phpEnd)] != phpEnd[i]) {
|
|
endsWithPhp = false;
|
|
break;
|
|
}
|
|
endsWithPhp = true;
|
|
}
|
|
}
|
|
|
|
if (endsWithPhp) {
|
|
phpReturn = php_cgi(r->requestDir, r);
|
|
if (phpReturn != NULL) {
|
|
return returnPHPRequest(socket, phpReturn, ssl);
|
|
} else {
|
|
return return500Request(socket, ssl);
|
|
}
|
|
}
|
|
|
|
// If requesting root directory change to index.html
|
|
if (!strcmp(r->requestDir, "/")) {
|
|
workingReqDir = "index.html";
|
|
} else {
|
|
workingReqDir = r->requestDir;
|
|
}
|
|
char *reqDir = calloc((strlen(WEB_ROOT) + strlen(workingReqDir) + 1), sizeof(char));
|
|
|
|
sprintf(reqDir, "%s%s", WEB_ROOT, workingReqDir);
|
|
|
|
fp = fopen(reqDir, "r");
|
|
|
|
if (fp == NULL) {
|
|
sprintf(errResponse, "Error opening file: %s", workingReqDir);
|
|
printDebug(errResponse);
|
|
return404Request(socket, ssl);
|
|
return -1;
|
|
}
|
|
|
|
while((ch = fgetc(fp)) != EOF) {
|
|
if (i == size) {
|
|
size *= 2;
|
|
fileContent = realloc(fileContent, size);
|
|
}
|
|
fileContent[i] = ch;
|
|
i++;
|
|
}
|
|
|
|
return200Request(socket, fileContent, ssl);
|
|
|
|
fclose(fp);
|
|
free(reqDir);
|
|
free(fileContent);
|
|
return 0;
|
|
}
|
|
|
|
int handlePUTRequest(int socket, struct HTTPRequest *r, SSL *ssl) {
|
|
FILE *fp;
|
|
char *reqDir;
|
|
char * workingReqDir;
|
|
char errResponse[256];
|
|
|
|
if (!strcmp(r->requestDir, "/")) {
|
|
workingReqDir = "index.html";
|
|
} else {
|
|
workingReqDir = r->requestDir;
|
|
}
|
|
|
|
reqDir = calloc(strlen(WEB_ROOT) + strlen(workingReqDir), sizeof(char));
|
|
sprintf(reqDir, "%s%s", WEB_ROOT, workingReqDir);
|
|
|
|
fp = fopen(reqDir, "w");
|
|
if (fp == NULL) {
|
|
sprintf(errResponse, "Error opening file: %s", workingReqDir);
|
|
printDebug(errResponse);
|
|
return return404Request(socket, ssl);
|
|
}
|
|
|
|
fprintf(fp, "%s", r->requestBody);
|
|
|
|
free(reqDir);
|
|
fclose(fp);
|
|
return return201Request(socket, r->requestBody, ssl);
|
|
}
|
|
|
|
int handleDELETERequest(int socket, struct HTTPRequest *r, SSL *ssl) {
|
|
char *reqDir;
|
|
char * workingReqDir;
|
|
char logLine[256];
|
|
|
|
if (!strcmp(r->requestDir, "/")) {
|
|
workingReqDir = "index.html";
|
|
} else {
|
|
workingReqDir = r->requestDir;
|
|
}
|
|
|
|
reqDir = calloc(strlen(WEB_ROOT) + strlen(workingReqDir), sizeof(char));
|
|
sprintf(reqDir, "%s%s", WEB_ROOT, workingReqDir);
|
|
|
|
if (remove(reqDir) == 0) {
|
|
sprintf(logLine, "Deleted file");
|
|
free(reqDir);
|
|
return return200Request(socket, NULL, ssl);
|
|
} else {
|
|
printDebug("Failed to delete file");
|
|
free(reqDir);
|
|
if (errno == 1) { // Permission denided
|
|
return return403Request(socket, ssl);
|
|
} else { // Catch all (likely file != exist)
|
|
return return404Request(socket, ssl);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int handlePOSTRequest(int socket, struct HTTPRequest *r, SSL *ssl) {
|
|
char *phpReturn = NULL;
|
|
// Supported data types application/x-www-form-urlencoded application/json
|
|
if (r->requestConLen == NULL) { // Return 411 if length var not specified
|
|
printDebug("Content Length was not sent in POST request");
|
|
return return411Request(socket, ssl);
|
|
}
|
|
|
|
if (r->requestConType != NULL) {
|
|
if (!strcmp(r->requestConType, "application/x-www-form-utlencoded") == 0) {
|
|
printDebug("Application From Selected");
|
|
} else {
|
|
printDebug("Content will likely get parsed wrong");
|
|
}
|
|
}
|
|
|
|
char phpEnd[5] = ".php";
|
|
bool endsWithPhp = false;
|
|
if (strlen(phpEnd) <= strlen(r->requestDir)) {
|
|
for (int i = 0; i < strlen(phpEnd); i++) {
|
|
if (r->requestDir[i + strlen(r->requestDir) - strlen(phpEnd)] != phpEnd[i]) {
|
|
endsWithPhp = false;
|
|
break;
|
|
}
|
|
endsWithPhp = true;
|
|
}
|
|
}
|
|
|
|
if (endsWithPhp) {
|
|
phpReturn = php_cgi(r->requestDir, r);
|
|
if (phpReturn != NULL) {
|
|
return returnPHPRequest(socket, phpReturn, ssl);
|
|
}
|
|
} else {
|
|
return return200Request(socket, NULL, ssl);
|
|
}
|
|
return return500Request(socket, ssl);
|
|
}
|
|
|
|
int handleRequest(unsigned char buffer[], int socket, SSL *ssl) {
|
|
struct HTTPRequest r; // Holds relevant HTTP request information
|
|
r.requestConLen = malloc(sizeof(char));
|
|
r.requestConType = NULL;
|
|
int checkerr = 0;
|
|
|
|
// Grabbing relevant information out of request
|
|
checkerr = parseHTTPRequest(buffer, &r);
|
|
if (checkerr != 0) { // Checking for HTTP parsing error
|
|
printDebug("Error parsing...");
|
|
if (checkerr == -1) {
|
|
printDebug("Error reading request, returning empty 500");
|
|
return500Request(socket, ssl);
|
|
} else {
|
|
printDebug("Error parsing, returning 501");
|
|
return501Request(socket, ssl);
|
|
}
|
|
} else {
|
|
checkerr = checkHTTPVersion(r.requestVersion);
|
|
if (checkerr != 0) {
|
|
return505Request(socket, ssl);
|
|
} else {
|
|
if (!strcmp(r.requestType, "GET")) {
|
|
handleGetRequest(socket, &r, ssl);
|
|
} else if (!strcmp(r.requestType, "POST")) {
|
|
handlePOSTRequest(socket, &r, ssl);
|
|
} else if (!strcmp(r.requestType, "PUT")) {
|
|
handlePUTRequest(socket, &r, ssl);
|
|
} else if (!strcmp(r.requestType, "DELETE")) {
|
|
handleDELETERequest(socket, &r, ssl);
|
|
} else if (!strcmp(r.requestType, "CONNECT")) {
|
|
return200Request(socket, NULL, ssl);
|
|
} else if (!strcmp(r.requestType, "HEAD")) {
|
|
return200Request(socket, NULL, ssl);
|
|
} else {
|
|
return500Request(socket, ssl);
|
|
}
|
|
}
|
|
}
|
|
|
|
free(r.requestConLen);
|
|
return 0;
|
|
}
|
|
|
|
void timeoutChild(int sig) {
|
|
timeout = 1;
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
struct sockaddr_in address;
|
|
int server_fd, new_socket;
|
|
int port = 0; // Define what port server listens on
|
|
int checkerr = 0; // Used for error checking
|
|
int addrlen = sizeof(address);
|
|
|
|
char *certFile = malloc(sizeof(char));
|
|
char *privKeyFile = malloc(sizeof(char));
|
|
certFile[0] = '\0';
|
|
privKeyFile[0] = '\0';
|
|
|
|
uint32_t listenAddrNum = -1;
|
|
char *listenAddr = malloc(sizeof(char));
|
|
listenAddr[0] = '\0';
|
|
|
|
SSL_CTX *ctx = NULL;
|
|
|
|
size_t bufSize = BUFF_READ;
|
|
unsigned char *buffer = calloc(bufSize, sizeof(unsigned char));
|
|
|
|
// Setting up options
|
|
static const struct option long_options[] = {
|
|
{"help", no_argument, NULL, 'h'},
|
|
{"port", required_argument, NULL, 'p'},
|
|
{"listen", required_argument, NULL, 'l'},
|
|
{"cert", required_argument, NULL, 'c'},
|
|
{"privkey", required_argument, NULL, 'k'},
|
|
{"verbose", no_argument, &verbose_flag, 1},
|
|
{0, 0, 0, 0}
|
|
};
|
|
|
|
const char* usage =
|
|
"Usage: seaweb [options]\n\n"
|
|
" -h --help\t\t\tShows this message\n"
|
|
" -p --port\t\t\tStarts webserver on passed port\n"
|
|
" -l --listen\t\t\tDefines what addr to listen on (default 0.0.0.0)\n"
|
|
" -c --cert\t\t\tPath to certificate\n"
|
|
" -k --privkey\t\t\tPath to private key\n"
|
|
"\n"
|
|
"\n"
|
|
" --verbose\t\t\tPrints debug messages\n"
|
|
"\n";
|
|
|
|
int c;
|
|
while (1) {
|
|
int option_index = 0;
|
|
c = getopt_long(argc, argv, "hp:l:c:k:", long_options, &option_index);
|
|
if(c == -1) { // Break if no more options are present to parse
|
|
break;
|
|
}
|
|
switch(c) {
|
|
case 'h':
|
|
printf("%s", usage);
|
|
exit(EXIT_SUCCESS);
|
|
case 'p':
|
|
sscanf(optarg, "%d", &port);
|
|
break;
|
|
case 'l':
|
|
listenAddr = calloc(strlen(optarg), sizeof(char));
|
|
strcpy(listenAddr, optarg);
|
|
listenAddrNum = addr2sin_addr(listenAddr);
|
|
if (listenAddrNum == -1) {
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
break;
|
|
case 'c':
|
|
certFile = calloc(strlen(optarg), sizeof(char));
|
|
strcpy(certFile, optarg);
|
|
printf("Cert: %s\n", certFile);
|
|
break;
|
|
case 'k':
|
|
privKeyFile = calloc(strlen(optarg), sizeof(char));
|
|
strcpy(privKeyFile, optarg);
|
|
printf("Priv: %s\n", privKeyFile);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Argument checks
|
|
if (port == 0) { // Setting default port if none is passed
|
|
port = 8080;
|
|
}
|
|
if (!((strlen(certFile) > 0) == (strlen(privKeyFile) > 0))) { // XNOR of string lengths
|
|
// Checking what flag was not passed
|
|
if (strlen(certFile)) { // Privkey not passed
|
|
printf("If certificate file is specified, a private key files needs to be specified\n");
|
|
} else if (strlen(privKeyFile)) { // Cert not passed
|
|
printf("If privkey file is specified, a certificate files needs to be specified\n");
|
|
}
|
|
printf("Exiting...\n");
|
|
exit(EXIT_FAILURE);
|
|
} else if ( (strlen(certFile) > 0) && (strlen(privKeyFile) > 0) ) { // Enabling HTTPS
|
|
enableHTTPS = 1;
|
|
}
|
|
|
|
if ( enableHTTPS == 1 ) {
|
|
printf("Opening secure socket on port: %d\n", port);
|
|
checkerr = createSecureSocket(port, &server_fd, &address, &addrlen, listenAddrNum,
|
|
&ctx, certFile, privKeyFile);
|
|
if ( ctx == NULL ) {
|
|
printf("Error creating ctx\n");
|
|
}
|
|
} else {
|
|
printf("Opening socket on port: %d\n", port);
|
|
checkerr = createSocket(port, &server_fd, &address, &addrlen, listenAddrNum);
|
|
}
|
|
|
|
if (checkerr != 0) {
|
|
perror("Error creating socket");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
// Handle incoming requests
|
|
while(1) {
|
|
if ((new_socket = accept(server_fd, (struct sockaddr *)&address,
|
|
(socklen_t *)&addrlen))<0) {
|
|
perror("Accept connection error");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
// Forking process
|
|
pid_t pid;
|
|
pid = fork();
|
|
|
|
if (pid == 0) {
|
|
pid_t pid2;
|
|
pid2 = fork();
|
|
|
|
if (pid2 == 0) {
|
|
bufSize = BUFF_READ;
|
|
if ( enableHTTPS ) {
|
|
size_t buffCont = 1;
|
|
SSL *ssl;
|
|
ssl = SSL_new(ctx);
|
|
SSL_set_fd(ssl, new_socket);
|
|
SSL_accept(ssl);
|
|
do {
|
|
buffCont = SSL_read(ssl, buffer, BUFF_READ);
|
|
if (strlen((char *)buffer) == bufSize) {
|
|
bufSize *= 2;
|
|
buffer = realloc(buffer, bufSize);
|
|
}
|
|
} while(buffCont == 0);
|
|
if (strlen((char *)buffer) != 0) {
|
|
handleRequest(buffer, new_socket, ssl);
|
|
free(buffer);
|
|
} else {
|
|
printDebug("Error reading from socket");
|
|
}
|
|
} else {
|
|
size_t buffCont = 1;
|
|
do {
|
|
buffCont = read(new_socket, buffer, BUFF_READ);
|
|
if (strlen((char *)buffer) == bufSize) {
|
|
bufSize *= 2;
|
|
buffer = realloc(buffer, bufSize);
|
|
}
|
|
} while(buffCont == 0);
|
|
|
|
handleRequest(buffer, new_socket, NULL);
|
|
free(buffer);
|
|
}
|
|
exit(EXIT_SUCCESS);
|
|
} else if (pid2 < 0) {
|
|
printDebug("Error forking supervisor...");
|
|
} else {
|
|
int status;
|
|
signal(SIGALRM, timeoutChild);
|
|
alarm(2);
|
|
pause();
|
|
if (timeout) {
|
|
status = waitpid(pid, NULL, WNOHANG);
|
|
if (status == 0) {
|
|
printDebug("Killing child");
|
|
kill(pid2, 9);
|
|
wait(NULL);
|
|
}
|
|
}
|
|
exit(EXIT_SUCCESS);
|
|
}
|
|
close(new_socket);
|
|
} else if (pid < 0) {
|
|
printDebug("Error forking...");
|
|
} else {
|
|
signal(SIGCHLD, SIG_IGN);
|
|
close(new_socket);
|
|
continue;
|
|
}
|
|
}
|
|
free(privKeyFile);
|
|
free(certFile);
|
|
free(listenAddr);
|
|
free(buffer);
|
|
close(server_fd);
|
|
exit(EXIT_SUCCESS);
|
|
}
|
|
|