Sindbad~EG File Manager

Current Path : /usr/home/beeson/public_html/WebMathXpert/Demos/PolygonDemo/
Upload File :
Current File : //usr/home/beeson/public_html/WebMathXpert/Demos/PolygonDemo/PolygonServer.c

// 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