Skip to content

Instantly share code, notes, and snippets.

@databoose
Created August 18, 2020 08:49
Show Gist options
  • Save databoose/9ece0fc041a368e2b30c61c8e5f05b9c to your computer and use it in GitHub Desktop.
Save databoose/9ece0fc041a368e2b30c61c8e5f05b9c to your computer and use it in GitHub Desktop.
server
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <pthread.h>
#include <stdbool.h>
#include <dirent.h>
#define SA struct sockaddr // cast shortener
#define SERVER_TICKRATE 300 // every 300ms is a tick
#define SERVER_BACKLOG 50 // max 50 clients in queue
#define TIMEOUT_IN 13
#define TIMEOUT_OUT 13
#include "include/logger.h"
#include "include/main.h"
void showhelp()
{
printf("\n");
printf("clearscr : clears screen\n");
printf("showthreads : shows current amount of running threads\n");
printf("ban <ip address> : prevents \n");
printf("help/cmds : shows help/cmds\n");
printf("\n");
}
void thread_store(enum THREAD_STORE_OPTION opt) {
FILE *fptr;
thread_logger *thl_threadstore = new_thread_logger(debug_mode);
if (opt == create) {
LOGF_DEBUG(thl_threadstore, 0, "Creating directory for shared memory storage", "printf");
if (system("mkdir /dev/shm/linkup-varstore") <= -1) {
printf("possible system() error : %s (Error code %d)\n", strerror(errno), errno);
errno = 0; // keeping errno fresh incase current function didn't call it
}
}
if (opt == update) {
remove("/dev/shm/linkup-varstore/thread_count");
if (system(appendcmd) <= -1) { //update file with new value
printf("possible system() error : %s (Error code %d)\n", strerror(errno), errno);
errno = 0; // keeping errno fresh incase current function didn't call it
}
fptr = fopen("/dev/shm/linkup-varstore/thread_count", "r");
while (!feof(fptr))
{
if (fscanf(fptr, "%d", &thread_count) == 0) {
printf("possible fscaf error : %s (Error code %d)\n", strerror(errno), errno);
errno = 0;
}
}
fclose(fptr);
}
clear_thread_logger(thl_threadstore);
}
int lengthofchar(char* tempstring)
{
int cnt;
int charcount;
charcount = 0;
for (cnt=0; tempstring[cnt]; cnt++) {
if (tempstring[cnt] != ' ') {
charcount++;
}
}
return charcount;
}
void cmd_input() {
thread_logger *thl_cmdinput = new_thread_logger(debug_mode);
LOGF_DEBUG(thl_cmdinput, 0 , "cmd input thread started", "printf");
for (;;)
{
// LOGF_DEBUG(thl_cmdinput, 0 , "for ;; ran", "printf");
usleep(600);
char input_cmd[35];
memset(&input_cmd[0], '\0', sizeof(input_cmd));
int scanfret = scanf("%s", input_cmd);
if (scanfret > 1) { LOGF_DEBUG(thl_cmdinput, 0, "Potential error, scanf ret %d", scanfret); }
// printf("input_cmd : %s\n", input_cmd);
if (strstr(input_cmd, "clearscr") != NULL) {
printf("\e[1;1H\e[2J"); // POSIX clearscreen
printf("\n");
}
else if (strstr(input_cmd, "showthreads") != NULL) {
thread_store(update);
printf("Connection threads : %d\n",thread_count - 2); // minus two because we're not including this cmd_input() thread and main thread
printf("\n");
}
else if ((strcmp(input_cmd, "ban") == 0) || (banning == true)) {
if (banning == true) {
strcpy(ipaddr, input_cmd);
LOGF_INFO(thl_cmdinput, 0, "%s banned from opening connection threads", ipaddr, "printf");
banning = false; // we aint banning anymore
}
if (strcmp(input_cmd, "ban") == 0) { banning = true; }
}
else if (strcmp(input_cmd, "help") == 0 || strcmp(input_cmd, "cmds") == 0) { showhelp(); }
else { printf("Command not recognized\n"); }
}
clear_thread_logger(thl_cmdinput);
pthread_exit(0);
}
void set_timeout(int servsockfd, int timeout_input_seconds, int timeout_output_seconds)
{
/*
Setting options :
- SO_RCVTIMO, to set timeout for input operations
- SO_SNDTIMEO, to set timeout for output operations
*/
struct timeval timeout;
timeout.tv_usec = 0;
timeout.tv_sec = 0;
timeout.tv_sec = timeout_input_seconds;
if (setsockopt(servsockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)) < 0) {
printf("setsockopt so_rcvtimeo unsuccessful : %s (Error code %d)\n", strerror(errno), errno);
errno = 0;
}
else
{
timeout.tv_sec = timeout_output_seconds;
if (setsockopt(servsockfd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout)) < 0) {
printf("setsockopt so_sndtimo unsuccessful : %s (Error code %d)\n", strerror(errno), errno);
errno = 0;
}
}
//printf("Timeout set\n");
}
void handle_connection(void* p_clisock) // thread functions need to be a void pointer, and they need to accept any arg variable as a void pointer as well
{
thread_logger *thl = new_thread_logger(debug_mode);
LOGF_DEBUG(thl, 0, "TID : %ld", (pthread_self() / 100000), NULL);
set_timeout(servsockfd, TIMEOUT_IN, TIMEOUT_OUT);
int clisock = *((int*)p_clisock);
free(p_clisock); // we don't need the pointer anymore.
// at this point, do whatever you want to here, the code below is specific to this application
char *verif_recv_str = "Ar4#8Pzw<&M00Nk";
char verif_send_str[110] = "4Ex{Y**y8wOh!T00";
char recv_buf[110];
int recv_status;
recv_status = recv(clisock, (void *)recv_buf, (size_t)sizeof(recv_buf), 0);
if (recv_status == -1) {
LOGF_ERROR(thl, 0, "Error reading from socket : (TID : %ld)\n", (pthread_self() / 100000));
LOGF_ERROR(thl, 0, "%s (%d) \n", strerror(errno), errno);
errno = 0;
close(clisock);
pthread_exit(0);
}
LOGF_DEBUG(thl, 0, "Waiting for verification string from client ... ", "printf");
if (strcmp(verif_recv_str, recv_buf) == 0)
{
LOGF_DEBUG(thl, 0, "Verified", "printf");
memset(&recv_buf[0], '\0', sizeof(recv_buf));
int send_status;
send_status = send(clisock, (void *)verif_send_str, (size_t)lengthofchar(verif_send_str), 0);
if (send_status == -1) {
printf("Error writing to socket : ");
printf("%s (Error code %d) \n", strerror(errno), errno);
errno = 0;
close(clisock);
pthread_exit(0);
}
}
clear_thread_logger(thl);
close(clisock);
pthread_exit(0);
}
int main(enum MAIN_OPTION opt) {
thread_logger *thl = new_thread_logger(debug_mode);
if (opt != skip_to_connloop)
{
thread_store(create);
self_pid = getpid();
sprintf(appendcmd, "ps hH p %d | wc -l > /dev/shm/linkup-varstore/thread_count", self_pid);
servsockfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in serv_addr;
struct sockaddr_in cli_addr;
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(64912);
serv_addr.sin_addr.s_addr = inet_addr("10.0.0.224");
memset(&cli_addr, 0, sizeof(struct sockaddr_in)); //initializing cli_addr struct
if (setsockopt(servsockfd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) < 0) {
LOGF_ERROR(thl, 0, "setsockopt so_reuseaddr unsuccessful : %s (Error code %d)\n", strerror(errno), errno);
errno = 0;
}
LOGF_DEBUG(thl, 0, "Set reuse", NULL);
LOGF_DEBUG(thl, 0, "Binding...", NULL);
int bind_status;
bind_status = bind(servsockfd, (SA*)&serv_addr, sizeof(serv_addr));
if (bind_status == -1) {
LOGF_ERROR(thl, 0, "Bind unsuccessful : %s (Error code %d)", strerror(errno), errno);
errno = 0;
if (errno == 98) {
LOGF_ERROR(thl, 0, "More than one process running maybe?", NULL);
exit(0);
}
}
int listen_status;
LOGF_INFO(thl, 0, "Listening...", NULL);
listen_status = listen(servsockfd, SERVER_BACKLOG); // second param is backlog, aka how many connections can wait in one point in time
if (listen_status == -1) {
LOGF_ERROR(thl, 0, "Listen unsuccessful : %s (Error code %d)\n", strerror(errno), errno);
errno = 0;
}
// user now has input
pthread_t input_thread;
pthread_create(&input_thread, NULL, (void *)cmd_input, NULL);
}
for (;;) {
usleep(SERVER_TICKRATE);
int clisock;
socklen_t cli_addr_size = sizeof(cli_addr);
clisock = accept(servsockfd, (SA*)&cli_addr, &cli_addr_size); // last two parameters should fill an optionable client struct for info
if (clisock >= 0) {
printf("\n");
if (strcmp(inet_ntoa(cli_addr.sin_addr), ipaddr) == 0) { //if banned ip matches ipaddr string
LOGF_DEBUG(thl,0, "Banned IP address %s attempted to connect, refusing to open connection thread", inet_ntoa(cli_addr.sin_addr));
main(skip_to_connloop); // half works, fixme
}
else {
LOGF_INFO(thl, 0, "Connection accepted from : %s:%d", inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port));
pthread_t sckthread;
int *pclient = malloc(sizeof(int));
*pclient = clisock;
pthread_create(&sckthread, NULL, (void *)handle_connection, pclient);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment