Grupo 5 - Universidad Simón Bolívar

Anuncio
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
Descargar