]> git.llucax.com Git - z.facultad/75.74/practicos.git/blob - practicas/pipi/src/libtcp.c
Se agrega una primera aproximación al NameServer. Se implementa el parser y
[z.facultad/75.74/practicos.git] / practicas / pipi / src / libtcp.c
1 /* LibTcp - Released underOpen Software License v. 2.0
2  *
3  * This Open Software License (the "License") applies to any original work of authorship 
4  * (the "Original Work") whose owner (the "Licensor") has placed the following notice 
5  * immediately following the copyright notice for the Original Work:
6  *
7  *     Licensed under the Open Software License version 2.0
8  *
9  * See http://www.opensource.org/licenses/osl-2.0.php or the LICENSE file for more
10  * details.
11  */
12
13 #include "libtcp.h"
14
15 /** Abre un socket en modo activo para establecer una conexión con un servidor.
16  *
17  * Esta función es utilizada por los clientes para establecer una conexión TCP
18  * con un servidor. 
19  *
20  * \param servidor Nombre del host server
21  * \param port Número del puerto
22  * \return >0 El descriptor del socket, si se conecto al servidor.
23  * \return -2 Si no existe el nombre del servidor.
24  * \return -1 Si hubo error en la conexion y se debe consultar errno.
25  */
26 int libtcp_open_activo (const char *server, int port)
27 {
28         int sockfd; /* socket de la conexion */
29         struct sockaddr_in serv_addr;
30         struct hostent *ptr_server; /*puntero a dir del server(gethostbyname)*/
31
32         /* Borrar la estructura (poner en cero) */ 
33         bzero ((char *) &serv_addr, sizeof(serv_addr));
34         
35         /*      Inicializo familia de direcciones (protocolo IP) */
36         serv_addr.sin_family = AF_INET;
37
38         /* Cargar port en el socket: Convertir Host-TO-Network-Short integer */
39         serv_addr.sin_port = htons (port);
40
41         /* Cargo dirección del server en el socket. Convertir nombre del host en su direccion */
42         ptr_server = gethostbyname (server); 
43         if (ptr_server == NULL) {
44                 /* No existe nombre de host. Posible falla en resolución de nombre */
45                 return -2;
46         }
47         memcpy (&serv_addr.sin_addr, ptr_server->h_addr, ptr_server->h_length);
48
49         /* Abro como un socket de TCP (Internet stream socket) */
50         if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
51                 /* Error en la creacion del socket */
52                 return -1;
53         }
54
55         if (connect (sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
56                 /* TODO : Deberia ser un codigo de error diferente, asi puedo diferenciarlos */
57                 return -1;
58         }
59
60   return sockfd;
61 }
62
63 /** Abre un socket en modo pasivo usando protocolo TCP.
64  *
65  * La función se encarga de inicializar y crear el socket, y
66  * luego enlazarla con el SO.
67  * 
68  * \param port Puerto sobre el cual atiende este servidor
69  * \return >0 El socket, si la operacion fue exitosa
70  * \return <0 Si hubo un error (ver errno)
71  */
72 int libtcp_open_pasivo (int port)
73 {
74         char mostrar[80]; /* mensajes en la pantalla */ 
75         int     sockfd; /* socket que sirve como template */ 
76         struct sockaddr_in      serv_addr;
77
78         bzero ((char *)&serv_addr, sizeof (serv_addr));
79         serv_addr.sin_family = AF_INET; /* Familia protocolos TCP/IP */
80         serv_addr.sin_addr.s_addr = htonl (INADDR_ANY); /* Cualquier cliente */ 
81         serv_addr.sin_port = htons ((unsigned short)port); /* Port en formato red */
82
83         /* Crea un socket para TCP (un Internet stream socket) */
84         if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
85                 return -1;
86         }
87
88         // Reusamos address
89         int yes = 1;
90         if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *) &yes,
91                         sizeof(yes)) < 0)
92         {
93                 perror ("setsockopt");
94                 close (sockfd);
95                 return -1;
96         }
97
98         sprintf (mostrar, "LibTcp::ServerPasivo: socket creado %d\n", sockfd);
99         write (fileno(stdout), mostrar, strlen (mostrar));
100
101         /* Vincular el socket con la direccion local */
102         if (bind (sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0) {
103                 return -1;
104         }
105
106         sprintf (mostrar, "LibTcp::Server: se hizo el bind\n");
107         write(fileno(stdout), mostrar, strlen(mostrar));
108
109   /* Definir la cola de espera = hasta 5 clientes */
110         listen(sockfd, 5);
111
112         sprintf (mostrar, "LibTcp::Server: se hizo el listen con el socket %d\n", sockfd);
113         write(fileno(stdout), mostrar, strlen(mostrar));
114
115         return sockfd;
116 }
117
118 /** Lee de a un byte por vez a un buffer hasta encontrar un "\n".
119  * 
120  *  La cadena leída es terminada en "\0".
121  *
122  *  \return El tamaño, en caracteres, de la cadena leida.
123  *      \param fd       Descriptor del socket
124  *      \param ptr Puntero al buffer 
125  *      \param maxlong Tamaño del buffer (en bytes)
126  *      \TODO Soporte de caracteres multibyte
127  */
128 int libtcp_receive (int fd, char *ptr, unsigned int maxlong)
129 {
130         unsigned n;
131         int     car;
132         char    c;
133
134         for (n = 0; n < maxlong; n++) {
135                 if ((car = read (fd, &c, sizeof (char))) == 1) {
136                         *ptr++ = c;
137                         if (c == '\n')
138                                 break;
139                         } else if (car == 0) {
140                                 if (n == 1)
141                                         /* EOF, sin datos leidos */
142                                         return 0;
143                                 else
144                                         break;          /* EOF, se leyo algo */
145                 } else
146                         return -1;
147         }
148
149         *ptr = '\0';
150         return n;
151 }
152
153 /** Lee una informacion binaria */
154 int libtcp_receive_bin (int fd, void *ptr, unsigned int n)
155 {
156         int     nfaltan, nrecibidos;
157         char *p = (char*) ptr;
158
159         nfaltan = n;
160         while (nfaltan > 0) {
161                 nrecibidos = read (fd, p, nfaltan);
162                 if (nrecibidos <= 0)
163                         return nrecibidos;
164
165                 nfaltan -= nrecibidos;
166                 p       += nrecibidos;
167         }
168
169         return n - nfaltan;
170 }
171
172
173 /** Escribe n bytes sobre un descriptor.
174  *
175  *  Si no se escribieron n bytes, trata de repetir hasta que se hayan escrito
176  *  los n bytes.
177  *
178  *  Se debe usar esta funcion cuando el descriptor en un stream socket.
179  *  
180  *      \param fd Descriptor del socket
181  *      \param ptr Puntero al mensaje
182  *      \param n cantidad de bytes
183  */
184 int libtcp_send (int fd, const void *ptr, unsigned int n)
185 {
186         int     nfaltan, nenviados;
187         const char *p = (const char *) ptr;
188
189         nfaltan = n;
190         while (nfaltan > 0) {
191                 nenviados = write (fd, p, nfaltan);
192                 if (nenviados <= 0)
193                         return nenviados;
194
195                 nfaltan -= nenviados;
196                 p       += nenviados;
197         }
198
199         return n - nfaltan;
200 }
201