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 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;
}
Exemple #4
0
void notifyplugin_run(NotifyPluginEvent* event, Host* node) {
	MAGIC_ASSERT(event);

	debug("event started");

	/* check in with epoll to make sure we should carry out the notification */
	Epoll* epoll = (Epoll*) host_lookupDescriptor(node, event->epollHandle);
	epoll_tryNotify(epoll);

	debug("event finished");
}
Exemple #5
0
static void _host_unmonitorDescriptor(Host* host, gint handle) {
	MAGIC_ASSERT(host);

	Descriptor* descriptor = host_lookupDescriptor(host, handle);
	if(descriptor) {
		if(descriptor->type == DT_TCPSOCKET || descriptor->type == DT_UDPSOCKET)
		{
			Socket* socket = (Socket*) descriptor;
			_host_disassociateInterface(host, socket);
		}

		g_hash_table_remove(host->descriptors, (gconstpointer) &handle);
	}
}
Exemple #6
0
gint system_socketPair(gint domain, gint type, gint protocol, gint fds[2]) {
	/* create a pair of connected sockets, i.e. a bi-directional pipe */
	if(domain != AF_UNIX) {
		errno = EAFNOSUPPORT;
		return -1;
	}

	/* only support non-blocking sockets */
	gboolean isBlocking = FALSE;

	/* clear non-blocking flags if set to get true type */
	gint realType = type;
	if(realType & SOCK_NONBLOCK) {
		realType = realType & ~SOCK_NONBLOCK;
		isBlocking = FALSE;
	}
	if(realType & SOCK_CLOEXEC) {
		realType = realType & ~SOCK_CLOEXEC;
		isBlocking = FALSE;
	}

	if(realType != SOCK_STREAM) {
		errno = EPROTONOSUPPORT;
		return -1;
	}

	gint result = 0;
	Host* node = _system_switchInShadowContext();

	if(isBlocking) {
		warning("we only support non-blocking sockets: please bitwise OR 'SOCK_NONBLOCK' with type flags");
		errno = EPROTONOSUPPORT;
		result = -1;
	}

	if(result == 0) {
		gint handle = host_createDescriptor(node, DT_SOCKETPAIR);

		Channel* channel = (Channel*) host_lookupDescriptor(node, handle);
		gint linkedHandle = channel_getLinkedHandle(channel);

		fds[0] = handle;
		fds[1] = linkedHandle;
	}

	_system_switchOutShadowContext(node);
	return result;
}
Exemple #7
0
gint system_pipe2(gint pipefds[2], gint flags) {
	/* we only support non-blocking sockets, and require
	 * SOCK_NONBLOCK to be set immediately */
	gboolean isBlocking = TRUE;

	/* clear non-blocking flags if set to get true type */
	if(flags & O_NONBLOCK) {
		flags = flags & ~O_NONBLOCK;
		isBlocking = FALSE;
	}
	if(flags & O_CLOEXEC) {
		flags = flags & ~O_CLOEXEC;
		isBlocking = FALSE;
	}

	Host* node = _system_switchInShadowContext();
	gint result = 0;

	/* check inputs for what we support */
	if(isBlocking) {
		warning("we only support non-blocking pipes: please bitwise OR 'O_NONBLOCK' with flags");
		result = EINVAL;
	} else {
		gint handle = host_createDescriptor(node, DT_PIPE);

		Channel* channel = (Channel*) host_lookupDescriptor(node, handle);
		gint linkedHandle = channel_getLinkedHandle(channel);

		pipefds[0] = handle; /* reader */
		pipefds[1] = linkedHandle; /* writer */
	}

	_system_switchOutShadowContext(node);

	if(result != 0) {
		errno = result;
		return -1;
	}

	return 0;
}
Exemple #8
0
gint system_ioctl(int fd, unsigned long int request, va_list farg) {
	/* check if this is a socket */
	if(fd < MIN_DESCRIPTOR){
		errno = EBADF;
		return -1;
	}

	gint result = 0;

	/* normally, the type of farg depends on the request */
	Host* node = _system_switchInShadowContext();
	Descriptor* descriptor = host_lookupDescriptor(node, fd);

	if(descriptor) {
		DescriptorType t = descriptor_getType(descriptor);
		if(t == DT_TCPSOCKET || t == DT_UDPSOCKET) {
			Socket* socket = (Socket*) descriptor;
			if(request == SIOCINQ || request == FIONREAD) {
				gsize bufferLength = socket_getInputBufferLength(socket);
				gint* lengthOut = va_arg(farg, int*);
				*lengthOut = (gint)bufferLength;
			} else if (request == SIOCOUTQ || request == TIOCOUTQ) {
Exemple #9
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 #10
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 #11
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 #12
0
gint system_setSockOpt(gint fd, gint level, gint optname, const gpointer optval,
		socklen_t optlen) {
	if(!optval) {
		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) {
			DescriptorType t = descriptor_getType(descriptor);
			switch (optname) {
				case SO_SNDBUF: {
					if(optlen < sizeof(gint)) {
						warning("called setsockopt with SO_SNDBUF with optlen < %i", (gint)(sizeof(gint)));
						errno = EINVAL;
						result = -1;
					} else if (t != DT_TCPSOCKET && t != DT_UDPSOCKET) {
						warning("called setsockopt with SO_SNDBUF on non-socket");
						errno = ENOPROTOOPT;
						result = -1;
					} else {
						gint v = *((gint*) optval);
						socket_setOutputBufferSize((Socket*)descriptor, (gsize)v*2);
					}
					break;
				}

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

				case SO_REUSEADDR: {
					// TODO implement this!
					// XXX Tor actually uses this option!!
					debug("setsockopt SO_REUSEADDR not yet implemented");
					break;
				}

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

	_system_switchOutShadowContext(node);
	return result;
}
Exemple #13
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;
}
Exemple #14
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 #15
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;
}
Exemple #16
0
gboolean host_isShadowDescriptor(Host* host, gint handle) {
	MAGIC_ASSERT(host);
	return host_lookupDescriptor(host, handle) == NULL ? FALSE : TRUE;
}