Example #1
0
/* Get native file descriptor. */
static MVMint64 mvm_fileno(MVMThreadContext *tc, MVMOSHandle *h) {
    MVMIOSyncPipeData *data = (MVMIOSyncPipeData *)h->body.data;
    uv_os_fd_t fd;
    if (uv_fileno((uv_handle_t *)data->ss.handle, &fd) >= 0)
        return (MVMint64)fd;
    return -1;
}
Example #2
0
static bool
connection_tls_handshake(Client *client)
{
    uv_os_fd_t fd;
    struct tls *context = NULL;
    int ret = TLS_READ_AGAIN;

    if(uv_fileno((uv_handle_t *)client->handle, &fd) != 0)
    {
        return false;
    }

    while((ret = tls_accept_socket(CurrentConnectionState.ServerContext,
                                  &context, fd)) != 0)
    {
        if(ret == -1)
        {
            return false;
        }
    }

    client->TlsContext = context;
    tls_get_cert_fingerprint(client->TlsContext, client->CertificateFp,
                             sizeof(client->CertificateFp));

    return true;
}
Example #3
0
void
connection_start_read(Client *client)
{
    if(client == NULL)
    {
        return;
    }

    if(client->TlsContext != NULL)
    {
        uv_os_fd_t fd;
        uv_poll_t *handle = Malloc(sizeof(uv_poll_t));

        handle->data = client;

        uv_fileno((uv_handle_t *)client->handle, &fd);

        uv_poll_init(serverstate_get_event_loop(), handle, fd);
        if(uv_poll_start(handle, UV_READABLE, connection_poll_callback) < 0)
        {
            client_free(client);
        }
    }
    else
    {
        if(uv_read_start((uv_stream_t *)client->handle,
                         connection_allocate_buffer_callback,
                         connection_on_read_callback) < 0)
        {
            client_free(client);
        }
    }
}
Example #4
0
int SocketAccept(uv_stream_t *const sstream, struct tls *const ssecure, SocketRef *const out) {
	SocketRef socket = calloc(1, sizeof(struct Socket));
	if(!socket) return UV_ENOMEM;
	int rc = uv_tcp_init(async_loop, socket->stream);
	if(rc < 0) goto cleanup;
	rc = uv_accept(sstream, (uv_stream_t *)socket->stream);
	if(rc < 0) goto cleanup;
	if(ssecure) {
		uv_os_fd_t fd;
		rc = uv_fileno((uv_handle_t *)socket->stream, &fd);
		if(rc < 0) goto cleanup;
		for(;;) {
			int event = tls_accept_socket(ssecure, &socket->secure, fd);
			if(0 == event) break;
			rc = tls_poll((uv_stream_t *)socket->stream, event);
			if(rc < 0) goto cleanup;
		}
	}
	socket->rdmem = NULL;
	*socket->rd = uv_buf_init(NULL, 0);
	*socket->wr = uv_buf_init(NULL, 0);
	*out = socket; socket = NULL;
cleanup:
	SocketFree(&socket);
	return rc;
}
Example #5
0
static int luv_fileno(lua_State* L) {
  uv_handle_t* handle = luv_check_handle(L, 1);
  uv_os_fd_t fd;
  int ret = uv_fileno(handle, &fd);
  if (ret < 0) return luv_error(L, ret);
  lua_pushinteger(L, (LUA_INTEGER)fd);
  return 1;
}
Example #6
0
static int set_tcp_option(uv_handle_t *handle, int option, int val)
{
	uv_os_fd_t fd = 0;
	if (uv_fileno(handle, &fd) == 0) {
		return setsockopt(fd, IPPROTO_TCP, option, &val, sizeof(val));
	}
	return 0; /* N/A */
}
Example #7
0
void WebSocket::onReadable(uv_poll_t *p, int status, int events)
{
    SocketData *socketData = (SocketData *) p->data;

    // this one is not needed, read will do this!
    if (status < 0) {
        WebSocket(p).close(true, 1006);
        return;
    }

    char *src = socketData->server->recvBuffer;
    memcpy(src, socketData->spill, socketData->spillLength);
    uv_os_fd_t fd;
    uv_fileno((uv_handle_t *) p, &fd);

    ssize_t received;
    if (socketData->ssl) {
        received = SSL_read(socketData->ssl, src + socketData->spillLength, Server::LARGE_BUFFER_SIZE - socketData->spillLength);
    } else {
        received = recv(fd, src + socketData->spillLength, Server::LARGE_BUFFER_SIZE - socketData->spillLength, 0);
    }

    if (received == -1 || received == 0) {
        // do we have a close frame in our buffer, and did we already set the state as CLOSING?
        if (socketData->state == CLOSING && socketData->controlBuffer.length()) {
            std::tuple<unsigned short, char *, size_t> closeFrame = Parser::parseCloseFrame(socketData->controlBuffer);
            if (!std::get<0>(closeFrame)) {
                std::get<0>(closeFrame) = 1006;
            }
            WebSocket(p).close(true, std::get<0>(closeFrame), std::get<1>(closeFrame), std::get<2>(closeFrame));
        } else {
            WebSocket(p).close(true, 1006);
        }
        return;
    }

    // do not parse any data once in closing state
    if (socketData->state == CLOSING) {
        return;
    }

    // cork sends into one large package
#ifdef __linux
    int cork = 1;
    setsockopt(fd, IPPROTO_TCP, TCP_CORK, &cork, sizeof(int));
#endif

    Parser::consume(socketData->spillLength + received, src, socketData, p);

#ifdef __linux
    cork = 0;
    setsockopt(fd, IPPROTO_TCP, TCP_CORK, &cork, sizeof(int));
#endif
}
Example #8
0
void Connection::on_connect(Connector* connector) {
  Connection* connection = static_cast<Connection*>(connector->data());

  if (!connection->connect_timer_.is_running()) {
    return; // Timed out
  }

  if (connector->status() == 0) {
    LOG_DEBUG("Connected to host %s on connection(%p)",
              connection->host_->address_string().c_str(),
              static_cast<void*>(connection));

#ifdef HAVE_NOSIGPIPE
    // This must be done after connection for the socket file descriptor to be
    // valid.
    uv_os_fd_t fd = 0;
    int enabled = 1;
    if (uv_fileno(copy_cast<uv_tcp_t*, uv_handle_t*>(&connection->socket_), &fd) != 0 ||
        setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&enabled, sizeof(int)) != 0) {
      LOG_WARN("Unable to set socket option SO_NOSIGPIPE for host %s",
               connection->host_->address_string().c_str());
    }
#endif

    if (connection->ssl_session_) {
      uv_read_start(copy_cast<uv_tcp_t*, uv_stream_t*>(&connection->socket_),
                    Connection::alloc_buffer_ssl, Connection::on_read_ssl);
    } else {
      uv_read_start(copy_cast<uv_tcp_t*, uv_stream_t*>(&connection->socket_),
                    Connection::alloc_buffer, Connection::on_read);
    }

    connection->set_state(CONNECTION_STATE_CONNECTED);

    if (connection->ssl_session_) {
      connection->ssl_handshake();
    } else {
      connection->on_connected();
    }
  } else {
    connection->notify_error("Connect error '" +
                             std::string(UV_ERRSTR(connector->status(), connection->loop_)) +
                             "'");
  }
}
Example #9
0
/*
 * TTY control
 */
static void tty_read(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf)
{
	/* Set output streams */
	FILE *out = stdout, *outerr = stderr;
	uv_os_fd_t stream_fd = 0;
	uv_fileno((uv_handle_t *)stream, &stream_fd);
	if (stream_fd != STDIN_FILENO) {
		if (nread <= 0) { /* Close if disconnected */
			uv_close((uv_handle_t *)stream, (uv_close_cb) free);
			return;
		}
		uv_os_fd_t dup_fd = dup(stream_fd);
		if (dup_fd >= 0) {
			out = outerr = fdopen(dup_fd, "w");
		}
	}
	/* Execute */
	if (stream && buf && nread > 0) {
		char *cmd = buf->base;
		if (cmd[nread - 1] == '\n') {
			cmd[nread - 1] = '\0';
		}
		struct engine *engine = stream->data;
		lua_State *L = engine->L;
		int ret = engine_cmd(engine, cmd);
		const char *message = "";
		if (lua_gettop(L) > 0) {
			message = lua_tostring(L, -1);
		}
		if (stream_fd != STDIN_FILENO) {
			fprintf(stdout, "%s\n", cmd); /* Duplicate command to logs */
			fprintf(out, "%s\n> ", message); /* Duplicate output to sender */
		}
		fprintf(ret ? stderr : stdout, "%s\n> ", message);
		lua_settop(L, 0);
		free(buf->base);
	}
	fflush(out);
	/* Close if redirected */
	if (stream_fd != STDIN_FILENO) {
		fclose(out); /* outerr is the same */
	}

}
Example #10
0
static PyObject *
Stream_func_fileno(Stream *self)
{
    int err;
    uv_os_fd_t fd;

    RAISE_IF_HANDLE_NOT_INITIALIZED(self, NULL);
    RAISE_IF_HANDLE_CLOSED(self, PyExc_HandleClosedError, NULL);

    err = uv_fileno(UV_HANDLE(self), &fd);
    if (err < 0) {
        RAISE_STREAM_EXCEPTION(err, UV_HANDLE(self));
        return NULL;
    }

    /* us_os_fd_t is a HANDLE on Windows which is a 64-bit data type but which
     * is guaranteed to contain only values < 2^24.
     * For more information, see: http://www.viva64.com/en/k/0005/ */
    return PyInt_FromLong((long) fd);
}
Example #11
0
WebSocket::Address WebSocket::getAddress()
{
    uv_os_fd_t fd;
    uv_fileno((uv_handle_t *) p, &fd);

    sockaddr_storage addr;
    socklen_t addrLength = sizeof(addr);
    getpeername(fd, (sockaddr *) &addr, &addrLength);

    static __thread char buf[INET6_ADDRSTRLEN];

    if (addr.ss_family == AF_INET) {
        sockaddr_in *ipv4 = (sockaddr_in *) &addr;
        inet_ntop(AF_INET, &ipv4->sin_addr, buf, sizeof(buf));
        return {ntohs(ipv4->sin_port), buf, "IPv4"};
    } else {
        sockaddr_in6 *ipv6 = (sockaddr_in6 *) &addr;
        inet_ntop(AF_INET6, &ipv6->sin6_addr, buf, sizeof(buf));
        return {ntohs(ipv6->sin6_port), buf, "IPv6"};
    }
}
Example #12
0
int uv__getsockpeername(const uv_handle_t* handle,
                        uv__peersockfunc func,
                        struct sockaddr* name,
                        int* namelen,
                        int delayed_error) {

  int result;
  uv_os_fd_t fd;

  result = uv_fileno(handle, &fd);
  if (result != 0)
    return result;

  if (delayed_error)
    return uv_translate_sys_error(delayed_error);

  result = func((SOCKET) fd, name, namelen);
  if (result != 0)
    return uv_translate_sys_error(WSAGetLastError());

  return 0;
}
Example #13
0
File: process.c Project: kidaa/luv
static int luv_spawn(lua_State* L) {
  uv_process_t* handle;
  uv_process_options_t options;
  size_t i, len = 0;
  int ret;

  memset(&options, 0, sizeof(options));
  options.exit_cb = exit_cb;
  options.file = luaL_checkstring(L, 1);
  options.flags = 0;

  // Make sure the 2nd argument is a table
  luaL_checktype(L, 2, LUA_TTABLE);

  // get the args list
  lua_getfield(L, 2, "args");
  // +1 for inserted command at front
  if (lua_type(L, -1) == LUA_TTABLE) {
    len = 1 + lua_rawlen(L, -1);
  }
  else if (lua_type(L, -1) != LUA_TNIL) {
    luv_clean_options(&options);
    return luaL_argerror(L, 3, "args option must be table");
  }
  else {
    len = 1;
  }
  // +1 for null terminator at end
  options.args = malloc((len + 1) * sizeof(*options.args));
  if (!options.args) {
    luv_clean_options(&options);
    return luaL_error(L, "Problem allocating args");
  }
  options.args[0] = (char*)options.file;
  for (i = 1; i < len; ++i) {
    lua_rawgeti(L, -1, i);
    options.args[i] = (char*)lua_tostring(L, -1);
    lua_pop(L, 1);
  }
  options.args[len] = NULL;
  lua_pop(L, 1);

  // get the stdio list
  lua_getfield(L, 2, "stdio");
  if (lua_type(L, -1) == LUA_TTABLE) {
    options.stdio_count = len = lua_rawlen(L, -1);
    options.stdio = malloc(len * sizeof(*options.stdio));
    if (!options.stdio) {
      luv_clean_options(&options);
      return luaL_error(L, "Problem allocating stdio");
    }
    for (i = 0; i < len; ++i) {
      lua_rawgeti(L, -1, i + 1);
      // integers are assumed to be file descripters
      if (lua_type(L, -1) == LUA_TNUMBER) {
        options.stdio[i].flags = UV_INHERIT_FD;
        options.stdio[i].data.fd = lua_tointeger(L, -1);
      }
      // userdata is assumed to be a uv_stream_t instance
      else if (lua_type(L, -1) == LUA_TUSERDATA) {
        uv_os_fd_t fd;
        uv_stream_t* stream = luv_check_stream(L, -1);
        int err = uv_fileno((uv_handle_t*)stream, &fd);
        if (err == UV_EINVAL || err == UV_EBADF) {
          options.stdio[i].flags = UV_CREATE_PIPE | UV_READABLE_PIPE | UV_WRITABLE_PIPE;
        }
        else {
          options.stdio[i].flags = UV_INHERIT_STREAM;
        }
        options.stdio[i].data.stream = stream;
      }
      else if (lua_type(L, -1) == LUA_TNIL) {
        options.stdio[i].flags = UV_IGNORE;
      }
      else {
        luv_clean_options(&options);
        return luaL_argerror(L, 2, "stdio table entries must be nil, uv_stream_t, or integer");
      }
      lua_pop(L, 1);
    }
  }
  else if (lua_type(L, -1) != LUA_TNIL) {
    luv_clean_options(&options);
    return luaL_argerror(L, 2, "stdio option must be table");
  }
  lua_pop(L, 1);

  // Get the env
  lua_getfield(L, 2, "env");
  if (lua_type(L, -1) == LUA_TTABLE) {
    len = lua_rawlen(L, -1);
    options.env = malloc((len + 1) * sizeof(*options.env));
    if (!options.env) {
      luv_clean_options(&options);
      return luaL_error(L, "Problem allocating env");
    }
    for (i = 0; i < len; ++i) {
      lua_rawgeti(L, -1, i + 1);
      options.env[i] = (char*)lua_tostring(L, -1);
      lua_pop(L, 1);
    }
    options.env[len] = NULL;
  }
  else if (lua_type(L, -1) != LUA_TNIL) {
    luv_clean_options(&options);
    return luaL_argerror(L, 2, "env option must be table");
  }
  lua_pop(L, 1);

  // Get the cwd
  lua_getfield(L, 2, "cwd");
  if (lua_type(L, -1) == LUA_TSTRING) {
    options.cwd = (char*)lua_tostring(L, -1);
  }
  else if (lua_type(L, -1) != LUA_TNIL) {
    luv_clean_options(&options);
    return luaL_argerror(L, 2, "cwd option must be string");
  }
  lua_pop(L, 1);

  // Check for uid
  lua_getfield(L, 2, "uid");
  if (lua_type(L, -1) == LUA_TNUMBER) {
    options.uid = lua_tointeger(L, -1);
    options.flags |= UV_PROCESS_SETUID;
  }
  else if (lua_type(L, -1) != LUA_TNIL) {
    luv_clean_options(&options);
    return luaL_argerror(L, 2, "uid option must be number");
  }
  lua_pop(L, 1);

  // Check for gid
  lua_getfield(L, 2, "gid");
  if (lua_type(L, -1) == LUA_TNUMBER) {
    options.gid = lua_tointeger(L, -1);
    options.flags |= UV_PROCESS_SETGID;
  }
  else if (lua_type(L, -1) != LUA_TNIL) {
    luv_clean_options(&options);
    return luaL_argerror(L, 2, "gid option must be number");
  }
  lua_pop(L, 1);

  // Check for the boolean flags
  lua_getfield(L, 2, "verbatim");
  if (lua_toboolean(L, -1)) {
    options.flags |= UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS;
  }
  lua_pop(L, 1);
  lua_getfield(L, 2, "detached");
  if (lua_toboolean(L, -1)) {
    options.flags |= UV_PROCESS_DETACHED;
  }
  lua_pop(L, 1);
  lua_getfield(L, 2, "hide");
  if (lua_toboolean(L, -1)) {
    options.flags |= UV_PROCESS_WINDOWS_HIDE;
  }
  lua_pop(L, 1);

  handle = lua_newuserdata(L, sizeof(*handle));
  handle->type = UV_PROCESS;
  handle->data = luv_setup_handle(L);

  if (!lua_isnoneornil(L, 3)) {
    luv_check_callback(L, handle->data, LUV_EXIT, 3);
  }

  ret = uv_spawn(luv_loop(L), handle, &options);

  luv_clean_options(&options);
  if (ret < 0) {
    /* The async callback is required here because luajit GC may reclaim the
     * luv handle before libuv is done closing it down.
     */
    uv_close((uv_handle_t*)handle, luv_spawn_close_cb);
    return luv_error(L, ret);
  }
  lua_pushinteger(L, handle->pid);
  return 2;
}
Example #14
0
void WebSocket::close(bool force, unsigned short code, char *data, size_t length)
{
    uv_os_fd_t fd;
    uv_fileno((uv_handle_t *) p, &fd);
    SocketData *socketData = (SocketData *) p->data;

    if (socketData->state != CLOSING) {
        socketData->state = CLOSING;
        if (socketData->prev == socketData->next) {
            socketData->server->clients = nullptr;
        } else {
            if (socketData->prev) {
                ((SocketData *) socketData->prev->data)->next = socketData->next;
            } else {
                socketData->server->clients = socketData->next;
            }
            if (socketData->next) {
                ((SocketData *) socketData->next->data)->prev = socketData->prev;
            }
        }

        // reuse prev as timer, mark no timer set
        socketData->prev = nullptr;

        // call disconnection callback on first close (graceful or force)
        socketData->server->disconnectionCallback(p, code, data, length);
    } else if (!force) {
        std::cerr << "WARNING: Already gracefully closed: " << p << std::endl;
        return;
    }

    if (force) {
        // delete all messages in queue
        while (!socketData->messageQueue.empty()) {
            SocketData::Queue::Message *message = socketData->messageQueue.front();
            if (message->callback) {
                message->callback(nullptr, message->callbackData, true);
            }
            socketData->messageQueue.pop();
        }

        uv_poll_stop(p);
        uv_close((uv_handle_t *) p, [](uv_handle_t *handle) {
            delete (uv_poll_t *) handle;
        });

        ::close(fd);
        SSL_free(socketData->ssl);
        socketData->controlBuffer.clear();

        // cancel force close timer
        if (socketData->prev) {
            uv_timer_stop((uv_timer_t *) socketData->prev);
            uv_close((uv_handle_t *) socketData->prev, [](uv_handle_t *handle) {
                delete (uv_timer_t *) handle;
            });
        }

        delete socketData->pmd;
        delete socketData;
    } else {
        // force close after 15 seconds
        socketData->prev = (uv_poll_t *) new uv_timer_t;
        uv_timer_init(socketData->server->loop, (uv_timer_t *) socketData->prev);
        ((uv_timer_t *) socketData->prev)->data = p;
        uv_timer_start((uv_timer_t *) socketData->prev, [](uv_timer_t *timer) {
            WebSocket((uv_poll_t *) timer->data).close(true, 1006);
        }, 15000, 0);

        char *sendBuffer = socketData->server->sendBuffer;
        if (code) {
            length = std::min<size_t>(1024, length) + 2;
            *((uint16_t *) &sendBuffer[length + 2]) = htons(code);
            memcpy(&sendBuffer[length + 4], data, length - 2);
        }
        write(sendBuffer, formatMessage(sendBuffer, &sendBuffer[length + 2], length, CLOSE, length), false, [](WebSocket webSocket, void *data, bool cancelled) {
            uv_os_fd_t fd;
            uv_fileno((uv_handle_t *) webSocket.p, &fd);
            SocketData *socketData = (SocketData *) webSocket.p->data;
            if (socketData->ssl) {
                SSL_shutdown(socketData->ssl);
            }
            shutdown(fd, SHUT_WR);
        });
    }
}
Example #15
0
// async Unix send (has a Message struct in the start if transferOwnership)
void WebSocket::write(char *data, size_t length, bool transferOwnership, void(*callback)(WebSocket webSocket, void *data, bool cancelled), void *callbackData)
{
    uv_os_fd_t fd;
    uv_fileno((uv_handle_t *) p, &fd);

    ssize_t sent = 0;
    SocketData *socketData = (SocketData *) p->data;
    if (!socketData->messageQueue.empty()) {
        goto queueIt;
    }

    if (socketData->ssl) {
        sent = SSL_write(socketData->ssl, data, length);
    } else {
        sent = ::send(fd, data, length, MSG_NOSIGNAL);
    }

    if (sent == (int) length) {
        // everything was sent in one go!
        if (transferOwnership) {
            delete [] (data - sizeof(SocketData::Queue::Message));
        }

        if (callback) {
            callback(p, callbackData, false);
        }

    } else {
        // not everything was sent
        if (sent == -1) {
            // check to see if any error occurred
            if (socketData->ssl) {
                int error = SSL_get_error(socketData->ssl, sent);
                if (error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_WRITE) {
                    goto queueIt;
                }
            } else {
#ifdef _WIN32
                if (WSAGetLastError() == WSAENOBUFS || WSAGetLastError() == WSAEWOULDBLOCK) {
#else
                if (errno == EAGAIN || errno == EWOULDBLOCK) {
#endif
                    goto queueIt;
                }
            }

            // error sending!
            if (transferOwnership) {
                delete [] (data - sizeof(SocketData::Queue::Message));
            }
            return;
        } else {

            queueIt:
            sent = std::max<ssize_t>(sent, 0);

            // queue the rest of the message!
            SocketData::Queue::Message *messagePtr;
            if (transferOwnership) {
                messagePtr = (SocketData::Queue::Message *) (data - sizeof(SocketData::Queue::Message));
                messagePtr->data = data + sent;
                messagePtr->length = length - sent;
                messagePtr->nextMessage = nullptr;
            } else {
                // we need to copy the buffer
                messagePtr = (SocketData::Queue::Message *) new char[sizeof(SocketData::Queue::Message) + length - sent];
                messagePtr->length = length - sent;
                messagePtr->data = ((char *) messagePtr) + sizeof(SocketData::Queue::Message);
                messagePtr->nextMessage = nullptr;
                memcpy(messagePtr->data, data + sent, messagePtr->length);
            }

            messagePtr->callback = callback;
            messagePtr->callbackData = callbackData;
            ((SocketData *) p->data)->messageQueue.push(messagePtr);

            // only start this if we just broke the 0 queue size!
            uv_poll_start(p, UV_WRITABLE | UV_READABLE, [](uv_poll_t *handle, int status, int events) {

                // handle all poll errors with forced disconnection
                if (status < 0) {
                    WebSocket(handle).close(true, 1006);
                    return;
                }

                // handle reads if available
                if (events & UV_READABLE) {
                    onReadable(handle, status, events);
                    if (!(events & UV_WRITABLE)) {
                        return;
                    }
                }

                SocketData *socketData = (SocketData *) handle->data;

                if (socketData->state == CLOSING) {
                    if (uv_is_closing((uv_handle_t *) handle)) {
                        return;
                    } else {
                        uv_poll_start(handle, UV_READABLE, onReadable);
                    }
                }

                uv_os_fd_t fd;
                uv_fileno((uv_handle_t *) handle, &fd);

                do {
                    SocketData::Queue::Message *messagePtr = socketData->messageQueue.front();

                    ssize_t sent;
                    if (socketData->ssl) {
                        sent = SSL_write(socketData->ssl, messagePtr->data, messagePtr->length);
                    } else {
                        sent = ::send(fd, messagePtr->data, messagePtr->length, MSG_NOSIGNAL);
                    }

                    if (sent == (int) messagePtr->length) {

                        if (messagePtr->callback) {
                            messagePtr->callback(handle, messagePtr->callbackData, false);
                        }

                        socketData->messageQueue.pop();
                    } else {
                        if (sent == -1) {
                            // check to see if any error occurred
                            if (socketData->ssl) {
                                int error = SSL_get_error(socketData->ssl, sent);
                                if (error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_WRITE) {
                                    return;
                                }
                            } else {
                #ifdef _WIN32
                                if (WSAGetLastError() == WSAENOBUFS || WSAGetLastError() == WSAEWOULDBLOCK) {
                #else
                                if (errno == EAGAIN || errno == EWOULDBLOCK) {
                #endif
                                    return;
                                }
                            }

                            // error sending!
                            uv_poll_start(handle, UV_READABLE, onReadable);
                            return;
                        } else {
                            // update the Message
                            messagePtr->data += sent;
                            messagePtr->length -= sent;
                            return;
                        }
                    }
                } while (!socketData->messageQueue.empty());

                // only receive when we have fully sent everything
                uv_poll_start(handle, UV_READABLE, onReadable);
            });
        }
    }
Example #16
0
void uv_custom_poll_cb(uv_poll_t *req, int status, int events) {
	/*
	 * Make sure we execute in the main thread
	 */
	const uv_thread_t pth_cur_id = uv_thread_self();
	assert(uv_thread_equal(&pth_main_id, &pth_cur_id));	

	struct uv_custom_poll_t *custom_poll_data = NULL;
	struct iobuf_t *send_io = NULL;
	char buffer[BUFFER_SIZE];
	uv_os_fd_t fd = 0;
	long int fromlen = 0;
	int r = 0, n = 0;

	custom_poll_data = req->data;
	if(custom_poll_data == NULL) {
		uv_poll_stop(req);
		return;
	}

	/*
	 * Status == -9: Socket is unreachable
	 * Events == 0: Client-end got disconnected
	 */
	r = uv_fileno((uv_handle_t *)req, &fd);
	if(status < 0 || events == 0) {
		if(status == -9) {
			logprintf(LOG_ERR, "uv_custom_poll_cb: socket not responding");
		} else {
			logprintf(LOG_ERR, "uv_custom_poll_cb: %s", uv_strerror(status));
		}
		if(custom_poll_data->close_cb != NULL) {
			custom_poll_data->close_cb(req);
		}
		if(!uv_is_closing((uv_handle_t *)req)) {
			uv_poll_stop(req);
		}
		if(fd > 0) {
			close(fd);
		}
		return;
	}

	custom_poll_data->started = 1;

	send_io = &custom_poll_data->send_iobuf;

	memset(&buffer, 0, BUFFER_SIZE);

	if(uv_is_closing((uv_handle_t *)req)) {
		return;
	}

	r = uv_fileno((uv_handle_t *)req, &fd);
	if(r != 0) {
		logprintf(LOG_ERR, "uv_fileno: %s", uv_strerror(r));
		return;
	}

	if(custom_poll_data->is_ssl == 1 && custom_poll_data->ssl.init == 0) {
		custom_poll_data->ssl.init = 1;
		struct mbedtls_ssl_config *ssl_conf = &ssl_client_conf;
		if(custom_poll_data->is_server == 1) {
			custom_poll_data->ssl.handshake = 1;
			ssl_conf = &ssl_server_conf;
		}
		if((r = mbedtls_ssl_setup(&custom_poll_data->ssl.ctx, ssl_conf)) < 0) {
			mbedtls_strerror(r, (char *)&buffer, BUFFER_SIZE);
			logprintf(LOG_ERR, "mbedtls_ssl_setup: %s", buffer);
			FREE(req);
			return;
		}

		if((r = mbedtls_ssl_session_reset(&custom_poll_data->ssl.ctx)) < 0) {
			mbedtls_strerror(r, (char *)&buffer, BUFFER_SIZE);
			logprintf(LOG_ERR, "mbedtls_ssl_session_reset: %s", buffer);
			FREE(req);
			return;
		}
		// mbedtls_debug_set_threshold(2);
		mbedtls_ssl_set_bio(&custom_poll_data->ssl.ctx, &fd, mbedtls_net_send, mbedtls_net_recv, NULL);
		mbedtls_ssl_conf_dbg(ssl_conf, my_debug, stdout);
		if(custom_poll_data->host != NULL) {
			mbedtls_ssl_set_hostname(&custom_poll_data->ssl.ctx, custom_poll_data->host);
		}
	}

	if(custom_poll_data->is_ssl == 1 && custom_poll_data->ssl.handshake == 0) {
		n = mbedtls_ssl_handshake(&custom_poll_data->ssl.ctx);
		if(n == MBEDTLS_ERR_SSL_WANT_READ) {
			custom_poll_data->doread = 1;
			custom_poll_data->dowrite = 0;
			goto end;
		} else if(n == MBEDTLS_ERR_SSL_WANT_WRITE) {
			/*LCOV_EXCL_START*/
			custom_poll_data->dowrite = 1;
			custom_poll_data->doread = 0;
			goto end;
			/*LCOV_EXCL_STOP*/
		}
		if(n == MBEDTLS_ERR_SSL_WANT_READ || n == MBEDTLS_ERR_SSL_WANT_WRITE) {
		} else if(n < 0) {
			/*LCOV_EXCL_START*/
			mbedtls_strerror(n, (char *)&buffer, BUFFER_SIZE);
			logprintf(LOG_NOTICE, "mbedtls_ssl_handshake: %s", buffer);
			uv_poll_stop(req);
			return;
			/*LCOV_EXCL_STOP*/
		} else {
			custom_poll_data->ssl.handshake = 1;
		}
		custom_poll_data->dowrite = 1;
		goto end;
	}

	if(events & UV_WRITABLE) {
		if(send_io->len > 0) {
			if(custom_poll_data->is_ssl == 1) {
				n = mbedtls_ssl_write(&custom_poll_data->ssl.ctx, (unsigned char *)send_io->buf, send_io->len);
					if(n == MBEDTLS_ERR_SSL_WANT_READ) {
						/*LCOV_EXCL_START*/
						custom_poll_data->doread = 1;
						custom_poll_data->dowrite = 0;
						goto end;
						/*LCOV_EXCL_STOP*/
					} else if(n == MBEDTLS_ERR_SSL_WANT_WRITE) {
						/*LCOV_EXCL_START*/
						custom_poll_data->dowrite = 1;
						custom_poll_data->doread = 0;
						goto end;
						/*LCOV_EXCL_STOP*/
					}
				if(n == MBEDTLS_ERR_SSL_WANT_READ || n == MBEDTLS_ERR_SSL_WANT_WRITE) {
				} else if(n < 0) {
					/*LCOV_EXCL_START*/
					mbedtls_strerror(n, (char *)&buffer, BUFFER_SIZE);
					logprintf(LOG_NOTICE, "mbedtls_ssl_handshake: %s", buffer);
					uv_poll_stop(req);
					return;
					/*LCOV_EXCL_STOP*/
				}
			} else {
				n = (int)send((unsigned int)fd, send_io->buf, send_io->len, 0);
			}
			if(n > 0) {
				iobuf_remove(send_io, n);
				if(send_io->len > 0) {
					custom_poll_data->dowrite = 1;
				} else {
					custom_poll_data->dowrite = 0;
					if(custom_poll_data->doclose == 1 && send_io->len == 0) {
						custom_poll_data->doread = 0;
						goto end;
					} else {
						custom_poll_data->dowrite = 0;
						if(custom_poll_data->write_cb != NULL) {
							custom_poll_data->write_cb(req);
						}
					}
				}
			} else if(n == 0) {
			} else if(custom_poll_data->is_ssl == 0 && n < 0 && errno != EAGAIN && errno != EINTR) {
				if(errno == ECONNRESET) {
					uv_poll_stop(req);
					return;
				} else {
					uv_poll_stop(req);
					return;
				}
			}
		} else {
			custom_poll_data->dowrite = 0;
			if(custom_poll_data->doclose == 1 && send_io->len == 0) {
				custom_poll_data->doread = 0;
				goto end;
			} else {
				custom_poll_data->dowrite = 0;
				if(custom_poll_data->write_cb != NULL) {
					custom_poll_data->write_cb(req);
				}
			}
		}
	}

	if(send_io->len > 0) {
		custom_poll_data->dowrite = 1;
	}

	if(events & UV_READABLE) {
		if(custom_poll_data->is_ssl == 1) {
			n = mbedtls_ssl_read(&custom_poll_data->ssl.ctx, (unsigned char *)buffer, BUFFER_SIZE);
			if(n == MBEDTLS_ERR_SSL_WANT_READ) {
				custom_poll_data->doread = 1;
				custom_poll_data->dowrite = 0;
				goto end;
			} else if(n == MBEDTLS_ERR_SSL_WANT_WRITE) {
				/*LCOV_EXCL_START*/
				custom_poll_data->dowrite = 1;
				custom_poll_data->doread = 0;
				goto end;
				/*LCOV_EXCL_STOP*/
			} else if(n == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
				custom_poll_data->doread = 0;
				if(custom_poll_data->read_cb != NULL) {
					custom_poll_data->read_cb(req, &custom_poll_data->recv_iobuf.len, custom_poll_data->recv_iobuf.buf);
				}
			}
			if(n == MBEDTLS_ERR_SSL_WANT_READ || n == MBEDTLS_ERR_SSL_WANT_WRITE) {
			} else if(n < 0) {
				if(n == MBEDTLS_ERR_NET_RECV_FAILED) {
					/*
					 * FIXME: New client not yet accepted
					 */
					if(custom_poll_data->read_cb != NULL) {
						one = 1;
						custom_poll_data->read_cb(req, &one, NULL);
					}
				} else if(n != MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
					mbedtls_strerror(n, (char *)&buffer, BUFFER_SIZE);
					logprintf(LOG_NOTICE, "mbedtls_ssl_handshake: %s", buffer);
					uv_poll_stop(req);
				}
				return;
			}
		} else {
			if(custom_poll_data->custom_recv == 0) {
				if(custom_poll_data->is_udp == 1) {
					n = (int)recv((unsigned int)fd, buffer, BUFFER_SIZE, 0);
				} else {
#ifdef _WIN32
					n = recvfrom((SOCKET)fd, buffer, BUFFER_SIZE, 0, NULL, (socklen_t *)&fromlen);
#else
					n = recvfrom(fd, buffer, BUFFER_SIZE, 0, NULL, (socklen_t *)&fromlen);
#endif
				}
			}
		}

		if(custom_poll_data->custom_recv == 0) {
			if(n > 0) {
				iobuf_append(&custom_poll_data->recv_iobuf, buffer, n);
				custom_poll_data->doread = 0;
				if(custom_poll_data->read_cb != NULL) {
					custom_poll_data->read_cb(req, &custom_poll_data->recv_iobuf.len, custom_poll_data->recv_iobuf.buf);
				}
			} else if(n < 0 && errno != EINTR) {
#ifdef _WIN32
				switch(WSAGetLastError()) {
					case WSAENOTCONN:
						if(custom_poll_data->read_cb != NULL) {
							one = 1;
							custom_poll_data->read_cb(req, &one, NULL);
						}
					break;
					case WSAEWOULDBLOCK:
#else
				switch(errno) {
					case ENOTCONN:
						if(custom_poll_data->read_cb != NULL) {
							one = 1;
							custom_poll_data->read_cb(req, &one, NULL);
						}
					break;
#if defined EAGAIN
					case EAGAIN:
#endif
#if defined EWOULDBLOCK && EWOULDBLOCK != EAGAIN
					case EWOULDBLOCK:
#endif
#endif
						custom_poll_data->doread = 1;
					break;
					default:
					break;
				}
			/*
			 * Client was disconnected
			 */
			} else if(n == 0) {
				custom_poll_data->doclose = 1;
				custom_poll_data->doread = 0;
				goto end;
			}
		} else {
			custom_poll_data->doread = 0;
			if(custom_poll_data->read_cb != NULL) {
				zero = 0;
				custom_poll_data->read_cb(req, &zero, NULL);
			}
		}
	}
Example #17
0
void dfk_http(dfk_coro_t* coro, dfk_tcp_socket_t* sock, dfk_http_t* http)
{
  DFK_UNUSED(coro);
  assert(sock);
  assert(http);
  dfk_t* dfk = coro->dfk;

  {
    uv_os_fd_t fd;
    uv_fileno((uv_handle_t*) &sock->_socket, &fd);
    struct linger l = {
      .l_onoff = 1,
      .l_linger = 10
    };
    setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l));
  }

  /* Arena for per-connection data */
  dfk_arena_t connection_arena;
  dfk_arena_init(&connection_arena, http->dfk);
  DFK_DBG(dfk, "{%p} initialize connection arena %p",
      (void*) sock, (void*) &connection_arena);

  /* Requests processed within this connection */
  ssize_t nrequests = 0;
  int keepalive = 1;

  while (keepalive) {
    /* Arena for per-request data */
    dfk_arena_t request_arena;
    dfk_arena_init(&request_arena, http->dfk);
    DFK_DBG(dfk, "{%p} initialize request arena %p",
        (void*) sock, (void*) &request_arena);

    dfk_http_request_t req;
    /** @todo check return value */
    dfk_http_request_init(&req, http, &request_arena, &connection_arena, sock);

    int err = dfk_http_request_read_headers(&req);
    if (err != dfk_err_ok) {
      DFK_ERROR(dfk, "{%p} dfk_http_request_read_headers failed with %s",
          (void*) http, dfk_strerr(dfk, err));
      keepalive = 0;
      goto cleanup;
    }

    DFK_DBG(http->dfk, "{%p} request parsing done, "
        "%s %.*s HTTP/%hu.%hu \"%.*s\"",
        (void*) http,
        http_method_str((enum http_method) req.method),
        (int) req.url.size, req.url.data,
        req.major_version,
        req.minor_version,
        (int) req.user_agent.size, req.user_agent.data);

    /* Determine requested connection type */
    dfk_buf_t connection = dfk_strmap_get(&req.headers,
        DFK_HTTP_CONNECTION, sizeof(DFK_HTTP_CONNECTION) - 1);
    if (connection.size) {
      if (!strncmp(connection.data, "close", DFK_MIN(connection.size, 5))) {
        keepalive = 0;
      }
      if (!strncmp(connection.data, "Keep-Alive", DFK_MIN(connection.size, 10))) {
        keepalive = 1;
      }
    } else {
      keepalive = !(req.major_version == 1 && req.minor_version == 0);
    }
    DFK_DBG(http->dfk, "{%p} client requested %skeepalive connection",
        (void*) http, keepalive ? "" : "not ");

    dfk_http_response_t resp;
    /** @todo check return value */
    dfk_http_response_init(&resp, &req, &request_arena, &connection_arena, sock, keepalive);

    DFK_DBG(http->dfk, "{%p} run request handler", (void*) http);
    int hres = http->_handler(http->_handler_ud, http, &req, &resp);
    DFK_INFO(http->dfk, "{%p} http handler returned %s",
        (void*) http, dfk_strerr(http->dfk, hres));
    if (hres != dfk_err_ok) {
      resp.status = DFK_HTTP_INTERNAL_SERVER_ERROR;
    }

    /* Fix request handler possible protocol violations */
    if (req.major_version < resp.major_version) {
      DFK_WARNING(http->dfk,
          "{%p} request handler attempted HTTP version upgrade from %d.%d to %d.%d",
          (void*) http, req.major_version, req.minor_version,
          resp.major_version, resp.minor_version);
      resp.major_version = req.major_version;
      resp.minor_version = req.minor_version;
    } else if (req.minor_version < resp.minor_version) {
      DFK_WARNING(http->dfk,
          "{%p} request handler attempted HTTP version upgrade from %d.%d to %d.%d",
          (void*) http, req.major_version, req.minor_version,
          resp.major_version, resp.minor_version);
      resp.minor_version = req.minor_version;
    }

    if (!keepalive && resp.keepalive) {
      DFK_WARNING(http->dfk, "{%p} request handler enabled keepalive, although "
          "client have not requested", (void*) http);
    }

    /*
     * Keep connection alive only if it was requested by the client and request
     * handler did not refuse.
     */
    keepalive = keepalive && resp.keepalive;

    if (keepalive
        && http->keepalive_requests >= 0
        && nrequests + 1 >= http->keepalive_requests) {
      DFK_INFO(http->dfk, "{%p} maximum number of keepalive requests (%llu) "
          "for connection {%p} has reached, close connection",
          (void*) http, (unsigned long long) http->keepalive_requests,
          (void*) sock);
      keepalive = 0;
    }

#if DFK_DEBUG
    {
      dfk_buf_t connection = dfk_strmap_get(&req.headers,
          DFK_HTTP_CONNECTION, sizeof(DFK_HTTP_CONNECTION) - 1);
      if (connection.size) {
        DFK_WARNING(http->dfk, "{%p} manually set header \""
            DFK_HTTP_CONNECTION " : %.*s\" will be overwritten"
            " use dfk_http_response_t.keepalive instead",
            (void*) http, (int) connection.size, connection.data);
      }
    }
#endif

    if (!keepalive) {
      dfk_http_response_set(&resp,
          DFK_HTTP_CONNECTION, sizeof(DFK_HTTP_CONNECTION) - 1, "close", 5);
    } else {
      dfk_http_response_set(&resp,
          DFK_HTTP_CONNECTION, sizeof(DFK_HTTP_CONNECTION) - 1, "Keep-Alive", 10);
    }

    /** @todo remove kludge */
    dfk_http_response_set(&resp, "Content-Length", 14, "0", 1);

    dfk_http_response_flush_headers(&resp);

    /*
     * If request handler hasn't read all bytes of the body, we have to
     * skip them at this point.
     */
    if (req.content_length > 0 && req._body_nread < req.content_length) {
      size_t bytesremain = req.content_length - req._body_nread;
      DFK_DBG(dfk, "{%p} bytes read by handler %llu, need to flush %llu",
          (void*) http, (unsigned long long ) req._body_nread,
          (unsigned long long) bytesremain);
      char buf[1024];
      while (bytesremain) {
        ssize_t nread = dfk_http_request_read(&req, buf,
            DFK_MIN(bytesremain, sizeof(buf)));
        if (nread < 0) {
          DFK_ERROR(dfk, "{%p} failed to flush request body", (void*) http);
          keepalive = 0;
          goto cleanup;
        }
        bytesremain -= nread;
      }
    }

    ++nrequests;

cleanup:
    DFK_DBG(dfk, "{%p} cleaup per-request resources", (void*) http);
    /** @todo check for return value */
    dfk_http_response_free(&resp);
    dfk_http_request_free(&req);
    dfk_arena_free(&request_arena);
  }

  dfk_arena_free(&connection_arena);

  DFK_DBG(dfk, "{%p} wait for client to close connection", (void*) http);
  DFK_CALL_RVOID(dfk, dfk_tcp_socket_shutdown(sock));
  int err = dfk_tcp_socket_wait_disconnect(sock, 1000);
  if (err == dfk_err_timeout) {
    DFK_WARNING(dfk, "{%p} client has not closed connection, force close", (void*) http);
  }
  if (err != dfk_err_ok) {
    DFK_ERROR(dfk, "{%p} dfk_tcp_socket_wait_disconnect returned %s",
        (void*) http, dfk_strerr(dfk, err));
  }
  DFK_DBG(http->dfk, "{%p} close socket", (void*) http);
  DFK_CALL_RVOID(http->dfk, dfk_tcp_socket_close(sock));
}