From 829c8e16d81ac4f88f192e103b50ea874850696a Mon Sep 17 00:00:00 2001 From: solusipse Date: Fri, 6 Sep 2013 04:01:55 +0200 Subject: [PATCH] first stable version --- Makefile | 15 ++++ README.md | 80 ++++++++++++++++++ fiche.c | 238 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ fiche.h | 46 +++++++++++ 4 files changed, 379 insertions(+) create mode 100644 Makefile create mode 100755 fiche.c create mode 100644 fiche.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f0f7518 --- /dev/null +++ b/Makefile @@ -0,0 +1,15 @@ +# ----------------------------------- +# Fiche MAKEFILE +# https://github.com/solusipse/fiche +# solusipse.net +# ----------------------------------- + +CC=gcc +CFLAGS=-pthread -O2 +prefix=/usr/local + +all: fiche.c + $(CC) -o fiche $(CFLAGS) fiche.c + +install: fiche + install -m 0755 fiche $(prefix)/bin diff --git a/README.md b/README.md index 130f94c..395f70a 100644 --- a/README.md +++ b/README.md @@ -2,3 +2,83 @@ fiche ===== Command line pastebin for sharing terminal output. + +## Installation ## + +1. Clone into repository: + + ``` + https://github.com/solusipse/fiche.git + ``` + +2. Build program: + + ``` + make + ``` + +3. Install: + + ``` + sudo make install + ``` + +## Client-side usage ## + +Self explanatory live examples: + +``` +ls -la | nc localhost 9999 +``` + +``` +cat file.txt | nc someserverrunningfiche.net 1234 +``` + +``` +echo just testing! | nc code.solusipse.net 9999 +``` + +If you already haven't set up your server on localhost, try third line! My server is providing terminal +pastebin server powered by fiche - ```code.solusipse.net``` on port ```9999```. + +- To upload text you need to have netcat installed (to check if netcat is installed, simply type ```nc``` in terminal). + +## Server-side usage ## + +``` +usage: fiche [-bdpqs]. + [-d host_domain.com] [-p port] [-s slug_size] + [-o output_directory] [-b buffer_size] [-q queue_size] +``` + +These are command line arguments. You don't have to provide any, but doing that is recommended. Without them, program +will use these default settings: + +```C +domain = "http://localhost/"; +basedir= "~/code/"; +port = 9999; +slug_size = 4; +buffer_size = 8192; +queue_size = 100; +``` + +### Basic arguments ### + +Most important is providing **basedir** and **domain**. + +Basedir should be **absolute** path to directory where you would like to store text files. + +Domain should be provided in such format ```domain.com```. + +Slug size: ```yourserver.com/SLUG_OF_CHOSEN_LENGTH/```. + +### Parameters for advanced users ### + +- Buffer size +- Queue size + +### License ### + +Fiche is MIT licensed. diff --git a/fiche.c b/fiche.c new file mode 100755 index 0000000..e7c3f5e --- /dev/null +++ b/fiche.c @@ -0,0 +1,238 @@ +/* +Fiche - terminal pastebin +Still in development, not usable! +*/ + +#include "fiche.h" + +int main(int argc, char **argv) +{ + srand((unsigned int) time(0)); + + set_basedir(); + parse_parameters(argc, argv); + startup_message(); + + int listen_socket, address_lenght, optval = 1; + struct sockaddr_in server_address; + + listen_socket = create_socket(); + setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval , sizeof(int)); + + server_address = set_address(server_address); + bind_to_port(listen_socket, server_address); + + while (1) perform_connection(listen_socket); +} + +void *thread_connection(void *args) +{ + char buffer[BUFSIZE]; + int n, client = *(int *)args; + bzero(buffer, BUFSIZE); + + int status = recv(client, buffer, BUFSIZE, 0); + + if (status != -1) + { + char slug[SLUG_SIZE]; + generate_url(buffer, slug); + + char response[strlen(slug) + strlen(DOMAIN) + 2]; + strcpy(response, DOMAIN); + strcat(response, slug); + strcat(response, "/\n"); + write(client, response, strlen(response)); + } + else + { + printf("Invalid connection.\n"); + write(client, "Use netcat.\n", 13); + } + + close(client); + pthread_exit(NULL); + return NULL; +} + +void perform_connection(int listen_socket) +{ + void *status = 0; + pthread_t thread_id; + struct sockaddr_in client_address; + + int address_lenght = sizeof(client_address); + int connection_socket = accept(listen_socket, (struct sockaddr *) &client_address, &address_lenght); + + struct timeval timeout; + timeout.tv_sec = 10; + timeout.tv_usec = 0; + + if (setsockopt (connection_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)) < 0) + error(); + if (setsockopt (connection_socket, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout)) < 0) + error(); + + get_client_address(client_address); + + if (pthread_create(&thread_id, NULL, &thread_connection, &connection_socket) != 0) + error(); + else + pthread_detach(thread_id); + +} + +void display_date() +{ + time_t rawtime; + struct tm *timeinfo; + + time(&rawtime); + timeinfo = localtime(&rawtime); + printf("%s", asctime(timeinfo)); +} + +void get_client_address(struct sockaddr_in client_address) +{ + display_line(); + + struct hostent *hostp; + char *hostaddrp; + + hostp = gethostbyaddr((const char *)&client_address.sin_addr.s_addr, sizeof(client_address.sin_addr.s_addr), AF_INET); + if (hostp == NULL) error(); + + hostaddrp = inet_ntoa(client_address.sin_addr); + if (hostaddrp == NULL) error(); + + display_date(); + printf("Client: %s (%s)\n", hostaddrp, hostp->h_name); +} + +int create_socket() +{ + int lsocket = socket(AF_INET, SOCK_STREAM, 0); + if (lsocket < 0) + error(); + else return lsocket; +} + +struct sockaddr_in set_address(struct sockaddr_in server_address) +{ + bzero((char *) &server_address, sizeof(server_address)); + server_address.sin_family = AF_INET; + server_address.sin_addr.s_addr = htonl(INADDR_ANY); + server_address.sin_port = htons((unsigned short)PORT); + return server_address; +} + +void bind_to_port(int listen_socket, struct sockaddr_in server_address) +{ + if (bind(listen_socket, (struct sockaddr *) &server_address, sizeof(server_address)) < 0) + error(); + if (listen(listen_socket, QUEUE_SIZE) < 0) + error(); +} + +void generate_url(char *buffer, char *slug) +{ + int i; + int time_seed = time(0); + memset(slug, '\0', sizeof(slug)); + + for (i = 0; i <= SLUG_SIZE - 1; i++) + { + int symbol_id = rand_r(&time_seed) % strlen(symbols); + slug[i] = symbols[symbol_id]; + } + + while (create_directory(slug) == -1) + { + int symbol_id = rand() % strlen(symbols); + slug[strlen(slug)] = symbols[symbol_id]; + } + + save_to_file(slug, buffer); +} + +int create_directory(char *slug) +{ + char *directory = malloc(100); + + strcpy(directory, BASEDIR); + strcat(directory, slug); + + mkdir(BASEDIR, S_IRWXU | S_IRGRP | S_IROTH); + int result = mkdir(directory, S_IRWXU | S_IRGRP | S_IROTH); + + free(directory); + + return result; +} + +void save_to_file(char *slug, char *buffer) +{ + char *directory = malloc(strlen(BASEDIR) + strlen(slug) + strlen("/index.html")); + strcpy(directory, BASEDIR); + strcat(directory, slug); + strcat(directory, "/index.html"); + + FILE *fp; + fp = fopen(directory, "w"); + fprintf(fp, "%s", buffer); + fclose(fp); + + printf("Saved to: %s\n", directory); + free(directory); +} + +void set_basedir() +{ + BASEDIR = getenv("HOME"); + strcat(BASEDIR, "/code/"); +} + +void startup_message() +{ + printf("Fiche started listening on port %d.\n", PORT); + printf("Domain name: %s\n", DOMAIN); + printf("Saving files to: %s\n", BASEDIR); +} + +void parse_parameters(int argc, char **argv) +{ + int c; + + while ((c = getopt (argc, argv, "p:b:q:s:d:o:")) != -1) + switch (c) + { + case 'd': + snprintf(DOMAIN, sizeof DOMAIN, "%s%s%s", "http://", optarg, "/"); + break; + case 'p': + PORT = atoi(optarg); + break; + case 'b': + BUFSIZE = atoi(optarg); + printf("Buffer size set to: %d.\n", BUFSIZE); + break; + case 'q': + QUEUE_SIZE = atoi(optarg); + printf("Queue size set to: %d.\n", QUEUE_SIZE); + break; + case 's': + SLUG_SIZE = atoi(optarg); + printf("Slug size set to: %d.\n", SLUG_SIZE); + break; + case 'o': + BASEDIR = optarg; + if((BASEDIR[strlen(BASEDIR) - 1]) != '/') + strcat(BASEDIR, "/"); + break; + default: + printf("usage: fiche [-bdpqs].\n"); + printf(" [-d host_domain.com] [-p port] [-s slug_size]\n"); + printf(" [-o output_directory] [-b buffer_size] [-q queue_size]\n"); + exit(1); + } +} \ No newline at end of file diff --git a/fiche.h b/fiche.h new file mode 100644 index 0000000..c83de63 --- /dev/null +++ b/fiche.h @@ -0,0 +1,46 @@ +/* +Fiche - terminal pastebin +*/ + +#ifndef FICHE_H +#define FICHE_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int BUFSIZE = 8192; +int QUEUE_SIZE = 100; +int PORT = 9999; +int SLUG_SIZE = 4; +char *BASEDIR; +char DOMAIN[128] = "http://localhost/"; +const char *symbols = "abcdefghijklmnopqrstuvwxyz0123456789"; + +int create_socket(); +int create_directory(char *slug); + +void bind_to_port(int listen_socket, struct sockaddr_in serveraddr); +void display_line(){printf("====================================\n");} +void error(){perror("ERROR"); exit(1);} +void display_date(); +void get_client_address(struct sockaddr_in client_address); +void perform_connection(int listen_socket); +void generate_url(char *buffer, char *slug); +void save_to_file(char *buffer, char *slug); +void startup_message(); +void set_basedir(); +void parse_parameters(int argc, char **argv); + +struct sockaddr_in set_address(struct sockaddr_in serveraddr); + +#endif \ No newline at end of file