-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathsocket.h
More file actions
196 lines (181 loc) · 5.7 KB
/
socket.h
File metadata and controls
196 lines (181 loc) · 5.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
#ifndef SOCKET_H
#define SOCKET_H
/*
* TDA Socket.
* Por simplificación este TDA se enfocará solamente
* en sockets IPv4 para TCP.
* */
class Socket {
private:
int skt;
bool closed;
int stream_status;
/*
* Construye el socket pasándole directamente el file descriptor.
* */
explicit Socket(int skt);
/*
* Checkea que el file descriptor (skt) sea "valido".
*
* No hace un checkeo muy exhaustivo, simplemente verifica que
* no sea -1.
*
* En un object RAII como este, el atributo skt esta siempre
* bien definido (distinto de -1) **salvo** cuando es movido.
*
* En teoría una vez movido el objecto, este no puede ser usado
* ya q queda invalido.
*
* En el caso de Socket, al moverse se setea skt a -1.
*
* En lenguajes como Rust usar un objeto "ya movido" falla
* en tiempo de compilación.
*
* En C++, bueno, es C++ y el comportamiento es indefinido :D.
*
* Este check es para ayudarte a detectar ese caso y lanzar una
* excepción. No es lo más bonito del universo pero te dará una
* pista de que puede estar andando mal.
* */
void chk_skt_or_fail() const;
public:
/*
* Constructores para `Socket` tanto para conectarse a un servidor
* (`Socket::Socket(const char*, const char*)`) como para ser usado
* por un servidor (`Socket::Socket(const char*)`).
*
* Muchas librerías de muchos lenguajes ofrecen una única formal de inicializar
* los sockets y luego métodos (post-inicialización) para establecer
* la conexión o ponerlo en escucha.
*
* Otras librerías/lenguajes van por tener una inicialización para
* el socket activo y otra para el pasivo.
*
* Este TDA va por ese lado.
*
* Para `Socket::Socket(const char*, const char*)`, <hostname>/<servname> es la dirección
* de la máquina remota a la cual se quiere conectar.
*
* Para `Socket::Socket(const char*)`, buscara una dirección local válida
* para escuchar y aceptar conexiones automáticamente en el <servname> dado.
*
* En caso de error los constructores lanzaran una excepción.
* */
Socket(
const char *hostname,
const char *servname);
explicit Socket(const char *servname);
/*
* Deshabilitamos el constructor por copia y operador asignación por copia
* ya que no queremos que se puedan copiar objetos `Socket`.
*
* Se podrían copiar?, no. Si bien un `Socket` el un `int` y un `bool` y seria
* trivial copiarlo, conceptualmente ese `int` no es meramente un número
* sino un file descriptor, un identificador que tiene asociado varios
* recursos del lado del sistema operativo.
*
* Copiar un `int` no implica que esos recursos son copiados (es como
* copiar un puntero y pretender que el objeto apuntado se copie mágicamente).
*
* Más aun no tiene sentido pensar en copiar un socket. Un socket
* representa una conexión algo q no se puede copiar.
*
* Lo mismo pasa con otros recursos. Un archivo referenciado por `FILE*`.
* Copiar ese puntero no implica que realmente tendrás una copia del archivo
* en tu disco rígido.
*
* Por eso deshabilitamos la copia. No tiene sentido.
* */
Socket(const Socket&) = delete;
Socket& operator=(const Socket&) = delete;
/*
* Hacemos que el `Socket` sea movible.
* */
Socket(Socket&&);
Socket& operator=(Socket&&);
/* `Socket::sendsome` lee hasta `sz` bytes del buffer y los envía. La función
* puede enviar menos bytes sin embargo.
*
* `Socket::recvsome` por el otro lado recibe hasta `sz` bytes y los escribe
* en el buffer (que debe estar pre-allocado). La función puede recibir
* menos bytes sin embargo.
*
* Si el socket detecto que la conexión fue cerrada, el metodo
* `is_stream_send_closed` o `is_stream_recv_closed` (segun corresponda)
* retornaran `true`, de otro modo sera `false`.
*
* Retorna 0 si se cerro el socket,
* o positivo que indicara cuantos bytes realmente se enviaron/recibieron.
*
* Si hay un error se lanza una excepción.
*
* Lease manpage de `send` y `recv`
* */
int sendsome(
const void *data,
unsigned int sz
);
int recvsome(
void *data,
unsigned int sz
);
/*
* `Socket::sendall` envía exactamente `sz` bytes leídos del buffer, ni más,
* ni menos. `Socket::recvall` recibe exactamente sz bytes.
*
* Si hay un error se lanza una excepción.
*
* Si no hubo un error pero el socket se cerro durante el envio/recibo
* de los bytes y algunos bytes fueron enviados/recibidos,
* se lanza también una excepción.
*
* Si en cambio ningún byte se pudo enviar/recibir, se retorna 0.
*
* En ambos casos, donde el socket se cerró,
* `is_stream_send_closed` o `is_stream_recv_closed` (segun corresponda)
* retornara `true`.
*
* En caso de éxito se retorna la misma cantidad de bytes pedidos
* para envio/recibo, lease `sz`.
*
* */
int sendall(
const void *data,
unsigned int sz
);
int recvall(
void *data,
unsigned int sz
);
/*
* Acepta una conexión entrante y retorna un nuevo socket
* construido a partir de ella.
*
* En caso de error, se lanza una excepción.
* */
Socket accept();
/*
* Cierra la conexión ya sea parcial o completamente.
* Lease manpage de `shutdown`
* */
void shutdown(int how);
/*
* Determina si el stream de envio (send) o de recepción (recv)
* están cerrado (sea por que se hizo un shutdown o por que el
* otro endpoint hizo un shutdown).
* */
bool is_stream_send_closed() const;
bool is_stream_recv_closed() const;
/*
* Cierra el socket. El cierre no implica un `shutdown`
* que debe ser llamado explícitamente.
* */
int close();
/*
* Destruye el socket. Si aun esta conectado,
* se llamara a `Socket::shutdown` y `Socket::close`
* automáticamente.
* */
~Socket();
};
#endif