]> git.llucax.com Git - z.facultad/75.74/practicos.git/blob - practicas/pipi-2da-entrega/src/libtcp.c
Tag de 2da entrega.
[z.facultad/75.74/practicos.git] / practicas / pipi-2da-entrega / 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 #ifdef DEBUG2
99         sprintf (mostrar, "LibTcp::ServerPasivo: socket creado %d\n", sockfd);
100         write (fileno(stdout), mostrar, strlen (mostrar));
101 #endif
102
103         /* Vincular el socket con la direccion local */
104         if (bind (sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0) {
105                 return -1;
106         }
107
108 #ifdef DEBUG2
109         sprintf (mostrar, "LibTcp::Server: se hizo el bind\n");
110         write(fileno(stdout), mostrar, strlen(mostrar));
111 #endif
112
113   /* Definir la cola de espera = hasta 5 clientes */
114         listen(sockfd, 5);
115
116 #ifdef DEBUG2
117         sprintf (mostrar, "LibTcp::Server: se hizo el listen con el socket %d\n", sockfd);
118         write(fileno(stdout), mostrar, strlen(mostrar));
119 #endif
120
121         return sockfd;
122 }
123
124 /** Lee de a un byte por vez a un buffer hasta encontrar un "\n".
125  * 
126  *  La cadena leída es terminada en "\0".
127  *
128  *  \return El tamaño, en caracteres, de la cadena leida.
129  *      \param fd       Descriptor del socket
130  *      \param ptr Puntero al buffer 
131  *      \param maxlong Tamaño del buffer (en bytes)
132  *      \TODO Soporte de caracteres multibyte
133  */
134 int libtcp_receive (int fd, char *ptr, unsigned int maxlong)
135 {
136         unsigned n;
137         int     car;
138         char    c;
139
140         for (n = 0; n < maxlong; n++) {
141                 if ((car = read (fd, &c, sizeof (char))) == 1) {
142                         *ptr++ = c;
143                         if (c == '\n')
144                                 break;
145                         } else if (car == 0) {
146                                 if (n == 1)
147                                         /* EOF, sin datos leidos */
148                                         return 0;
149                                 else
150                                         break;          /* EOF, se leyo algo */
151                 } else
152                         return -1;
153         }
154
155         *ptr = '\0';
156         return n;
157 }
158
159 /** Lee una informacion binaria */
160 int libtcp_receive_bin (int fd, void *ptr, unsigned int n)
161 {
162         int     nfaltan, nrecibidos;
163         char *p = (char*) ptr;
164
165         nfaltan = n;
166         while (nfaltan > 0) {
167                 nrecibidos = read (fd, p, nfaltan);
168                 if (nrecibidos <= 0)
169                         return nrecibidos;
170
171                 nfaltan -= nrecibidos;
172                 p       += nrecibidos;
173         }
174
175         return n - nfaltan;
176 }
177
178
179 /** Escribe n bytes sobre un descriptor.
180  *
181  *  Si no se escribieron n bytes, trata de repetir hasta que se hayan escrito
182  *  los n bytes.
183  *
184  *  Se debe usar esta funcion cuando el descriptor en un stream socket.
185  *  
186  *      \param fd Descriptor del socket
187  *      \param ptr Puntero al mensaje
188  *      \param n cantidad de bytes
189  */
190 int libtcp_send (int fd, const void *ptr, unsigned int n)
191 {
192         int     nfaltan, nenviados;
193         const char *p = (const char *) ptr;
194
195         nfaltan = n;
196         while (nfaltan > 0) {
197                 nenviados = write (fd, p, nfaltan);
198                 if (nenviados <= 0)
199                         return nenviados;
200
201                 nfaltan -= nenviados;
202                 p       += nenviados;
203         }
204
205         return n - nfaltan;
206 }
207