PageRenderTime 87ms CodeModel.GetById 2ms app.highlight 60ms RepoModel.GetById 13ms app.codeStats 0ms

/src/host/descriptor/shd-socket.c

https://github.com/amiller/shadow
C | 431 lines | 309 code | 86 blank | 36 comment | 35 complexity | 0dbbc1acb36bd42c60eb14450cb04aba MD5 | raw file
  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}