Beispiel #1
0
static void _epoll_check(Epoll* epoll, EpollWatch* watch) {
	MAGIC_ASSERT(epoll);
	MAGIC_ASSERT(watch);

	/* check if we need to schedule a notification */
	gboolean needsNotify = _epollwatch_needsNotify(watch);
	gboolean isScheduled = (epoll->flags & EF_SCHEDULED) ? TRUE : FALSE;

	gpointer watchKey = descriptor_getHandleReference(watch->descriptor);

	if(needsNotify) {
		/* we need to report an event to user */
		g_hash_table_replace(epoll->reports, watchKey, watch);

		if(!isScheduled) {
			/* schedule a notification event for our node */
			NotifyPluginEvent* event = notifyplugin_new(epoll->super.handle);
			SimulationTime delay = 1;
			worker_scheduleEvent((Event*)event, delay, 0);

			epoll->flags |= EF_SCHEDULED;
		}
	} else {
		/* no longer needs reporting */
		g_hash_table_remove(epoll->reports, watchKey);
	}
}
Beispiel #2
0
static gint _host_monitorDescriptor(Host* host, Descriptor* descriptor) {
	MAGIC_ASSERT(host);

	/* make sure there are no collisions before inserting */
	gint* handle = descriptor_getHandleReference(descriptor);
	utility_assert(handle && !host_lookupDescriptor(host, *handle));
	g_hash_table_replace(host->descriptors, handle, descriptor);

	return *handle;
}
static void _networkinterface_scheduleNextReceive(NetworkInterface* interface) {
	/* the next packets need to be received and processed */
	SimulationTime batchTime = worker_getConfig()->interfaceBatchTime;

	/* receive packets in batches */
	while(!g_queue_is_empty(interface->inBuffer) &&
			interface->receiveNanosecondsConsumed <= batchTime) {
		/* get the next packet */
		Packet* packet = g_queue_pop_head(interface->inBuffer);
		utility_assert(packet);

		/* successfully received */
		packet_addDeliveryStatus(packet, PDS_RCV_INTERFACE_RECEIVED);
		_networkinterface_pcapWritePacket(interface, packet);

		/* free up buffer space */
		guint length = packet_getPayloadLength(packet) + packet_getHeaderSize(packet);
		interface->inBufferLength -= length;

		/* calculate how long it took to 'receive' this packet */
		interface->receiveNanosecondsConsumed += (length * interface->timePerByteDown);

		/* hand it off to the correct socket layer */
		gint key = packet_getDestinationAssociationKey(packet);
		Socket* socket = g_hash_table_lookup(interface->boundSockets, GINT_TO_POINTER(key));

		/* if the socket closed, just drop the packet */
		gint socketHandle = -1;
		if(socket) {
			socketHandle = *descriptor_getHandleReference((Descriptor*)socket);
			socket_pushInPacket(socket, packet);
		} else {
			packet_addDeliveryStatus(packet, PDS_RCV_INTERFACE_DROPPED);
		}

		packet_unref(packet);

		/* count our bandwidth usage by interface, and by socket handle if possible */
		tracker_addInputBytes(host_getTracker(worker_getCurrentHost()),(guint64)length, socketHandle);
	}

	/*
	 * we need to call back and try to receive more, even if we didnt consume all
	 * of our batch time, because we might have more packets to receive then.
	 */
	SimulationTime receiveTime = (SimulationTime) floor(interface->receiveNanosecondsConsumed);
	if(receiveTime >= SIMTIME_ONE_NANOSECOND) {
		/* we are 'receiving' the packets */
		interface->flags |= NIF_RECEIVING;
		/* call back when the packets are 'received' */
		InterfaceReceivedEvent* event = interfacereceived_new(interface);
		/* event destination is our node */
		worker_scheduleEvent((Event*)event, receiveTime, 0);
	}
}
static void _networkinterface_scheduleNextReceive(NetworkInterface* interface) {
	/* the next packets need to be received and processed */
	SimulationTime batchTime = worker_getConfig()->interfaceBatchTime;

	/* receive packets in batches */
	while(!g_queue_is_empty(interface->inBuffer) &&
			interface->receiveNanosecondsConsumed <= batchTime) {
		/* get the next packet */
		Packet* packet = g_queue_pop_head(interface->inBuffer);
		g_assert(packet);

		/* free up buffer space */
		guint length = packet_getPayloadLength(packet) + packet_getHeaderSize(packet);
		interface->inBufferLength -= length;

		/* hand it off to the correct socket layer */
		gint key = packet_getDestinationAssociationKey(packet);
		Socket* socket = g_hash_table_lookup(interface->boundSockets, GINT_TO_POINTER(key));

		gchar* packetString = packet_getString(packet);
		debug("packet in: %s", packetString);
		g_free(packetString);

		_networkinterface_pcapWritePacket(interface, packet);

		/* if the socket closed, just drop the packet */
		gint socketHandle = -1;
		if(socket) {
			socketHandle = *descriptor_getHandleReference((Descriptor*)socket);
			gboolean needsRetransmit = socket_pushInPacket(socket, packet);
			if(needsRetransmit) {
				/* socket can not handle it now, so drop it */
				_networkinterface_dropInboundPacket(interface, packet);
			}
		}

		/* successfully received, calculate how long it took to 'receive' this packet */
		interface->receiveNanosecondsConsumed += (length * interface->timePerByteDown);
		tracker_addInputBytes(node_getTracker(worker_getPrivate()->cached_node),(guint64)length, socketHandle);
	}

	/*
	 * we need to call back and try to receive more, even if we didnt consume all
	 * of our batch time, because we might have more packets to receive then.
	 */
	SimulationTime receiveTime = (SimulationTime) floor(interface->receiveNanosecondsConsumed);
	if(receiveTime >= SIMTIME_ONE_NANOSECOND) {
		/* we are 'receiving' the packets */
		interface->flags |= NIF_RECEIVING;
		/* call back when the packets are 'received' */
		InterfaceReceivedEvent* event = interfacereceived_new(interface);
		/* event destination is our node */
		worker_scheduleEvent((Event*)event, receiveTime, 0);
	}
}
Beispiel #5
0
void epoll_descriptorStatusChanged(Epoll* epoll, Descriptor* descriptor) {
	MAGIC_ASSERT(epoll);

	/* make sure we are actually watching the descriptor */
	EpollWatch* watch = g_hash_table_lookup(epoll->watches,
			descriptor_getHandleReference(descriptor));

	/* if we are not watching, its an error because we shouldn't be listening */
	g_assert(watch && (watch->descriptor == descriptor));

	/* trigger notify if needed */
	_epoll_check(epoll, watch);
}
void networkinterface_packetDropped(NetworkInterface* interface, Packet* packet) {
    MAGIC_ASSERT(interface);

    /* hand it off to the correct socket layer */
    gint key = packet_getSourceAssociationKey(packet);
    Socket* socket = g_hash_table_lookup(interface->boundSockets, GINT_TO_POINTER(key));

    /* if the socket closed, just drop the packet */
    gint socketHandle = -1;
    if(socket) {
        socketHandle = *descriptor_getHandleReference((Descriptor*)socket);
        socket_dropPacket(socket, packet);
    }
}
/* round robin queuing discipline ($ man tc)*/
static Packet* _networkinterface_selectRoundRobin(NetworkInterface* interface, gint* socketHandle) {
	Packet* packet = NULL;

	while(!packet && !g_queue_is_empty(interface->rrQueue)) {
		/* do round robin to get the next packet from the next socket */
		Socket* socket = g_queue_pop_head(interface->rrQueue);
		packet = socket_pullOutPacket(socket);
		*socketHandle = *descriptor_getHandleReference((Descriptor*)socket);

		if(socket_peekNextPacket(socket)) {
			/* socket has more packets, and is still reffed from before */
			g_queue_push_tail(interface->rrQueue, socket);
		} else {
			/* socket has no more packets, unref it from the sendable queue */
			descriptor_unref((Descriptor*) socket);
		}
	}

	return packet;
}
/* first-in-first-out queuing discipline ($ man tc)*/
static Packet* _networkinterface_selectFirstInFirstOut(NetworkInterface* interface, gint* socketHandle) {
	/* use packet priority field to select based on application ordering.
	 * this is really a simplification of prioritizing on timestamps. */
	Packet* packet = NULL;

	while(!packet && !priorityqueue_isEmpty(interface->fifoQueue)) {
		/* do fifo to get the next packet from the next socket */
		Socket* socket = priorityqueue_pop(interface->fifoQueue);
		packet = socket_pullOutPacket(socket);
		*socketHandle = *descriptor_getHandleReference((Descriptor*)socket);

		if(socket_peekNextPacket(socket)) {
			/* socket has more packets, and is still reffed from before */
			priorityqueue_push(interface->fifoQueue, socket);
		} else {
			/* socket has no more packets, unref it from the sendable queue */
			descriptor_unref((Descriptor*) socket);
		}
	}

	return packet;
}
Beispiel #9
0
gint epoll_getEvents(Epoll* epoll, struct epoll_event* eventArray,
		gint eventArrayLength, gint* nEvents) {
	MAGIC_ASSERT(epoll);
	g_assert(nEvents);

	epoll->lastWaitTime = worker_getPrivate()->clock_now;

	/* return the available events in the eventArray, making sure not to
	 * overflow. the number of actual events is returned in nEvents.
	 *
	 * @todo: could be more efficient if we kept track of which descriptors
	 * are ready at any given time, at the cost of code complexity (we'd have
	 * to manage descriptors in multiples structs, update when deleted, etc)
	 */
	GHashTableIter iter;
	gpointer key, value;
	gint i = 0;
	g_hash_table_iter_init(&iter, epoll->watches);

	while(g_hash_table_iter_next(&iter, &key, &value)) {
		EpollWatch* watch = value;
		MAGIC_ASSERT(watch);

		/* return the event types that are actually available if they are registered
		 * without removing our knowledge of what was registered
		 */
		enum DescriptorStatus status = descriptor_getStatus(watch->descriptor);
		gboolean isReadable = (status & DS_READABLE) ? TRUE : FALSE;
		gboolean waitingReadable = (watch->event.events & EPOLLIN) ? TRUE : FALSE;
		gboolean isWritable = (status & DS_WRITABLE) ? TRUE : FALSE;
		gboolean waitingWritable = (watch->event.events & EPOLLOUT) ? TRUE : FALSE;

		if((isReadable && waitingReadable) || (isWritable && waitingWritable)) {
			/* report the event */
			eventArray[i] = watch->event;
			eventArray[i].events =
					isReadable && isWritable ? EPOLLIN|EPOLLOUT : isReadable ? EPOLLIN : EPOLLOUT;

			/* no longer needs to be reported. if the user does not take action,
			 * we'll mark it as needs reporting again in ensureNotifyTriggers */
			g_hash_table_remove(epoll->reports, descriptor_getHandleReference(watch->descriptor));

			i++;
		}

		/* if we've filled everything, stop iterating */
		if(i >= eventArrayLength) {
			break;
		}
	}

	if(i < eventArrayLength) {
		/* now we have to get events from the OS descriptors */
		struct epoll_event osEvents[20];
		/* since we are in shadow context, this will be forwarded to the OS epoll */
		gint nos = epoll_wait(epoll->osEpollDescriptor, osEvents, 20, 0);

		if(nos == -1) {
			warning("error in epoll_wait for OS events on epoll fd %i", epoll->osEpollDescriptor);
		}

		for(gint j = 0; j < nos; j++) {
			eventArray[i] = osEvents[j];
			i++;
			/* if we've filled everything, stop iterating */
			if(i >= eventArrayLength) {
				break;
			}
		}
	}

	*nEvents = i;

	return 0;
}
Beispiel #10
0
gint epoll_control(Epoll* epoll, gint operation, Descriptor* descriptor,
		struct epoll_event* event) {
	MAGIC_ASSERT(epoll);

	debug("epoll descriptor %i, operation %i, descriptor %i",
			epoll->super.handle, operation, descriptor->handle);

	switch (operation) {
		case EPOLL_CTL_ADD: {
			/* EEXIST op was EPOLL_CTL_ADD, and the supplied file descriptor
			 * fd is already registered with this epoll instance. */
			if(_epoll_isWatchingDescriptor(epoll, descriptor)) {
				return EEXIST;
			}

			/* start watching for status changes */
			EpollWatch* watch = _epollwatch_new(epoll, descriptor, event);
			g_hash_table_replace(epoll->watches, descriptor_getHandleReference(descriptor), watch);

			/* initiate a callback if the new watched descriptor is ready */
			_epoll_check(epoll, watch);

			break;
		}

		case EPOLL_CTL_MOD: {
			/* ENOENT op was EPOLL_CTL_MOD, and fd is not
			 * registered with this epoll instance. */
			if(!_epoll_isWatchingDescriptor(epoll, descriptor)) {
				return ENOENT;
			}

			EpollWatch* watch = g_hash_table_lookup(epoll->watches,
						descriptor_getHandleReference(descriptor));

			g_assert(watch && event);
			watch->event = *event;

			/* initiate a callback if the new event type on the watched descriptor is ready */
			_epoll_check(epoll, watch);

			break;
		}

		case EPOLL_CTL_DEL: {
			/* ENOENT op was EPOLL_CTL_DEL, and fd is not
			 * registered with this epoll instance. */
			if(!_epoll_isWatchingDescriptor(epoll, descriptor)) {
				return ENOENT;
			}

			g_hash_table_remove(epoll->watches, descriptor_getHandleReference(descriptor));

			break;
		}

		default: {
			warning("ignoring unrecognized operation");
			break;
		}
	}

	return 0;
}
Beispiel #11
0
static gboolean _epoll_isWatchingDescriptor(Epoll* epoll, Descriptor* descriptor) {

	EpollWatch* watch = g_hash_table_lookup(epoll->watches,
			descriptor_getHandleReference(descriptor));
	return watch == NULL ? FALSE : TRUE;
}