Sindbad~EG File Manager
// Original date 8.29.23, author M. Beeson
// after advice from ChatGPT
// 8.30.23 added call to svgPolygon
// 8.30.23 added signal_handler per ChatGPT
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <errno.h>
#include <assert.h>
#include "svgPolygon.h"
#include "uthash.h"
#define PORT 12347
#define MAX_BUFFER_SIZE (1 << 16)
#define MAX_SESSIONID 33 // 32 characters, plus a null terminator
#define MAX_POLYGONS 5
static char buffer[MAX_BUFFER_SIZE];
static char outbuffer[MAX_BUFFER_SIZE];
static int sockfd;
typedef struct doc {
char sessionId[MAX_SESSIONID]; // key
int Polygons[MAX_POLYGONS]; // previously drawn polygons, init to zero
int nPolygons;
UT_hash_handle hh; // makes this structure hashable
} Document;
static Document *AllDocuments = NULL; // initialize hash table
void createDocument( char *sessionId)
// make a new Document (on the heap) and add it to the hash table
{
Document *doc = (Document *) malloc(sizeof(Document));
assert(doc); // malloc worked
strncpy(doc->sessionId,sessionId,MAX_SESSIONID);
doc->nPolygons = 0;
printf("Creating document for %s\n", sessionId);
// Add the document to the hash table
HASH_ADD_STR(AllDocuments, sessionId, doc);
}
void signal_handler(int signo)
{
if (signo == SIGINT || signo == SIGTERM) {
printf("Received termination signal. Closing socket...\n");
close(sockfd); // Close the socket before exiting
exit(0);
}
}
int process_polygon (char *sessionID, char *message, char *param, char *outbuffer)
// handle the polygon message
{ int n;
if(param == NULL)
{
strcpy( outbuffer, "You didn't enter a number > 2 after \"polygon\".");
return 1;
}
int nfields = sscanf(param,"%d", &n);
if ( nfields == 1 && n > 2 )
{
if (svgPolygon(n, 100, outbuffer, MAX_BUFFER_SIZE)== 0)
{
Document *theDoc;
printf("About to hash %s\n", sessionID);
HASH_FIND_STR(AllDocuments,sessionID,theDoc);
assert(theDoc); // it better already be in the hash table
if(theDoc-> nPolygons == MAX_POLYGONS) // move every entry down one, discarding the 0th entry
{
for(int k = 1; k< MAX_POLYGONS;k++)
{ theDoc-> Polygons[k-1] = theDoc-> Polygons[k];
}
--theDoc->nPolygons;
}
theDoc->Polygons[theDoc->nPolygons] = n;
++theDoc->nPolygons;
printf("About to send data\n");
printf("%s\n",outbuffer);
return 0;
}
else
{
printf("SV generation error, \n");
return 1;
}
}
else
{
strcpy( outbuffer, "You didn't enter a number > 2 after \"polygon\".");
return 1;
}
}
/*___________________________________________________________________________*/
int process_polygon_history (char *sessionID, char *message, char *param, char *outbuffer)
// return (in outputbuffer) the array of Polygons from the document, as a comma-separated string
{
Document *theDoc;
HASH_FIND_STR(AllDocuments,sessionID,theDoc);
assert(theDoc); // it better already be in the hash table
outbuffer[0] = 0;
for(int k = 0;k<theDoc->nPolygons; k++)
{ if(k < theDoc->nPolygons)
sprintf(outbuffer + strlen(outbuffer), "%d,", theDoc->Polygons[k]);
else
sprintf(outbuffer + strlen(outbuffer), "%d", theDoc->Polygons[k]); // no comma on last item
}
printf("About to send polygon history:\n");
printf("%s", outbuffer);
return 0;
}
/*___________________________________________________________________________*/
int process_message(char *sessionId, char *message, char *param, char *outbuffer)
// returns 0 for success or nonzero for various errors
{ printf("process_message received %s %s\n", message, param);
if (!strcmp(message, "polygon"))
return process_polygon(sessionId, message, param, outbuffer);
if (!strcmp(message, "polygon_history"))
return process_polygon_history(sessionId, message, param, outbuffer);
return 1;
}
/*___________________________________________________________________________*/
int main() {
struct sockaddr_in serverAddr;
socklen_t addr_size;
static char buffer[MAX_BUFFER_SIZE];
static char outbuffer[MAX_BUFFER_SIZE];
// Create socket
sockfd = socket(AF_INET, SOCK_STREAM, 0);
// Configure server address
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(PORT);
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
memset(serverAddr.sin_zero, '\0', sizeof(serverAddr.sin_zero));
int reuse = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1)
{
perror("setsockopt");
return 1; // Handle the error
}
// Bind socket to address and port
if (bind(sockfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == -1)
{
perror("Socket bind error");
close(sockfd);
return 1;
}
// Listen for incoming connections
if (listen(sockfd, 10) == -1)
{
perror("Socket listen error");
close(sockfd);
return 1;
}
printf("Listening on port %d...\n", PORT);
while (1) {
printf("Top of loop\n");
int newsockfd;
struct sockaddr_in clientAddr;
addr_size = sizeof(clientAddr);
// Accept incoming connection
newsockfd = accept(sockfd, (struct sockaddr*)&clientAddr, &addr_size);
if (newsockfd == -1)
{
perror("Socket accept error");
continue; // Continue to the next iteration
}
printf("Accepted connection\n");
// Set up file descriptors for select
fd_set readSet;
FD_ZERO(&readSet);
FD_SET(newsockfd, &readSet);
// Set up timeout for select (2 seconds)
struct timeval timeout;
timeout.tv_sec = 5; // Seconds
timeout.tv_usec = 0; // Microseconds
// Wait for data with a timeout
int selectResult = select(newsockfd + 1, &readSet, NULL, NULL, &timeout);
if (selectResult == -1)
{
perror("Select error");
close(newsockfd);
continue; // Continue to the next iteration
}
else if (selectResult == 0)
{
// Timeout occurred
printf("Receive timeout\n");
close(newsockfd);
continue; // Continue to the next iteration
}
// Receive data from client
ssize_t dataSize = recv(newsockfd, buffer, sizeof(buffer), 0);
if (dataSize <= 0)
{
perror("Socket receive error");
close(newsockfd);
continue; // Continue to the next iteration
}
// process data
buffer[dataSize] = '\0';
printf("Received data: %s\n", buffer);
char *sessionId = strtok(buffer, "| "); // Get the session ID
char *message = strtok(NULL, "| ");
char *param = strtok(NULL, "| "); // which might be NULL
if (sessionId == NULL || message == NULL)
{
perror("Invalid message format");
close(newsockfd);
continue; // Continue to the next iteration
}
// Is this a new sessionId or not?
Document *storedDoc = (Document *) sizeof(Document);
HASH_FIND_STR(AllDocuments, sessionId, storedDoc); // the first sessionId is the local variable
if (storedDoc == NULL)
{ // new sessionID
createDocument(sessionId);
printf("Created document for %s\n", sessionId);
}
else
{
printf("Found existing document for %s\n", sessionId);
}
int err = process_message(sessionId, message, param, outbuffer);
if(!err)
{
if( send(newsockfd,outbuffer, strlen(outbuffer),0) == -1)
{ perror("Socket send error");
}
}
else
{
printf("Not processed: %s", outbuffer);
}
printf("closing connection\n");
// Close the connection
close(newsockfd);
}
return 0;
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists