<file_sep>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>	//strlen
#include <sys/socket.h>
#include <arpa/inet.h>	//inet_addr
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <ctype.h>
//    ..... #include <sys/wait.h>

#define MAXPENDING 5
#define MAX_BUFF_LEN 255
int servSock;
int clntSock;

static pid_t child_pid;
static pid_t parent_pid;



void DieWithError(char *errorMessage) {

    perror(errorMessage);
    exit(1);
}



void store_messages(char *reciever, char *sender, char* message) {

    FILE *fp = NULL;
    char _fname[strlen(reciever) + strlen("-sms.txt") + 1];



   
    strcpy(_fname,reciever);
    strcat(_fname,"-sms.txt");

    printf("reciever== %s sender== %s, _fname== %s",reciever,sender,_fname);

    fp = fopen(_fname, "a");
    if (fp == NULL) {

        printf("Could not store message with name:%s", reciever);
        fclose(fp);
        exit(1);
    }
    //create the file
    fputs(reciever, fp);
    fputs(";", fp);
    fputs(sender, fp);
    fputs(";", fp);
    fputs(message, fp);
    fputs("\n", fp);
    fclose(fp);

}


void read_messages(char *fname){

    printf(" *** ENTERED read_messages\n");

    printf(" *** read_messages, fname== %s\n",fname);
    FILE *fp = NULL;
    char *lineptr = NULL;
    char *buffer = NULL;
    char reply [ strlen("There is no such name") +1];
    memset( reply,0, strlen("There is no such name") + 1);
    size_t n = 0;
    ssize_t bread = 0;


    strcpy(reply, "There is no such name");
    fp = fopen(fname, "r");
    if (fp == NULL){
        //no such file name
        printf(" *** read_messages, replying no such name\n");
        send(clntSock,reply, strlen(reply),0);
        return;
    }

    //file exists and can be read
    fp = fopen(fname,"r+");

    //send every message
    bread = getline(&lineptr,&n,fp);
    while(bread > -1){

        if (bread > 0) {

            printf(" *** read_messages, replying with message [%s]...\n",lineptr);
            send(clntSock, lineptr, strlen(lineptr), 0);
            bread = getline(&lineptr, &n, fp);
        }
    }
    if (lineptr == NULL){

        free(lineptr);

        printf(" *** read_messages, replying with Internal Error ...\n");
        memset(reply,0, strlen(reply));
        strcpy(reply, "Internal error");
         send( clntSock,reply, strlen(reply),0 );

        printf(" **** Error in getline\n");
        return ;
    }



    printf(" *** read_messages, replying with NO MORE MESSAGES ...\n");
    strcpy(reply, "NO MORE MESSAGES");
    send( clntSock,reply, strlen(reply),0 );

    free(lineptr);

}




void message_handler(char *buffer) {

    char *verb = NULL;
    char *token = NULL;
    char *reciever = NULL;
    char *sender = NULL;
    char *msg = NULL;
    char replying_buffer[MAX_BUFF_LEN+1];
    memset(replying_buffer,0,MAX_BUFF_LEN+1);

    printf("\n *****  message_handler ... \n");
    printf("buffer= [%s]\n",buffer);

    //convert string to lower case

    token = strtok(buffer, ";");

    int _count = 0;
    //_count < 2 for token to hold "TO"
    while (token != NULL) {

        if (_count == 0)
            verb = token;
        else if (_count == 1)
            reciever = token;
        else if (_count == 2)
            sender = token;
        else if (_count == 3)
            msg = token;

        token = strtok(NULL, ";");

        _count++;
    }


    //deal with errors
    if (verb == NULL){

        printf(" No Verb in message, reply to client...\n ");
        strcpy(replying_buffer, "No verb\n");
        send(clntSock, replying_buffer, strlen(replying_buffer), 0);
        return;
    }

    if ( reciever == NULL){

        printf(" No reciever in message, reply to client...\n ");
        strcpy(replying_buffer, "No reciever\n");
        send(clntSock, replying_buffer, strlen(replying_buffer), 0);
        return;
    }

    // --------  if verb === store then check more

    if (strcmp("store", verb) == 0) {

        printf(" verb=fetch ... check sender, message ...\n");
        if (sender == NULL) {

            printf(" Verb= fetch, no sender...\n ");
            strcpy(replying_buffer, "No sender\n");
            send(clntSock, replying_buffer, strlen(replying_buffer), 0);
            return;
        }

        if (msg == NULL) {

            printf(" Verb= fetch, no message...\n ");
            strcpy(replying_buffer, "No message\n");
            send(clntSock, replying_buffer, strlen(replying_buffer), 0);
            return;
        }

    }

    printf(" *** verb == %s, receiver=%s, sender=%s, msg=%s\n", verb, reciever,sender,msg);

    //must reply with total messages of this user
    if (strcmp("fetch", verb) == 0) {

        printf(" fetch ... replying [Retrieving messages...]...\n");
        strcpy(replying_buffer, "Retrieving messages...\n");
        send(clntSock, replying_buffer, strlen(replying_buffer),0);

        char filename[strlen(reciever) + 9];

        memset(filename,0, strlen(reciever) + 9);
        strcpy(filename,reciever);
        strcat(filename, "-sms.txt");

        printf(" *** BEFORE read_messages filename== %s\n",filename);
        read_messages(filename);

        printf(" fetch ... finished.\n");
    }
    //must write the messages
    else if ( strcmp("store", verb) == 0 ) {

        printf(" store ... replying ...\n");
        strcpy(replying_buffer, "Message accepted and stored:\n");
        send(clntSock,replying_buffer, strlen(replying_buffer),0);
        //store messages
        store_messages(reciever,sender,msg);
        printf(" store ... replyed.\n");

   }else{

        printf(" bad verb ... replying ...\n");
        strcpy(replying_buffer, "Message declined. Bad verb\n");
        send(clntSock,replying_buffer, strlen(replying_buffer),0);
        printf(" bad verb ... replyed.\n");
    }

}

void HandleTCPClient(){


    //initiating buffer
    char buffer[129], reply_buffer[129];
    memset(buffer,0,129);
    memset(reply_buffer,0,129);

    printf("\n HandleTCPClient start servicing client...\n");
    

    //accept message from client
    ssize_t bytes_read = recv(clntSock, buffer, 128, 0);

    if (bytes_read > 0 ) {

        printf("Received message : [%s]\n ", buffer);

       printf("Entering message_handler()");
        message_handler(buffer);

    }
    else
        printf("Error in receiving data from client\n");




    //shutdown client
    shutdown(clntSock,SHUT_WR);

    printf("\n HandleTCPClient ended servicing client...\n");
}




void sigintHandler(int sig_num){

    write(1,"  Caught signal... closing ports and exiting the program..\n",strlen("  Caught signal... closing ports and exiting the program..\n")+1);
    close(servSock);
    close(clntSock);
    _exit(1);

}

int main(int argc , char *argv[])
{


    printf("argc== %d\n", argc);
    if (argc != 2) DieWithError("Error: Expected server port number as argument\n");


    signal(SIGINT, sigintHandler);



    struct sockaddr_in sockServAddr;
    struct sockaddr_in sockClntAddr;
    unsigned short sockServPort;
    unsigned int clntLen;



    sockServPort = atoi(argv[1]);

    if( (servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0){
        DieWithError("socket() failed");
    }

    int enable = 1;
    if (setsockopt(servSock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0) {
        DieWithError("setsockopt(SO_REUSEADDR) failed");
    }



    memset(&sockServAddr, 0, sizeof(sockServAddr));
    sockServAddr.sin_family = AF_INET;
    sockServAddr.sin_port = htons(sockServPort);
    sockServAddr.sin_addr.s_addr = htonl(INADDR_ANY);





    if (bind(servSock, (struct sockaddr *) &sockServAddr, sizeof(sockServAddr)) < 0) {
        DieWithError("bind() failed");
    }


    parent_pid = getpid();
    printf("Socket Server starts listening with pid= %d...\n",parent_pid);

    if(listen(servSock, MAXPENDING) < 0) {
        DieWithError("listen() failed");
    }



#pragma clang diagnostic push
#pragma ide diagnostic ignored "EndlessLoop"
    while(1) {


        clntLen = sizeof(sockClntAddr);
        if ((clntSock = accept(servSock, (struct sockaddr *) &sockClntAddr, &clntLen)) < 0) {
            DieWithError("accept() failed");
        }

        //fork for multiple clients
        child_pid = fork();

        if ( child_pid == 0 ){
            // we are in child now

            //close parent socket, we dont need in child
            close(servSock);

            pid_t my_pid = getpid();
            printf("Child created with pID= %d, while parent is: %d\n\n", my_pid, parent_pid);
            // here we should process clients request.....

            printf("Handling client %s\n", inet_ntoa(sockClntAddr.sin_addr));

            printf("Entering HandleTCPClient()...\n");
            HandleTCPClient() ;

            close(clntSock);

            printf(" *** child :: socket closed, exiting...\n");

            exit(0);

        }
        else if(parent_pid > 0 ) {
            printf("we are in Father. child's pid is %d\n", parent_pid);
        }
        else if (parent_pid == -1){

            printf("Could not fork()");
            close(clntSock);
            exit(1);
        }



    }


    printf("Closing sockets\n");
    close(servSock);

    return 0;
}<file_sep># Message_Client-Server
Messaging Client - Server application

## Message Socket Server (server.c)
- Uses TCP/IP (stream socket)
- Requieres:
  1. 1 command parameter
  2. The port number to bind to
- Binds on **ANY** IP address of it's host (and on local host, 127.0.0.1)
- Uses fork() in order to serve multiple clients stimuntaniously 
- Uses a buffer of 255 bytes (global macro #define MAX_BUFF_LEN 255)
- Traps **Ctr+C** from console so that before the server terminates, the sockets       will be closed
- The protocol which is used on Application level for the connection  between server and client is the following:
>VERB;reciepient[;sender;message] (comma delimited line)  
wheres:
 - If verb is "fetch", it means: "fetch every message for the following reciepient"
 - If verb is "strore", it means: "store the message with reciepient, sender, message"  
  So, when the client (for example: with username == george) wants to send a message to user Kyriakos, he will have to send the following string: "store;Kyriakos;george;hi Kyriakos"  
    
    
  >Also, when the client (for example username == george) wants to see his messages, he has to type the following string: fetch;george  

## Server Operation
- When the server binds and listens on IP, it waits theconnection of a client
- When a client connects, the server must open a socket again with the server and send it's message. After serving the client, server's socket close  
  
By doing so, server doesn't get on blocking mode if a client fails or be late to inform that it's messages have finished.


## Message client (cleint.c)
- Uses TCP/IP (stream socket)
- Requires:
  1. IP address of the server
  2. The number of port that the server will listen to
- Has a menu with 3 operations such as:
  1. Send message
  2. Read message
  3. Exit


## Client operation
According to the server's mode of operation and the predefined client's protocol, for each request to the server creates a socket ( connect() ), sends the request ( send() ) and takes the answer. Then the client closes the socket and returns to menu.

  

<file_sep>
#include <stdio.h>      /* for printf() and fprintf() */
#include <stdlib.h>     /* for atoi() and exit() */
#include <string.h>	    /* for memset() strlen  */
#include <sys/socket.h> /* for socket(), bind(), connect(), recv() and send() */
#include <arpa/inet.h>	/* for sockaddr_in and inet_ntoa() inet_addr */ 
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>     /* for close() */
#include <sys/time.h>

#include <errno.h>

#include <signal.h>    /* for signals */
#include <sys/wait.h> /* for waitpid() */


#define PORT 5129
#define DEF_PROTO  SOCK_STREAM
#define GET_SMS_VERB "fetch"
#define SEND_SMS_VERB "store"
#define RECEIVEBUFFSIZE 128
#define BUFFER_SIZE 1024


void DieWithError(char *errorMessage) {

    perror(errorMessage);
    exit(1);
}



void sendSms( char * serveridaddress, unsigned short port, char * username ){

    printf(" ** sendSMS called...\n");

    //establish communication with the server
    struct sockaddr_in server;
    server.sin_addr.s_addr = inet_addr(serveridaddress);
    server.sin_family = AF_INET;
    server.sin_port = htons( port );



    int s ;
    int socket_type = DEF_PROTO;
    if((s = socket(AF_INET , socket_type , 0 )) < 0 )
    {
        printf(" sendSms: ERROR Could not create socket.");
        return ;
    }
    printf(" sendSms: Socket created.\n");

    printf(" sendSms: Connecting to sms server...");
    if (connect(s , (struct sockaddr *)&server , sizeof(server)) < 0)
    {
        printf(" sendSms: connect error");
        return;
    }
    printf(" sendSms: Connected. \n");



    //read stdin
    char *buffer = NULL;
    char *to =NULL ;
    char message[255];

    //catch previous enter
   getchar();

    printf(" Type the receipient (50chars max): ");
    size_t n = 0;
    n = getline(&to,&n,stdin);
    if(n<1) {
        printf(" failed to read line for receipient !");
        return;
    }
    to[strlen(to)-1]=0; // clear LF at the end

    //get message
    printf(" Type your sms: ");
    n = 0;
    n = getline(&buffer,&n,stdin);
    if(n<1) {
        printf(" failed to read line for sms !");
        return;
    }
    buffer[strlen(buffer)-1]=0; // clear LF at the end

    if (n >= BUFFER_SIZE - strlen(buffer) ) {
        printf(" Message too long\n");
        return;
    }

    //create the message to send to server
    sprintf(message, "%s;%s;%s;%s",SEND_SMS_VERB,to,username,buffer);
    printf(" sendSms: sending message [%s] \n", message);


    //Receive a reply from the server
    char server_reply[8000];
    memset(server_reply,0,8000);

    char recvbuff[RECEIVEBUFFSIZE+1];
    memset(recvbuff,0,RECEIVEBUFFSIZE+1);


    if( send(s , message , strlen(message) , 0) < 0)		// == SOCKET_ERROR
    {
        printf(" sendSms: Send failed");
        return ;
    }
    printf(" sendSms: Sms sent succesfully.\n");

    printf("============================================================= receiving reply ...\n");
    int recv_size;
    while( (recv_size = recv(s , recvbuff , RECEIVEBUFFSIZE , 0)) > 0 )
        // if((recv_size = recv(s , server_reply , 8000 , 0)) == SOCKET_ERROR)
    {
        //Add a NULL terminating character to make it a proper string before printing
        recvbuff[recv_size] = '\0';
        printf(" receiveSms: received %d bytes:[%s]\n", recv_size, recvbuff);
        strcat(server_reply, recvbuff);
        // ??? if( stricmp(verb,  "sendsms") == 0 ) break;
    }
    printf("============================ reception completed.\n");
    printf(" sendSms: Total server reply:\n");
    printf("%s\n",server_reply);
    // close socket and cleanup
    printf(" sendSms: Closing socket and exiting... \n");
    close(s);
    printf("============================ \n socket closed. End\n");

    free(buffer);
    return;
}


void receiveSms( char * serveridaddress, unsigned short port, char * username ){

    printf(" ** receiveSMS called...\n");
    struct sockaddr_in server;
    // SOCKET s = INVALID_SOCKET;
    server.sin_addr.s_addr = inet_addr(serveridaddress);
    server.sin_family = AF_INET;
    server.sin_port = htons( port );

    int socket_type = DEF_PROTO;
    int iResult;
    char message[255];

    int s ;
    if((s = socket(AF_INET , socket_type , 0 )) < 0 )
    {
        printf(" receiveSms: ERROR Could not create socket.");
        return ;
    }
    printf(" receiveSms: Socket created.\n");

    //Connect to remote server
    printf(" receiveSms: Connecting to sms server...");
    if (connect(s , (struct sockaddr *)&server , sizeof(server)) < 0)
    {
        printf(" receiveSms: connect error");
        return;
    }
    printf(" receiveSms: Connected. \n");

    sprintf(message, "%s;%s", GET_SMS_VERB, username );
    printf(" receiveSms: sending message [%s] \n", message);

    //Receive a reply from the server
    char server_reply[8000];
    memset(server_reply,0,8000);

    char recvbuff[RECEIVEBUFFSIZE+1];
    memset(recvbuff,0,RECEIVEBUFFSIZE+1);


    if( send(s , message , strlen(message) , 0) < 0)		// == SOCKET_ERROR
    {
        printf(" receiveSms: Send failed");
        return ;
    }
    printf(" receiveSms: Data Send.\n");

    printf("============================================================= receiving ...\n");
    int recv_size;
    while( (recv_size = recv(s , recvbuff , RECEIVEBUFFSIZE , 0)) > 0 )
    {
        //Add a NULL terminating character to make it a proper string before printing
        recvbuff[recv_size] = '\0';
        printf(" receiveSms: received %d bytes:[%s]\n", recv_size, recvbuff);
        strcat(server_reply, recvbuff);
    }
    
    printf("============================================================= reception completed.\n");
    printf(" receiveSms: Total server reply:\n");
    printf("%s\n",server_reply);
    // close socket and cleanup
    printf(" receiveSms: Closing socket and exiting... \n");
    close(s);
    printf("=============================================================\n socket closed. End\n");

    return;
}
  

int main(int argc , char *argv[])
{

    char username[50];
    char * serveridaddress;
    char * serverport;
    unsigned short port = PORT ;

    if( argc < 3) {
        printf("\n Bad client execution parameters !\n");
        printf(" Usage: ./client server_ip_address server_port \n");
        printf(" Exiting\n");
        return(1);
    }

    serveridaddress = argv[1];
    serverport = argv[2];
    port = atoi(argv[2]);

    memset(username,0,50);
    printf("\n ===== sms Socket Client ===== \n");
    printf(" by <NAME>.: 2022201900219\n\n");
    printf(" Enter username to continue (up to 50 chars):");
    scanf(" %s", username);

    int menuchoice=0;
    while(menuchoice!=3) {
        printf("\n ===== sms Socket Client ===== \n");
        printf(" using serverer %s:%d, username:%s \n",serveridaddress,port,username);
        printf(" Choices are:\n");
        printf(" 1. Send sms \n");
        printf(" 2. Receive smses \n");
        printf(" 3. Quit \n");
        printf(" Enter your choice: ");
        scanf(" %d", &menuchoice);


        if(menuchoice==3) break;


        if(menuchoice==1)  sendSms( serveridaddress,port,username );


        if(menuchoice==2)  receiveSms( serveridaddress,port,username );
        


    }
    printf("\n sms Client Program Finished.\n");
    return 0;
}


