Advertisement
Guest User

servidor

a guest
Sep 11th, 2016
105
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 16.03 KB | None | 0 0
  1. #include <iostream>
  2. #include <sys/socket.h>
  3. #include <netinet/in.h>
  4. #include <string.h>
  5. #include <unistd.h>
  6. #include <pthread.h>
  7. #include <unordered_map>
  8. #include <vector>
  9. #include "auxiliares.h"
  10. #include "Mensaje.h"
  11. #include "Log.h"
  12. #define MAX_CLIENTS 5
  13.  
  14. using namespace std;
  15.  
  16. struct argthread {
  17.     int clientFD= 0;
  18.     pthread_t* thread= NULL;
  19.     char* user=NULL;
  20.     char* clave= NULL;
  21. };
  22.  
  23.  
  24. class NoSePudoCrearServidorException : public runtime_error {
  25.  
  26. public:
  27.     NoSePudoCrearServidorException() : runtime_error("No se pudo crear el servidor") {
  28.     }
  29.  
  30. };
  31.  
  32.  
  33. class servidorPOO {
  34.  
  35. private:
  36.     static int fileDescrpt;
  37.     string nombreArchivoCsv;
  38.     struct sockaddr_in serv_addr, cli_addr;
  39.     socklen_t pesoCli_adrr;
  40.     pthread_t threadControl;
  41.     pthread_attr_t attr;
  42.     bool serverOn = false;
  43.     static vector<argthread_t *> conectados;
  44.     static unordered_map<string, string> usuarios;
  45.     static vector<Mensaje> mensajes;
  46.     static pthread_mutex_t mutex_mensajes;
  47.     // Log logger; --> un atributo va a ser un objeto Log para logear.
  48.  
  49.     static void *controlInput(void *serverStatus) {
  50.  
  51.         cout << "ESPERANDO CLIENTES" << endl << "Presione * para salir..." << endl;
  52.  
  53.         string input;
  54.         while (true) {
  55.             cin >> input;
  56.  
  57.             if (input.compare("*") == 0) {
  58.                 *((bool *) serverStatus) = false;
  59.                 cerrarConexiones();
  60.                 shutdown(fileDescrpt, SHUT_RDWR);
  61.                 return NULL;
  62.             }
  63.         }
  64.     }
  65.  
  66.     static void cerrarConexiones() {
  67.         size_t numConexiones = conectados.size();
  68.  
  69.         for (size_t i = 0; i < numConexiones; i++) {
  70.             argthread_t *actual = conectados[i];
  71.             shutdown(actual->clientFD, SHUT_RDWR);
  72.             // No libero el resto de las cosas de argthread porque se liberan
  73.             // al final de la funcion procesarMensajes
  74.         }
  75.     }
  76.  
  77.     void cargarUsuarios(string filename) {
  78.  
  79.         char *linea = NULL;
  80.         size_t len = 0;
  81.         FILE *archivo = fopen(filename.c_str(), "r");
  82.  
  83.         while (getline(&linea, &len, archivo) != -1) {
  84.             string usuario = strtok(linea, ",");
  85.             string password = strtok(NULL, ",");
  86.             usuarios[usuario] = password;
  87.         }
  88.  
  89.         fclose(archivo);
  90.     }
  91.  
  92.     static bool esValido(string usuario, string clave) {
  93.         usuario.erase(usuario.length() - 1);
  94.         if (usuarios.find(usuario) == usuarios.end())
  95.             return false;
  96.  
  97.         return (usuarios[usuario] == clave);
  98.     }
  99.  
  100.     static bool pedirLogin(FILE *mensajeCliente, argthread_t *arg) {
  101.  
  102.  
  103.         size_t len = 0;
  104.         char* user = NULL;
  105.         char* pass = NULL;
  106.  
  107.         // Pido el usuario al cliente
  108.         getline(&user, &len, mensajeCliente);
  109.         getline(&pass, &len, mensajeCliente);
  110.  
  111.         // Chequeo si el user ya esta conectado
  112.         vector<argthread_t *>::iterator it;
  113.         for (it = conectados.begin(); it != conectados.end();) {
  114.             if (it.operator*()->user != NULL){
  115.                 if (strcmp(it.operator*()->user,user) == 0){
  116.                     return false;
  117.                 }
  118.             }
  119.             it++;
  120.         }
  121.  
  122.         string user_s(user);
  123.         string pass_s(pass);
  124.  
  125.         if(esValido(user_s, pass_s)){
  126.             arg->user = user;
  127.             arg->clave = pass;
  128.             return true;
  129.         }
  130.  
  131.         return false;
  132.     }
  133.  
  134.     static void mandarUsuarios(int sockNewFileDescrpt) {
  135.         //Consigo las claves del hash de usuarios
  136.         vector<string> keys;
  137.         for (auto kv : usuarios) {
  138.             keys.push_back(kv.first);
  139.         }
  140.  
  141.         //Los junto en un vector separados por un espacio
  142.         string texto;
  143.         for (int i = 0; i < keys.size(); i++) {
  144.             texto += keys[i] + ",";
  145.         }
  146.         texto += "\n";
  147.  
  148.         //Transformo string en char*
  149.         char *textoUsuarios = new char[texto.length() + 1];
  150.         strcpy(textoUsuarios, texto.c_str());
  151.  
  152.         //Mando el vector al cliente
  153.         ssize_t bytesEscritos = write(sockNewFileDescrpt, textoUsuarios, strlen(textoUsuarios));
  154.         delete textoUsuarios;
  155.  
  156.         if (bytesEscritos < 0) {
  157.             perror("ERROR --> No se pudo responder al cliente");
  158.             exit(1);
  159.         }
  160.     }
  161.  
  162.     static void kickearUsuario(argthread_t* arg) {
  163.  
  164.  
  165.         vector<argthread_t *>::iterator it;
  166.         for (it = conectados.begin(); it != conectados.end();) {
  167.  
  168.  
  169.             if (it.operator*()->user != NULL && arg->user != NULL){
  170.                 if (strcmp(it.operator*()->user, arg->user) == 0){
  171.                     it = conectados.erase(it);
  172.  
  173.                     return;
  174.                 }
  175.             }
  176.             else if (arg->user != NULL){
  177.                 it++;
  178.             }
  179.             else{
  180.                 it = conectados.erase(it);
  181.                 return;
  182.             }
  183.         }
  184.     }
  185.  
  186.     static void agregarMensaje(char* emisorChar, char *textoInicial) {
  187.         if (textoInicial==NULL){
  188.             printf("ERROR");
  189.             exit(1);
  190.         }
  191.  
  192.         string emisor(emisorChar);
  193.         emisor.erase(emisor.length()-1);
  194.  
  195.         //me fijo cuanto mide el destinatario
  196.         int l=0;
  197.         for (l;l<=strlen(textoInicial);l++){
  198.             if (textoInicial[l] == '$')  break;
  199.         }
  200.  
  201.         //sabiendo el largo del destinatario se el largo del mensaje
  202.         char msg[strlen(textoInicial)-l];
  203.         char dest[l];
  204.         dest[l]='\0';
  205.         //guardo el destinatario
  206.         for (int d=0;d<l;d++) dest[d]=textoInicial[d];
  207.  
  208.         //guardo el mensaje
  209.         l++;
  210.         for(int m=0;l<=strlen(textoInicial);m++){
  211.             msg[m]=textoInicial[l];
  212.             l++;
  213.         }
  214.         string destinatario(dest);
  215.         string mensaje(msg);
  216.  
  217.         //string destinatario = strtok(textoInicial, "$");
  218.         //string mensaje = " ACA ESTA EL ERROR HAY QUE PARSEAR SIN NULL";
  219.         int result; // para el mutex
  220.         if (destinatario == "TODOS") {
  221.             result = pthread_mutex_lock(&mutex_mensajes);
  222.             for (auto kv : usuarios) {
  223.                 Mensaje mensajeNuevo(emisor,kv.first,mensaje);
  224.  
  225.                 // Lockeo el mutex a mensajes
  226.                 if (result != 0) perror("Fallo el pthread_mutex_lock en agregar msjs (a todos)");
  227.  
  228.                 mensajes.push_back(mensajeNuevo);
  229.  
  230.                 // Unlockeo el mutex a mensajes
  231.                 result = pthread_mutex_unlock(&mutex_mensajes);
  232.                 if (result != 0) perror("Fallo el pthread_mutex_lock en agregar msjs (a todos)");
  233.             }
  234.         }
  235.         else {
  236.          
  237.             Mensaje mensajeNuevo(emisor,destinatario, mensaje);
  238.  
  239.             // Lockeo el mutex a mensajess
  240.             result = pthread_mutex_lock(&mutex_mensajes);
  241.             if (result != 0) perror("Fallo el pthread_mutex_lock en agregar msjs (a todos)");
  242.  
  243.             mensajes.push_back(mensajeNuevo);
  244.  
  245.             // Unlockeo el mutex a mensajes
  246.             result = pthread_mutex_unlock(&mutex_mensajes);
  247.             if (result != 0) perror("Fallo el pthread_mutex_lock en agregar msjs (a todos)");
  248.         }
  249.         return;
  250.     }
  251.  
  252.  
  253.     static void *procesarMensajes(void *arg) {
  254.         char *linea;
  255.         size_t len = 0;
  256.         ssize_t bytesLeidos;
  257.         ssize_t bytesEscritos;
  258.         int sockNewFileDescrpt = ((argthread_t *) arg)->clientFD;
  259.         pthread_t *thread = ((argthread_t *) arg)->thread;
  260.         FILE *mensajeCliente = fdopen(sockNewFileDescrpt, "r");
  261.  
  262.         // Registro del usuario
  263.         if (!pedirLogin(mensajeCliente, (argthread_t *) arg)) {
  264.             write(sockNewFileDescrpt, "fallo la conexion al sistema.\n", 30);
  265.             fclose(mensajeCliente);
  266.             close(sockNewFileDescrpt);
  267.             kickearUsuario((argthread_t*) arg);
  268.             free(arg);
  269.             free(thread);
  270.             return NULL;    // Salgo del thread
  271.         }
  272.  
  273.         bytesEscritos = write(sockNewFileDescrpt, "conectado al servidor\n", 22);
  274.         // ToDo Escribir en el logger que se conecto
  275.         cout << "Se conectó " << ((argthread_t *) arg)->user << endl;
  276.         mandarUsuarios(sockNewFileDescrpt);
  277.         char recibo[202];
  278.         while (true) {
  279.  
  280.             // Primer getline para recibir instruccion
  281.  
  282.             bytesLeidos = getline(&linea, &len, mensajeCliente);
  283.  
  284.             if (bytesLeidos < 0) {
  285.                 cout << "Se desconectó " << ((argthread_t *) arg)->user << endl;
  286.                 free(linea);
  287.                 break;
  288.             }
  289.  
  290.             cout << "Mensaje recibido del cliente: " << linea;
  291.  
  292.  
  293.             // Opcion enviar mensaje
  294.             if (strcmp(linea, "/E/\n") == 0) {
  295.                 //bytesLeidos = getline(&linea, &len, mensajeCliente);
  296.                 read(sockNewFileDescrpt,recibo,203);
  297.                 if (bytesLeidos < 0) {
  298.                     cout << "Se desconectó " << ((argthread_t *) arg)->user << endl;
  299.                    // free(linea);
  300.                     break;
  301.                     }
  302.                 agregarMensaje(((argthread_t *) arg)->user,recibo);
  303.                 //bytesEscritos = write(sockNewFileDescrpt, "\n", 1);
  304.  
  305.             }
  306.  
  307.                 // Opcion recibir msjs
  308.             else if (strcmp(linea, "/R/\n") == 0) {
  309.                 string receptor(((argthread_t *) arg)->user);
  310.                 receptor.erase(receptor.length() - 1);
  311.                 vector<Mensaje>::iterator it;
  312.                
  313.                 int result; //para el mutex
  314.  
  315.                 // Lockeo el mutex a mensajes
  316.                 result = pthread_mutex_lock(&mutex_mensajes);
  317.                 if (result != 0) perror("Fallo el pthread_mutex_lock en agregar msjs (a todos)");
  318.  
  319.                 for (it = mensajes.begin(); it != mensajes.end();) {
  320.                     if (it->getNameReceptor() == receptor) {
  321.                         string nombreDelEmisor = it->getNameEmisor();
  322.                         string mensajeEmisor = it->getMensaje();
  323.                         string texto = nombreDelEmisor + " dice: " + mensajeEmisor;
  324.                         char *mensaje = new char[texto.length() + 1];
  325.                         strcpy(mensaje, texto.c_str());
  326.  
  327.                         //Mando el vector al cliente
  328.                         ssize_t bytesEscritos = write(sockNewFileDescrpt, mensaje, strlen(mensaje));
  329.                         delete mensaje;
  330.  
  331.                         if (bytesEscritos < 0) {
  332.                             perror("ERROR --> No se pudo responder al cliente");
  333.                             exit(1);
  334.                         }
  335.                         it = mensajes.erase(it);
  336.                     }
  337.                     else it++;
  338.                 }
  339.                
  340.                 // Unlockeo el mutex a mensajes
  341.                 result = pthread_mutex_unlock(&mutex_mensajes);
  342.                 if (result != 0) perror("Fallo el pthread_mutex_lock en agregar msjs (a todos)");
  343.                
  344.                 char* fin = "$\n";
  345.                 write(sockNewFileDescrpt,fin,strlen(fin));
  346.             }
  347.                 // Opcion desconectar del servidor (para liberar memoria)
  348.             else if (strcmp(linea, "/D/\n") == 0){
  349.  
  350.             } // Desconectar desde el servidor tambien
  351.  
  352.  
  353.  
  354.             free(linea);
  355.             linea = NULL;
  356.  
  357.             // Write del tilde (proximamente sin uso)
  358.            // bytesEscritos = write(sockNewFileDescrpt, "\xE2\x9C\x93\n", 4);
  359.  
  360.             if (bytesEscritos < 0) {
  361.                 perror("ERROR --> No se pudo responder al cliente");
  362.                 exit(1);
  363.             }
  364.         }
  365.  
  366.         close(sockNewFileDescrpt);
  367.         kickearUsuario((argthread_t*) arg);
  368.         free(arg);
  369.         free(thread);
  370.         fclose(mensajeCliente);
  371.         cout << "Llego a liberar las cosas del argthread" << endl;
  372.         return NULL;
  373.     }
  374.  
  375. public:
  376.     servidorPOO(unsigned short int numPuerto, string nombreArchivo) {
  377.  
  378.         nombreArchivoCsv = nombreArchivo;
  379.  
  380.         pthread_attr_init(&attr);
  381.         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  382.         mutex_mensajes = PTHREAD_MUTEX_INITIALIZER;
  383.  
  384.  
  385.         // Creo thread de CONTROL
  386.         if (pthread_create(&threadControl, &attr, controlInput, &serverOn) != 0) {
  387.             // ToDo logger...
  388.             cerr << "ERROR --> No se pudo crear thread de control" << endl;
  389.             pthread_attr_destroy(&attr);
  390.             throw NoSePudoCrearServidorException();
  391.         }
  392.  
  393.         bzero(&serv_addr, sizeof(serv_addr));   // Inicializo structs
  394.         bzero(&cli_addr, sizeof(cli_addr));
  395.  
  396.         fileDescrpt = socket(AF_INET, SOCK_STREAM, 0);
  397.  
  398.         if (fileDescrpt < 0) {
  399.             // ToDo pedirle al logger que escriba el error ( i.e. logger.error("yada yada") )
  400.             cerr << "ERROR --> No se pudo abrir socket" << endl;
  401.             pthread_attr_destroy(&attr);
  402.             throw NoSePudoCrearServidorException();
  403.         }
  404.  
  405.         serv_addr.sin_family = AF_INET;
  406.         serv_addr.sin_addr.s_addr = INADDR_ANY;
  407.         serv_addr.sin_port = htons(numPuerto);  // --> convierte de hostbyte order a network byte order
  408.  
  409.         // Aviso al SO que asocie el programa al socket creado
  410.         if (bind(fileDescrpt, (const sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
  411.             // ToDo pedirle al logger...
  412.             close(fileDescrpt);
  413.             pthread_attr_destroy(&attr);
  414.             throw NoSePudoCrearServidorException();
  415.         }
  416.  
  417.         // Comienza a escuchar a los clientes que se quieren conectar y los va encolando
  418.         if (listen(fileDescrpt, MAX_CLIENTS) < 0) {
  419.             // ToDo pedirle al logger...
  420.             cerr << "ERROR --> Falla en listen" << endl;
  421.             close(fileDescrpt);
  422.             pthread_attr_destroy(&attr);
  423.             throw NoSePudoCrearServidorException();
  424.         }
  425.  
  426.         serverOn = true;
  427.         cargarUsuarios(nombreArchivo);
  428.  
  429.  
  430.     }
  431.  
  432.     void aceptarClientes() {
  433.  
  434.         while (serverOn) {
  435.             int newFileDescrpt = accept(fileDescrpt, (sockaddr *) &cli_addr, &pesoCli_adrr);
  436.             if (newFileDescrpt < 0) {
  437.                 // ToDo pedirle al logger...
  438.                 cerr << "ERROR --> No se pudo aceptar cliente" << endl;
  439.                 continue;
  440.             }
  441.  
  442.             // ToDo falta en el caso de que no falle, crear los threads y agregarlos a la lista
  443.  
  444.             argthread_t *arg = (argthread_t *) malloc(sizeof(argthread_t));
  445.  
  446.             if (!arg) {
  447.                 close(newFileDescrpt);  // rechazo cliente
  448.                 // ToDo logger...
  449.                 cerr << "ERROR --> Falta memoria para cliente" << endl;
  450.                 continue;
  451.             }
  452.  
  453.             pthread_t *thread = (pthread_t *) malloc(sizeof(pthread_t));
  454.  
  455.             if (!thread) {
  456.                 close(newFileDescrpt); // rechazo cliente
  457.                 // ToDo logger...
  458.                 cerr << "ERROR --> Falta memoria para thread de cliente" << endl;
  459.                 continue;
  460.             }
  461.  
  462.             arg->clientFD = newFileDescrpt;
  463.             arg->thread = thread;
  464.             arg->user = NULL;
  465.             arg->clave = NULL;
  466.             conectados.push_back(arg);
  467.             if (pthread_create(thread, &attr, procesarMensajes, arg) != 0) {
  468.                 cerr << "ERROR --> Creación de thread fallida" << endl;
  469.                 conectados.pop_back();
  470.                 close(newFileDescrpt);      // Rechazar este cliente
  471.                 free(thread);
  472.                 free(arg);
  473.             }
  474.  
  475.         }
  476.     }
  477. };
  478.  
  479. vector<argthread_t*> servidorPOO::conectados;
  480. unordered_map<string, string> servidorPOO::usuarios;
  481. int servidorPOO::fileDescrpt;
  482. vector<Mensaje> servidorPOO::mensajes;
  483. pthread_mutex_t servidorPOO::mutex_mensajes;
  484.  
  485. int main(int argc, char** argv) {
  486.  
  487.  
  488.     if (argc < 3) {
  489.         fprintf(stderr, "Modo de Uso: %s <archivo-usuarios> <n° puerto>\n", argv[0]);
  490.         exit(EXIT_SUCCESS);
  491.     }
  492.  
  493.     unsigned short int numPuerto = (unsigned short) strtoull(argv[2], NULL, 0);
  494.  
  495.     servidorPOO server = servidorPOO(numPuerto, argv[1]);
  496.     server.aceptarClientes();
  497.  
  498.     return 0;
  499. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement