From: thepeople Date: Fri, 12 Feb 2010 00:36:12 +0000 (+0000) Subject: commit package to go along with the last commit, thanks fofware X-Git-Url: http://git.archive.openwrt.org/?a=commitdiff_plain;h=7dfd14a7638e6d5999ffde12c77047375f055dba;p=packages.git commit package to go along with the last commit, thanks fofware git-svn-id: svn://svn.openwrt.org/openwrt/packages@19589 3c298f89-4303-0410-b956-a3cf2f4a3e73 --- diff --git a/net/remotectrl/Makefile b/net/remotectrl/Makefile new file mode 100644 index 000000000..4fc66fda2 --- /dev/null +++ b/net/remotectrl/Makefile @@ -0,0 +1,48 @@ +# +# Copyright (C) 2006 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=chillisocket +PKG_RELEASE:=1 + +include $(INCLUDE_DIR)/package.mk +include $(INCLUDE_DIR)/kernel.mk + +define Package/chillisocket + SECTION:=Testing + CATEGORY:=Testing +# DEPENDS:= + TITLE:=Socket library server client +endef + +TARGET_CPPFLAGS := \ + -I$(STAGING_DIR)/usr/include/ \ + -I$(LINUX_DIR)/include \ + -I$(PKG_BUILD_DIR) \ + $(TARGET_CPPFLAGS) + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) + $(CP) ./src/* $(PKG_BUILD_DIR)/ +endef + +define Build/Compile + CFLAGS="$(TARGET_CPPFLAGS) $(TARGET_CFLAGS)" \ + $(MAKE) -C $(PKG_BUILD_DIR) \ + $(TARGET_CONFIGURE_OPTS) \ + LIBS="$(TARGET_LDFLAGS) -lm" +endef + +define Package/chillisocket/install + $(INSTALL_DIR) $(1)/bin +# $(INSTALL_BIN) $(PKG_BUILD_DIR)/libChSocket.a $(1)/bin/libChSocket.a + $(INSTALL_BIN) $(PKG_BUILD_DIR)/servselect $(1)/bin/servselect + $(INSTALL_BIN) $(PKG_BUILD_DIR)/clientselect $(1)/bin/clientselect +endef + +$(eval $(call BuildPackage,chillisocket)) diff --git a/net/remotectrl/src/Makefile b/net/remotectrl/src/Makefile new file mode 100644 index 000000000..017fd830b --- /dev/null +++ b/net/remotectrl/src/Makefile @@ -0,0 +1,30 @@ +ifndef CFLAGS +CFLAGS = -O2 -g -I ../src +endif +VERSION=0.1 + +LIBS=-lnl + +# Ficheros objeto que van dentro de la minilibrería. +LIBCHSOCK=\ + Socket_Servidor.o\ + Socket_Cliente.o\ + Socket.o + +all: servselect clientselect server_socket +# clientselect libChSocket.a + +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $^ + +#libChSocket.a : libChSocket.a($(LIBCHSOCK)) + +servselect: servselect.o Socket_Servidor.o Socket.o + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) + +clientselect: clientselect.o Socket.o Socket_Cliente.o + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) +# cc clientselect.c -I$(LIBCHSOCKET) -L$(LIBCHSOCKET) -lChSocket -o clientselect + +server_socket: server_socket.o remotectrl.o + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) diff --git a/net/remotectrl/src/Makefile.inc b/net/remotectrl/src/Makefile.inc new file mode 100644 index 000000000..ca56ed8f8 --- /dev/null +++ b/net/remotectrl/src/Makefile.inc @@ -0,0 +1,17 @@ +prefix=/usr +DESTDIR= + +COPTS=-O2 +WOPTS=-pedantic -Werror -Wall +FPIC=-fPIC +CFLAGS=$(COPTS) $(WOPTS) -std=gnu99 + +AR=ar +CC=gcc +RANLIB=ranlib +INSTALL=install +MKDIR=mkdir + +LINK=$(CC) +SHLIB_EXT=so +SHLIB_FLAGS=-shared -Wl,-soname,$(SHLIB_FILE) diff --git a/net/remotectrl/src/Socket.c b/net/remotectrl/src/Socket.c new file mode 100644 index 000000000..2c6bb495a --- /dev/null +++ b/net/remotectrl/src/Socket.c @@ -0,0 +1,417 @@ +/* +* Javier Abellan, 20 Jun 2000 +* +* Funciones de lectura y escritura en sockets +* +* MODIFICACIONES: +* 4 Septiembre 2003: Añadidas funciones para sockets UDP. +*/ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Socket.h" + +#define BUFFER_SIZE 13 + +int ReadTcpSocket (int fd, char **Datos) +{ + int Leido = 0; + struct head_t *head; + int Aux=0; + char buffer[BUFFER_SIZE]; + char *message; + message = malloc(BUFFER_SIZE); + while (1){ + bzero(buffer, BUFFER_SIZE); + Aux = read(fd, buffer, BUFFER_SIZE-1); + if (Leido==0){ + message = memcpy(message, buffer, Aux); + head = malloc(sizeof(struct head_t)); + head = memcpy(head,buffer,Aux); + } else { + message = realloc(message,(strlen(message)+Aux)); + if (Aux == BUFFER_SIZE-1) + message = strcat(message,buffer); + else + message = strncat(message,buffer,Aux); + } + Leido += Aux; + +printf("msg=%s Leido=%d\n", message, Leido); + if (Aux < BUFFER_SIZE-1 || Leido == head->len ) + break; + } + *Datos=realloc(*Datos,Leido+1); + memcpy(*Datos,head,sizeof(struct head_t)); + memcpy(*Datos+12, message, Leido); + return Leido; +} + +int WriteTcpSocket(int fd, int type, int command, char *data){ + int Escrito = 0; + int Aux = 0; + + int Longitud = (sizeof(int)*3)+strlen((char *)data); + struct s_msg *Datos; + Datos = malloc(Longitud); + Datos->type = type; + Datos->command = command; + Datos->len = Longitud; + strcpy(Datos->data, data); + printf("Longitud=%d convertido Type=%d Command=%d Len=%d Data=%s\n",Longitud, Datos->type, Datos->command, Datos->len, Datos->data); + printf("Longitud=%d int=%d\n", Longitud,sizeof(int)); +/* + if ((fd == -1) || (Datos == NULL) || (Longitud < 1)) + return -1; + +*/ +//printf("Data:%s", *Datos); + while (Escrito < Longitud) + { + Aux = write (fd, Datos + Escrito, Longitud - Escrito); + if (Aux > 0) + { + Escrito = Escrito + Aux; + } + else + { + if (Aux == 0) + return Escrito; + else + return -1; + } + } + free(Datos); + return Escrito; +} + +/* +* Lee datos del socket. Supone que se le pasa un buffer con hueco +* suficiente para los datos. Devuelve el numero de bytes leidos o +* 0 si se cierra fichero o -1 si hay error. +*/ +int Lee_Socket1 (int fd, char *Datos, int Longitud) +{ + int Leido = 0; + int Aux = 0; + + + /* + * Comprobacion de que los parametros de entrada son correctos + */ + if ((fd == -1) || (Datos == NULL) || (Longitud < 1)) + return -1; + + /* + * Mientras no hayamos leido todos los datos solicitados + */ + + while (Leido < Longitud) + { + Aux = read (fd, Datos + Leido, Longitud - Leido); + if (Aux > 0) + { + /* + * Si hemos conseguido leer datos, incrementamos la variable + * que contiene los datos leidos hasta el momento + */ + Leido = Leido + Aux; + } + else + { + /* + * Si read devuelve 0, es que se ha cerrado el socket. Devolvemos + * los caracteres leidos hasta ese momento + */ + if (Aux == 0) + return Leido; + if (Aux == -1) + { + /* + * En caso de error, la variable errno nos indica el tipo + * de error. + * El error EINTR se produce si ha habido alguna + * interrupcion del sistema antes de leer ningun dato. No + * es un error realmente. + * El error EGAIN significa que el socket no esta disponible + * de momento, que lo intentemos dentro de un rato. + * Ambos errores se tratan con una espera de 100 microsegundos + * y se vuelve a intentar. + * El resto de los posibles errores provocan que salgamos de + * la funcion con error. + */ + switch (errno) + { + case EINTR: + case EAGAIN: + usleep (100); + break; + default: + return -1; + } + } + } + } + + /* + * Se devuelve el total de los caracteres leidos + */ + return Leido; +} + +/* +* Escribe dato en el socket cliente. Devuelve numero de bytes escritos, +* o -1 si hay error. +*/ +int Escribe_Socket (int fd, char *Datos, int Longitud) +{ + int Escrito = 0; + int Aux = 0; + + /* + * Comprobacion de los parametros de entrada + */ + if ((fd == -1) || (Datos == NULL) || (Longitud < 1)) + return -1; + + /* + * Bucle hasta que hayamos escrito todos los caracteres que nos han + * indicado. + */ + while (Escrito < Longitud) + { + Aux = write (fd, Datos + Escrito, Longitud - Escrito); + if (Aux > 0) + { + /* + * Si hemos conseguido escribir caracteres, se actualiza la + * variable Escrito + */ + Escrito = Escrito + Aux; + } + else + { + /* + * Si se ha cerrado el socket, devolvemos el numero de caracteres + * leidos. + * Si ha habido error, devolvemos -1 + */ + if (Aux == 0) + return Escrito; + else + return -1; + } + } + + /* + * Devolvemos el total de caracteres leidos + */ + return Escrito; +} + +/** + * Lee un mensaje de un socket udp. Los parámetros que se pasan son: + * - Descriptor fd del socket del que se quiere leer. + * - Estructura Remoto, en la que se devolverá los datos del que ha enviado el + * mensaje que acabamos de leer. + * - Longitud_Remoto de la estructura anterior. Debe pasarse relleno con el tamaño + * de Remoto y se devolverá rellena con el tamaño de los datos en Remoto. + * - Buffer de Datos donde se quiere que aparezca el mensaje. + * - Longitud_Datos del buffer anterior. + * + * Devuelve el número de bytes leidos o -1 en caso de error. + */ +int Lee_Socket_Udp ( + int fd, struct sockaddr *Remoto, socklen_t *Longitud_Remoto, + char *Datos, int Longitud_Datos) +{ + int Leido = 0; + int Aux = 0; + + /* + * Comprobacion de que los parametros de entrada son correctos + */ + if ((fd == -1) || (Datos == NULL) || (Longitud_Datos < 1) + || (Remoto == NULL) || (Longitud_Remoto == NULL)) + { + return -1; + } + + /* + * Mientras no hayamos leido todos los datos solicitados + */ + while (Leido < Longitud_Datos) + { + Aux = recvfrom (fd, Datos + Leido, Longitud_Datos - Leido, 0, + Remoto, Longitud_Remoto); + + if (Aux > 0) + { + /* + * Si hemos conseguido leer datos, incrementamos la variable + * que contiene los datos leidos hasta el momento + */ + Leido = Leido + Aux; + } + else + { + /* + * Si read devuelve 0, es que se ha cerrado el socket. Devolvemos + * los caracteres leidos hasta ese momento + */ + if (Aux == 0) + return Leido; + if (Aux == -1) + { + /* + * En caso de error, la variable errno nos indica el tipo + * de error. + * El error EINTR se produce si ha habido alguna + * interrupcion del sistema antes de leer ningun dato. No + * es un error realmente. + * El error EGAIN significa que el socket no esta disponible + * de momento, que lo intentemos dentro de un rato. + * Ambos errores se tratan con una espera de 100 microsegundos + * y se vuelve a intentar. + * El resto de los posibles errores provocan que salgamos de + * la funcion con error. + */ + switch (errno) + { + case EINTR: + case EAGAIN: + usleep (100); + break; + default: + return -1; + } + } + } + } + + /* + * Se devuelve el total de los caracteres leidos + */ + return Leido; +} + +/** +* Escribe dato en el socket cliente. Devuelve numero de bytes escritos, +* o -1 si hay error. +* - fd es el descriptor del socket. +* - Remoto es el destinatario del mensaje, a quién se lo queremos enviar. +* - Longitud_Remoto es el tamaño de Remoto en bytes. +* - Datos es el mensaje que queremos enviar. +* - Longitud_Datos es el tamaño del mensaje en bytes. +*/ +int Escribe_Socket_Udp (int fd, struct sockaddr *Remoto, + socklen_t Longitud_Remoto, char *Datos, int Longitud_Datos) +{ + int Escrito = 0; + int Aux = 0; + + /* + * Comprobacion de los parametros de entrada + */ + if ((fd == -1) || (Datos == NULL) || (Longitud_Datos < 1) + || (Remoto == NULL) ) + { + return -1; + } + + /* + * Bucle hasta que hayamos escrito todos los caracteres que nos han + * indicado. + */ + while (Escrito < Longitud_Datos) + { + Aux = sendto (fd, Datos + Escrito, Longitud_Datos - Escrito, 0, + Remoto, Longitud_Remoto); + + if (Aux > 0) + { + /* + * Si hemos conseguido escribir caracteres, se actualiza la + * variable Escrito + */ + Escrito = Escrito + Aux; + } + else + { + /* + * Si se ha cerrado el socket, devolvemos el numero de caracteres + * leidos. + * Si ha habido error, devolvemos -1 + */ + if (Aux == 0) + return Escrito; + else + { + return -1; + } + } + } + + /* + * Devolvemos el total de caracteres leidos + */ + return Escrito; +} + + +/** + * Rellena una estructura sockaddr_in con los datos que se le pasan. Esta estrutura es + * útil para el envio o recepción de mensajes por sockets Udp o para abrir conexiones. + * Se le pasa el host. Puede ser NULL (para abrir socket servidor Udp o para recepción de + * mensajes de cualquier host). + * Se le pasa el servicio. Puede ser NULL (para abrir socket cliente Udp). + * Se le pasa una estructura sockaddr_in que devolverá rellena. + * Se le pasa una Longitud. Debe contener el tamaño de la estructura sockaddr_in y + * devolverá el tamaño de la estructura una vez rellena. + * Devuelve -1 en caso de error. + */ +int Dame_Direccion_Udp (char *Host, char *Servicio, struct sockaddr_in *Servidor, + int *Longitud_Servidor) +{ + struct servent *Puerto; + struct hostent *Maquina; + + /* Comprobación de parámetros */ + if (Servidor == NULL) return -1; + + /* Relleno del primer campo de la estructura */ + Servidor->sin_family = AF_INET; + + /* Si nos han pasado un host ... */ + if (Host != NULL) + { + /* ... obtenemos la dirección del host y la ponemos en la estructura */ + Maquina = gethostbyname (Host); + if (Maquina == NULL) + return -1; + + Servidor->sin_addr.s_addr = ((struct in_addr *)(Maquina->h_addr))->s_addr; + } + else + /* Si no nos han pasado un host, ponemos cualquier host. */ + Servidor->sin_addr.s_addr = INADDR_ANY; + + /* Si servicio en NULL, hacemos que el puerto lo eliga el sistema operativo + libremente.*/ + if (Servicio == NULL) + Servidor->sin_port = 0; + else + { + /* Si el servicio no es NULL, lo obtenemos. */ + Puerto = getservbyname (Servicio, "udp"); + if (Puerto == NULL) + return -1; + Servidor->sin_port = Puerto->s_port; + } +} diff --git a/net/remotectrl/src/Socket.h b/net/remotectrl/src/Socket.h new file mode 100644 index 000000000..d83d62a8d --- /dev/null +++ b/net/remotectrl/src/Socket.h @@ -0,0 +1,86 @@ +/** + * Javier Abellán, 20 Junio 2000 + * + * Funciones de lectura y escritura de la librería de sockets. + * + * MODIFICACIONES: + * 4 de Septiembre de 2003. Añadidas funciones Lee_Socket_Udp(), + * Escribe_Socket_Udp() y Dame_Direccion_Udp() + */ +#ifndef _SOCKET_H +#define _SOCKET_H + +#include + +/* +enum +{ + MSG_OK = 0, + MSG_QRY, + MSG_START, + MSG_PART, + MSG_END, +}; +int ReadTcpSocket(int fd, char **msg); +int WriteTcpSocket(int fd, struct *Datos); +*/ +struct head_t { + int type; + int command; + int len; +}; + +struct s_msg { + int type; + int command; + int len; + char data[30]; +}; + +int ReadTcpSocket (int fd, char **Datos); +int WriteTcpSocket (int fd, int type, int command, char *Datos); + +/** Lee Datos de tamaño Longitud de un socket cuyo descriptor es fd. + * Devuelve el numero de bytes leidos o -1 si ha habido error */ +int Lee_Socket1 (int fd, char *Datos, int Longitud); + +/** Envia Datos de tamaño Longitud por el socket cuyo descriptor es fd. + * Devuelve el número de bytes escritos o -1 si ha habido error. */ +int Escribe_Socket (int fd, char *Datos, int Longitud); + +/** Lee un mensaje de un socket UDP. + * Se le pasa el descriptor fd del socket que atiende los mensajes. + * Se le pasa uns estructura sockaddr que nos devolverá rellena con los datos del que nos + * ha enviado el mensaje, de forma que podamos responderle. + * Se le pasa el tamaño de la estructura Remoto. En la misma variable nos devolverá el + * tamaño de los datos devueltos. + * Se le pasa un buffer de datos para el mensaje y el tamaño en bytes que deseamos leer. + */ +int Lee_Socket_Udp (int fd, struct sockaddr *Remoto, socklen_t *Longitud_Remoto, + char *Datos, int Longitud_Datos); + +/** Envia un mensaje por un socket UDP + * Se le pasa el descriptor de socket por el que debe enviar. + * Se le pasa el destinatario del mensaje en una estructura Remoto. + * Se le pasa el tamaño de dicha estructura en Longitud_Remoto. + * Se le pasa el buffer de datos que debe enviar en Datos. + * Se le pasa la longitud del buffer de datos en Longitud. + * Devuelve el número de bytes enviados o -1 si ha habido algún error. + */ +int Escribe_Socket_Udp (int fd, struct sockaddr *Remoto, + socklen_t Longitud_Remoto, char *Datos, int Longitud); + +/** + * Rellena una estructura sockaddr_in con los datos que se le pasan. Esta estrutura es + * útil para el envio o recepción de mensajes por sockets Udp o para abrir conexiones. + * Se le pasa el host. Puede ser NULL (para abrir socket servidor Udp o para recepción de + * mensajes de cualquier host). + * Se le pasa el servicio. Puede ser NULL (para abrir socket cliente Udp). + * Se le pasa una estructura sockaddr_in que devolverá rellena. + * Se le pasa una Longitud. Debe contener el tamaño de la estructura sockaddr_in y + * devolverá el tamaño de la estructura una vez rellena. + * Devuelve -1 en caso de error. + */ +int Dame_Direccion_Udp (char *Host, char *Servicio, struct sockaddr_in *Servidor, + int *Longitud); +#endif diff --git a/net/remotectrl/src/Socket_Cliente.c b/net/remotectrl/src/Socket_Cliente.c new file mode 100644 index 000000000..2919c722e --- /dev/null +++ b/net/remotectrl/src/Socket_Cliente.c @@ -0,0 +1,131 @@ +/* Javier Abellán, 20 Junio 2000 + * + * Funciones para abrir/establecer sockets de un cliente con un servidor. + * + * MODIFICACIONES: + * 4 Septiembre 2003. Añadida función Abre_Conexion_Udp() + */ + + +/* +* Includes del sistema +*/ +#include +#include +#include +#include +#include +#include +#include +#include + +/* +* Conecta con un servidor Unix, en la misma maquina. +* Devuelve descriptor de socket si todo es correcto, -1 si hay error. +*/ +int Abre_Conexion_Unix (char *Servicio) +{ + struct sockaddr_un Direccion; + int Descriptor; + + strcpy (Direccion.sun_path, Servicio); + Direccion.sun_family = AF_UNIX; + + /* Se abre el descriptor del socket */ + Descriptor = socket (AF_UNIX, SOCK_STREAM, 0); + if (Descriptor == -1) + return -1; + + /* Se establece la conexion. + * Devuelve 0 si todo va bien, -1 en caso de error */ + if (connect ( + Descriptor, + (struct sockaddr *)&Direccion, + strlen (Direccion.sun_path) + sizeof (Direccion.sun_family)) == -1) + { + return -1; + } + + return Descriptor; +} + +/* +* Conecta con un servidor remoto a traves de socket INET +*/ +int Abre_Conexion_Inet ( + char *Host_Servidor, + char *Servicio) +{ + struct sockaddr_in Direccion; + struct servent *Puerto; + struct hostent *Host; + int Descriptor; + +/* + Puerto = getservbyname (Servicio, "tcp"); + Puerto = 15557; + if (Puerto == NULL) + return -1; +*/ + + Host = gethostbyname (Host_Servidor); + if (Host == NULL) + return -1; + + Direccion.sin_family = AF_INET; + Direccion.sin_addr.s_addr = ((struct in_addr *)(Host->h_addr))->s_addr; +// Direccion.sin_port = Puerto->s_port; + Direccion.sin_port = 15557; + + Descriptor = socket (AF_INET, SOCK_STREAM, 0); + if (Descriptor == -1) + return -1; + + if (connect ( + Descriptor, + (struct sockaddr *)&Direccion, + sizeof (Direccion)) == -1) + { + return -1; + } + + return Descriptor; +} + + +/* + * Prepara un socket para un cliente UDP. + * Asocia un socket a un cliente UDP en un servicio cualquiera elegido por el sistema, + * de forma que el cliente tenga un sitio por el que enviar y recibir mensajes. + * Devuelve el descriptor del socket que debe usar o -1 si ha habido algún error. + */ +int Abre_Conexion_Udp () +{ + struct sockaddr_in Direccion; + int Descriptor; + + /* Se abre el socket UDP (DataGRAM) */ + Descriptor = socket (AF_INET, SOCK_DGRAM, 0); + if (Descriptor == -1) + { + return -1; + } + + /* Se rellena la estructura de datos necesaria para hacer el bind() */ + Direccion.sin_family = AF_INET; /* Socket inet */ + Direccion.sin_addr.s_addr = htonl(INADDR_ANY); /* Cualquier dirección IP */ + Direccion.sin_port = htons(0); /* Dejamos que linux eliga el servicio */ + + /* Se hace el bind() */ + if (bind ( + Descriptor, + (struct sockaddr *)&Direccion, + sizeof (Direccion)) == -1) + { + close (Descriptor); + return -1; + } + + /* Se devuelve el Descriptor */ + return Descriptor; +} diff --git a/net/remotectrl/src/Socket_Cliente.h b/net/remotectrl/src/Socket_Cliente.h new file mode 100644 index 000000000..18004aa9d --- /dev/null +++ b/net/remotectrl/src/Socket_Cliente.h @@ -0,0 +1,25 @@ +/* + * Javier Abellán. 14 Abril 2003 + * + * Funciones para que un cliente pueda abrir sockets con un servidor. + */ +#ifndef _SOCKET_CLIENTE_H +#define _SOCKET_CLIENTE_H + +#include + +/** + * Abre un socket UNIX con un servidor que esté en la misma máquina y que atienda al + * servicio de nombre Servicio. + */ +int Abre_Conexion_Unix (char *Servicio); + +/** + * Abre un socket INET con un servidor que esté corriendo en Host_Servidor y que atienda + * al servicio cuyo nombre es Servicio. + * Host_Servidor debe estar dado de alta en /etc/hosts. + * Servicio debe estar dado de alta en /etc/services como tcp. + */ +int Abre_Conexion_Inet (char *Host_Servidor, char *Servicio); + +#endif diff --git a/net/remotectrl/src/Socket_Servidor.c b/net/remotectrl/src/Socket_Servidor.c new file mode 100644 index 000000000..23bf09446 --- /dev/null +++ b/net/remotectrl/src/Socket_Servidor.c @@ -0,0 +1,224 @@ +/* +* Javier Abellan, 20 Jun 2000 +* +* Funciones para la apertura de un socket servidor y la conexion con sus +* clientes +* +* MODIFICACIONES: +* 4 Septiembre 2003: Añadida función Abre_Socket_Udp() +*/ + +/* Includes del sistema */ +#include +#include +#include +#include +#include +#include +#include + +/* +* Abre socket servidor UNIX. Se le pasa el servicio que se desea atender. +* Deja el socket preparado +* para aceptar conexiones de clientes. +* Devuelve el descritor del socket servidor, que se debera pasar +* a la funcion Acepta_Conexion_Cliente(). Devuelve -1 en caso de error +*/ +int Abre_Socket_Unix (char *Servicio) +{ + struct sockaddr_un Direccion; + int Descriptor; + + /* + * Se abre el socket + */ + Descriptor = socket (AF_UNIX, SOCK_STREAM, 0); + if (Descriptor == -1) + return -1; + + /* + * Se rellenan en la estructura Direccion los datos necesarios para + * poder llamar a la funcion bind() + */ + strcpy (Direccion.sun_path, Servicio); + Direccion.sun_family = AF_UNIX; + + if (bind ( + Descriptor, + (struct sockaddr *)&Direccion, + strlen (Direccion.sun_path) + sizeof (Direccion.sun_family)) == -1) + { + /* + * En caso de error cerramos el socket y devolvemos error + */ + close (Descriptor); + return -1; + } + + /* + * Avisamos al sistema que comience a atender peticiones de clientes. + */ + if (listen (Descriptor, 1) == -1) + { + close (Descriptor); + return -1; + } + + /* + * Se devuelve el descriptor del socket servidor + */ + return Descriptor; +} + +/* +* Se le pasa un socket de servidor y acepta en el una conexion de cliente. +* devuelve el descriptor del socket del cliente o -1 si hay problemas. +* Esta funcion vale para socket AF_INET o AF_UNIX. +*/ +int Acepta_Conexion_Cliente (int Descriptor) +{ + socklen_t Longitud_Cliente; + struct sockaddr Cliente; + int Hijo; + + /* + * 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 + */ + Longitud_Cliente = sizeof (Cliente); + Hijo = accept (Descriptor, &Cliente, &Longitud_Cliente); + if (Hijo == -1) + return -1; + + /* + * Se devuelve el descriptor en el que esta "enchufado" el cliente. + */ + return Hijo; +} + +/* +* Abre un socket servidor de tipo AF_INET. Devuelve el descriptor +* del socket o -1 si hay probleamas +* Se pasa como parametro el nombre del servicio. Debe estar dado +* de alta en el fichero /etc/services +*/ +int Abre_Socket_Inet (char *Servicio) +{ + struct sockaddr_in Direccion; + struct sockaddr Cliente; + socklen_t Longitud_Cliente; + struct servent *Puerto; + int Descriptor; + + /* + * se abre el socket + */ + Descriptor = socket (AF_INET, SOCK_STREAM, 0); + if (Descriptor == -1) + return -1; + + /* + * Se obtiene el servicio del fichero /etc/services + */ +/* + Puerto = getservbyname (Servicio, "tcp"); + + Puerto = 15557; + + if (Puerto == NULL) + return -1; +*/ + /* + * Se rellenan los campos de la estructura Direccion, necesaria + * para la llamada a la funcion bind() + */ +/* + struct hostent *Host; + Host = gethostbyname ("192.168.1.1"); + if (Host == NULL) + return -1; +*/ + + Direccion.sin_family = AF_INET; +// Direccion.sin_port = Puerto->s_port; + Direccion.sin_port = htons(15557); + Direccion.sin_addr.s_addr =INADDR_ANY; +// Direccion.sin_addr.s_addr = ((struct in_addr *)(Host->h_addr))->s_addr; + if (bind ( + Descriptor, + (struct sockaddr *)&Direccion, + sizeof(struct sockaddr)) == -1) + { + close (Descriptor); + return -1; + } + + /* + * Se avisa al sistema que comience a atender llamadas de clientes + */ + if (listen (Descriptor, 1) == -1) + { + close (Descriptor); + return -1; + } + + /* + * Se devuelve el descriptor del socket servidor + */ + return Descriptor; +} + +/** + * Abre un socket inet de udp. + * Se le pasa el nombre de servicio del socket al que debe atender. + * Devuelve el descriptor del socket abierto o -1 si ha habido algún error. + */ +int Abre_Socket_Udp (char *Servicio) +{ + struct sockaddr_in Direccion; + struct servent *Puerto = NULL; + int Descriptor; + + /* + * se abre el socket + */ + Descriptor = socket (AF_INET, SOCK_DGRAM, 0); + if (Descriptor == -1) + { + return -1; + } + + /* + * Se obtiene el servicio del fichero /etc/services + */ + Puerto = getservbyname (Servicio, "udp"); + if (Puerto == NULL) + { + return -1; + } + + /* + * Se rellenan los campos de la estructura Direccion, necesaria + * para la llamada a la funcion bind() y se llama a esta. + */ + Direccion.sin_family = AF_INET; + Direccion.sin_port = Puerto->s_port; + Direccion.sin_addr.s_addr = INADDR_ANY; + + if (bind ( + Descriptor, + (struct sockaddr *)&Direccion, + sizeof (Direccion)) == -1) + { + close (Descriptor); + return -1; + } + + /* + * Se devuelve el descriptor del socket servidor + */ + return Descriptor; +} diff --git a/net/remotectrl/src/Socket_Servidor.h b/net/remotectrl/src/Socket_Servidor.h new file mode 100644 index 000000000..72ac9a04e --- /dev/null +++ b/net/remotectrl/src/Socket_Servidor.h @@ -0,0 +1,38 @@ +/** + * Javier Abellán. 14 Abril 2003 + * + * Funciones para que un servidor puede abrir sockets para atender un servicio y aceptar + * conexiones de un cliente. + */ +#ifndef _SOCKET_SERVIDOR_H +#define _SOCKET_SERVIDOR_H + +/** + * Abre un socket INET para atender al servicio cuyo nombre es Servicio. + * El Servicio debe estar dado de alta en /etc/services como tcp. + * Devuelve el descriptor del socket que atiende a ese servicio o -1 si ha habido error. + */ +int Abre_Socket_Inet (char *Servicio); + + +/** + * Abre un socket UDP para atender al servicio cuyo nombre es Servicio. + * El Servicio debe estar dado de alta en /etc/services como udp. + * Devuelve el descriptor del socket que atiende a ese servicio o -1 si ha habido error. + */ +int Abre_Socket_Udp (char *Servicio); + + +/** + * Abre un socket UNIX para atender al servicio cuyo nombre es Servicio. + * Devuelve el descriptor del socket que atiende a ese servicio o -1 si ha habido error. + */ +int Abre_Socket_Unix (char *Servicio); + +/** + * Acepta un cliente para un socket INET. + * Devuelve el descriptor de la conexión con el cliente o -1 si ha habido error. + */ +int Acepta_Conexion_Cliente (int Descriptor); + +#endif diff --git a/net/remotectrl/src/clientselect.c b/net/remotectrl/src/clientselect.c new file mode 100644 index 000000000..b8478e33d --- /dev/null +++ b/net/remotectrl/src/clientselect.c @@ -0,0 +1,47 @@ +/* + * Javier Abellán. 14 de Abril de 2003 + * + * Ejemplo de como un servidor puede manejar varios clientes con select(). + * Este programa hace de cliente de dicho servidor. + */ +#include "Socket.h" +#include "Socket_Cliente.h" + +/* Programa principal. Abre la conexión, recibe su número de cliente y + * luego envía dicho número cada segundo */ +main() +{ + int sock; /* descriptor de conexión con el servidor */ + struct s_msg *buffer; /* buffer de lectura de datos procedentes del servidor */ + int error; /* error de lectura por el socket */ + buffer = malloc(sizeof(struct s_msg)); + /* Se abre una conexión con el servidor */ + sock = Abre_Conexion_Inet ("localhost", "cpp_java"); + + /* Se lee el número de cliente, dato que nos da el servidor. Se escribe + * dicho número en pantalla.*/ + error = ReadTcpSocket (sock, &buffer); +// struct s_msg Datos; +// *Datos = malloc(sizeof struct s_msg); +// error = ReadTcpSocket (sock, &Datos); +// printf("%d %d %s\n",Datos.type, Datos.command, Datos.data); + /* Si ha habido error de lectura lo indicamos y salimos */ + if (error < 1) + { + printf ("Me han cerrado la conexión\n"); + exit(-1); + } +printf("Se leyeron %d bytes\n", error); + /* Se escribe el número de cliente que nos ha enviado el servidor */ + printf ("type=%d\ncommand=%d\nlen=%d\ndata=%s\n", buffer->type, buffer->command, buffer->len, buffer->data); + printf ("Soy cliente\n%s\n", buffer); + + /* Bucle infinito. Envia al servidor el número de cliente y espera un + * segundo */ +// while (1) +// { +// Escribe_Socket (sock, (char *)&buffer, sizeof(int)); +// sleep (1); +// } +} + diff --git a/net/remotectrl/src/remotectrl.c b/net/remotectrl/src/remotectrl.c new file mode 100644 index 000000000..73c14bed6 --- /dev/null +++ b/net/remotectrl/src/remotectrl.c @@ -0,0 +1,251 @@ +#include "remotectrl.h" + +int write_msg( struct rmt_socket_t *sckHnd, uint32_t id, uint32_t extra, char *message ){ + msg_head_t header; + int rslt; + header.id = id; + header.len = strlen(message); + header.extra = extra; + rslt = send(sckHnd->fd,&header,sizeof(struct msg_head_t),0); + if (rslt != -1 && header.len > 0) { + sckHnd->Tx += rslt; + rslt = send(sckHnd->fd, message, header.len, 0); + if (rslt > 0) + { + sckHnd->Tx += rslt; + rslt += sizeof(struct msg_head_t); + } + } + return rslt; +} + +int read_msg( struct rmt_socket_t *sckHnd, msg_head_t *head, char **message ) +{ + msg_head_t header; + int rslt; + char *buffer; + int reading = 0; + int aux = 0; + rslt = recv(sckHnd->fd, head, sizeof(struct msg_head_t), 0); +// printf("head->id=%d head->extra=%d head->len=%d\n",head->id,head->extra,head->len); + if (rslt == sizeof(struct msg_head_t) ) { + sckHnd->Rx += rslt; + buffer = malloc(head->len+1); + while ( reading < head->len ){ + memset(buffer,'\0', head->len+1); + aux = recv(sckHnd->fd, buffer, head->len, 0); + switch ( aux ) { + case -1: + switch (errno){ + case EINTR: + case EAGAIN: + usleep (100); + break; + default: + return -1; + } + break; + case 0: // mean socket was closed + sckHnd->Rx += reading; + return reading; + break; + break; + default: + if (reading == 0) + *message=malloc(aux+1); + else + *message=(char*)realloc(*message,(reading+aux+1)*sizeof(char)); + memcpy(*message+reading, buffer, aux); + reading += aux; + } + } + free(buffer); + sckHnd->Rx += reading; + reading += rslt; + return reading; + } + return rslt; +} + +void rmtctrl_srv(struct rmt_socket_t srv, struct rmt_socket_t *client, int *activeClients) +{ + fd_set fdRead; + int maxHnd; + int i; + struct timeval nowait; + memset((char *)&nowait,0,sizeof(nowait)); + + rmtctrl_cleanClients(client, activeClients); + FD_ZERO (&fdRead); + FD_SET (srv.fd, &fdRead); + + for (i=0; i<*activeClients; i++) + FD_SET (client[i].fd, &fdRead); + + maxHnd = rmtctrl_maxValue (client, *activeClients); + + if (maxHnd < srv.fd) + maxHnd = srv.fd; + + select (maxHnd + 1, &fdRead, NULL, NULL,&nowait); + for (i=0; i<*activeClients; i++) + { + if (FD_ISSET (client[i].fd, &fdRead)) + { + rmtctrl_msg_proccess(&client[i]); + } + } + if (FD_ISSET (srv.fd, &fdRead)) + rmtctrl_newClient(srv,client, &(*activeClients)); +} + +void rmtctrl_msg_proccess(struct rmt_socket_t *client) +{ + msg_head_t header; + char *msg=NULL; + int rslt; + rslt = read_msg(client,&header,&msg); + if (rslt > 0) + { + switch (header.id) + { + case QRY_STATUS: + rslt = write_msg(client,MSG_END,0, "Bienvenido a mi servidor.\nStatus\n" ); + break; + case QRY_CONNECTED_LIST: + rslt = write_msg(client,MSG_START,0, "List of Connected\n" ); + rslt = write_msg(client,MSG_PART,0, "Username IPAddrs Status\n" ); + rslt = write_msg(client,MSG_PART,0, "pepe1 198.164.234.224 Authenticated\n" ); + rslt = write_msg(client,MSG_PART,0, "pepe2 198.164.234.220 Authenticated\n" ); + rslt = write_msg(client,MSG_PART,0, "pepe3 198.164.234.221 Authenticated\n" ); + rslt = write_msg(client,MSG_PART,0, "pepe4 198.164.234.223 Authenticated\n" ); + rslt = write_msg(client,MSG_PART,0, "pepe5 198.164.234.227 Authenticated\n" ); + rslt = write_msg(client,MSG_END,0, "pepe6 198.164.234.224 Authenticated\n" ); + break; + default: + rslt = write_msg(client,MSG_END,9, "Unknow command.\n" ); + } + } + else + { + printf("Desde %s se recibieron %d bytes y se enviaron %d bytes\n",inet_ntoa(client->addr.sin_addr),client->Rx,client->Tx); + close(client->fd); /* cierra fd_rmt_client */ + printf("Client cerro conexión desde %s\n",inet_ntoa(client->addr.sin_addr) ); + client->fd = -1; + } + if ( msg != NULL) free(msg); +} + +void rmtctrl_newClient(struct rmt_socket_t srv, struct rmt_socket_t *client, int *activeClients) +{ + int rslt; + int cli = (*activeClients); + rmtctrl_accept(srv,&client[cli]); + if (client[(*activeClients)].fd != -1) + { + (*activeClients)++; + } + if ((*activeClients) >= MAX_CLIENTS) + { + (*activeClients)--; + rslt = write_msg(&client[(*activeClients)],MSG_END,0, "Sorry Server is too Busy\n Try more late\n" ); + if (rslt > 0) client[(*activeClients)].Tx += rslt; + rmtctrl_close(&client[(*activeClients)]); + } +} + +void rmtctrl_close ( struct rmt_socket_t *client ) +{ + printf("Desde %s se recibieron %d bytes y se enviaron %d bytes\n",inet_ntoa(client->addr.sin_addr),client->Rx,client->Tx); + close(client->fd); /* cierra fd_rmt_client */ + printf("Se cerro conexión desde %s\n",inet_ntoa(client->addr.sin_addr) ); + client->fd = -1; +} + +void rmtctrl_accept (struct rmt_socket_t srv, struct rmt_socket_t *client ) +{ + int sin_size=sizeof(struct sockaddr_in); + int int_Send; + struct sockaddr_in addr; + + if ((client->fd = accept(srv.fd,(struct sockaddr *)&client->addr,&sin_size))!=-1) + { + client->Rx = 0; + client->Tx = 0; + unsigned char c = sizeof(uint32_t); + int_Send = send(client->fd, &c, 1, 0); + if (int_Send > 0) client->Tx += int_Send; + printf("Se abrió una conexión desde %s\n", inet_ntoa(client->addr.sin_addr)); + } +} + +struct rmt_socket_t initSrv(){ + struct rmt_socket_t srv; + if ((srv.fd=socket(AF_INET, SOCK_STREAM, 0)) == -1 ) { + printf("error en socket()\n"); + exit(-1); + } + srv.addr.sin_family = AF_INET; + srv.addr.sin_port = htons(PORT); + srv.addr.sin_addr.s_addr = INADDR_ANY; + bzero(&(srv.addr.sin_zero),8); + + if(bind(srv.fd,(struct sockaddr*)&srv.addr,sizeof(struct sockaddr))==-1) { + printf("error en bind() \n"); + exit(-1); + } + + if(listen(srv.fd,BACKLOG) == -1) { + printf("error en listen()\n"); + exit(-1); + } + return srv; +} + +//void cleanClients (int *table, int *n) +void rmtctrl_cleanClients (struct rmt_socket_t *client, int *n) +{ + int i,j; + + if ((client == NULL) || ((*n) == 0)) + return; + + j=0; + for (i=0; i<(*n); i++) + { + if (client[i].fd != -1) + { + client[j].fd = client[i].fd; + client[j].addr = client[i].addr; + client[j].Rx = client[i].Rx; + client[j].Tx = client[i].Tx; + j++; + } + } + + *n = j; +} + +int rmtctrl_maxValue (struct rmt_socket_t *client, int n) +{ + int i; + int max; + + if ((client == NULL) || (n<1)) + return 0; + + max = client[0].fd; + for (i=0; i max) + max = client[i].fd; + + return max; +} + + +/* +void main() +{ + rmtctrl_srv(); +} +*/ diff --git a/net/remotectrl/src/remotectrl.h b/net/remotectrl/src/remotectrl.h new file mode 100644 index 000000000..b0b5b0383 --- /dev/null +++ b/net/remotectrl/src/remotectrl.h @@ -0,0 +1,49 @@ +/* Estos son los ficheros de cabecera usuales */ +#include +#include +#include +#include +#include + +#define PORT 15557 /* El puerto que ser? abierto */ +#define BACKLOG 2 /* El n?mero de conexiones permitidas */ +#define MAX_CLIENTS 10 + +enum +{ + MSG_OK = 0, + MSG_START = 1, + MSG_PART = 2, + MSG_END = 3, + QRY_STATUS = 100, + QRY_CONNECTED_LIST = 101, + QRY_MACADDR = 102, + QRY_IPADDR = 103, + QRY_USERNAME = 104, +}; + +typedef struct msg_head_t { + uint32_t id; + uint32_t extra; + uint32_t len; +} msg_head_t; + +typedef struct rmt_socket_t { + int fd; + struct sockaddr_in addr; + int Rx; + int Tx; +} rmt_socket_t; + + +int write_msg( struct rmt_socket_t *sckHnd, uint32_t id, uint32_t extra, char *message ); +int read_msg( struct rmt_socket_t *sckHnd, msg_head_t *head, char **message ); + +struct rmt_socket_t initSrv(); +void rmtctrl_srv(struct rmt_socket_t srv, struct rmt_socket_t *client, int *activeClients); + +void rmtctrl_accept (struct rmt_socket_t srv, struct rmt_socket_t *client ); +void rmtctrl_cleanClients (struct rmt_socket_t *client, int *n); +void rmtctrl_msg_proccess(struct rmt_socket_t *client); +void rmtctrl_newClient(struct rmt_socket_t srv, struct rmt_socket_t *client, int *activeClients); +void rmtctrl_close ( struct rmt_socket_t *client ); diff --git a/net/remotectrl/src/server_socket.c b/net/remotectrl/src/server_socket.c new file mode 100644 index 000000000..fcc5a6b8d --- /dev/null +++ b/net/remotectrl/src/server_socket.c @@ -0,0 +1,22 @@ +#include "remotectrl.h" + +int main(){ + time_t tim; + struct rmt_socket_t srv; + struct rmt_socket_t client[MAX_CLIENTS]; + int activeClients = 0; /* Número clientes conectados */ + + srv = initSrv(); + +// client = initClients(); + + + while (1){ + tim=time(NULL); + printf("%s", ctime(&tim) ); + rmtctrl_srv(srv,client,&activeClients); + usleep (100); + } + return 0; +} + diff --git a/net/remotectrl/src/servselect.c b/net/remotectrl/src/servselect.c new file mode 100644 index 000000000..c5eace696 --- /dev/null +++ b/net/remotectrl/src/servselect.c @@ -0,0 +1,194 @@ +/* + * Javier Abellán. 14 de Abril de 2003 + * + * Ejemplo de como un servidor puede manejar varios clientes con select(). + * Este programa hace de servidor. + */ +#include +#include +#include +#include +#include + +#define MAX_CLIENTES 10 + +/* Prototipos de las funciones definidas en este fichero */ +void nuevoCliente (int servidor, int *clientes, int *nClientes); +int dameMaximo (int *tabla, int n); +void compactaClaves (int *tabla, int *n); + +/* + * Programa principal. + * Crea un socket servidor y se mete en un select() a la espera de clientes. + * Cuando un cliente se conecta, le atiende y lo añade al select() y vuelta + * a empezar. + */ +main() +{ + int socketServidor; /* Descriptor del socket servidor */ + int socketCliente[MAX_CLIENTES];/* Descriptores de sockets con clientes */ + int numeroClientes = 0; /* Número clientes conectados */ + fd_set descriptoresLectura; /* Descriptores de interes para select() */ + int buffer; /* Buffer para leer de los socket */ + int maximo; /* Número de descriptor más grande */ + int i; /* Para bubles */ + + /* Se abre el socket servidor, avisando por pantalla y saliendo si hay + * algún problema */ + socketServidor = Abre_Socket_Inet ("cpp_java"); + if (socketServidor == -1) + { + perror ("Error al abrir servidor"); + exit (-1); + } + + /* Bucle infinito. + * Se atiende a si hay más clientes para conectar y a los mensajes enviados + * por los clientes ya conectados */ + while (1) + { + /* Cuando un cliente cierre la conexión, se pondrá un -1 en su descriptor + * de socket dentro del array socketCliente. La función compactaClaves() + * eliminará dichos -1 de la tabla, haciéndola más pequeña. + * + * Se eliminan todos los clientes que hayan cerrado la conexión */ + compactaClaves (socketCliente, &numeroClientes); + + /* Se inicializa descriptoresLectura */ + FD_ZERO (&descriptoresLectura); + + /* Se añade para select() el socket servidor */ + FD_SET (socketServidor, &descriptoresLectura); + + /* Se añaden para select() los sockets con los clientes ya conectados */ + for (i=0; i 0)) + printf ("Cliente %d envía %s\n", i+1, buffer); + else + { + /* Se indica que el cliente ha cerrado la conexión y se + * marca con -1 el descriptor para que compactaClaves() lo + * elimine */ + printf ("Cliente %d ha cerrado la conexión\n", i+1); + socketCliente[i] = -1; + } + } + } + + /* Se comprueba si algún cliente nuevo desea conectarse y se le + * admite */ + if (FD_ISSET (socketServidor, &descriptoresLectura)) + nuevoCliente (socketServidor, socketCliente, &numeroClientes); + } +} + +/* + * Crea un nuevo socket cliente. + * Se le pasa el socket servidor y el array de clientes, con el número de + * clientes ya conectados. + */ +void nuevoCliente (int servidor, int *clientes, int *nClientes) +{ + /* Acepta la conexión con el cliente, guardándola en el array */ + clientes[*nClientes] = Acepta_Conexion_Cliente (servidor); + (*nClientes)++; + + /* Si se ha superado el maximo de clientes, se cierra la conexión, + * se deja todo como estaba y se vuelve. */ + if ((*nClientes) >= MAX_CLIENTES) + { + close (clientes[(*nClientes) -1]); + (*nClientes)--; + return; + } + + /* Envía su número de cliente al cliente */ + +// Escribe_Socket1 (clientes[(*nClientes)-1], (char *)nClientes, sizeof(int)); + char pepe[] = "Mensaje del server uno"; +/* + char mensa[] = "Mensaje del server uno"; + struct s_msg *pepe; + pepe = calloc(pepe,12+strlen(mensa)+2); + pepe->type = 1; + pepe->command = 0; + pepe->len = strlen(mensa); + strcpy(pepe->data,mensa); + printf("int=%d s_msg=%d pepe=%d\n",sizeof(int),sizeof(struct s_msg), sizeof((struct s_msg *)pepe)); + printf("type=%d command=%d len=%d data=%s\n", pepe->type, pepe->command, pepe->len, pepe->data); +*/// +// pepe.data = strcpy(pepe.data,"Mensaje del server uno"); + Escribe_Socket (clientes[(*nClientes)-1], pepe, strlen(pepe)); + int escribio; +// escribio = WriteTcpSocket (clientes[(*nClientes)-1], 0,0, "Connected Ok" ); + /* Escribe en pantalla que ha aceptado al cliente y vuelve */ +// printf ("Aceptado cliente %d %d\n", *nClientes, escribio); + return; +} + +/* + * Función que devuelve el valor máximo en la tabla. + * Supone que los valores válidos de la tabla son positivos y mayores que 0. + * Devuelve 0 si n es 0 o la tabla es NULL */ +int dameMaximo (int *tabla, int n) +{ + int i; + int max; + + if ((tabla == NULL) || (n<1)) + return 0; + + max = tabla[0]; + for (i=0; i max) + max = tabla[i]; + + return max; +} + +/* + * Busca en array todas las posiciones con -1 y las elimina, copiando encima + * las posiciones siguientes. + * Ejemplo, si la entrada es (3, -1, 2, -1, 4) con *n=5 + * a la salida tendremos (3, 2, 4) con *n=3 + */ +void compactaClaves (int *tabla, int *n) +{ + int i,j; + + if ((tabla == NULL) || ((*n) == 0)) + return; + + j=0; + for (i=0; i<(*n); i++) + { + if (tabla[i] != -1) + { + tabla[j] = tabla[i]; + j++; + } + } + + *n = j; +} +