Variant socket_server_impl( const HostURL &hosturl, int flags, /* = STREAM_SERVER_BIND|STREAM_SERVER_LISTEN */ VRefParam errnum /* = null */, VRefParam errstr /* = null */ ) { errnum = 0; errstr = empty_string(); auto sock = create_new_socket(hosturl, errnum, errstr); if (!sock) { return false; } sockaddr_storage sa_storage; struct sockaddr *sa_ptr; size_t sa_size; if (!set_sockaddr(sa_storage, sock, hosturl.getHost().c_str(), hosturl.getPort(), sa_ptr, sa_size)) { return false; } int yes = 1; setsockopt(sock->fd(), SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); if ((flags & k_STREAM_SERVER_BIND) != 0 && ::bind(sock->fd(), sa_ptr, sa_size) < 0) { SOCKET_ERROR(sock, "unable to bind to given address", errno); return false; } if ((flags & k_STREAM_SERVER_LISTEN) != 0 && listen(sock->fd(), 128) < 0) { SOCKET_ERROR(sock, "unable to listen on socket", errno); return false; } return Variant(std::move(sock)); }
SmartPtr<SSLSocket> SSLSocket::Create( int fd, int domain, const HostURL &hosturl, double timeout) { CryptoMethod method; const std::string scheme = hosturl.getScheme(); if (scheme == "ssl") { method = CryptoMethod::ClientSSLv23; } else if (scheme == "sslv2") { method = CryptoMethod::ClientSSLv2; } else if (scheme == "sslv3") { method = CryptoMethod::ClientSSLv3; } else if (scheme == "tls") { method = CryptoMethod::ClientTLS; } else { return nullptr; } auto sock = makeSmartPtr<SSLSocket>( fd, domain, hosturl.getHost().c_str(), hosturl.getPort()); sock->m_data->m_method = method; sock->m_data->m_connect_timeout = timeout; sock->m_data->m_enable_on_connect = true; return sock; }
static SmartPtr<Socket> create_new_socket( const HostURL &hosturl, Variant &errnum, Variant &errstr ) { int domain = hosturl.isIPv6() ? AF_INET6 : AF_INET; int type = SOCK_STREAM; const std::string scheme = hosturl.getScheme(); if (scheme == "udp" || scheme == "udg") { type = SOCK_DGRAM; } else if (scheme == "unix") { domain = AF_UNIX; } auto sock = makeSmartPtr<Socket>( socket(domain, type, 0), domain, hosturl.getHost().c_str(), hosturl.getPort() ); if (!sock->valid()) { SOCKET_ERROR(sock, "unable to create socket", errno); errnum = sock->getError(); errstr = HHVM_FN(socket_strerror)(sock->getError()); sock.reset(); } return sock; }
req::ptr<SSLSocket> SSLSocket::Create( int fd, int domain, const HostURL &hosturl, double timeout, const req::ptr<StreamContext>& ctx) { CryptoMethod method; const std::string scheme = hosturl.getScheme(); if (scheme == "ssl") { method = CryptoMethod::ClientSSLv23; } else if (scheme == "sslv2") { method = CryptoMethod::ClientSSLv2; } else if (scheme == "sslv3") { method = CryptoMethod::ClientSSLv3; } else if (scheme == "tls") { method = CryptoMethod::ClientTLS; } else if ( scheme == "tcp" || (scheme.empty() && (domain == AF_INET || domain == AF_INET6)) ) { method = CryptoMethod::NoCrypto; } else { return nullptr; } auto sock = req::make<SSLSocket>( fd, domain, ctx, hosturl.getHost().c_str(), hosturl.getPort()); sock->m_data->m_method = method; sock->m_data->m_connect_timeout = timeout; sock->m_data->m_enable_on_connect = true; return sock; }
req::ptr<SSLSocket> SSLSocket::Create( int fd, int domain, const HostURL &hosturl, double timeout, const req::ptr<StreamContext>& ctx, bool nonblocking ) { CryptoMethod method; const std::string scheme = hosturl.getScheme(); if (scheme == "ssl") { method = CryptoMethod::ClientSSLv23; } else if (scheme == "sslv2") { method = CryptoMethod::ClientSSLv2; } else if (scheme == "sslv3") { method = CryptoMethod::ClientSSLv3; } else if (scheme == "tls") { method = CryptoMethod::ClientTLS; } else if ( scheme == "tcp" || (scheme.empty() && (domain == AF_INET || domain == AF_INET6)) ) { method = CryptoMethod::NoCrypto; } else { return nullptr; } return Create(fd, domain, method, hosturl.getHost(), hosturl.getPort(), timeout, ctx, nonblocking); }
static bool create_new_socket(const HostURL &hosturl, Variant &errnum, Variant &errstr, Resource &ret, Socket *&sock) { int domain = hosturl.isIPv6() ? AF_INET6 : AF_INET; int type = SOCK_STREAM; const std::string scheme = hosturl.getScheme(); if (scheme == "udp" || scheme == "udg") { type = SOCK_DGRAM; } else if (scheme == "unix") { domain = AF_UNIX; } sock = new Socket(socket(domain, type, 0), domain, hosturl.getHost().c_str(), hosturl.getPort()); ret = Resource(sock); if (!sock->valid()) { SOCKET_ERROR(sock, "unable to create socket", errno); errnum = sock->getError(); errstr = HHVM_FN(socket_strerror)(sock->getError()); return false; } return true; }
static Variant new_socket_connect(const HostURL &hosturl, double timeout, Variant &errnum, Variant &errstr) { int domain = AF_UNSPEC; int type = SOCK_STREAM; auto const& scheme = hosturl.getScheme(); SmartPtr<Socket> sock; SmartPtr<SSLSocket> sslsock; std::string sockerr; int error; if (scheme == "udp" || scheme == "udg") { type = SOCK_DGRAM; } else if (scheme == "unix") { domain = AF_UNIX; } int fd = -1; if (domain == AF_UNIX) { sockaddr_storage sa_storage; struct sockaddr *sa_ptr; size_t sa_size; fd = socket(domain, type, 0); sock = makeSmartPtr<Socket>( fd, domain, hosturl.getHost().c_str(), hosturl.getPort()); if (!set_sockaddr(sa_storage, sock, hosturl.getHost().c_str(), hosturl.getPort(), sa_ptr, sa_size)) { // set_sockaddr raises its own warning on failure return false; } if (connect_with_timeout(fd, sa_ptr, sa_size, timeout, hosturl, sockerr, error) != 0) { SOCKET_ERROR(sock, sockerr.c_str(), error); errnum = sock->getLastError(); errstr = HHVM_FN(socket_strerror)(sock->getLastError()); return false; } } else { struct addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = domain; hints.ai_socktype = type; auto port = folly::to<std::string>(hosturl.getPort()); auto host = hosturl.getHost(); struct addrinfo *aiHead; int errcode = getaddrinfo(host.c_str(), port.c_str(), &hints, &aiHead); if (errcode != 0) { errstr = String(gai_strerror(errcode), CopyString); return false; } SCOPE_EXIT { freeaddrinfo(aiHead); }; for (struct addrinfo *ai = aiHead; ai != nullptr; ai = ai->ai_next) { domain = ai->ai_family; fd = socket(domain, ai->ai_socktype, ai->ai_protocol); if (fd == -1) { continue; } if (connect_with_timeout(fd, ai->ai_addr, ai->ai_addrlen, timeout, hosturl, sockerr, error) == 0) { break; } close(fd); fd = -1; } sslsock = SSLSocket::Create(fd, domain, hosturl, timeout); if (sslsock) { sock = sslsock; } else { sock = makeSmartPtr<Socket>(fd, domain, hosturl.getHost().c_str(), hosturl.getPort()); } } if (!sock->valid()) { SOCKET_ERROR(sock, sockerr.empty() ? "unable to create socket" : sockerr.c_str(), error); errnum = sock->getLastError(); errstr = HHVM_FN(socket_strerror)(sock->getLastError()); return false; } if (sslsock && !sslsock->onConnect()) { raise_warning("Failed to enable crypto"); return false; } return Variant(std::move(sock)); }