Exemplo n.º 1
0
gsize socket_getOutputBufferSpace(Socket* socket) {
    MAGIC_ASSERT(socket);
    utility_assert(socket->outputBufferSize >= socket->outputBufferLength);
    gsize bufferSize = socket_getOutputBufferSize(socket);
    if(bufferSize < socket->outputBufferLength) {
        return 0;
    } else {
        return bufferSize - socket->outputBufferLength;
    }
}
Exemplo n.º 2
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;

		/* create the UDP packet */
		Packet* packet = packet_new(buffer + offset, copyLength);
		packet_setUDP(packet, PUDP_NONE, socket_getBinding(&(udp->super)),
				udp->super.boundPort, destinationIP, destinationPort);

		/* 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 = node_getTracker(worker_getPrivate()->cached_node);
	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;
}
Exemplo n.º 3
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;
}
Exemplo n.º 4
0
gint system_getSockOpt(gint fd, gint level, gint optname, gpointer optval,
		socklen_t* optlen) {
	if(!optlen) {
		errno = EFAULT;
		return -1;
	}

	Host* node = _system_switchInShadowContext();
	Descriptor* descriptor = host_lookupDescriptor(node, fd);

	gint result = 0;

	/* TODO: implement socket options */
	if(descriptor) {
		if(level == SOL_SOCKET || level == SOL_IP || level == SOL_TCP) {
			DescriptorType t = descriptor_getType(descriptor);
			switch (optname) {
				case TCP_INFO: {
					if(t == DT_TCPSOCKET) {
						if(optval) {
							TCP* tcp = (TCP*)descriptor;
							tcp_getInfo(tcp, (struct tcp_info *)optval);
						}
						*optlen = sizeof(struct tcp_info);
						result = 0;
					} else {
						warning("called getsockopt with TCP_INFO on non-TCP socket");
						errno = ENOPROTOOPT;
						result = -1;
					}

					break;
				}

				case SO_SNDBUF: {
					if(*optlen < sizeof(gint)) {
						warning("called getsockopt with SO_SNDBUF with optlen < %i", (gint)(sizeof(gint)));
						errno = EINVAL;
						result = -1;
					} else if (t != DT_TCPSOCKET && t != DT_UDPSOCKET) {
						warning("called getsockopt with SO_SNDBUF on non-socket");
						errno = ENOPROTOOPT;
						result = -1;
					} else {
						if(optval) {
							*((gint*) optval) = (gint) socket_getOutputBufferSize((Socket*)descriptor);
						}
						*optlen = sizeof(gint);
					}
					break;
				}

				case SO_RCVBUF: {
					if(*optlen < sizeof(gint)) {
						warning("called getsockopt with SO_RCVBUF with optlen < %i", (gint)(sizeof(gint)));
						errno = EINVAL;
						result = -1;
					} else if (t != DT_TCPSOCKET && t != DT_UDPSOCKET) {
						warning("called getsockopt with SO_RCVBUF on non-socket");
						errno = ENOPROTOOPT;
						result = -1;
					} else {
						if(optval) {
							*((gint*) optval) = (gint) socket_getInputBufferSize((Socket*)descriptor);
						}
						*optlen = sizeof(gint);
					}
					break;
				}

				case SO_ERROR: {
					if(optval) {
						*((gint*)optval) = 0;
					}
					*optlen = sizeof(gint);

					result = 0;
					break;
				}

				default: {
					warning("getsockopt optname %i not implemented", optname);
					errno = ENOSYS;
					result = -1;
					break;
				}
			}
		} else {
			warning("getsockopt level %i not implemented", level);
			errno = ENOSYS;
			result = -1;
		}
	} else {
		errno = EBADF;
		result = -1;
	}

	_system_switchOutShadowContext(node);
	return result;
}
Exemplo n.º 5
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;
}