Exemple #1
0
gint host_epollControl(Host* host, gint epollDescriptor, gint operation,
		gint fileDescriptor, struct epoll_event* event) {
	MAGIC_ASSERT(host);

	/* EBADF  epfd is not a valid file descriptor. */
	Descriptor* descriptor = host_lookupDescriptor(host, epollDescriptor);
	if(descriptor == NULL) {
		return EBADF;
	}

	DescriptorStatus status = descriptor_getStatus(descriptor);
	if(status & DS_CLOSED) {
		warning("descriptor handle '%i' not a valid open descriptor", epollDescriptor);
		return EBADF;
	}

	/* EINVAL epfd is not an epoll file descriptor */
	if(descriptor_getType(descriptor) != DT_EPOLL) {
		return EINVAL;
	}

	/* now we know its an epoll */
	Epoll* epoll = (Epoll*) descriptor;

	/* if this is for a system file, forward to system call */
	if(!host_isShadowDescriptor(host, fileDescriptor)) {
		gint osfd = host_getOSHandle(host, fileDescriptor);
		osfd = osfd >= 0 ? osfd : fileDescriptor;

		gint oldEventFD = event->data.fd;
		event->data.fd = osfd;
		gint result = epoll_controlOS(epoll, operation, osfd, event);
		event->data.fd = oldEventFD;

		return result;
	}

	/* EBADF  fd is not a valid shadow file descriptor. */
	descriptor = host_lookupDescriptor(host, fileDescriptor);
	if(descriptor == NULL) {
		return EBADF;
	}

	status = descriptor_getStatus(descriptor);
	if(status & DS_CLOSED) {
		warning("descriptor handle '%i' not a valid open descriptor", fileDescriptor);
		return EBADF;
	}

	return epoll_control(epoll, operation, descriptor, event);

}
Exemple #2
0
gint host_epollGetEvents(Host* host, gint handle,
		struct epoll_event* eventArray, gint eventArrayLength, gint* nEvents) {
	MAGIC_ASSERT(host);

	/* EBADF  epfd is not a valid file descriptor. */
	Descriptor* descriptor = host_lookupDescriptor(host, handle);
	if(descriptor == NULL) {
		return EBADF;
	}

	DescriptorStatus status = descriptor_getStatus(descriptor);
	if(status & DS_CLOSED) {
		warning("descriptor handle '%i' not a valid open descriptor", handle);
		return EBADF;
	}

	/* EINVAL epfd is not an epoll file descriptor */
	if(descriptor_getType(descriptor) != DT_EPOLL) {
		return EINVAL;
	}

	Epoll* epoll = (Epoll*) descriptor;
	gint ret = epoll_getEvents(epoll, eventArray, eventArrayLength, nEvents);

	for(gint i = 0; i < *nEvents; i++) {
	    if(!host_isShadowDescriptor(host, eventArray[i].data.fd)) {
	        /* the fd is a file that the OS handled for us, translate to shadow fd */
	        eventArray[i].data.fd = host_getShadowHandle(host, eventArray[i].data.fd);
	        utility_assert(eventArray[i].data.fd >= 0);
	    }
	}

	return ret;
}
Exemple #3
0
static gboolean _epollwatch_needsNotify(EpollWatch* watch) {
	MAGIC_ASSERT(watch);

	/* check status */
	enum DescriptorStatus status = descriptor_getStatus(watch->descriptor);

	/* check if we care about the status */
	gboolean isActive = (status & DS_ACTIVE) ? TRUE : FALSE;
	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(isActive && ((isReadable && waitingReadable) || (isWritable && waitingWritable))) {
		return TRUE;
	} else {
		return FALSE;
	}
}
Exemple #4
0
gint host_acceptNewPeer(Host* host, gint handle, in_addr_t* ip, in_port_t* port, gint* acceptedHandle) {
	MAGIC_ASSERT(host);

	Descriptor* descriptor = host_lookupDescriptor(host, handle);
	if(descriptor == NULL) {
		warning("descriptor handle '%i' not found", handle);
		return EBADF;
	}

	DescriptorStatus status = descriptor_getStatus(descriptor);
	if(status & DS_CLOSED) {
		warning("descriptor handle '%i' not a valid open descriptor", handle);
		return EBADF;
	}

	DescriptorType type = descriptor_getType(descriptor);
	if(type != DT_TCPSOCKET) {
		return EOPNOTSUPP;
	}

	return tcp_acceptServerPeer((TCP*)descriptor, ip, port, acceptedHandle);
}
Exemple #5
0
gint host_listenForPeer(Host* host, gint handle, gint backlog) {
	MAGIC_ASSERT(host);

	Descriptor* descriptor = host_lookupDescriptor(host, handle);
	if(descriptor == NULL) {
		warning("descriptor handle '%i' not found", handle);
		return EBADF;
	}

	DescriptorStatus status = descriptor_getStatus(descriptor);
	if(status & DS_CLOSED) {
		warning("descriptor handle '%i' not a valid open descriptor", handle);
		return EBADF;
	}

	DescriptorType type = descriptor_getType(descriptor);
	if(type != DT_TCPSOCKET) {
		warning("wrong type for descriptor handle '%i'", handle);
		return EOPNOTSUPP;
	}

	Socket* socket = (Socket*) descriptor;
	TCP* tcp = (TCP*) descriptor;

	if(!socket_isBound(socket)) {
		/* implicit bind */
		in_addr_t bindAddress = htonl(INADDR_ANY);
		in_port_t bindPort = _host_getRandomFreePort(host, bindAddress, type);
        if(!bindPort) {
            return EADDRNOTAVAIL;
        }

		_host_associateInterface(host, socket, bindAddress, bindPort);
	}

	tcp_enterServerMode(tcp, backlog);
	return 0;
}
Exemple #6
0
gint host_getPeerName(Host* host, gint handle, const struct sockaddr* address, socklen_t* len) {
	MAGIC_ASSERT(host);

	Descriptor* descriptor = host_lookupDescriptor(host, handle);
	if(descriptor == NULL) {
		warning("descriptor handle '%i' not found", handle);
		return EBADF;
	}

	DescriptorStatus status = descriptor_getStatus(descriptor);
	if(status & DS_CLOSED) {
		warning("descriptor handle '%i' not a valid open descriptor", handle);
		return EBADF;
	}

	DescriptorType type = descriptor_getType(descriptor);
	if(type != DT_TCPSOCKET) {
		return ENOTCONN;
	}

	Socket* sock = (Socket*)descriptor;
	in_addr_t ip = 0;
	in_port_t port = 0;

	gboolean hasPeer = socket_getPeerName(sock, &ip, &port);
	if(hasPeer) {
	    if(socket_isUnix(sock)) {
            struct sockaddr_un* saddr = (struct sockaddr_un*) address;
            saddr->sun_family = AF_UNIX;
            gchar* unixPath = socket_getUnixPath(sock);
            if(unixPath) {
                g_snprintf(saddr->sun_path, 107, "%s\\0", unixPath);
                *len = offsetof(struct sockaddr_un, sun_path) + strlen(saddr->sun_path) + 1;
            } else {
                *len = sizeof(sa_family_t);
            }
	    } else {
Exemple #7
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;
}
Exemple #8
0
gint host_connectToPeer(Host* host, gint handle, const struct sockaddr* address) {
	MAGIC_ASSERT(host);

	sa_family_t family = 0;
	in_addr_t peerIP = 0;
	in_port_t peerPort = 0;

    if(address->sa_family == AF_INET) {
        struct sockaddr_in* saddr = (struct sockaddr_in*) address;

        family = saddr->sin_family;
        peerIP = saddr->sin_addr.s_addr;
        peerPort = saddr->sin_port;

    } else if (address->sa_family == AF_UNIX) {
        struct sockaddr_un* saddr = (struct sockaddr_un*) address;

        family = saddr->sun_family;
        gchar* sockpath = saddr->sun_path;

        peerIP = htonl(INADDR_LOOPBACK);
        gpointer val = g_hash_table_lookup(host->unixPathToPortMap, sockpath);
        if(val) {
            peerPort = (in_port_t)GPOINTER_TO_UINT(val);
        }
    }

	in_addr_t loIP = htonl(INADDR_LOOPBACK);

	/* make sure we will be able to route this later */
	if(peerIP != loIP) {
		Address* myAddress = networkinterface_getAddress(host->defaultInterface);
		Address* peerAddress = dns_resolveIPToAddress(worker_getDNS(), peerIP);
		if(!peerAddress || !topology_isRoutable(worker_getTopology(), myAddress, peerAddress)) {
			/* can't route it - there is no node with this address */
			gchar* peerAddressString = address_ipToNewString(peerIP);
			warning("attempting to connect to address '%s:%u' for which no host exists", peerAddressString, ntohs(peerPort));
			g_free(peerAddressString);
			return ECONNREFUSED;
		}
	}

	Descriptor* descriptor = host_lookupDescriptor(host, handle);
	if(descriptor == NULL) {
		warning("descriptor handle '%i' not found", handle);
		return EBADF;
	}

	DescriptorStatus status = descriptor_getStatus(descriptor);
	if(status & DS_CLOSED) {
		warning("descriptor handle '%i' not a valid open descriptor", handle);
		return EBADF;
	}

	DescriptorType type = descriptor_getType(descriptor);
	if(type != DT_TCPSOCKET && type != DT_UDPSOCKET) {
		warning("wrong type for descriptor handle '%i'", handle);
		return ENOTSOCK;
	}

	Socket* socket = (Socket*) descriptor;

	if(!socket_isFamilySupported(socket, family)) {
		return EAFNOSUPPORT;
	}

	if(type == DT_TCPSOCKET) {
		gint error = tcp_getConnectError((TCP*)socket);
		if(error) {
			return error;
		}
	}

	if (address->sa_family == AF_UNIX) {
        struct sockaddr_un* saddr = (struct sockaddr_un*) address;
        socket_setUnixPath(socket, saddr->sun_path, FALSE);
    }

	if(!socket_isBound(socket)) {
		/* do an implicit bind to a random port.
		 * use default interface unless the remote peer is on loopback */
		in_addr_t defaultIP = networkinterface_getIPAddress(host->defaultInterface);

		in_addr_t bindAddress = loIP == peerIP ? loIP : defaultIP;
		in_port_t bindPort = _host_getRandomFreePort(host, bindAddress, type);
        if(!bindPort) {
            return EADDRNOTAVAIL;
        }

		_host_associateInterface(host, socket, bindAddress, bindPort);
	}

	return socket_connectToPeer(socket, peerIP, peerPort, family);
}
Exemple #9
0
gint host_bindToInterface(Host* host, gint handle, const struct sockaddr* address) {
	MAGIC_ASSERT(host);

	in_addr_t bindAddress = 0;
	in_port_t bindPort = 0;

	if(address->sa_family == AF_INET) {
	    struct sockaddr_in* saddr = (struct sockaddr_in*) address;
	    bindAddress = saddr->sin_addr.s_addr;
	    bindPort = saddr->sin_port;
	} else if (address->sa_family == AF_UNIX) {
	    struct sockaddr_un* saddr = (struct sockaddr_un*) address;
	    /* cant bind twice to the same unix path */
	    if(g_hash_table_lookup(host->unixPathToPortMap, saddr->sun_path)) {
	        return EADDRINUSE;
	    }
        bindAddress = htonl(INADDR_LOOPBACK);
        bindPort = 0; /* choose a random free port below */
	}

	Descriptor* descriptor = host_lookupDescriptor(host, handle);
	if(descriptor == NULL) {
		warning("descriptor handle '%i' not found", handle);
		return EBADF;
	}

	DescriptorStatus status = descriptor_getStatus(descriptor);
	if(status & DS_CLOSED) {
		warning("descriptor handle '%i' not a valid open descriptor", handle);
		return EBADF;
	}

	DescriptorType type = descriptor_getType(descriptor);
	if(type != DT_TCPSOCKET && type != DT_UDPSOCKET) {
		warning("wrong type for descriptor handle '%i'", handle);
		return ENOTSOCK;
	}

	/* make sure we have an interface at that address */
	if(!_host_doesInterfaceExist(host, bindAddress)) {
		return EADDRNOTAVAIL;
	}

	Socket* socket = (Socket*) descriptor;

	/* make sure socket is not bound */
	if(socket_isBound(socket)) {
		warning("socket already bound to requested address");
		return EINVAL;
	}

	/* make sure we have a proper port */
	if(bindPort == 0) {
		/* we know it will be available */
		bindPort = _host_getRandomFreePort(host, bindAddress, type);
		if(!bindPort) {
		    return EADDRNOTAVAIL;
		}
	} else {
		/* make sure their port is available at that address for this protocol. */
		if(!_host_isInterfaceAvailable(host, bindAddress, type, bindPort)) {
			return EADDRINUSE;
		}
	}

	/* bind port and set associations */
	_host_associateInterface(host, socket, bindAddress, bindPort);

	if (address->sa_family == AF_UNIX) {
        struct sockaddr_un* saddr = (struct sockaddr_un*) address;
        gchar* sockpath = g_strndup(saddr->sun_path, 108); /* UNIX_PATH_MAX=108 */
        socket_setUnixPath(socket, sockpath, TRUE);
        g_hash_table_replace(host->unixPathToPortMap, sockpath, GUINT_TO_POINTER(bindPort));
    }

	return 0;
}