Universidad Simón Bolívar Departamento de Computación y Tecnología de la Información Curso de Redes I CI-4815 Trimestre Septiembre Diciembre 2013 Proyecto I Autores: Lairon Acosta. Carnet: 09-10927 Jueves 28 de Noviembre de 2013 Explicación del Diagrama de Secuencia 1. El programa cchat1 envia comando “men Hola” al servidor, este lo recibe y lo envia a todos los usuarios conectados a las mismas salas de chat que cchat1, en este caso a cchat2 que recibe el mensaje. 2. El programa cchat1 envia comando “usu” al servidor, este lo recibe y procesa la petición, busca todos los usuarios conectados y le envia respuesta al programa cchat1. 3. El programa cchat1 envia comando “sal” al servidor, este lo recibe y procesa la petición, busca todas las salas disponibles y le envia respuesta al programa cchat1. 4. El programa cchat1 envia comando “crea nueva” al servidor, este lo recibe y procesa la petición, crea una sala de nombre 'nueva' y le envia respuesta al programa cchat1 de sala creada exitosamente. 5. El programa cchat1 envia comando “des” al servidor, este lo recibe y procesa la petición, dessuscribe al cliente cchat1 de todas las salas a la que esta conectado y le envia respuesta al programa cchat1 de operación exitosa. 6. El programa cchat1 envia comando “sus nueva” al servidor, este lo recibe y procesa la petición, suscribe al cliente cchat1 a la sala de nombre 'nueva' y le envia respuesta al programa cchat1 de suscricción exitosa. 7. El programa cchat1 envia comando “men chao” al servidor, este lo recibe y lo envia a todos los usuarios conectados a las mismas salas de chat que cchat1, en este caso a cchat2 que recibe el mensaje. Explicación de los Aspectos del Proyecto 1- Verificación de comandos: Para la verificación de los comandos se utilizó “Expresiones Regulares”. Estas permitieron verificar tanto patrones de comando como tipo de cada parámetro de forma más fácil. Por lo tanto, las expresiones regulares usadas para cada comando válido se muestran a continuación: • expMensaje[] = " *men *[a-zA-Z0-9.,-?'¡¿!\"#$%&/()@+-/*\\][a-zA-Z 0-9.,-?'¡¿!\"#$%&/() @+-/*\\]* *$"; • expCrearSala[] = " *cre *[a-zA-Z0-9][a-zA-Z0-9]* *$"; • expSuscribeSala[] = " *sus *[a-zA-Z0-9][a-zA-Z0-9]* *$"; • expEliminaSala[] = " *eli *[a-zA-Z0-9][a-zA-Z0-9]* *$"; • expSalas[] = " *sal *$"; • expUsuarios[] = " *usu *$"; • expDesSuscribir[] = " *des *$"; • expFueraChat[] = " *fue *$"; 2- Estructuras de datos: Se crearon especificamente dos estructuras de datos, la primera para almacenar la información de cada usuario conectado al servidor y la segunda para administrar las salas disponibles del servidor. • Primera estructura: ◦ Id socket de usuario ◦ Nombre de usuario ◦ Estado de usuario: ▪ Conectado ▪ Desconectado ◦ Salas de usuario • Segunda estructura: ◦ Nombre de sala ◦ Estado de sala: ▪ Activa ▪ Desactiva 3- Cliente/Servidor multihilo: Se usó la nocion de Cliente/Servidor multihilo. De tal manera, para cada cliente se crearon dos hilos, uno para que recibiera las respuestas del servidor y otro para enviar peticiones al servidor. De la misma forma, para el servidor se creó un hilo por cada cliente aceptado para recibir peticiones, este hilo ejecuta una funcion para gestionar las distintas peticiones de los clientes. 4- Funciones de los comandos(diseño del programador): • Comando 'men (texto)': este comando envia el (texto) a todos los usuarios conectados a la misma sala del enviador. No se envia el (texto) así mismo por cuestiones de acuerdos, debido a que en el enunciado no tiene ésta restricción explícita. • Comando 'sus (Sala)': este comando suscribe al usuario que lo invoca a una sala que este disponible, es decir, que este creada. Si la sala no existe le envía un aviso al usuario. • Comando 'cre (Sala)': este comando hace que el usuario que lo invoca cree una sala que no haya sido creada y simultaneamente lo suscribe a ella. Si la sala ya fué creada le envía un aviso al usuario. • Comando 'eli (Sala)': este comando hace que el usuario que lo invoca elimine una sala cualquiera que este creada. Simultaneamente, des-sucribe a todos los usuarios que esten suscritos a ella y les envía un mensaje informando que la sala ha sido eliminada. Si la sala no existe le envía un aviso al usuario. • Comando 'sal ': Este comando le muestra por pantalla al usuario que lo invoca una lista de las salas disponibles del servidor. • Comando 'usu ': Este comando le muestra por pantalla al usuario que lo invoca una lista de los usuarios suscritos al servidor, incluyéndolo a él mismo. • Comando 'fue ': Este comando le permite al usuario que lo invoca terminar el programa de introducción de comandos y al mismo tiempo la terminación del programa cchat. Además, le envía un aviso al usuario de que ha terminado su ejecución de comandos y programa cchat. 5- Restricciones de parámetros de las llamadas cchat y schat: Para la llamada del programa schat, tenemos que los parámetros de entrada podran venir en cualquier orden. Destacando que el parámetro de la opcion '-s' puede existir o no. Llamada: schat [-p <puerto>] [-s <sala>] Para la llamada del programa cchat, los parámetros podrán venir en cualquier orden igualmente, pero los parámetros de cada opción son obligatorios. Destacando con esto, que debe existir archivo de entrada obligatoriamente para la opción '-a'. Esto debido acuerdo tomado por el programador. Llamada: cchat [-h <host>] [-p <puerto>] [-n <nombre>][-a <archivo>] 6- Entradas inválidas en llamadas y comportamiento a tomar: Se presentan una serie de entradas inválidas o errores y sus respectivos manejos: • Error abriendo socket: El programa termina su ejecución y envía mensaje de error abriendo socket. • Error en el puerto: El programa termina su ejecución y envía mensaje de error en el puerto. • Error en el host: El programa termina su ejecución y envía mensaje de error en el host. • Error realizando 'bind' socket: El programa termina su ejecución y envía mensaje de error en el bind. • Error realizando 'listen' socket: El programa termina su ejecución y envía mensaje de error en el listen. • Error realizando 'connect' socket: El programa termina su ejecución y envía mensaje de error en el connect. • Número inválido de argumentos: El programa termina su ejecución y envía mensaje de error número inválido de argumentos. • Error de opción inválida: El programa termina su ejecución y envía mensaje de error de opción no corresponde o no es válida. • Error de opción en posición inválida: El programa termina su ejecución y envía mensaje de error de opción en posición inválida. • Error en compilar expresión regular(no aparecerá): El programa termina su ejecución y envía mensaje de error de expresión regular no compilada. • Error abriendo archivo: El programa termina su ejecución y envía mensaje de error abriendo archivo. • Error al crear hilo: El programa termina su ejecución y envía mensaje de error al crear hilo en el cliente o servidor. 7- Estado del proyecto: El proyecto tiene 100% de funcionalidad y está 100% documentado. /* Proyecto 1: Redes ci4815 Programa: Cliente.c Realizado por: Lairon Acosta Version: 2.7 -----------------------------Includes del sistema */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <Cola.h> #include <netdb.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <SocketCliente.h> #include <pthread.h> #include <sys/syscall.h> #include <sys/resource.h> #include <errno.h> #include <sys/stat.h> #include <unistd.h> #include <dirent.h> #include <fcntl.h> #include <sys/time.h> /*funcion: funcion principal que realiza las acciones de un cliente argc: cantidad de argumentos argv: argumentos de la llamada del cliente */ main ( int argc, char *argv[] ) { //Declaracion de variables Cola cola = NULL; char host[100]; char puerto[100]; char nombre[100]; char archivo[100]; char Cadena[100]; int fd_socket; int rc1, rc2; long id_hilo; pthread_t threads[2]; Parametros *comandos; // Comando de entrada: cchat [-h <host>] [-p <puerto>] [-n <nombre>][-a <archivo>] //si hay 9 argumentos, proceso argumentos if ( argc == 9 ) { /* llamo a funcion que identificara la correspondencia de los argumentos del programa principal */ procesarArgumentosCliente(argc, argv, &cola); strcpy(host, damePrimero(&cola)); //Obtengo host strcpy(puerto, damePrimero(&cola)); //Obtengo puerto strcpy(nombre, damePrimero(&cola)); //Obtengo nombre strcpy(archivo, damePrimero(&cola)); //Obtengo archivo cola=NULL; //destruccion de la cola free(cola); //sino envio error } else { printf ("Programa %s.c: Error: numero invalido de argumentos.\n", argv[0]); exit(-1); } // Inicia configuracion de conexion de Sockets //Se abre la conexion con el cliente fd_socket = ConexionInetCliente(host,puerto); /* Allocate memory for pthread_create() arguments */ comandos = calloc(1,sizeof(struct parametros)); //si hay memoria if (comandos == NULL) { printf("Error: no hay memoria para almacenar argumentos"); exit(-1); } //almaceno numero de socket y nombre de archivo comandos[0].idSocketUsuario = fd_socket; strcpy(comandos[0].texto,archivo); if ( fd_socket == -1) { printf("ERROR DE CONEXION INET\n"); exit(-1); } else { //socket para enviar el nombre del usuario send( fd_socket , nombre, strlen(nombre)+1, 0); //crea hilo para enviar mensajes if ( ( rc1 = pthread_create( &threads[0], NULL, enviarMensaje, &comandos[0])) ) { printf("Error al crear hilo para recibir mensaje\n"); close(fd_socket); exit(-1); } //crea hilo para recibir mensajes if ( ( rc2 = pthread_create( &threads[1], NULL, recibirMensaje, (void *)(intptr_t) fd_socket)) ) { printf("Error al crear hilo para enviar mensaje\n"); close(fd_socket); exit(-1); } //envio comandos del archivo sino hubo errores de archivo if(!enviarComandos(fd_socket, archivo)){ printf("Error abriendo archivo y no envio comandos del archivo\n"); exit(-1); } //espero por los hilos creados pthread_join( threads[0], NULL); pthread_join( threads[1], NULL); } //cierro socket close(fd_socket); } /* Proyecto 1: Redes ci4815 Programa: SocketCliente.c Realizado por: Lairon Acosta Version: 1.3 ----------------------------Includes del sistema */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <Cola.h> #include <netdb.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <sys/syscall.h> #include <sys/resource.h> #include <errno.h> #include <sys/stat.h> #include <unistd.h> #include <dirent.h> #include <fcntl.h> #include <sys/time.h> #include <regex.h> #include <SocketCliente.h> /*******Implementaciones de metodos********/ /*funcion: realiza conexion de sockets con el servidor arg1: direccion ip o nombre de maquina del cliente arg2: puerto donde recibira la conexion return: descriptor de conexion */ int ConexionInetCliente ( char *host, char *puerto) { //Declaracion de variables int fd_socket; struct sockaddr_in address; struct in_addr inaddr; struct hostent *host_cliente; // Inicia configuracion de conexion de Sockets // Si el argumento se puede convertir en una direccion IP lo hace, de lo contrario busca en DNS if ( inet_aton(host,&inaddr) ) { host_cliente = gethostbyaddr((char *) &inaddr, sizeof(inaddr), AF_INET); //printf("host by ip\n"); } else { host_cliente = gethostbyname(host); //printf("host by name\n"); } //verifica si se obtuvo error en la obtencion del hostent if (!host_cliente) { printf("Error en el host\n"); return -1; //exit(1); } //Llenamos la estructura para TCP/IP address.sin_family = AF_INET; //DIR PROTOCOLO address.sin_addr.s_addr = ((struct in_addr *)(host_cliente->h_addr))->s_addr; //dir HOST //verifica si se obtuvo error en el puerto if ( !(address.sin_port = htons(atoi(puerto))) ) { //dir PUERTO printf("Error en el puerto\n"); return -1; //exit(1); } //Abrimos el socket if(( fd_socket = socket (PF_INET, SOCK_STREAM, 0)) < 0) { printf("Error abriendo el socket\n"); return -1; //exit(1); } //Conectamos el socket if ( (connect(fd_socket, (struct sockaddr *) &address, sizeof(address))) == -1 ) { printf("Error en funcion -connect- del socket: \n"); perror("connect"); return -1; //exit(1); } return fd_socket; } /*funcion: envia mensajes al servidor arg1: descriptor de conexion */ void *enviarMensaje ( void * id_hilo ) { char buffer[300]; int id; struct parametros *comandos = (struct parametros *) id_hilo; id = comandos->idSocketUsuario; while(1) { fgets(buffer , 300 , stdin); send( id , buffer, strlen(buffer)+1, 0); } } /*funcion: recibe mensajes del servidor arg1: descriptor de conexion */ void *recibirMensaje ( void *id_hilo ) { char buffer[300]; int id; id = (int)(intptr_t)id_hilo; while(1) { recv( id, buffer, 300, 0); if( strcmp(buffer,"fue")==0){ printf("Termino la ejecucion de comandos y el programa cchat satisfactoriamente.\n\n"); exit(-1); } printf("%s\n",buffer); fflush(stdout); } } /*funcion: envia comandos de un archivo al servidor arg1: id de usuario a que pertenece el archivo arg2: nombre del archivo int: 1 si envio comandos exitosamente, 0 sino. */ int enviarComandos(int id, char *archivo) { FILE *ficheroEntrada; char buffere[200]; int j=0; //abro archivo de entrada ficheroEntrada = fopen( archivo , "r" ); if (!ficheroEntrada) { //IMPRIME ERROR //printf("mensaje: **ERROR ABRIENDO ARCHIVO DE ENTRADA\n"); return 0; } else { //Extrae cada palabra del archivo while (feof(ficheroEntrada) == 0) { fgets(buffere,200,ficheroEntrada); if (feof(ficheroEntrada) == 0) { printf("%s",buffere); send( id , buffere, strlen(buffere)+1, 0); strcpy(buffere, ""); sleep(1); } } fclose(ficheroEntrada); return 1; //CIERRA EL archivo de entrada } } /*funcion: procesa los argumentos de la llamada Cliente arg1: cantidad de argumentos arg2: lista de argumentos arg3: cola que saldra modificada */ void procesarArgumentosCliente(int numeroArg, char *argv[], Cola *cola) { char retorno[5][50]; // Comando de entrada: cchat [-h <host>] [-p <puerto>] [-n <nombre>][-a <archivo>] if( strcmp(argv[1],"-h") == 0 ) { //copia el host en la posicion 0 del arreglo retorno strcpy(retorno[0],argv[2]); if( strcmp(argv[3],"-p") == 0 ) { //copia el puerto en la posicion 1 del arreglo retorno strcpy(retorno[1],argv[4]); if( strcmp(argv[5],"-n") == 0 ) { //copia el nombre en la posicion 2 del arreglo retorno strcpy(retorno[2],argv[6]); if( strcmp(argv[7],"-a") == 0 ) { //copia el archivo en la posicion 3 del arreglo retorno strcpy(retorno[3],argv[8]); } else { printf ("Error: argumento -a en pos invalida\n"); exit(1); } } else if( strcmp(argv[7],"-n") == 0 ) { //copia el nombre en la posicion 2 del arreglo retorno strcpy(retorno[2],argv[8]); if( strcmp(argv[5],"-a") == 0 ) { //copia el archivo en la posicion 3 del arreglo retorno strcpy(retorno[3],argv[6]); } else { printf ("Error: argumento -a en pos invalida\n"); exit(1); } } else { printf ("Error: argumento -n no corresponde\n"); exit(1); } } else if( strcmp(argv[5],"-p") == 0 ) { //copia el puerto en la posicion 1 del arreglo retorno strcpy(retorno[1],argv[6]); if( strcmp(argv[3],"-n") == 0 ) { //copia el nombre en la posicion 2 del arreglo retorno strcpy(retorno[2],argv[4]); if( strcmp(argv[7],"-a") == 0 ) { //copia el archivo en la posicion 3 del arreglo retorno strcpy(retorno[3],argv[8]); } else { printf ("Error: argumento -a en pos invalida\n"); exit(1); } } else if( strcmp(argv[7],"-n") == 0 ) { //copia el nombre en la posicion 2 del arreglo retorno strcpy(retorno[2],argv[8]); if( strcmp(argv[3],"-a") == 0 ) { //copia el archivo en la posicion 3 del arreglo retorno strcpy(retorno[3],argv[4]); } else { printf ("Error: argumento -a en pos invalida\n"); exit(1); } } else { printf ("Error: argumento -n en pos invalida\n"); exit(1); } } else if( strcmp(argv[7],"-p") == 0 ) { //copia el puerto en la posicion 1 del arreglo retorno strcpy(retorno[1],argv[8]); if( strcmp(argv[3],"-n") == 0 ) { //copia el nombre en la posicion 2 del arreglo retorno strcpy(retorno[2],argv[4]); if( strcmp(argv[5],"-a") == 0 ) { //copia el archivo en la posicion 3 del arreglo retorno strcpy(retorno[3],argv[6]); } else { printf ("Error: argumento -a en pos invalida\n"); exit(1); } } else if( strcmp(argv[5],"-n") == 0 ) { //copia el nombre en la posicion 2 del arreglo retorno strcpy(retorno[2],argv[6]); if( strcmp(argv[3],"-a") == 0 ) { //copia el archivo en la posicion 3 del arreglo retorno strcpy(retorno[3],argv[4]); } else { printf ("Error: argumento -a en pos invalida\n"); exit(1); } } else { printf ("Error: argumento -n en pos invalida\n"); exit(1); } } else { printf ("Error: argumento -p en pos invalida\n"); exit(1); } } else if ( strcmp(argv[3],"-h") == 0 ) { //copia el host en la posicion 1 del arreglo retorno strcpy(retorno[0],argv[4]); if( strcmp(argv[1],"-p") == 0 ) { //copia el puerto en la posicion 1 del arreglo retorno strcpy(retorno[1],argv[2]); if( strcmp(argv[5],"-n") == 0 ) { //copia el nombre en la posicion 2 del arreglo retorno strcpy(retorno[2],argv[6]); if( strcmp(argv[7],"-a") == 0 ) { //copia el archivo en la posicion 3 del arreglo retorno strcpy(retorno[3],argv[8]); } else { printf ("Error: argumento -a en pos invalida\n"); exit(1); } } else if( strcmp(argv[7],"-n") == 0 ) { //copia el nombre en la posicion 2 del arreglo retorno strcpy(retorno[2],argv[8]); if( strcmp(argv[5],"-a") == 0 ) { //copia el archivo en la posicion 3 del arreglo retorno strcpy(retorno[3],argv[6]); } else { printf ("Error: argumento -a en pos invalida\n"); exit(1); } } else { printf ("Error: argumento -n en pos invalida\n"); exit(1); } } else if( strcmp(argv[5],"-p") == 0 ) { //copia el puerto en la posicion 1 del arreglo retorno strcpy(retorno[1],argv[6]); if( strcmp(argv[1],"-n") == 0 ) { //copia el nombre en la posicion 2 del arreglo retorno strcpy(retorno[2],argv[2]); if( strcmp(argv[7],"-a") == 0 ) { //copia el archivo en la posicion 3 del arreglo retorno strcpy(retorno[3],argv[8]); } else { printf ("Error: argumento -a en pos invalida\n"); exit(1); } } else if( strcmp(argv[7],"-n") == 0 ) { //copia el nombre en la posicion 2 del arreglo retorno strcpy(retorno[2],argv[8]); if( strcmp(argv[1],"-a") == 0 ) { //copia el archivo en la posicion 3 del arreglo retorno strcpy(retorno[3],argv[2]); } else { printf ("Error: argumento -a en pos invalida\n"); exit(1); } } else { printf ("Error: argumento -n en pos invalida\n"); exit(1); } } else if( strcmp(argv[7],"-p") == 0 ) { //copia el puerto en la posicion 1 del arreglo retorno strcpy(retorno[1],argv[8]); if( strcmp(argv[1],"-n") == 0 ) { //copia el nombre en la posicion 2 del arreglo retorno strcpy(retorno[2],argv[2]); if( strcmp(argv[5],"-a") == 0 ) { //copia el archivo en la posicion 3 del arreglo retorno strcpy(retorno[3],argv[6]); } else { printf ("Error: argumento -a en pos invalida\n"); exit(1); } } else if( strcmp(argv[5],"-n") == 0 ) { //copia el nombre en la posicion 2 del arreglo retorno strcpy(retorno[2],argv[6]); if( strcmp(argv[1],"-a") == 0 ) { //copia el archivo en la posicion 3 del arreglo retorno strcpy(retorno[3],argv[2]); } else { printf ("Error: argumento -a en pos invalida\n"); exit(1); } } else { printf ("Error: argumento -n en pos invalida\n"); exit(1); } } else { printf ("Error: argumento -p en pos invalida\n"); exit(1); } } else if ( strcmp(argv[5],"-h") == 0 ) { //copia el host en la posicion 1 del arreglo retorno strcpy(retorno[0],argv[6]); if( strcmp(argv[1],"-p") == 0 ) { //copia el puerto en la posicion 1 del arreglo retorno strcpy(retorno[1],argv[2]); if( strcmp(argv[3],"-n") == 0 ) { //copia el nombre en la posicion 2 del arreglo retorno strcpy(retorno[2],argv[4]); if( strcmp(argv[7],"-a") == 0 ) { //copia el archivo en la posicion 3 del arreglo retorno strcpy(retorno[3],argv[8]); } else { printf ("Error: argumento -a en pos invalida\n"); exit(1); } } else if( strcmp(argv[7],"-n") == 0 ) { //copia el nombre en la posicion 2 del arreglo retorno strcpy(retorno[2],argv[8]); if( strcmp(argv[3],"-a") == 0 ) { //copia el archivo en la posicion 3 del arreglo retorno strcpy(retorno[3],argv[4]); } else { printf ("Error: argumento -a en pos invalida\n"); exit(1); } } else { printf ("Error: argumento -n en pos invalida\n"); exit(1); } } else if( strcmp(argv[3],"-p") == 0 ) { //copia el puerto en la posicion 1 del arreglo retorno strcpy(retorno[1],argv[4]); if( strcmp(argv[1],"-n") == 0 ) { //copia el nombre en la posicion 2 del arreglo retorno strcpy(retorno[2],argv[2]); if( strcmp(argv[7],"-a") == 0 ) { //copia el archivo en la posicion 3 del arreglo retorno strcpy(retorno[3],argv[8]); } else { printf ("Error: argumento -a en pos invalida\n"); exit(1); } } else if( strcmp(argv[7],"-n") == 0 ) { //copia el nombre en la posicion 2 del arreglo retorno strcpy(retorno[2],argv[8]); if( strcmp(argv[1],"-a") == 0 ) { //copia el archivo en la posicion 3 del arreglo retorno strcpy(retorno[3],argv[2]); } else { printf ("Error: argumento -a en pos invalida\n"); exit(1); } } else { printf ("Error: argumento -n en pos invalida\n"); exit(1); } } else if( strcmp(argv[7],"-p") == 0 ) { //copia el puerto en la posicion 1 del arreglo retorno strcpy(retorno[1],argv[8]); if( strcmp(argv[1],"-n") == 0 ) { //copia el nombre en la posicion 2 del arreglo retorno strcpy(retorno[2],argv[2]); if( strcmp(argv[3],"-a") == 0 ) { //copia el archivo en la posicion 3 del arreglo retorno strcpy(retorno[3],argv[4]); } else { printf ("Error: argumento -a en pos invalida\n"); exit(1); } } else if( strcmp(argv[3],"-n") == 0 ) { //copia el nombre en la posicion 2 del arreglo retorno strcpy(retorno[2],argv[4]); if( strcmp(argv[1],"-a") == 0 ) { //copia el archivo en la posicion 3 del arreglo retorno strcpy(retorno[3],argv[2]); } else { printf ("Error: argumento -a en pos invalida\n"); exit(1); } } else { printf ("Error: argumento -n en pos invalida\n"); exit(1); } } else { printf ("Error: argumento -p en pos invalida\n"); exit(1); } } else if ( strcmp(argv[7],"-h") == 0 ) { //copia el host en la posicion 1 del arreglo retorno strcpy(retorno[0],argv[8]); if( strcmp(argv[1],"-p") == 0 ) { //copia el puerto en la posicion 1 del arreglo retorno strcpy(retorno[1],argv[2]); if( strcmp(argv[3],"-n") == 0 ) { //copia el nombre en la posicion 2 del arreglo retorno strcpy(retorno[2],argv[4]); if( strcmp(argv[5],"-a") == 0 ) { //copia el archivo en la posicion 3 del arreglo retorno strcpy(retorno[3],argv[6]); } else { printf ("Error: argumento -a en pos invalida\n"); exit(1); } } else if( strcmp(argv[5],"-n") == 0 ) { //copia el nombre en la posicion 2 del arreglo retorno strcpy(retorno[2],argv[6]); if( strcmp(argv[3],"-a") == 0 ) { //copia el archivo en la posicion 3 del arreglo retorno strcpy(retorno[3],argv[4]); } else { printf ("Error: argumento -a en pos invalida\n"); exit(1); } } else { printf ("Error: argumento -n en pos invalida\n"); exit(1); } } else if( strcmp(argv[3],"-p") == 0 ) { //copia el puerto en la posicion 1 del arreglo retorno strcpy(retorno[1],argv[4]); if( strcmp(argv[1],"-n") == 0 ) { //copia el nombre en la posicion 2 del arreglo retorno strcpy(retorno[2],argv[2]); if( strcmp(argv[5],"-a") == 0 ) { //copia el archivo en la posicion 3 del arreglo retorno strcpy(retorno[3],argv[6]); } else { printf ("Error: argumento -a en pos invalida\n"); exit(1); } } else if( strcmp(argv[5],"-n") == 0 ) { //copia el nombre en la posicion 2 del arreglo retorno strcpy(retorno[2],argv[6]); if( strcmp(argv[1],"-a") == 0 ) { //copia el archivo en la posicion 3 del arreglo retorno strcpy(retorno[3],argv[2]); } else { printf ("Error: argumento -a en pos invalida\n"); exit(1); } } else { printf ("Error: argumento -n en pos invalida\n"); exit(1); } } else if( strcmp(argv[5],"-p") == 0 ) { //copia el puerto en la posicion 1 del arreglo retorno strcpy(retorno[1],argv[6]); if( strcmp(argv[1],"-n") == 0 ) { //copia el nombre en la posicion 2 del arreglo retorno strcpy(retorno[2],argv[2]); if( strcmp(argv[3],"-a") == 0 ) { //copia el archivo en la posicion 3 del arreglo retorno strcpy(retorno[3],argv[4]); } else { printf ("Error: argumento -a en pos invalida\n"); exit(1); } } else if( strcmp(argv[3],"-n") == 0 ) { //copia el nombre en la posicion 2 del arreglo retorno strcpy(retorno[2],argv[4]); if( strcmp(argv[1],"-a") == 0 ) { //copia el archivo en la posicion 3 del arreglo retorno strcpy(retorno[3],argv[2]); } else { printf ("Error: argumento -a en pos invalida\n"); exit(1); } } else { printf ("Error: argumento -n en pos invalida\n"); exit(1); } } else { printf ("Error: argumento -p en pos invalida\n"); exit(1); } } else { printf ("Error: argumento -h en pos invalida\n"); exit(1); } InsertarPalabra (cola, InsertarPalabra (cola, InsertarPalabra (cola, InsertarPalabra (cola, } retorno[0]); retorno[1]); retorno[2]); retorno[3]); /* Proyecto 1: Redes ci4815 Programa: SocketCliente.h Realizado por: Lairon Acosta Version: 1.5 */ /*Definiciones de tipos y estructuras de datos*/ /* Estructura para manejar los comandos del archivo var1: contenido del archivo var2: id de usuario al que le pertenece el archivo */ typedef struct parametros { char texto[300]; int idSocketUsuario; } Parametros; /*******Definiciones de metodos********/ /*funcion: realiza conexion de sockets con el servidor arg1: direccion ip o nombre de maquina del cliente arg2: puerto donde recibira la conexion return: descriptor de conexion */ int ConexionInet (char *host, char *puerto); /*funcion: envia mensajes al servidor arg1: descriptor de conexion */ void *enviarMensaje ( void *id_hilo ); /*funcion: recibe mensajes del servidor arg1: descriptor de conexion */ void *recibirMensaje ( void *id_hilo ); /*funcion: procesa los argumentos de la llamada Cliente arg1: cantidad de argumentos arg2: lista de argumentos arg3: cola que saldra modificada */ void procesarArgumentosCliente(int numeroArg, char *argv[], Cola *cola); /*funcion: envia comandos de un archivo al servidor arg1: id de usuario a que pertenece el archivo arg2: nombre del archivo int: 1 si envio comandos exitosamente, 0 sino. */ int enviarComandos(int id, char *archivo); /* Proyecto 1: Redes ci4815 Programa: Servidor.c Realizado por: Lairon Acosta Version: 4.8 -----------------------------Includes del sistema */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <Cola.h> #include <netdb.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <pthread.h> #include <sys/syscall.h> #include <sys/resource.h> #include <SocketServidor.h> /*funcion: administra los comandos enviados por el cliente arg1: descriptor de conexion */ void *funcionesUsuario( void *p); //VARIABLES GLOBALES dataUsuario usuario[100]; salaUsuario sistemaSala[150]; int clientes = 0; pthread_mutex_t mutex; /*funcion: funcion principal que realiza las acciones de un servidor argc: cantidad de argumentos argv: argumentos de la llamada del cliente */ main(int argc, char *argv[]) { //Declaracion de variables Cola cola = NULL; char puerto[100]; char sala[100]; char Cadena[100]; char nombreUser[147]; int fd_socket, fd_socketCliente, i, rc; int id; pthread_t threads[100]; //Inicializacion de variales pthread_mutex_init (&mutex, NULL); //inicializa el mutex //bloquear area compartida, mutex pthread_mutex_lock (&mutex); for( i=0 ; i<100 ; i++ ) { strcpy( usuario[i].nombreUsuario, " "); } // Comando de entrada: schat [-p <puerto>] [-s <sala>] if ( argc == 5 ) { /* llamo a funcion que identificara la correspondencia de los argumentos del programa principal */ procesarArgumentosServidor(argc, argv, &cola); strcpy(puerto, damePrimero(&cola)); //Obtengo host strcpy(sala, damePrimero(&cola)); //Obtengo puerto cola=NULL; //destruccion de la cola free(cola); } else if( argc == 4 ) { /* llamo a funcion que identificara la correspondencia de los argumentos del programa principal */ procesarArgumentosServidor2(argc, argv, &cola); strcpy(puerto, damePrimero(&cola)); //Obtengo host strcpy(sala, damePrimero(&cola)); //Obtengo puerto cola=NULL; //destruccion de la cola free(cola); } else { printf ("Programa %s.c: Error: numero invalido de argumentos.\n", argv[0]); exit(-1); } //incorporo el numero de salas strcpy(sistemaSala[0].nombreSala, "tamaño"); sistemaSala[0].numeroSala = 1; //incorporo la sala por defecto en el arreglo de salas strcpy(sistemaSala[1].nombreSala, sala); sistemaSala[1].numeroSala = 1; //Almaceno al servidor como usuario por defecto //Almaceno la sala por defecto id = clientes; usuario[id].idSocket = 0; strcpy(usuario[id].nombreUsuario, "Servidor"); usuario[id].conectadoUsuario = 1; //strcpy(usuario[id].nombreSala, sala); InsertarPalabra(&usuario[id].salas, sala); //aumento clientes para comenzar a recibir clientes++; //desbloquear area compartida, mutex pthread_mutex_unlock (&mutex); // Inicia configuracion de conexion de Sockets //Se abre la conexion con el servidor fd_socket = ConexionInetServidor(puerto); if ( fd_socket == -1 ) { printf("ERROR DE CONEXION INET\n"); exit(-1); } //Me quedo esperando peticiones de usuarios para aceptar for (;;) { //Servidor espera solicitudes del cliente fd_socketCliente = AceptaConexionInetCliente(fd_socket); if ( fd_socketCliente == -1 ) { printf ("Error al aceptar solicitudes de clientes\n"); exit (-1); } else { //bloquear area compartida, mutex pthread_mutex_lock (&mutex); id = clientes; //le asigna id a usuario nuevo //almaceno fd_socket de usuario usuario[id].idSocket = fd_socketCliente; //si la sala por defecto fue eliminada if(sistemaSala[1].numeroSala == -1) { //marco usuario como desconectado usuario[id].conectadoUsuario = 0; usuario[id].salas = NULL; } else { //marco usuario como conectado usuario[id].conectadoUsuario = 1; //almaceno nombre sala de usuario InsertarPalabra(&usuario[id].salas, sala); } //desbloquear area compartida, mutex pthread_mutex_unlock (&mutex); //para recibir nombre de usuario recv(usuario[id].idSocket, nombreUser, 100, 0); //bloquear area compartida, mutex pthread_mutex_lock (&mutex); //almaceno nombre de usuario strcpy(usuario[id].nombreUsuario,nombreUser); strcpy(nombreUser, ""); clientes++; //aumento el numero de clientes //desbloquear area compartida, mutex pthread_mutex_unlock (&mutex); //creo hilo por cada cliente aceptado y proceso su peticion if ( (rc = pthread_create( &threads[id], NULL, funcionesUsuario, (void *) (intptr_t)id)) ) { printf("Error al crear el hilo de funciones de usuarios\n"); close(id); exit(-1); } } } //Espero por los hilos de clientes que se estan procesando pthread_join( threads[id], NULL); //Se cierran los sockets close (fd_socketCliente); //cliente close (fd_socket); //servidor } void *funcionesUsuario( void *p) { int ide; ide = (int)(intptr_t)p; char buffer[300]; char funcion[147]; char mensaje[300]; char nombreAuxiliar[147]; char nombreAuxiliar2[147]; int i, longitud, destino,j=0,e=0,tam=0,numSalas=0; //expresiones regulares para los formatos de comandos y parametros char expMensaje[] = " *men *[a-zA-Z0-9.,-?'¡¿!\"#$%&/()@+-/*\\][a-zA-Z 0-9.,-?'¡¿!\"#$%&/ ()@+-/*\\]* *$"; char expCrearSala[] = " *cre *[a-zA-Z0-9][a-zA-Z0-9]* *$"; char expSuscribeSala[] = " *sus *[a-zA-Z0-9][a-zA-Z0-9]* *$"; char expEliminaSala[] = " *eli *[a-zA-Z0-9][a-zA-Z0-9]* *$"; char expSalas[] = " *sal *$"; char expUsuarios[] = " *usu *$"; char expDesSuscribir[] = " *des *$"; char expFueraChat[] = " *fue *$"; //me quedo esperando comandos por cliente cualquiera while(1) { j=0; e=0; tam=0; numSalas=0; recv(usuario[ide].idSocket, buffer, 300, 0); longitud = strlen(buffer); buffer[longitud-1]='\0'; //vacio buffers strcpy( nombreAuxiliar2, ""); //vacio buffers strcpy( nombreAuxiliar, ""); //guardo el nombre del usuario en otra variable strcpy( nombreAuxiliar2, usuario[ide].nombreUsuario); printf ("%s: %s\n",nombreAuxiliar2, buffer); /*****************************COMANDOS*********************************/ //envio mensaje a todos los usuarios conectados a la misma //sala del servidor if( formatoValido( expMensaje, buffer) == 1 ) { //bloquear area compartida, mutex pthread_mutex_lock (&mutex); //obtengo nombre de comando y parametro strcpy(funcion, primeraPalabra(buffer, longitud)); //guardo el nombre del usuario en otra variable strcpy( nombreAuxiliar, usuario[ide].nombreUsuario); //concateno para mejorar el formato del mensaje a enviar strcat( nombreAuxiliar, " dice: "); strcat( nombreAuxiliar, buffer); strcat( mensaje, nombreAuxiliar); //envio mensaje para cada usuario for(i = 1; i < clientes; i++) { //que sea distinto a mi mismo y que este conectado if( i != ide && usuario[i].conectadoUsuario == 1) { //numero de salas a la que esta suscrito el //usuario ide. tam = tamano(&usuario[ide].salas); //cada elemento de la cola de Salas de usuario for(j=1 ; j <= tam; j++) { //si otro usuario pertenece a mis salas if( pertenece( &usuario[i].salas, elemento(&usuario[ide ].salas,j) ) ) { j = tam+1; //desbloquear area compartida, mutex pthread_mutex_unlock (&mutex); //envio respuesta al cliente send( usuario[i].idSocket, mensaje, strlen(mensaje) +1, 0); //bloquear area compartida, mutex pthread_mutex_lock (&mutex); } } } } //desbloquear area compartida, mutex pthread_mutex_unlock (&mutex); //vacio buffers strcpy( mensaje, ""); strcpy( buffer, ""); strcpy( nombreAuxiliar, ""); //la peticion es mostrar las salas que posee el servidor } else if( formatoValido( expSalas, buffer) == 1 ) { //bloquear area compartida, mutex pthread_mutex_lock (&mutex); //obtengo el numero de salas en el servidor numSalas = sistemaSala[0].numeroSala; //concateno para mejorar formato de mensaje respuesta strcat( mensaje, "Salas del servidor: \n"); //almaceno las salas activas actuales for(i = 1; i <= numSalas; i++) { //si la sala no fue eliminada if(sistemaSala[i].numeroSala != -1) { //concateno para mejorar formato de mensaje respuesta strcat( mensaje, sistemaSala[i].nombreSala); strcat( mensaje, "\n"); } } //desbloquear area compartida, mutex pthread_mutex_unlock (&mutex); send( usuario[ide].idSocket, mensaje, strlen(mensaje)+1, 0); strcpy( mensaje, ""); strcpy( buffer, ""); //La peticion del usuario es crear una sala en el servidor. } else if( formatoValido( expCrearSala, buffer) == 1 ) { //bloquear area compartida, mutex pthread_mutex_lock (&mutex); //obtengo nombre de comando y parametro strcpy(funcion, primeraPalabra(buffer, longitud)); //obtengo el numero de salas en el servidor numSalas = sistemaSala[0].numeroSala; //se verifica si la sala ya existe for(i = 1; i <= numSalas ; i++) { //si encontro la sala, cambia la bandera 'j' a true if(strcmp(sistemaSala[i].nombreSala, buffer) == 0 && sistemaSala[i ].numeroSala != -1) { //cambio bandera a true j = 1; //termino ciclo i = numSalas + 1; } } //sino existe la sala proceso peticion accion if ( j == 0 ) { //concateno para mejorar formato de mensaje respuesta strcat( mensaje, "Se ha creado la sala "); strcat( mensaje, "\""); strcat( mensaje, buffer); strcat( mensaje, "\""); strcat( mensaje, " satisfactoriamente.\n"); //aumento el numero de salas sistemaSala[0].numeroSala++; //obtengo el numero de salas en el servidor numSalas = sistemaSala[0].numeroSala; //guardo el numeroSala de la nueva sala sistemaSala[numSalas].numeroSala = numSalas; //guardo el nombre de la nueva sala strcpy( sistemaSala[numSalas].nombreSala, buffer ); //agrego sala a cola de salas de usuario InsertarPalabra(&usuario[ide].salas,buffer); //coloco al usuario como conectado a la sala nueva usuario[ide].conectadoUsuario = 1; //desbloquear area compartida, mutex pthread_mutex_unlock (&mutex); //envio respuesta al cliente send( usuario[ide].idSocket, mensaje, strlen(mensaje)+1, 0); //si la sala ya existe, envio respuesta } else { //concateno para mejorar formato de mensaje de respuesta strcat( mensaje, "La sala ya existe. \n"); //desbloquear area compartida, mutex pthread_mutex_unlock (&mutex); //envio respuesta al cliente send( usuario[ide].idSocket, mensaje, strlen(mensaje)+1, 0); } //vacio buffers strcpy( mensaje, ""); strcpy( buffer, ""); //la peticion es mostrar una lista todos los usuarios conectados } else if ( formatoValido( expUsuarios, buffer) == 1 ) { //bloquear area compartida, mutex pthread_mutex_lock (&mutex); //concateno para mejorar el formato de mensaje a enviar strcat( mensaje, "Usuarios conectados: \n"); //para cada cliente verifico for(i = 1; i < clientes; i++) { //si el usuario esta conectado if( usuario[i].conectadoUsuario == 1 ) { //lo concateno con usuarios conectados strcat( mensaje, usuario[i].nombreUsuario); strcat( mensaje, "\n"); j=1; } } //hay usuarios conectados if (j==1) { //desbloquear area compartida, mutex pthread_mutex_unlock (&mutex); //envio respuesta al cliente send( usuario[ide].idSocket, mensaje, strlen(mensaje)+1, 0); } else { strcpy( mensaje, ""); //concateno para mejorar el formato de mensaje a enviarComandos strcat( mensaje, "No hay Usuarios conectados\n"); //desbloquear area compartida, mutex pthread_mutex_unlock (&mutex); //envio respuesta al cliente send( usuario[ide].idSocket, mensaje, strlen(mensaje)+1, 0); } //vacio buffers strcpy( mensaje, ""); strcpy( buffer, ""); //el usuario se suscribe a una sala } else if( formatoValido( expSuscribeSala, buffer) == 1 ) { //bloquear area compartida, mutex pthread_mutex_lock (&mutex); //obtengo nombre de comando y parametro strcpy(funcion, primeraPalabra(buffer, longitud)); //obtengo el numero de salas en el servidor numSalas = sistemaSala[0].numeroSala; //se verifica si la sala ya existe for(i = 1; i <= numSalas ; i++) { //si encontro la sala, cambia la bandera 'j' a true if(strcmp(sistemaSala[i].nombreSala, buffer) == 0 && sistemaSala[i ].numeroSala != -1) { //cambio bandera a true j = 1; //termino ciclo i = numSalas + 1; } } //si existe la sala, proceso peticion accion if ( j == 1 ) { if( pertenece( &usuario[ide].salas, buffer ) ) { //concateno para mejorar formato de mensaje de respuesta strcat( mensaje, "Usted ya esta suscrito a esta sala. \n"); //desbloquear area compartida, mutex pthread_mutex_unlock (&mutex); //envio respuesta al cliente send( usuario[ide].idSocket, mensaje, strlen(mensaje)+1, 0); } else { //concateno para mejorar formato de mensaje respuesta strcat( mensaje, "Suscrito a la sala "); strcat( mensaje, "\""); strcat( mensaje, buffer); strcat( mensaje, "\""); strcat( mensaje, " satisfactoriamente.\n"); //agrego sala a cola de salas de usuario InsertarPalabra(&usuario[ide].salas,buffer); //coloco al usuario como conectado a la sala nueva usuario[ide].conectadoUsuario = 1; //desbloquear area compartida, mutex pthread_mutex_unlock (&mutex); //envio respuesta al cliente send( usuario[ide].idSocket, mensaje, strlen(mensaje)+1, 0); } //si la sala no existe, envio respuesta } else { //concateno para mejorar formato de mensaje de respuesta strcat( mensaje, "La sala a suscribirse no existe. \n"); //desbloquear area compartida, mutex pthread_mutex_unlock (&mutex); //envio respuesta al cliente send( usuario[ide].idSocket, mensaje, strlen(mensaje)+1, 0); } //vacio buffers strcpy( mensaje, ""); strcpy( buffer, ""); //eliminar una sala del servidor } else if( formatoValido( expEliminaSala, buffer) == 1 ) { //bloquear area compartida, mutex pthread_mutex_lock (&mutex); //obtengo nombre de comando y parametro strcpy(funcion, primeraPalabra(buffer, longitud)); //obtengo el numero de salas en el servidor numSalas = sistemaSala[0].numeroSala; //se verifica si la sala ya existe for(i = 1; i <= numSalas ; i++) { //si encontro la sala, cambia la bandera 'j' a true if(strcmp(sistemaSala[i].nombreSala, buffer) == 0 && sistemaSala[i ].numeroSala != -1) { //elimino la sala sistemaSala[i].numeroSala = -1; //cambio bandera a true j = 1; //termino ciclo i = numSalas + 1; } } //si existe la sala, proceso peticion accion if ( j != 0 ) { //concateno para mejorar formato de mensaje respuesta strcat( mensaje, "Sala "); strcat( mensaje, "\""); strcat( mensaje, buffer); strcat( mensaje, "\""); strcat( mensaje, " eliminada satisfactoriamente.\n"); //envio mensaje para cada usuario for(i = 1; i < clientes; i++) { if( eliminarElemento( &usuario[i].salas, buffer ) ) { //numero de salas a la que esta suscrito el //usuario ide. tam = tamano(&usuario[i].salas); //sino esta suscrito a mas salas, lo des-suscribo if(tam == 0) { //coloco al usuario como desconectado usuario[i].conectadoUsuario = 0; } //desbloquear area compartida, mutex pthread_mutex_unlock (&mutex); //envio respuesta al cliente send( usuario[i].idSocket, mensaje, strlen(mensaje)+1, 0); //bloquear area compartida, mutex pthread_mutex_lock (&mutex); } } //desbloquear area compartida, mutex pthread_mutex_unlock (&mutex); //si la sala no existe, envio respuesta } else { //concateno para mejorar formato de mensaje de respuesta strcat( mensaje, "La sala a eliminar no existe. \n"); //desbloquear area compartida, mutex pthread_mutex_unlock (&mutex); //envio respuesta al cliente send( usuario[ide].idSocket, mensaje, strlen(mensaje)+1, 0); } //vacio buffers strcpy( mensaje, ""); strcpy( buffer, ""); //el usuario se des-suscribe de todas las salas } else if( formatoValido( expDesSuscribir, buffer) == 1 ) { //bloquear area compartida, mutex pthread_mutex_lock (&mutex); //guardo mensaje de des-suscripcion strcat( mensaje, "De-suscrito de todas las salas satisfactoriamente. \n"); //coloco al usuario como desconectado usuario[ide].conectadoUsuario = 0; //coloco al usuario sin ninguna sala usuario[ide].salas=NULL; //desbloquear area compartida, mutex pthread_mutex_unlock (&mutex); //envio respuesta al cliente send( usuario[ide].idSocket, mensaje, strlen(mensaje)+1, 0); //vacio buffers strcpy( mensaje, ""); strcpy( buffer, ""); //el usuario termina la ejecucion de su cchat } else if( formatoValido( expFueraChat, buffer) == 1 ) { //bloquear area compartida, mutex pthread_mutex_lock (&mutex); //obtengo nombre de comando strcpy(funcion, primeraPalabra(buffer, longitud)); //coloco al usuario como fuera del servidor usuario[ide].conectadoUsuario = -1; //coloco al usuario sin ninguna sala usuario[ide].salas=NULL; //desbloquear area compartida, mutex pthread_mutex_unlock (&mutex); //envio respuesta al cliente send( usuario[ide].idSocket, funcion, strlen(funcion)+1, 0); //vacio buffers strcpy( mensaje, ""); strcpy( buffer, ""); //dejo de atender peticiones de este cliente break; } else { //guardo mensaje de comando invalido strcat( mensaje, "\t'COMANDO INVALIDO, SERVICIO NO ENCONTRADO'\n"); //envio respuesta al cliente send( usuario[ide].idSocket, mensaje, strlen(mensaje)+1, 0); //vacio buffers strcpy( mensaje, ""); strcpy( buffer, ""); } fflush(stdout); } } /* Proyecto 1: Redes ci4815 Programa: SocketServidor.c Realizado por: Lairon Acosta Version: 1.4 ----------------------------Includes del sistema */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <Cola.h> #include <netdb.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <sys/syscall.h> #include <sys/resource.h> #include <errno.h> #include <sys/stat.h> #include <unistd.h> #include <dirent.h> #include <fcntl.h> #include <sys/time.h> #include <regex.h> #include <SocketServidor.h> /****Implementacion de metodos****/ /*funcion: realiza conexion de sockets arg1: puerto donde se hara la conexion return: descriptor de conexion */ int ConexionInetServidor (char *puerto) { //Declaracion de variables int fd_socket; struct sockaddr_in address; struct in_addr inaddr; struct hostent *host_cliente; //Abrimos el socket if(( fd_socket = socket (PF_INET, SOCK_STREAM, 0)) < 0) { printf("Error abriendo el socket\n"); return -1; //exit(1); } /* * Se rellenan los campos de la estructura Direccion, necesaria * para la llamada a la funcion bind() */ address.sin_family = AF_INET; address.sin_addr.s_addr =INADDR_ANY; //verifica si se obtuvo error en el puerto if ( !(address.sin_port = htons(atoi(puerto))) ) { //dir PUERTO printf("Error en el puerto\n"); return -1; //exit(1); } if ( bind( fd_socket, (struct sockaddr *) &address, sizeof (address) ) == -1) { printf("Error realizando el bind\n"); close (fd_socket); return -1; } /* * Se avisa al sistema que comience a atender llamadas de clientes */ if (listen (fd_socket, 1) == -1) { printf("Error realizando el listen\n"); close (fd_socket); return -1; } /* * Se devuelve el descriptor del socket servidor */ return fd_socket; } /*funcion: realiza la aceptacion de la conexion con el cliente arg1: descriptor de conexion return: descriptor de conexion */ int AceptaConexionInetCliente (int fd_socket) { socklen_t longitudCliente; struct sockaddr cliente; int acepta; /* * La llamada a la funcion accept requiere que el parametro * Longitud_Cliente contenga inicialmente el tamano de la * estructura Cliente que se le pase. A la vuelta de la * funcion, esta variable contiene la longitud de la informacion * util devuelta en Cliente */ longitudCliente = sizeof (cliente); acepta = accept (fd_socket, &cliente, &longitudCliente); if (acepta == -1) { return -1; } /* * Se devuelve el descriptor en el que esta "enchufado" el cliente. */ return acepta; } /*funcion: procesa los argumentos de la llamada Servidor1 arg1: cantidad de argumentos arg2: lista de argumentos arg3: cola que saldra modificada */ void procesarArgumentosServidor(int numeroArg, char *argv[], Cola *cola) { char retorno[3][50]; // Comando de entrada: schat [-p <puerto>] [-s <sala>] if( strcmp(argv[1],"-p") == 0 ) { //copia el nombre en la posicion 0 del arreglo retorno strcpy(retorno[0],argv[2]); if( strcmp(argv[3],"-s") == 0 ) { //copia el archivo en la posicion 1 del arreglo retorno strcpy(retorno[1],argv[4]); } else { printf ("Error: argumento -s no corresponde\n"); exit(1); } } else if( strcmp(argv[3],"-p") == 0 ) { //copia el nombre en la posicion 2 del arreglo retorno strcpy(retorno[0],argv[4]); if( strcmp(argv[1],"-s") == 0 ) { //copia el archivo en la posicion 3 del arreglo retorno strcpy(retorno[1],argv[2]); } else { printf ("Error: argumento -s no corresponde\n"); exit(1); } } else { printf ("Error: argumento -p no corresponde\n"); exit(1); } InsertarPalabra (cola, retorno[0]); InsertarPalabra (cola, retorno[1]); } /*funcion: procesa los argumentos de la llamada Servidor2 arg1: cantidad de argumentos arg2: lista de argumentos arg3: cola que saldra modificada */ void procesarArgumentosServidor2(int numeroArg, char *argv[], Cola *cola) { char retorno[3][50]; // Comando de entrada: schat [-p <puerto>] [-s] // Comando de entrada: schat [-s] [-p <puerto>] if( strcmp(argv[1],"-p") == 0 ) { //copia el nombre en la posicion 0 del arreglo retorno strcpy(retorno[0],argv[2]); if( strcmp(argv[3],"-s") == 0 ) { //copia el archivo en la posicion 1 del arreglo retorno strcpy(retorno[1],"actual"); } else { printf ("Error: argumento -s no corresponde\n"); exit(1); } } else if( strcmp(argv[2],"-p") == 0 ) { //copia el nombre en la posicion 2 del arreglo retorno strcpy(retorno[0],argv[3]); if( strcmp(argv[1],"-s") == 0 ) { //copia el archivo en la posicion 3 del arreglo retorno strcpy(retorno[1],"actual"); } else { printf ("Error: argumento -s no corresponde\n"); exit(1); } } else { printf ("Error: argumento -p no corresponde\n"); exit(1); } InsertarPalabra (cola, retorno[0]); InsertarPalabra (cola, retorno[1]); } /*funcion: obtiene primera palabra de una cadena arg1: cadena arg2: tamano de cadena return: primera palabra de la cadena */ char * primeraPalabra(char *cad, int tam) { char * palabra = malloc(100); int i,j=0; for( i=0 ; (i < tam && cad[i]!=' ' && cad[i]!='\n') ; i++) { palabra[j]=cad[i]; cad[i]=' '; j++; } palabra[j]='\0'; j=0; i = i+1; for( i ; i < tam && cad[i]!='\n' ; i++) { cad[j]=cad[i]; j++; } cad[j]='\0'; return palabra; } /*funcion: verifica si una cadena es una expresion regular valida arg1: expresion regular aplicar arg2: cadena de texto a verificar int: 1 si match, 0 sino. */ int formatoValido(char *expresion, char *texto) { regex_t regex; int rec; char msgbuf[100]; /* Compila la expresion regular */ rec = regcomp(&regex, expresion , 0); //verifico error if( rec ) { fprintf(stderr, "No se pudo compilar la expresion regular\n"); regfree(&regex); return 0; } /* Ejecuta la expresion regular */ rec = regexec(&regex, texto , 0, NULL, 0); if ( !rec ) { regfree(&regex); return 1; } else if ( rec == REG_NOMATCH ) { regfree(&regex); return 0; } else { regerror(rec, &regex, msgbuf, sizeof(msgbuf)); fprintf(stderr, "Regex match fallo: %s\n", msgbuf); regfree(&regex); return 0; } /* libera el compilador si quieres usar regex de nuevo */ regfree(&regex); } /* Proyecto 1: Redes ci4815 Programa: SocketServidor.h Realizado por: Lairon Acosta Version: 1.2 */ /*Definiciones de tipos y estructuras de datos*/ /* Estructura para manejar los usuarios var1: id socket de usuarios var2: nombre del usuario var3: conectado o desconectado (var3 = 1 si usuario esta conectado) (var3 = 0 si usuario esta desconectado) var4: Cola de salas a la que esta suscrito */ typedef struct datos { int idSocket; char nombreUsuario[100]; int conectadoUsuario; Cola salas; } Data; //variable de tipo Datos de usuario typedef Data dataUsuario; /* Estructura para manejar las salas var1: nombre de la sala var2: numero de la sala (var2 = -1 si sala esta eliminada) (var2 = 1 si sala no esta eliminada) */ typedef struct salas { char nombreSala[100]; int numeroSala; } Salas; //variable de tipo Datos de salas typedef Salas salaUsuario; /*******Definiciones de metodos********/ /*funcion: realiza conexion de sockets arg1: puerto donde se hara la conexion return: descriptor de conexion */ int ConexionInetServidor (char *puerto); /*funcion: realiza la aceptacion de la conexion con el cliente arg1: descriptor de conexion return: descriptor de conexion */ int AceptaConexionInetCliente (int fd_socket); /*funcion: procesa los argumentos de la llamada Servidor1 arg1: cantidad de argumentos arg2: lista de argumentos arg3: cola que saldra modificada */ void procesarArgumentosServidor(int numeroArg, char *argv[], Cola *cola); /*funcion: procesa los argumentos de la llamada Servidor2 arg1: cantidad de argumentos arg2: lista de argumentos arg3: cola que saldra modificada */ void procesarArgumentosServidor2(int numeroArg, char *argv[], Cola *cola); /*funcion: obtiene primera palabra de una cadena arg1: cadena arg2: tamano de cadena return: primera palabra de la cadena */ char * primeraPalabra(char *cad, int tam); /*funcion: verifica si una cadena es una expresion regular valida arg1: expresion regular aplicar arg2: cadena de texto a verificar int: 1 si match, 0 sino. */ int formatoValido(char *expresion, char *texto); /* Proyecto 1: Redes ci4815 Programa: Cola.c Realizado por: Lairon Acosta Version: 1.9 */ #include <stdlib.h> #include <stdio.h> #include <string.h> #include <Cola.h> //funcion: inserta una palabra en la cola //out: la cola modificada void InsertarPalabra (Cola *cola, char *pal ) { apNodo nodo, nodoAux; if (((apNodo)malloc(sizeof(tipoCaja)))==NULL) { printf("\nElemento no insertado por falta de memoria."); } else { /*Creamos un nodo para el valor a insertar*/ nodo = (apNodo)malloc(sizeof(tipoCaja)); strcpy (nodo->palabra, pal); nodo->sig = NULL; /* si la cola está vacía, el *cola sera el nuevo nodo*/ /* si no lo esta, insertamos el nuevo nodo al final de la cola*/ if(*cola == NULL) { *cola = nodo; } else { nodoAux = (*cola); while (nodoAux->sig != NULL) { nodoAux = nodoAux->sig; } nodoAux->sig = nodo; } } } //funcion: borra una palabra de la cola //out: retorna 0 si borro o 1 sino borro int BorrarPrimero(Cola *cola) { apNodo nodo; int borro = 1; borro=1; //1= no borro, 0= si borro nodo = *cola; if (nodo == NULL) { borro = 1; } else { (*cola) = (*cola)->sig; nodo->sig = NULL; free(nodo); borro = 0; } return (borro); } //funcion: imprime la cola en pantalla //out: salida standar void ImprimirCola(Cola *cola) { apNodo nodo; nodo = *cola; if (cola!=NULL) { while (nodo->sig != NULL){ printf(" -> %s ", nodo->palabra); printf("\n"); nodo = nodo->sig; } printf(" -> %s ", nodo->palabra); printf("\n"); printf("\n"); } else { printf(" Lista vacia\n\n"); } } //funcion: borra una palabra de la cola //out: retorna 0 si borro o 1 sino borro char * damePrimero(Cola *cola) { apNodo nodo; int borro = 1; char *word =malloc(300); borro=1; //1= no borro, 0= si borro nodo = *cola; if (nodo == NULL) { borro = 1; } else { strcpy(word,nodo->palabra); (*cola) = (*cola)->sig; nodo->sig = NULL; free(nodo); borro = 0; } return word; } //funcion: destruye la cola y libera espacio //out: espacio liberado void destruirCola(Cola *cola) { apNodo nodo; //si la cola no esta vacia if ((*cola)!=NULL) { /*Si la lista tiene mas de un nodo*/ while((*cola)->sig != NULL) { /*desplaza nodo y *cola y borra la caja apuntada por nodo*/ nodo = (*cola)->sig; (*cola)->sig = nodo->sig; free(nodo); } /*borra el nodo apuntado por *cola que es el ultimo nodo*/ free(*cola); *cola = NULL; } } //funcion: elimina un elemento de la cola //out: bool 1 true o 0 false int eliminarElemento(Cola *cola, char *palabra) { apNodo nodo, nodoAux; nodo = (*cola); int encontro = 0; //si la cola no esta vacia if ((*cola)!=NULL) { //cola de un solo elemento if((*cola)->sig == NULL) { //printf(" CASO un elemento\n\n"); if(strcmp(palabra,nodo->palabra)==0) { nodo = (*cola)->sig; free(nodo); //free(*cola); (*cola) =NULL; return 1; } return 0; } else { //printf(" CASO 2\n\n"); nodoAux = nodo->sig; if(nodo->sig != NULL && strcmp(palabra,nodo->palabra)==0) { (*cola) = nodo->sig; nodo = NULL; free(nodo); return 1; } else { while (nodo->sig != NULL) { //printf(" entro al while\n\n"); if(strcmp(palabra,nodoAux->palabra)==0) { //printf(" entro al while..CASO 1\n\n"); nodo->sig = nodoAux->sig; nodoAux->sig = NULL; nodo = nodoAux; nodoAux = nodoAux->sig; encontro = 1; } else { //printf(" entro al while..CASO 2\n\n"); nodo = nodoAux; nodoAux = nodoAux->sig; } // printf(" entro al while..next vuelta\n\n"); } if(encontro){ free(nodoAux); return 1; } return 0; } } } else { //printf(" CASO vacia\n\n"); return 0; } } //funcion: varifica si un elemento esta en la cola //out: bool 1 true 0 false int pertenece(Cola *cola, char *palabra) { apNodo nodo; nodo = *cola; if ((*cola)!=NULL) { while (nodo->sig != NULL){ if(strcmp(palabra, nodo->palabra)==0){ return 1; } nodo = nodo->sig; } if(strcmp(palabra, nodo->palabra)==0){ return 1; } return 0; } else { return 0; } } //funcion: calcula el tamano de la cola //out: int numero de elementos en cola int tamano(Cola *cola) { apNodo nodo; nodo = *cola; int tam = 0; if ((*cola)!=NULL) { while (nodo->sig != NULL) { tam++; nodo = nodo->sig; } tam++; return tam; } else { return tam; } } //funcion: busca un elemento de la cola //out: y lo retorna char * elemento(Cola *cola, int n) { apNodo nodo; nodo = *cola; int tam = 0; int actualTam = tamano(cola)+1; if ((*cola)!=NULL && n > 0 && n < actualTam ) { while (nodo->sig != NULL) { tam++; if( tam == n ) { return nodo->palabra; } nodo = nodo->sig; } tam++; if( tam == n) { return nodo->palabra; } return NULL; } else { return NULL; } } /* Proyecto 1: Redes ci4815 Programa: Cola.h Realizado por: Lairon Acosta Version: 2.3 */ /*Definiciones de tipos y estructuras de datos*/ //estructura para manejar una Cola typedef struct caja { char palabra[300]; struct caja *sig; } tipoCaja; //Variables de tipo Cola typedef tipoCaja *Cola; typedef tipoCaja *apNodo; //funcion: inserta una palabra en la cola //out: la cola modificada void InsertarPalabra(Cola *cola, char *pal ); //funcion: borra una palabra de la cola //out: retorna 0 si borro o 1 sino borro int BorrarPrimero(Cola *cola); //funcion: imprime la cola en pantalla //out: salida standar void ImprimirCola(Cola *cola); //funcion: obtengo primer elemento de la cola //out: cola modificada char * damePrimero(Cola *cola); //funcion: destruye la cola y libera espacio //out: espacio liberado void destruirCola(Cola *cola); //funcion: elimina un elemento de la cola //out: bool 1 true o 0 false int eliminarElemento(Cola *cola, char *palabra); //funcion: varifica si un elemento esta en la cola //out: bool 1 true 0 false int pertenece(Cola *cola, char *palabra); //funcion: calcula el tamano de la cola //out: int numero de elementos en cola int tamano(Cola *cola); //funcion: busca un elemento de la cola //out: y lo retorna char * elemento(Cola *cola, int n); MAKEFILE all : Cola.o SocketCliente.o SocketServidor.o -lpthread cchat schat CPPFLAGS = -g -I. cchat : Cliente.c cc -g -I. Cola.o SocketCliente.o Cliente.c -lpthread -o cchat schat : Servidor.c cc -g -I. Cola.o SocketServidor.o Servidor.c -lpthread -o schat clean : rm *.o cchat schat