gssize system_recvFrom(gint fd, gpointer buf, size_t n, gint flags, struct sockaddr* addr, socklen_t* len) { /* TODO flags are ignored */ /* check if this is a socket */ if(fd < MIN_DESCRIPTOR){ errno = EBADF; return -1; } in_addr_t ip = 0; in_port_t port = 0; Node* node = _system_switchInShadowContext(); gsize bytes = 0; gint result = node_receiveUserData(node, fd, buf, n, &ip, &port, &bytes); _system_switchOutShadowContext(node); if(result != 0) { errno = result; return -1; } /* check if they wanted to know where we got the data from */ if(addr != NULL && len != NULL && *len >= sizeof(struct sockaddr_in)) { struct sockaddr_in* si = (struct sockaddr_in*) addr; si->sin_addr.s_addr = ip; si->sin_port = port; si->sin_family = AF_INET; *len = sizeof(struct sockaddr_in); } return (gssize) bytes; }
gint system_epollCtl(gint epollDescriptor, gint operation, gint fileDescriptor, struct epoll_event* event) { /* * initial checks before passing on to node: * EINVAL if fd is the same as epfd, or the requested operation op is not * supported by this interface */ if(epollDescriptor == fileDescriptor) { errno = EINVAL; return -1; } /* switch into shadow and do the operation */ Node* node = _system_switchInShadowContext(); gint result = node_epollControl(node, epollDescriptor, operation, fileDescriptor, event); _system_switchOutShadowContext(node); /* * When successful, epoll_ctl() returns zero. When an error occurs, * epoll_ctl() returns -1 and errno is set appropriately. */ if(result != 0) { errno = result; return -1; } else { return 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; } /* check inputs for what we support */ if(isBlocking) { warning("we only support non-blocking pipes: please bitwise OR 'O_NONBLOCK' with flags"); errno = EINVAL; return -1; } Node* node = _system_switchInShadowContext(); gint handle = node_createDescriptor(node, DT_PIPE); Channel* channel = (Channel*) node_lookupDescriptor(node, handle); gint linkedHandle = channel_getLinkedHandle(channel); _system_switchOutShadowContext(node); pipefds[0] = handle; /* reader */ pipefds[1] = linkedHandle; /* writer */ return 0; }
gssize system_sendTo(gint fd, const gpointer buf, gsize n, gint flags, const struct sockaddr* addr, socklen_t len) { /* TODO flags are ignored */ /* check if this is a socket */ if(fd < MIN_DESCRIPTOR){ errno = EBADF; return -1; } in_addr_t ip = 0; in_port_t port = 0; /* check if they specified an address to send to */ if(addr != NULL && len >= sizeof(struct sockaddr_in)) { struct sockaddr_in* si = (struct sockaddr_in*) addr; ip = si->sin_addr.s_addr; port = si->sin_port; } Node* node = _system_switchInShadowContext(); gsize bytes = 0; gint result = node_sendUserData(node, fd, buf, n, ip, port, &bytes); _system_switchOutShadowContext(node); if(result != 0) { errno = result; return -1; } return (gssize) bytes; }
gint system_getHostName(gchar *name, size_t len) { Node* node = _system_switchInShadowContext(); gint result = 0; // in_addr_t ip = node_getDefaultIP(node); // const gchar* hostname = internetwork_resolveID(worker_getPrivate()->cached_engine->internet, (GQuark)ip); if(name != NULL && node != NULL) { /* resolve my address to a hostname */ const gchar* sysname = node_getName(node); if(sysname != NULL && len > strlen(sysname)) { if(strncpy(name, sysname, len) != NULL) { result = 0; goto done; } } } errno = EFAULT; result = -1; done: _system_switchOutShadowContext(node); return result; }
gint system_shutdown(gint fd, gint how) { Host* node = _system_switchInShadowContext(); warning("shutdown not implemented"); _system_switchOutShadowContext(node); errno = ENOSYS; return -1; }
gpointer system_malloc(gsize size) { Node* node = _system_switchInShadowContext(); gpointer ptr = malloc(size); tracker_addAllocatedBytes(node_getTracker(node), ptr, size); _system_switchOutShadowContext(node); return ptr; }
gint system_accept(gint fd, struct sockaddr* addr, socklen_t* len) { /* check if this is a virtual socket */ if(fd < MIN_DESCRIPTOR){ warning("intercepted a non-virtual descriptor"); errno = EBADF; return -1; } in_addr_t ip = 0; in_port_t port = 0; gint handle = 0; /* direct to node for further checks */ Node* node = _system_switchInShadowContext(); gint result = node_acceptNewPeer(node, fd, &ip, &port, &handle); _system_switchOutShadowContext(node); /* check if there was an error */ if(result != 0) { errno = result; return -1; } if(addr != NULL && len != NULL && *len >= sizeof(struct sockaddr_in)) { struct sockaddr_in* ai = (struct sockaddr_in*) addr; ai->sin_addr.s_addr = ip; ai->sin_port = port; ai->sin_family = AF_INET; *len = sizeof(struct sockaddr_in); } return handle; }
gssize system_recvMsg(gint fd, struct msghdr* message, gint flags) { /* TODO implement */ Host* node = _system_switchInShadowContext(); warning("recvmsg not implemented"); _system_switchOutShadowContext(node); errno = ENOSYS; return -1; }
gssize system_sendMsg(gint fd, const struct msghdr* message, gint flags) { /* TODO implement */ Node* node = _system_switchInShadowContext(); warning("sendmsg not implemented"); _system_switchOutShadowContext(node); errno = ENOSYS; return -1; }
gint system_accept4(gint fd, struct sockaddr* addr, socklen_t* len, gint flags) { /* just ignore the flags and call accept */ if(flags) { Host* node = _system_switchInShadowContext(); debug("accept4 ignoring flags argument"); _system_switchOutShadowContext(node); } return system_accept(fd, addr, len); }
gint system_setSockOpt(gint fd, gint level, gint optname, const gpointer optval, socklen_t optlen) { Node* node = _system_switchInShadowContext(); /* @todo: implement socket options */ debug("setsockopt not implemented. this is probably OK, depending on usage."); errno = ENOSYS; _system_switchOutShadowContext(node); return -1; }
gint system_close(gint fd) { /* check if this is a socket */ if(fd < MIN_DESCRIPTOR){ errno = EBADF; return -1; } Node* node = _system_switchInShadowContext(); gint r = node_closeUser(node, fd); _system_switchOutShadowContext(node); return r; }
gint system_epollCreate(gint size) { /* size should be > 0, but can otherwise be completely ignored */ if(size < 1) { errno = EINVAL; return -1; } /* switch into shadow and create the new descriptor */ Node* node = _system_switchInShadowContext(); gint handle = node_createDescriptor(node, DT_EPOLL); _system_switchOutShadowContext(node); return handle; }
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; }
gint system_epollPWait(gint epollDescriptor, struct epoll_event* events, gint maxevents, gint timeout, const sigset_t* signalSet) { /* * this is the same as system_epollWait, except it catches signals in the * signal set. lets just assume we have no signals to worry about. * forward to our regular wait method. * * @warning we dont handle signals */ if(signalSet) { Host* node = _system_switchInShadowContext(); warning("epollpwait using a signalset is not yet supported"); _system_switchOutShadowContext(node); } return system_epollWait(epollDescriptor, events, maxevents, timeout); }
gint system_epollWait(gint epollDescriptor, struct epoll_event* eventArray, gint eventArrayLength, gint timeout) { /* * EINVAL if maxevents is less than or equal to zero. */ if(eventArrayLength <= 0) { errno = EINVAL; return -1; } /* switch to shadow context and try to get events if we have any */ Node* node = _system_switchInShadowContext(); /* * initial checks: we can't block, so timeout must be 0. anything else will * cause a warning. if they seriously want to block by passing in -1, then * return interrupt below only if we have no events. * * @note log while in shadow context to get node info in the log */ if(timeout != 0) { warning("Shadow does not block, so the '%i' millisecond timeout will be ignored", timeout); } gint nEvents = 0; gint result = node_epollGetEvents(node, epollDescriptor, eventArray, eventArrayLength, &nEvents); _system_switchOutShadowContext(node); /* check if there was an error */ if(result != 0) { errno = result; return -1; } /* * if we dont have any events and they are trying to block, tell them their * timeout was interrupted. */ if(timeout != 0 && nEvents <= 0) { errno = EINTR; return -1; } /* the event count. zero is fine since they weren't expecting a timer. */ return nEvents; }
gint system_randomBytes(guchar* buf, gint numBytes) { Node* node = _system_switchInShadowContext(); Random* random = node_getRandom(node); gint bytesWritten = 0; while(numBytes > bytesWritten) { gint r = random_nextInt(random); gint copyLength = MIN(numBytes-bytesWritten, 4); g_memmove(buf+bytesWritten, &r, copyLength); bytesWritten += copyLength; } _system_switchOutShadowContext(node); return 1; }
gint system_listen(gint fd, gint backlog) { /* check if this is a socket */ if(fd < MIN_DESCRIPTOR){ errno = EBADF; return -1; } Node* node = _system_switchInShadowContext(); gint result = node_listenForPeer(node, fd, backlog); _system_switchOutShadowContext(node); /* check if there was an error */ if(result != 0) { errno = result; return -1; } return 0; }
gint system_socket(gint domain, gint type, gint protocol) { /* we only support non-blocking sockets, and require * SOCK_NONBLOCK to be set immediately */ gboolean isBlocking = FALSE; /* clear non-blocking flags if set to get true type */ if(type & SOCK_NONBLOCK) { type = type & ~SOCK_NONBLOCK; isBlocking = FALSE; } if(type & SOCK_CLOEXEC) { type = type & ~SOCK_CLOEXEC; isBlocking = FALSE; } gint result = 0; Host* node = _system_switchInShadowContext(); /* check inputs for what we support */ if(isBlocking) { warning("we only support non-blocking sockets: please bitwise OR 'SOCK_NONBLOCK' with type flags"); errno = EPROTONOSUPPORT; result = -1; } else if (type != SOCK_STREAM && type != SOCK_DGRAM) { warning("unsupported socket type \"%i\", we only support SOCK_STREAM and SOCK_DGRAM", type); errno = EPROTONOSUPPORT; result = -1; } else if(domain != AF_INET) { warning("trying to create socket with domain \"%i\", we only support PF_INET", domain); errno = EAFNOSUPPORT; result = -1; } if(result == 0) { /* we are all set to create the socket */ DescriptorType dtype = type == SOCK_STREAM ? DT_TCPSOCKET : DT_UDPSOCKET; result = host_createDescriptor(node, dtype); } _system_switchOutShadowContext(node); return result; }
int system_getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags) { /* FIXME this is not fully implemented */ if(!sa) { return EAI_FAIL; } gint retval = 0; Node* node = _system_switchInShadowContext(); GQuark convertedIP = (GQuark) (((struct sockaddr_in*)sa)->sin_addr.s_addr); const gchar* hostname = internetwork_resolveID(worker_getInternet(), convertedIP); if(hostname) { g_utf8_strncpy(host, hostname, hostlen); } else { retval = EAI_NONAME; } _system_switchOutShadowContext(node); return retval; }
void system_free(gpointer ptr) { Node* node = _system_switchInShadowContext(); free(ptr); tracker_removeAllocatedBytes(node_getTracker(node), ptr); _system_switchOutShadowContext(node); }
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; }
gint system_getRandom() { Node* node = _system_switchInShadowContext(); gint r = random_nextInt(node_getRandom(node)); _system_switchOutShadowContext(node); return r; }
gint system_getAddrInfo(gchar *name, const gchar *service, const struct addrinfo *hgints, struct addrinfo **res) { Node* node = _system_switchInShadowContext(); gint result = 0; *res = NULL; if(name != NULL && node != NULL) { /* node may be a number-and-dots address, or a hostname. lets hope for hostname * and try that first, o/w convert to the in_addr_t and do a second lookup. */ in_addr_t address = (in_addr_t) internetwork_resolveName(worker_getInternet(), name); if(address == 0) { /* name was not in hostname format. convert to IP format and try again */ struct in_addr inaddr; gint r = inet_pton(AF_INET, name, &inaddr); if(r == 1) { /* successful conversion to IP format, now find the real hostname */ GQuark convertedIP = (GQuark) inaddr.s_addr; const gchar* hostname = internetwork_resolveID(worker_getInternet(), convertedIP); if(hostname != NULL) { /* got it, so convertedIP is a valid IP */ address = (in_addr_t) convertedIP; } else { /* name not mapped by resolver... */ result = EAI_FAIL; goto done; } } else if(r == 0) { /* not in correct form... hmmm, too bad i guess */ result = EAI_NONAME; goto done; } else { /* error occured */ result = EAI_SYSTEM; goto done; } } /* should have address now */ struct sockaddr_in* sa = g_malloc(sizeof(struct sockaddr_in)); /* application will expect it in network order */ // sa->sin_addr.s_addr = (in_addr_t) htonl((guint32)(*addr)); sa->sin_addr.s_addr = address; sa->sin_family = AF_INET; /* libcurl expects this to be set */ struct addrinfo* ai_out = g_malloc(sizeof(struct addrinfo)); ai_out->ai_addr = (struct sockaddr*) sa; ai_out->ai_addrlen = sizeof(struct sockaddr_in); ai_out->ai_canonname = NULL; ai_out->ai_family = AF_INET; ai_out->ai_flags = 0; ai_out->ai_next = NULL; ai_out->ai_protocol = 0; ai_out->ai_socktype = SOCK_STREAM; *res = ai_out; result = 0; goto done; } errno = EINVAL; result = EAI_SYSTEM; done: _system_switchOutShadowContext(node); return result; }
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; }
static gint _system_addressHelper(gint fd, const struct sockaddr* addr, socklen_t* len, enum SystemCallType type) { /* check if this is a virtual socket */ if(fd < MIN_DESCRIPTOR){ warning("intercepted a non-virtual descriptor"); errno = EBADF; return -1; } /* check for proper addr */ if(addr == NULL) { errno = EFAULT; return -1; } if(len == NULL || *len < sizeof(struct sockaddr_in)) { errno = EINVAL; return -1; } struct sockaddr_in* saddr = (struct sockaddr_in*) addr; in_addr_t ip = saddr->sin_addr.s_addr; in_port_t port = saddr->sin_port; sa_family_t family = saddr->sin_family; /* direct to node for further checks */ Node* node = _system_switchInShadowContext(); gint result = EINVAL; switch(type) { case SCT_BIND: { result = node_bindToInterface(node, fd, ip, port); break; } case SCT_CONNECT: { result = node_connectToPeer(node, fd, ip, port, family); break; } case SCT_GETPEERNAME: case SCT_GETSOCKNAME: { result = type == SCT_GETPEERNAME ? node_getPeerName(node, fd, &(saddr->sin_addr.s_addr), &(saddr->sin_port)) : node_getSocketName(node, fd, &(saddr->sin_addr.s_addr), &(saddr->sin_port)); if(result == 0) { saddr->sin_family = AF_INET; *len = sizeof(struct sockaddr_in); } break; } default: { error("unrecognized system call type"); break; } } _system_switchOutShadowContext(node); /* check if there was an error */ if(result != 0) { errno = result; return -1; } return 0; }