C File transfer through UDP sockets (linux)

Viewed 105

I'm really new to sockets, and most of the code is written by taking pieces of code and advice from other threads and their answers, so this may be hard to read.

This thread specifically was the one I took most of the code from.

My assignment consists of creating an application that's able to connect to a server, and send and receive messages and files to other clients connected to it. Basically, each machine works as both client and server at the same time, being capable of sending and receiving packets for as long as they're connected to the server.

I'm already able to send and receive messages (strings), however, I'm not yet able to send or receive files, and quite frankly I have no idea how to do so, as we weren't explained much about sockets before being given this assignment.

Just in case, the sockets MUST be UDP. I can't use TCP in this case.

Here's the code:

    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    #include <stdio.h>
    #include <sys/stat.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <sys/socket.h>
    #include <stdlib.h>
    #include <string.h>
    #include <iostream>
    #include <sys/socket.h>
    #include <time.h>
    #include <netinet/in.h>
    #include <arpa/inet.h> // para inet_Addr, etc
    #include <netdb.h> // estructuras
    #include <sys/signal.h>
    #include <ctype.h>
    #include <openssl/md5.h>
    #include "PB.h"
    #include <fcntl.h>
    #include <ctime>
    #include <iomanip>

    #define MAX_LARGO_IP 16
    #define MAX_USPW 25
    #define MAX_LARGO_MENSAJE 255
    #define MAX_NOMBRE_ARCHIVO 20
    #define MAX_LARGO_ARCHIVO 65535
    #define BUFLEN 503

    int fd1;

    using namespace std;

    void printProgress (double percentage);

    unsigned long fsize(char* file)
    {
        FILE * f = fopen(file, "r");
        fseek(f, 0, SEEK_END);
        unsigned long len = (unsigned long)ftell(f);
        fclose(f);
        return len;
    }

    int main(int argc, char * argv[]){
        if (argc < 4)
        {
                cout << "\33[46m\33[31m[ERROR]:" << " Faltan argumentos: port, ipAuth, portAuth.\33[00m\n";
                exit (1);
        }

        // Signal handler
        // *********************************
        struct sigaction sa;
        memset (&sa, 0, sizeof (sa));
        sa.sa_handler = &manejadorSenhales;

        sigaction(SIGINT, &sa, NULL);
        sigaction(SIGTERM, &sa, NULL);
        sigaction(SIGPIPE, &sa, NULL);
        sigaction(SIGSEGV, &sa, NULL);
        sigaction(SIGKILL, &sa, NULL);
        signal(SIGALRM, SIG_IGN);
        // **********************************

        cout << "\33[34mRedes de Computadoras 2018\33[39m: Sistema de Mensajeria.\nEscuchando en el puerto " << argv[1] << ".\nProceso de pid: " << getpid() << ".\n";

        char * user = new(char[MAX_USPW]);  
        char * pass = new(char[MAX_LARGO_MENSAJE]);
        char * buf = new(char[MAX_LARGO_MENSAJE]);
        char * msjAnterior = new(char[MAX_LARGO_MENSAJE]);
        char * mensaje = new(char[MAX_LARGO_MENSAJE]);

        cout << "Usuario: ";
        cin >> user;
        cout << "Clave: ";
        cin >> pass;

        strcpy(mensaje, user);
        strcat(mensaje, "-");


    ///////////////////
    // AUTENTICATION // THIS PART CONNECTS YOU TO THE SERVER //////////////////////////////
    ///////////////////

        int numbytes;
        unsigned long ultimoRemitente = 0;
        strcpy(msjAnterior, "\0"); //inicializo el buffer como vacio

        fd1 = socket(AF_INET, SOCK_STREAM, 0);

        if (fd1 < 0){
            cout << "ERROR: socket()\n";
            exit (0);
        }

        struct hostent *he;
        struct sockaddr_in server;

        socklen_t longitudServer = sizeof(server);

        if ((he=gethostbyname(argv[2]))==NULL){       
            printf("ERROR: gethostbyname()\n");
                exit(0);
        }

        server.sin_family = AF_INET;
        server.sin_port = htons(atoi(argv[3])); 
        server.sin_addr = *((struct in_addr *)he->h_addr);  
        bzero(&(server.sin_zero),8);

        if(connect(fd1, (struct sockaddr *)&server, sizeof(struct sockaddr))==-1){ 
            printf("ERROR: connect()\n");
            exit(0);
        }

        if ((numbytes=recv(fd1,buf,MAX_LARGO_MENSAJE,0)) == -1){  
            printf("ERROR: recv()\n");
                exit(0);
        }

        buf[numbytes-2]='\0';

        if (strcmp(buf, "Redes 2019 - Obligatorio 2 - Autenticacion de Usuarios") != 0){
            printf("ERROR: protocolo incorrecto()\n");
                exit(0);
        }

        mensaje[strlen(mensaje) + 1] = '\n';
        mensaje[strlen(mensaje)] = '\r';

        send(fd1, mensaje, strlen(mensaje),0);

        if ((numbytes=recv(fd1,buf,MAX_LARGO_MENSAJE,0)) == -1){  
            printf("ERROR: recv()\n");
                exit(0);
        }

        buf[numbytes-2]='\0';

        if (strcmp(buf, "NO") == 0){
            printf("ERROR: Autenticacion Incorrecta.\n");
                exit(0);
        }

        if ((numbytes=recv(fd1,buf,MAX_LARGO_MENSAJE,0)) == -1){  
            printf("ERROR: recv()\n");
                exit(0);
        }

        buf[numbytes-2]='\0';

        struct sockaddr_in cliente;
        socklen_t largoCliente = sizeof(cliente);

        // ALL OF THIS IS USED TO SHOW DATE AND TIME OF EACH MESSAGE
        time_t timer, timerNew;       
        tm fechaActual, fechaNew; 
        time(&timer); 
        fechaActual=*(localtime(&timer)); 

        int archivo, n;

        cout << "Bienvenido " << buf << endl;

        close (fd1);

        int pid = fork();

        if (pid < 0){
            cout << "\33[46m\33[31m[ERROR]:" << " Imposible bifurcar.\33[00m\n";
            exit(0);
        }

        if (pid > 0){

    /////////////////
    // SERVER SIDE // WHERE MESSAGES AND FILES ARE RECEIVED ///////////////
    /////////////////

            printf("\33[34mRx\33[39m: Iniciada parte que recepciona mensajes. Pid %d\n", getpid());

            char ipOrigen[MAX_LARGO_IP];
            unsigned int fd_rx;
            char fname[MAX_NOMBRE_ARCHIVO];
            char flen[20];
            char messagef[BUFLEN];
            FILE *fp;
            fd_rx = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
            if(fd_rx < 0){
                cout << "ERROR: socket()\n";
                exit (0);
            }
            server.sin_family = AF_INET;
            server.sin_port = htons(atoi(argv[1])); 
            server.sin_addr.s_addr = INADDR_ANY;
            bzero(&(server.sin_zero),8);

            if(bind(fd_rx,(struct sockaddr*)&server, sizeof(struct sockaddr))){
                cout << "ERROR: bind()\n";
                exit (0);
            }
            while (true)
            {
                //sleep(3);
                if(recvfrom(fd_rx, buf, MAX_LARGO_MENSAJE, 0, (struct sockaddr *)&cliente, &largoCliente) == -1) // Si da error, poner sizeof(server) o &longitudServer 
                        printf("ERROR: 1 recvfrom()\n");
                else
                {
                    time(&timerNew); 
                    fechaNew=*(localtime(&timerNew));
                    // MAKES SURE A MESSAGE ISN'T SENT TWICE IN A SHORT AMOUNT OF TIME
                    if((strcmp(msjAnterior,buf) != 0)   || (fechaNew.tm_sec > fechaActual.tm_sec ) || (ultimoRemitente != cliente.sin_addr.s_addr))
                    {
                        time(&timer);
                        fechaActual=*(localtime(&timer)); 
                        cout << setfill('0');
                        cout << "[" << fechaActual.tm_year + 1900 << "." << setw(2) << fechaActual.tm_mon + 1 << "." << setw(2) << fechaActual.tm_mday
                        << " " << setw(2) << fechaActual.tm_hour << ":" << setw(2) << fechaActual.tm_min << "] " ; // SHOWS DATE AND TIME
                        strcpy(ipOrigen, inet_ntoa(cliente.sin_addr)); 
                        if(strcmp(buf, "peer_discover")==0)
                            cout << "envio de peer discover" << endl;
                        else if (strcmp(buf, "enviar") == 0)
                        {
            ///////////////////////////////////////////////////////////////
            ////// THIS IS WHERE THE FILE TRANSFER PART STARTS ////////////
            ///////////////////////////////////////////////////////////////
                            if(recvfrom(fd_rx, messagef, 20, 0, (struct sockaddr *)&cliente, &largoCliente) == -1)
                                printf("ERROR: 2 recvfrom()\n");
                            memset(messagef, 0, 503);
                            if(recvfrom(fd_rx, messagef, 20, 0, (struct sockaddr *)&cliente, &largoCliente) == -1)
                                printf("ERROR: 3 recvfrom()\n");
                            strcpy(flen, messagef);
                            unsigned long mm = atoi(messagef);
                            fp = fopen(flen, "wb");
                            int itr=1;
                            memset(messagef, 0, 503);
                            while(itr*503 < mm)
                            {
                                if(recvfrom(fd_rx, messagef, 503, 0, (struct sockaddr *)&cliente, &largoCliente) == -1){
                                    printf("ERROR: 4 recvfrom()\n");
                                    exit(0);
                                }
                                fwrite(messagef, 503, 1, fp);
                                memset(messagef, 0, 503);
                                itr++;
                            }
                            if (recvfrom(fd_rx, messagef, (mm % 503), 0, (struct sockaddr *)&cliente, &largoCliente) == -1)
                                printf("ERROR: 5 recvfrom()\n");
                            fwrite(messagef, (mm % 503), 1, fp);
                            memset(messagef, 0, 503);
                            fclose(fp);
                        }
            ///////////////////////////////////////////
            ////// FILE TRANSFER PART ENDS ////////////
            ///////////////////////////////////////////
                        else
                            cout << ipOrigen << " "  << buf << endl;    
                        strcpy(msjAnterior, buf); 
                        ultimoRemitente = cliente.sin_addr.s_addr;
                        strcpy(buf, "\0"); 
                    }
                }
            }
        } 
        else if (pid == 0)
        {
    ////////////////////
    // CLIENT SIDE ///// WHERE MESSAGES AND FILES ARE SENT FROM ////////////////
    ////////////////////
            printf("\33[34mTx\33[39m: Iniciada parte que transmite mensajes. Pid %d\n", getpid());

            char ipDestino[MAX_LARGO_IP]; 
            char buffS[MAX_LARGO_MENSAJE + 1];
            char message[MAX_LARGO_MENSAJE];
            char * enviar = new(char[7]);
            strcpy(enviar, "enviar");
            char fname[BUFLEN];
            unsigned long siz;
            char str[10];
            FILE *f;
            int enviados = 0;
            unsigned int fd_tx;
            fd_tx = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
            if(fd_tx < 0){
                cout << "ERROR: socket()\n";
                exit (0);
            }
            while (true)
            {
                server.sin_family = AF_INET;
                server.sin_port = htons(atoi(argv[1])); 
                bzero(&(server.sin_zero),8);
                cin >> ipDestino;
                if (ipDestino[0] == '*'){
                    int broadcastPermission = 1;
                    if (setsockopt(fd_tx, SOL_SOCKET, SO_BROADCAST, (void *) &broadcastPermission,sizeof(broadcastPermission)) < 0){
                        fprintf(stderr, "setsockopt error");
                        exit(1);
                       }
                }
                else if(ipDestino[0] == '&')
                    cout << "Se hace peer_discover" << endl;
                else if ((he=gethostbyname(ipDestino))==NULL){       
                        printf("ERROR: gethostbyname()\n");
                        exit(0);
                    }
                    server.sin_addr = *((struct in_addr *)he->h_addr);  
                cin.ignore(1,' ');
                cin.getline(buffS,MAX_LARGO_MENSAJE,'\n');
                printf("ipDestino: %s, mensaje: %s \n", ipDestino, buffS);
                if (buffS[0] == '&')    
                { 
            ///////////////////////////////////////////////////////////////
            ////// THIS IS WHERE THE FILE TRANSFER PART STARTS ////////////
            ///////////////////////////////////////////////////////////////
                    cout << "\nSE QUIERE MANDAR ARCHIVO\n";
                    sendto(fd_tx, enviar, sizeof(char), 0, (struct sockaddr *)& server, sizeof(server));
                    cout << "\nSE MANDO NOMBRE ARCHIVO\n";
                    int i = 8;
                    int j = 0;
                    while (buffS[i] != '\n'){
                        fname[j++] = buffS[i++];
                    }
                    cout << "nombre archivo: " << fname << endl; // muestra el nombre para saber si esta bien. ELIMINAR
                    sleep(1);
                    sendto(fd_tx, fname, 20, 0, (struct sockaddr *)&server, sizeof(server));
                    siz = fsize(fname);
                    sprintf(str, "%d", siz);
                    sendto(fd_tx, str, 20, 0, (struct sockaddr *)&server, sizeof(server));
                    f = fopen(fname, "rb");
                    memset(message, 0, 503);
                    fread(message, 503, 1, f);
                    int itr = 1;
                    while(itr*503 < siz)
                    {
                        if(sendto(fd_tx, message, 503, 0, (struct sockaddr*)&server, sizeof(server)) == -1){
                            cout << "ERROR: 1 send()\n";
                            exit(0);
                        }
                        memset(message, 0, 503);
                        fread(message, 503, 1, f);
                        itr++;
                    }
                    fread(message, (siz % 503), 1, f);
                    if(sendto(fd_tx, message, (siz % 503), 0, (struct sockaddr*)&server, sizeof(server)) == -1){
                        cout << "ERROR: 2 send()\n";
                        exit(0);
                    }
                    fclose(f);
                }
            ///////////////////////////////////////////
            ////// FILE TRANSFER PART ENDS ////////////
            ///////////////////////////////////////////
                else{
                    // SEND MESSAGES
                    enviados = sendto (fd_tx, buffS, sizeof(char) * (strlen(buffS) + 1), 0, (struct sockaddr *)&server, sizeof(server));
                    if(enviados != -1)
                        cout << enviados << "bytes enviados.\n" ;
                    else
                        cout << "No se pudo enviar el mensaje.\n";
                }
            }           
        }
    }

I'm sorry. It's really long as both server and client sides must be in the same file.

Upon trying to send a file, the program returns a SIGSEGV "segment violation" in the second cout, after the snedto.

cout << "\nSE QUIERE MANDAR ARCHIVO\n";
                        sendto(fd_tx, enviar, sizeof(char), 0, (struct sockaddr *)& server, sizeof(server));
                        cout << "\nSE MANDO NOMBRE ARCHIVO\n"; <--- RIGHT HERE

I'm guessing there's something wrong with the server side, but I have no idea what exactly it could be.

Any help would be greatly appreciated.

0 Answers
Related