]> git.llucax.com Git - z.facultad/75.74/practicos.git/blob - practicas/pipi/src/libtcp.c
Cosas de Distribuidos I.
[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 #ifdef DEBUG_LIBTCP
75         char mostrar[80]; /* mensajes en la pantalla */ 
76 #endif
77         int     sockfd; /* socket que sirve como template */ 
78         struct sockaddr_in      serv_addr;
79
80         bzero ((char *)&serv_addr, sizeof (serv_addr));
81         serv_addr.sin_family = AF_INET; /* Familia protocolos TCP/IP */
82         serv_addr.sin_addr.s_addr = htonl (INADDR_ANY); /* Cualquier cliente */ 
83         serv_addr.sin_port = htons ((unsigned short)port); /* Port en formato red */
84
85         /* Crea un socket para TCP (un Internet stream socket) */
86         if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
87                 return -1;
88         }
89
90         // Reusamos address
91         int yes = 1;
92         if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *) &yes,
93                         sizeof(yes)) < 0)
94         {
95                 perror ("setsockopt");
96                 close (sockfd);
97                 return -1;
98         }
99
100 #ifdef DEBUG_LIBTCP
101         sprintf (mostrar, "LibTcp::ServerPasivo: socket creado %d\n", sockfd);
102         write (fileno(stdout), mostrar, strlen (mostrar));
103 #endif
104
105         /* Vincular el socket con la direccion local */
106         if (bind (sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0) {
107                 return -1;
108         }
109
110 #ifdef DEBUG_LIBTCP
111         sprintf (mostrar, "LibTcp::Server: se hizo el bind\n");
112         write(fileno(stdout), mostrar, strlen(mostrar));
113 #endif
114
115   /* Definir la cola de espera = hasta 5 clientes */
116         listen(sockfd, 5);
117
118 #ifdef DEBUG_LIBTCP
119         sprintf (mostrar, "LibTcp::Server: se hizo el listen con el socket %d\n", sockfd);
120         write(fileno(stdout), mostrar, strlen(mostrar));
121 #endif
122
123         return sockfd;
124 }
125
126 /** Lee de a un byte por vez a un buffer hasta encontrar un "\n".
127  * 
128  *  La cadena leída es terminada en "\0".
129  *
130  *  \return El tamaño, en caracteres, de la cadena leida.
131  *      \param fd       Descriptor del socket
132  *      \param ptr Puntero al buffer 
133  *      \param maxlong Tamaño del buffer (en bytes)
134  *      \TODO Soporte de caracteres multibyte
135  */
136 int libtcp_receive (int fd, char *ptr, unsigned int maxlong)
137 {
138         unsigned n;
139         int     car;
140         char    c;
141
142         for (n = 0; n < maxlong; n++) {
143                 if ((car = read (fd, &c, sizeof (char))) == 1) {
144                         *ptr++ = c;
145                         if (c == '\n')
146                                 break;
147                         } else if (car == 0) {
148                                 if (n == 1)
149                                         /* EOF, sin datos leidos */
150                                         return 0;
151                                 else
152                                         break;          /* EOF, se leyo algo */
153                 } else
154                         return -1;
155         }
156
157         *ptr = '\0';
158         return n;
159 }
160
161 /** Lee una informacion binaria */
162 int libtcp_receive_bin (int fd, void *ptr, unsigned int n)
163 {
164         int     nfaltan, nrecibidos;
165         char *p = (char*) ptr;
166
167         nfaltan = n;
168         while (nfaltan > 0) {
169                 nrecibidos = read (fd, p, nfaltan);
170                 if (nrecibidos <= 0)
171                         return nrecibidos;
172
173                 nfaltan -= nrecibidos;
174                 p       += nrecibidos;
175         }
176
177         return n - nfaltan;
178 }
179
180
181 /** Escribe n bytes sobre un descriptor.
182  *
183  *  Si no se escribieron n bytes, trata de repetir hasta que se hayan escrito
184  *  los n bytes.
185  *
186  *  Se debe usar esta funcion cuando el descriptor en un stream socket.
187  *  
188  *      \param fd Descriptor del socket
189  *      \param ptr Puntero al mensaje
190  *      \param n cantidad de bytes
191  */
192 int libtcp_send (int fd, const void *ptr, unsigned int n)
193 {
194         int     nfaltan, nenviados;
195         const char *p = (const char *) ptr;
196
197         nfaltan = n;
198         while (nfaltan > 0) {
199                 nenviados = write (fd, p, nfaltan);
200                 if (nenviados <= 0)
201                         return nenviados;
202
203                 nfaltan -= nenviados;
204                 p       += nenviados;
205         }
206
207         return n - nfaltan;
208 }
209