]> git.llucax.com Git - z.facultad/75.74/practicos.git/blob - practicas/practica3-corregida/libtcp/libtcp.c
Corrección de práctica 3.
[z.facultad/75.74/practicos.git] / practicas / practica3-corregida / libtcp / 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 ((u_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         sprintf (mostrar, "LibTcp::ServerPasivo: socket creado %d\n", sockfd);
89         write (fileno(stdout), mostrar, strlen (mostrar));
90
91         /* Vincular el socket con la direccion local */
92         if (bind (sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0) {
93                 return -1;
94         }
95
96         sprintf (mostrar, "LibTcp::Server: se hizo el bind\n");
97         write(fileno(stdout), mostrar, strlen(mostrar));
98
99   /* Definir la cola de espera = hasta 5 clientes */
100         listen(sockfd, 5);
101
102         sprintf (mostrar, "LibTcp::Server: se hizo el listen con el socket %d\n", sockfd);
103         write(fileno(stdout), mostrar, strlen(mostrar));
104
105         return sockfd;
106 }
107
108 /** Lee de a un byte por vez a un buffer hasta encontrar un "\n".
109  * 
110  *  La cadena leída es terminada en "\0".
111  *
112  *  \return El tamaño, en caracteres, de la cadena leida.
113  *      \param fd       Descriptor del socket
114  *      \param ptr Puntero al buffer 
115  *      \param maxlong Tamaño del buffer (en bytes)
116  *      \TODO Soporte de caracteres multibyte
117  */
118 int libtcp_receive (int fd, char *ptr, unsigned int maxlong)
119 {
120         int     n, car;
121         char    c;
122
123         for (n = 0; n < maxlong; n++) {
124                 if ((car = read (fd, &c, sizeof (char))) == 1) {
125                         *ptr++ = c;
126                         if (c == '\n')
127                                 break;
128                         } else if (car == 0) {
129                                 if (n == 1)
130                                         /* EOF, sin datos leidos */
131                                         return 0;
132                                 else
133                                         break;          /* EOF, se leyo algo */
134                 } else
135                         return -1;
136         }
137
138         *ptr = '\0';
139         return n;
140 }
141
142 /** Lee una informacion binaria */
143 int libtcp_receive_bin (int fd, void *ptr, unsigned int maxlong)
144 {
145         return read (fd, ptr, maxlong);
146 }
147
148
149 /** Escribe n bytes sobre un descriptor.
150  *
151  *  Si no se escribieron n bytes, trata de repetir hasta que se hayan escrito
152  *  los n bytes.
153  *
154  *  Se debe usar esta funcion cuando el descriptor en un stream socket.
155  *  
156  *      \param fd Descriptor del socket
157  *      \param ptr Puntero al mensaje
158  *      \param n cantidad de bytes
159  */
160 int libtcp_send (int fd, const char *ptr, unsigned int n)
161 {
162         int     nfaltan, nenviados;
163
164         nfaltan = n;
165         while (nfaltan > 0) {
166                 nenviados = write (fd, ptr, nfaltan);
167                 if (nenviados <= 0)
168                         return nenviados;
169
170                 nfaltan -= nenviados;
171                 ptr     += nenviados;
172         }
173
174         return n - nfaltan;
175 }
176