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);
	}
}
Beispiel #2
0
gboolean socket_addToOutputBuffer(Socket* socket, Packet* packet) {
    MAGIC_ASSERT(socket);

    /* check if the packet fits */
    guint length = packet_getPayloadLength(packet);
    if(length > socket_getOutputBufferSpace(socket)) {
        return FALSE;
    }

    /* add to our queue */
    g_queue_push_tail(socket->outputBuffer, packet);
    socket->outputBufferLength += length;
    packet_addDeliveryStatus(packet, PDS_SND_SOCKET_BUFFERED);

    /* update the tracker input buffer stats */
    Tracker* tracker = host_getTracker(worker_getCurrentHost());
    Descriptor* descriptor = (Descriptor *)socket;
    tracker_updateSocketOutputBuffer(tracker, descriptor->handle, socket->outputBufferLength, socket->outputBufferSize);

    /* we just added a packet, we are no longer writable if full */
    if(socket_getOutputBufferSpace(socket) <= 0) {
        descriptor_adjustStatus((Descriptor*)socket, DS_WRITABLE, FALSE);
    }

    /* tell the interface to include us when sending out to the network */
    in_addr_t ip = packet_getSourceIP(packet);
    NetworkInterface* interface = host_lookupInterface(worker_getCurrentHost(), ip);
    networkinterface_wantsSend(interface, socket);

    return TRUE;
}
Beispiel #3
0
gboolean socket_addToInputBuffer(Socket* socket, Packet* packet) {
    MAGIC_ASSERT(socket);

    /* check if the packet fits */
    guint length = packet_getPayloadLength(packet);
    if(length > socket_getInputBufferSpace(socket)) {
        return FALSE;
    }

    /* add to our queue */
    g_queue_push_tail(socket->inputBuffer, packet);
    packet_ref(packet);
    socket->inputBufferLength += length;
    packet_addDeliveryStatus(packet, PDS_RCV_SOCKET_BUFFERED);

    /* update the tracker input buffer stats */
    Tracker* tracker = host_getTracker(worker_getCurrentHost());
    Descriptor* descriptor = (Descriptor *)socket;
    tracker_updateSocketInputBuffer(tracker, descriptor->handle, socket->inputBufferLength, socket->inputBufferSize);

    /* we just added a packet, so we are readable */
    if(socket->inputBufferLength > 0) {
        descriptor_adjustStatus((Descriptor*)socket, DS_READABLE, TRUE);
    }

    return TRUE;
}
Beispiel #4
0
void udp_processPacket(UDP* udp, Packet* packet) {
	MAGIC_ASSERT(udp);

	/* UDP packet contains data for user and can be buffered immediately */
	if(packet_getPayloadLength(packet) > 0) {
		if(!socket_addToInputBuffer((Socket*)udp, packet)) {
			packet_addDeliveryStatus(packet, PDS_RCV_SOCKET_DROPPED);
		}
	}
}
Beispiel #5
0
void worker_schedulePacket(Packet* packet) {
    /* get our thread-private worker */
    Worker* worker = _worker_getPrivate();
    if(slave_isKilled(worker->slave)) {
        /* the simulation is over, don't bother */
        return;
    }

    in_addr_t srcIP = packet_getSourceIP(packet);
    in_addr_t dstIP = packet_getDestinationIP(packet);

    Address* srcAddress = dns_resolveIPToAddress(worker_getDNS(), (guint32) srcIP);
    Address* dstAddress = dns_resolveIPToAddress(worker_getDNS(), (guint32) dstIP);

    if(!srcAddress || !dstAddress) {
        error("unable to schedule packet because of null addresses");
        return;
    }

    /* check if network reliability forces us to 'drop' the packet */
    gdouble reliability = topology_getReliability(worker_getTopology(), srcAddress, dstAddress);
    Random* random = host_getRandom(worker_getCurrentHost());
    gdouble chance = random_nextDouble(random);

    /* don't drop control packets with length 0, otherwise congestion
     * control has problems responding to packet loss */
    if(chance <= reliability || packet_getPayloadLength(packet) == 0) {
        /* the sender's packet will make it through, find latency */
        gdouble latency = topology_getLatency(worker_getTopology(), srcAddress, dstAddress);
        SimulationTime delay = (SimulationTime) ceil(latency * SIMTIME_ONE_MILLISECOND);

        PacketArrivedEvent* event = packetarrived_new(packet);
        worker_scheduleEvent((Event*)event, delay, (GQuark)address_getID(dstAddress));

        packet_addDeliveryStatus(packet, PDS_INET_SENT);
    } else {
        packet_addDeliveryStatus(packet, PDS_INET_DROPPED);
    }
}
void networkinterface_packetArrived(NetworkInterface* interface, Packet* packet) {
	MAGIC_ASSERT(interface);

	/* a packet arrived. lets try to receive or buffer it */
	guint length = packet_getPayloadLength(packet) + packet_getHeaderSize(packet);
	gssize space = interface->inBufferSize - interface->inBufferLength;
	utility_assert(space >= 0);

	if(length <= space) {
		/* we have space to buffer it */
		packet_ref(packet);
		g_queue_push_tail(interface->inBuffer, packet);
		interface->inBufferLength += length;
		packet_addDeliveryStatus(packet, PDS_RCV_INTERFACE_BUFFERED);

		/* we need a trigger if we are not currently receiving */
		if(!(interface->flags & NIF_RECEIVING)) {
			_networkinterface_scheduleNextReceive(interface);
		}
	} else {
		/* buffers are full, drop packet */
		packet_addDeliveryStatus(packet, PDS_RCV_INTERFACE_DROPPED);
	}
}
Beispiel #7
0
gssize udp_receiveUserData(UDP* udp, gpointer buffer, gsize nBytes, in_addr_t* ip, in_port_t* port) {
	MAGIC_ASSERT(udp);

	Packet* packet = socket_removeFromInputBuffer((Socket*)udp);
	if(!packet) {
		return -1;
	}

	/* copy lesser of requested and available amount to application buffer */
	guint packetLength = packet_getPayloadLength(packet);
	gsize copyLength = MIN(nBytes, packetLength);
	guint bytesCopied = packet_copyPayload(packet, 0, buffer, copyLength);

	utility_assert(bytesCopied == copyLength);
	packet_addDeliveryStatus(packet, PDS_RCV_SOCKET_DELIVERED);

	/* fill in address info */
	if(ip) {
		*ip = packet_getSourceIP(packet);
	}
	if(port) {
		*port = packet_getSourcePort(packet);
	}

	/* destroy packet, throwing away any bytes not claimed by the app */
	packet_unref(packet);

	/* update the tracker output buffer stats */
	Tracker* tracker = host_getTracker(worker_getCurrentHost());
	Socket* socket = (Socket* )udp;
	Descriptor* descriptor = (Descriptor *)socket;
	gsize outLength = socket_getOutputBufferLength(socket);
	gsize outSize = socket_getOutputBufferSize(socket);
	tracker_updateSocketOutputBuffer(tracker, descriptor->handle, outLength, outSize);

	debug("user read %u inbound UDP bytes", bytesCopied);

	return (gssize)bytesCopied;
}
static void _networkinterface_scheduleNextSend(NetworkInterface* interface) {
	/* the next packet needs to be sent according to bandwidth limitations.
	 * we need to spend time sending it before sending the next. */
	SimulationTime batchTime = worker_getConfig()->interfaceBatchTime;

	/* loop until we find a socket that has something to send */
	while(interface->sendNanosecondsConsumed <= batchTime) {
		gint socketHandle = -1;

		/* choose which packet to send next based on our queuing discipline */
		Packet* packet;
		switch(interface->qdisc) {
			case NIQ_RR: {
				packet = _networkinterface_selectRoundRobin(interface, &socketHandle);
				break;
			}
			case NIQ_FIFO:
			default: {
				packet = _networkinterface_selectFirstInFirstOut(interface, &socketHandle);
				break;
			}
		}
		if(!packet) {
			break;
		}

		packet_addDeliveryStatus(packet, PDS_SND_INTERFACE_SENT);

		/* now actually send the packet somewhere */
		if(networkinterface_getIPAddress(interface) == packet_getDestinationIP(packet)) {
			/* packet will arrive on our own interface */
			PacketArrivedEvent* event = packetarrived_new(packet);
			/* event destination is our node */
			worker_scheduleEvent((Event*)event, 1, 0);
		} else {
			/* let the worker schedule with appropriate delays */
			worker_schedulePacket(packet);
		}

		/* successfully sent, calculate how long it took to 'send' this packet */
		guint length = packet_getPayloadLength(packet) + packet_getHeaderSize(packet);

		interface->sendNanosecondsConsumed += (length * interface->timePerByteUp);
		tracker_addOutputBytes(host_getTracker(worker_getCurrentHost()),(guint64)length, socketHandle);
		_networkinterface_pcapWritePacket(interface, packet);

		/* sending side is done with its ref */
		packet_unref(packet);
	}

	/*
	 * we need to call back and try to send more, even if we didnt consume all
	 * of our batch time, because we might have more packets to send then.
	 */
	SimulationTime sendTime = (SimulationTime) floor(interface->sendNanosecondsConsumed);
	if(sendTime >= SIMTIME_ONE_NANOSECOND) {
		/* we are 'sending' the packets */
		interface->flags |= NIF_SENDING;
		/* call back when the packets are 'sent' */
		InterfaceSentEvent* event = interfacesent_new(interface);
		/* event destination is our node */
		worker_scheduleEvent((Event*)event, sendTime, 0);
	}
}
Beispiel #9
0
/*
 * this function builds a UDP packet and sends to the virtual node given by the
 * ip and port parameters. this function assumes that the socket is already
 * bound to a local port, no matter if that happened explicitly or implicitly.
 */
gssize udp_sendUserData(UDP* udp, gconstpointer buffer, gsize nBytes, in_addr_t ip, in_port_t port) {
	MAGIC_ASSERT(udp);

	gsize space = socket_getOutputBufferSpace(&(udp->super));
	if(space < nBytes) {
		/* not enough space to buffer the data */
		return -1;
	}

	/* break data into segments and send each in a packet */
	gsize maxPacketLength = CONFIG_DATAGRAM_MAX_SIZE;
	gsize remaining = nBytes;
	gsize offset = 0;

	/* create as many packets as needed */
	while(remaining > 0) {
		gsize copyLength = MIN(maxPacketLength, remaining);

		/* use default destination if none was specified */
		in_addr_t destinationIP = (ip != 0) ? ip : udp->super.peerIP;
		in_port_t destinationPort = (port != 0) ? port : udp->super.peerPort;

		in_addr_t sourceIP = 0;
		in_port_t sourcePort = 0;
		socket_getSocketName(&(udp->super), &sourceIP, &sourcePort);

		if(sourceIP == htonl(INADDR_ANY)) {
			/* source interface depends on destination */
			if(destinationIP == htonl(INADDR_LOOPBACK)) {
				sourceIP = htonl(INADDR_LOOPBACK);
			} else {
				sourceIP = host_getDefaultIP(worker_getCurrentHost());
			}
		}

		utility_assert(sourceIP && sourcePort && destinationIP && destinationPort);

		/* create the UDP packet */
		Packet* packet = packet_new(buffer + offset, copyLength);
		packet_setUDP(packet, PUDP_NONE, sourceIP, sourcePort, destinationIP, destinationPort);
		packet_addDeliveryStatus(packet, PDS_SND_CREATED);

		/* buffer it in the transport layer, to be sent out when possible */
		gboolean success = socket_addToOutputBuffer((Socket*) udp, packet);

		/* counter maintenance */
		if(success) {
			remaining -= copyLength;
			offset += copyLength;
		} else {
			warning("unable to send UDP packet");
			break;
		}
	}

	/* update the tracker output buffer stats */
	Tracker* tracker = host_getTracker(worker_getCurrentHost());
	Socket* socket = (Socket* )udp;
	Descriptor* descriptor = (Descriptor *)socket;
	gsize outLength = socket_getOutputBufferLength(socket);
	gsize outSize = socket_getOutputBufferSize(socket);
	tracker_updateSocketOutputBuffer(tracker, descriptor->handle, outLength, outSize);

	debug("buffered %"G_GSIZE_FORMAT" outbound UDP bytes from user", offset);

	return (gssize) offset;
}
Beispiel #10
0
void socket_pushInPacket(Socket* socket, Packet* packet) {
    MAGIC_ASSERT(socket);
    MAGIC_ASSERT(socket->vtable);
    packet_addDeliveryStatus(packet, PDS_RCV_SOCKET_PROCESSED);
    socket->vtable->process(socket, packet);
}