/src/host/descriptor/shd-socket.c
C | 431 lines | 309 code | 86 blank | 36 comment | 35 complexity | 0dbbc1acb36bd42c60eb14450cb04aba MD5 | raw file
Possible License(s): BSD-3-Clause
1/*
2 * The Shadow Simulator
3 * Copyright (c) 2010-2011, Rob Jansen
4 * See LICENSE for licensing information
5 */
6
7#include "shadow.h"
8
9void socket_free(gpointer data) {
10 Socket* socket = data;
11 MAGIC_ASSERT(socket);
12 MAGIC_ASSERT(socket->vtable);
13
14
15 if(socket->peerString) {
16 g_free(socket->peerString);
17 }
18 if(socket->boundString) {
19 g_free(socket->boundString);
20 }
21 if(socket->unixPath) {
22 g_free(socket->unixPath);
23 }
24
25 while(g_queue_get_length(socket->inputBuffer) > 0) {
26 packet_unref(g_queue_pop_head(socket->inputBuffer));
27 }
28 g_queue_free(socket->inputBuffer);
29
30 while(g_queue_get_length(socket->outputBuffer) > 0) {
31 packet_unref(g_queue_pop_head(socket->outputBuffer));
32 }
33 g_queue_free(socket->outputBuffer);
34
35 MAGIC_CLEAR(socket);
36 socket->vtable->free((Descriptor*)socket);
37}
38
39void socket_close(Socket* socket) {
40 MAGIC_ASSERT(socket);
41 MAGIC_ASSERT(socket->vtable);
42
43 Tracker* tracker = host_getTracker(worker_getCurrentHost());
44 Descriptor* descriptor = (Descriptor *)socket;
45 tracker_removeSocket(tracker, descriptor->handle);
46
47 socket->vtable->close((Descriptor*)socket);
48}
49
50gssize socket_sendUserData(Socket* socket, gconstpointer buffer, gsize nBytes,
51 in_addr_t ip, in_port_t port) {
52 MAGIC_ASSERT(socket);
53 MAGIC_ASSERT(socket->vtable);
54 return socket->vtable->send((Transport*)socket, buffer, nBytes, ip, port);
55}
56
57gssize socket_receiveUserData(Socket* socket, gpointer buffer, gsize nBytes,
58 in_addr_t* ip, in_port_t* port) {
59 MAGIC_ASSERT(socket);
60 MAGIC_ASSERT(socket->vtable);
61 return socket->vtable->receive((Transport*)socket, buffer, nBytes, ip, port);
62}
63
64TransportFunctionTable socket_functions = {
65 (DescriptorFunc) socket_close,
66 (DescriptorFunc) socket_free,
67 (TransportSendFunc) socket_sendUserData,
68 (TransportReceiveFunc) socket_receiveUserData,
69 MAGIC_VALUE
70};
71
72void socket_init(Socket* socket, SocketFunctionTable* vtable, DescriptorType type, gint handle,
73 guint receiveBufferSize, guint sendBufferSize) {
74 utility_assert(socket && vtable);
75
76 transport_init(&(socket->super), &socket_functions, type, handle);
77
78 MAGIC_INIT(socket);
79 MAGIC_INIT(vtable);
80
81 socket->vtable = vtable;
82
83 socket->protocol = type == DT_TCPSOCKET ? PTCP : type == DT_UDPSOCKET ? PUDP : PLOCAL;
84 socket->inputBuffer = g_queue_new();
85 socket->inputBufferSize = receiveBufferSize;
86 socket->outputBuffer = g_queue_new();
87 socket->outputBufferSize = sendBufferSize;
88
89 Tracker* tracker = host_getTracker(worker_getCurrentHost());
90 Descriptor* descriptor = (Descriptor *)socket;
91 tracker_addSocket(tracker, descriptor->handle, socket->protocol, socket->inputBufferSize, socket->outputBufferSize);
92}
93
94enum ProtocolType socket_getProtocol(Socket* socket) {
95 MAGIC_ASSERT(socket);
96 return socket->protocol;
97}
98
99/* interface functions, implemented by subtypes */
100
101gboolean socket_isFamilySupported(Socket* socket, sa_family_t family) {
102 MAGIC_ASSERT(socket);
103 MAGIC_ASSERT(socket->vtable);
104 return socket->vtable->isFamilySupported(socket, family);
105}
106
107gint socket_connectToPeer(Socket* socket, in_addr_t ip, in_port_t port, sa_family_t family) {
108 MAGIC_ASSERT(socket);
109 MAGIC_ASSERT(socket->vtable);
110
111 Tracker* tracker = host_getTracker(worker_getCurrentHost());
112 Descriptor* descriptor = (Descriptor *)socket;
113 tracker_updateSocketPeer(tracker, descriptor->handle, ip, ntohs(port));
114
115 return socket->vtable->connectToPeer(socket, ip, port, family);
116}
117
118void socket_pushInPacket(Socket* socket, Packet* packet) {
119 MAGIC_ASSERT(socket);
120 MAGIC_ASSERT(socket->vtable);
121 packet_addDeliveryStatus(packet, PDS_RCV_SOCKET_PROCESSED);
122 return socket->vtable->process(socket, packet);
123}
124
125void socket_dropPacket(Socket* socket, Packet* packet) {
126 MAGIC_ASSERT(socket);
127 MAGIC_ASSERT(socket->vtable);
128 return socket->vtable->dropPacket(socket, packet);
129}
130
131/* functions implemented by socket */
132
133Packet* socket_pullOutPacket(Socket* socket) {
134 return socket_removeFromOutputBuffer(socket);
135}
136
137Packet* socket_peekNextPacket(const Socket* socket) {
138 MAGIC_ASSERT(socket);
139 return g_queue_peek_head(socket->outputBuffer);
140}
141
142gboolean socket_getPeerName(Socket* socket, in_addr_t* ip, in_port_t* port) {
143 MAGIC_ASSERT(socket);
144 utility_assert(ip && port);
145
146 if(socket->peerIP == 0 || socket->peerPort == 0) {
147 return FALSE;
148 }
149
150 if(ip) {
151 *ip = socket->peerIP;
152 }
153 if(port) {
154 *port = socket->peerPort;
155 }
156
157 return TRUE;
158}
159
160void socket_setPeerName(Socket* socket, in_addr_t ip, in_port_t port) {
161 MAGIC_ASSERT(socket);
162
163 socket->peerIP = ip;
164 socket->peerPort = port;
165
166 /* store the new ascii name of this peer */
167 if(socket->peerString) {
168 g_free(socket->peerString);
169 }
170 gchar* ipString = address_ipToNewString(ip);
171 GString* stringBuffer = g_string_new(ipString);
172 g_free(ipString);
173 g_string_append_printf(stringBuffer, ":%u", ntohs(port));
174 socket->peerString = g_string_free(stringBuffer, FALSE);
175}
176
177gboolean socket_getSocketName(Socket* socket, in_addr_t* ip, in_port_t* port) {
178 MAGIC_ASSERT(socket);
179
180 /* boundAddress could be 0 (INADDR_NONE), so just check port */
181 if(!socket_isBound(socket)) {
182 return FALSE;
183 }
184
185 if(ip) {
186 *ip = socket->boundAddress;
187 }
188 if(port) {
189 *port = socket->boundPort;
190 }
191
192 return TRUE;
193}
194
195void socket_setSocketName(Socket* socket, in_addr_t ip, in_port_t port, gboolean isInternal) {
196 MAGIC_ASSERT(socket);
197
198 socket->boundAddress = ip;
199 socket->boundPort = port;
200
201 /* store the new ascii name of this socket endpoint */
202 if(socket->boundString) {
203 g_free(socket->boundString);
204 }
205
206 gchar* ipString = address_ipToNewString(ip);
207 GString* stringBuffer = g_string_new(ipString);
208 g_free(ipString);
209 g_string_append_printf(stringBuffer, ":%u (descriptor %i)", ntohs(port), socket->super.super.handle);
210 socket->boundString = g_string_free(stringBuffer, FALSE);
211
212 /* children of server sockets must not have the same key as the parent
213 * otherwise when the child is closed, the parent's interface association
214 * will be removed. in fact, they dont need a key because their parent
215 * will handle incoming packets and will hand them off as necessary */
216 if(isInternal) {
217 socket->associationKey = 0;
218 } else {
219 socket->associationKey = PROTOCOL_DEMUX_KEY(socket->protocol, port);
220 }
221
222 /* the socket is now bound */
223 socket->flags |= SF_BOUND;
224}
225
226gboolean socket_isBound(Socket* socket) {
227 MAGIC_ASSERT(socket);
228 return (socket->flags & SF_BOUND) ? TRUE : FALSE;
229}
230
231gint socket_getAssociationKey(Socket* socket) {
232 MAGIC_ASSERT(socket);
233 utility_assert((socket->flags & SF_BOUND));
234 return socket->associationKey;
235}
236
237gsize socket_getInputBufferSpace(Socket* socket) {
238 MAGIC_ASSERT(socket);
239 utility_assert(socket->inputBufferSize >= socket->inputBufferLength);
240 return (socket->inputBufferSize - socket->inputBufferLength);
241}
242
243gsize socket_getOutputBufferSpace(Socket* socket) {
244 MAGIC_ASSERT(socket);
245 utility_assert(socket->outputBufferSize >= socket->outputBufferLength);
246 return (socket->outputBufferSize - socket->outputBufferLength);
247}
248
249gsize socket_getInputBufferLength(Socket* socket) {
250 MAGIC_ASSERT(socket);
251 return socket->inputBufferLength;
252}
253
254gsize socket_getOutputBufferLength(Socket* socket) {
255 MAGIC_ASSERT(socket);
256 return socket->outputBufferLength;
257}
258
259gsize socket_getInputBufferSize(Socket* socket) {
260 MAGIC_ASSERT(socket);
261 return socket->inputBufferSize;
262}
263
264gsize socket_getOutputBufferSize(Socket* socket) {
265 MAGIC_ASSERT(socket);
266 return socket->outputBufferSize;
267}
268
269void socket_setInputBufferSize(Socket* socket, gsize newSize) {
270 MAGIC_ASSERT(socket);
271 if(newSize >= socket->inputBufferLength) {
272 socket->inputBufferSize = newSize;
273 socket->inputBufferSizePending = 0;
274 } else {
275 /* ensure positive size, reduce size as buffer drains */
276 socket->inputBufferSize = socket->inputBufferLength;
277 socket->inputBufferSizePending = newSize;
278 }
279}
280
281void socket_setOutputBufferSize(Socket* socket, gsize newSize) {
282 MAGIC_ASSERT(socket);
283 if(newSize >= socket->outputBufferLength) {
284 socket->outputBufferSize = newSize;
285 socket->outputBufferSizePending = 0;
286 } else {
287 /* ensure positive size, reduce size as buffer drains */
288 socket->outputBufferSize = socket->outputBufferLength;
289 socket->outputBufferSizePending = newSize;
290 }
291}
292
293gboolean socket_addToInputBuffer(Socket* socket, Packet* packet) {
294 MAGIC_ASSERT(socket);
295
296 /* check if the packet fits */
297 guint length = packet_getPayloadLength(packet);
298 if(length > socket_getInputBufferSpace(socket)) {
299 return FALSE;
300 }
301
302 /* add to our queue */
303 g_queue_push_tail(socket->inputBuffer, packet);
304 packet_ref(packet);
305 socket->inputBufferLength += length;
306 packet_addDeliveryStatus(packet, PDS_RCV_SOCKET_BUFFERED);
307
308 /* update the tracker input buffer stats */
309 Tracker* tracker = host_getTracker(worker_getCurrentHost());
310 Descriptor* descriptor = (Descriptor *)socket;
311 tracker_updateSocketInputBuffer(tracker, descriptor->handle, socket->inputBufferLength, socket->inputBufferSize);
312
313 /* we just added a packet, so we are readable */
314 if(socket->inputBufferLength > 0) {
315 descriptor_adjustStatus((Descriptor*)socket, DS_READABLE, TRUE);
316 }
317
318 return TRUE;
319}
320
321Packet* socket_removeFromInputBuffer(Socket* socket) {
322 MAGIC_ASSERT(socket);
323
324 /* see if we have any packets */
325 Packet* packet = g_queue_pop_head(socket->inputBuffer);
326 if(packet) {
327 /* just removed a packet */
328 guint length = packet_getPayloadLength(packet);
329 socket->inputBufferLength -= length;
330
331 /* check if we need to reduce the buffer size */
332 if(socket->inputBufferSizePending > 0) {
333 socket_setInputBufferSize(socket, socket->inputBufferSizePending);
334 }
335
336 /* update the tracker input buffer stats */
337 Tracker* tracker = host_getTracker(worker_getCurrentHost());
338 Descriptor* descriptor = (Descriptor *)socket;
339 tracker_updateSocketInputBuffer(tracker, descriptor->handle, socket->inputBufferLength, socket->inputBufferSize);
340
341 /* we are not readable if we are now empty */
342 if(socket->inputBufferLength <= 0) {
343 descriptor_adjustStatus((Descriptor*)socket, DS_READABLE, FALSE);
344 }
345 }
346
347 return packet;
348}
349
350gboolean socket_addToOutputBuffer(Socket* socket, Packet* packet) {
351 MAGIC_ASSERT(socket);
352
353 /* check if the packet fits */
354 guint length = packet_getPayloadLength(packet);
355 if(length > socket_getOutputBufferSpace(socket)) {
356 return FALSE;
357 }
358
359 /* add to our queue */
360 g_queue_push_tail(socket->outputBuffer, packet);
361 socket->outputBufferLength += length;
362 packet_addDeliveryStatus(packet, PDS_SND_SOCKET_BUFFERED);
363
364 /* update the tracker input buffer stats */
365 Tracker* tracker = host_getTracker(worker_getCurrentHost());
366 Descriptor* descriptor = (Descriptor *)socket;
367 tracker_updateSocketOutputBuffer(tracker, descriptor->handle, socket->outputBufferLength, socket->outputBufferSize);
368
369 /* we just added a packet, we are no longer writable if full */
370 if(socket_getOutputBufferSpace(socket) <= 0) {
371 descriptor_adjustStatus((Descriptor*)socket, DS_WRITABLE, FALSE);
372 }
373
374 /* tell the interface to include us when sending out to the network */
375 in_addr_t ip = packet_getSourceIP(packet);
376 NetworkInterface* interface = host_lookupInterface(worker_getCurrentHost(), ip);
377 networkinterface_wantsSend(interface, socket);
378
379 return TRUE;
380}
381
382Packet* socket_removeFromOutputBuffer(Socket* socket) {
383 MAGIC_ASSERT(socket);
384
385 /* see if we have any packets */
386 Packet* packet = g_queue_pop_head(socket->outputBuffer);
387 if(packet) {
388 /* just removed a packet */
389 guint length = packet_getPayloadLength(packet);
390 socket->outputBufferLength -= length;
391
392 /* check if we need to reduce the buffer size */
393 if(socket->outputBufferSizePending > 0) {
394 socket_setOutputBufferSize(socket, socket->outputBufferSizePending);
395 }
396
397 /* update the tracker input buffer stats */
398 Tracker* tracker = host_getTracker(worker_getCurrentHost());
399 Descriptor* descriptor = (Descriptor *)socket;
400 tracker_updateSocketOutputBuffer(tracker, descriptor->handle, socket->outputBufferLength, socket->outputBufferSize);
401
402 /* we are writable if we now have space */
403 if(socket_getOutputBufferSpace(socket) > 0) {
404 descriptor_adjustStatus((Descriptor*)socket, DS_WRITABLE, TRUE);
405 }
406 }
407
408 return packet;
409}
410
411gboolean socket_isUnix(Socket* socket) {
412 return (socket->flags & SF_UNIX) ? TRUE : FALSE;
413}
414
415void socket_setUnix(Socket* socket, gboolean isUnixSocket) {
416 MAGIC_ASSERT(socket);
417 socket->flags = isUnixSocket ? (socket->flags | SF_UNIX) : (socket->flags & ~SF_UNIX);
418}
419
420void socket_setUnixPath(Socket* socket, const gchar* path, gboolean isBound) {
421 MAGIC_ASSERT(socket);
422 if(isBound) {
423 socket->flags |= SF_UNIX_BOUND;
424 }
425 socket->unixPath = g_strdup(path);
426}
427
428gchar* socket_getUnixPath(Socket* socket) {
429 MAGIC_ASSERT(socket);
430 return socket->unixPath;
431}