void Comm::bind_gc () throw(socket_error) { // create socket gc_sockn = ::socket(AF_INET, SOCK_DGRAM, 0); if (gc_sockn == -1) { stop(); throw SOCKET_ERROR(errno); } #ifdef COMM_LISTEN // set bind address parameters struct sockaddr_in bind_addr; bind_addr.sin_family = AF_INET; bind_addr.sin_port = htons(GAMECONTROLLER_PORT); bind_addr.sin_addr.s_addr = htonl(INADDR_ANY); // bind socket to address if (::bind(gc_sockn, (const struct sockaddr*)&bind_addr, sizeof(bind_addr)) == -1) { stop(); throw SOCKET_ERROR(errno); } #endif // Set broadcast enabled on the socket int on = 1; setsockopt(gc_sockn, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)); //#ifdef COMM_LISTEN // Set socket to nonblocking io mode int flags = fcntl(gc_sockn, F_GETFL); fcntl(gc_sockn, F_SETFL, flags | O_NONBLOCK); //#endif }
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)); }
Variant f_socket_create_listen(int port, int backlog /* = 128 */) { Util::HostEnt result; if (!Util::safe_gethostbyname("0.0.0.0", result)) { return false; } struct sockaddr_in la; memcpy((char *) &la.sin_addr, result.hostbuf.h_addr, result.hostbuf.h_length); la.sin_family = result.hostbuf.h_addrtype; la.sin_port = htons((unsigned short)port); Socket *sock = new Socket(socket(PF_INET, SOCK_STREAM, 0), PF_INET, "0.0.0.0", port); Object ret(sock); if (!sock->valid()) { SOCKET_ERROR(sock, "unable to create listening socket", errno); return false; } if (::bind(sock->fd(), (struct sockaddr *)&la, sizeof(la)) < 0) { SOCKET_ERROR(sock, "unable to bind to given adress", errno); return false; } if (listen(sock->fd(), backlog) < 0) { SOCKET_ERROR(sock, "unable to listen on socket", errno); return false; } return ret; }
Variant f_socket_server(CStrRef hostname, int port /* = -1 */, VRefParam errnum /* = null */, VRefParam errstr /* = null */) { Object ret; Socket *sock = NULL; const char *name = hostname.data(); if (!create_new_socket(name, port, errnum, errstr, ret, sock, 0.0)) { return false; } assert(ret.get() && sock); sockaddr_storage sa_storage; struct sockaddr *sa_ptr; size_t sa_size; if (!set_sockaddr(sa_storage, sock, name, port, sa_ptr, sa_size)) { return false; } if (::bind(sock->fd(), sa_ptr, sa_size) < 0) { SOCKET_ERROR(sock, "unable to bind to given adress", errno); return false; } if (listen(sock->fd(), 128) < 0) { SOCKET_ERROR(sock, "unable to listen on socket", errno); return false; } return ret; }
Variant HHVM_FUNCTION(socket_create_listen, int port, int backlog /* = 128 */) { HostEnt result; if (!safe_gethostbyname("0.0.0.0", result)) { return false; } struct sockaddr_in la; memcpy((char *) &la.sin_addr, result.hostbuf.h_addr, result.hostbuf.h_length); la.sin_family = result.hostbuf.h_addrtype; la.sin_port = htons((unsigned short)port); auto sock = makeSmartPtr<Socket>( socket(PF_INET, SOCK_STREAM, 0), PF_INET, "0.0.0.0", port); if (!sock->valid()) { SOCKET_ERROR(sock, "unable to create listening socket", errno); return false; } if (::bind(sock->fd(), (struct sockaddr *)&la, sizeof(la)) < 0) { SOCKET_ERROR(sock, "unable to bind to given address", errno); return false; } if (listen(sock->fd(), backlog) < 0) { SOCKET_ERROR(sock, "unable to listen on socket", errno); return false; } return Variant(std::move(sock)); }
Variant HHVM_FUNCTION(socket_get_option, const Resource& socket, int level, int optname) { auto sock = cast<Socket>(socket); socklen_t optlen; switch (optname) { case SO_LINGER: { struct linger linger_val; optlen = sizeof(linger_val); if (getsockopt(sock->fd(), level, optname, (char*)&linger_val, &optlen) != 0) { SOCKET_ERROR(sock, "unable to retrieve socket option", errno); return false; } return make_map_array( s_l_onoff, linger_val.l_onoff, s_l_linger, linger_val.l_linger ); } break; case SO_RCVTIMEO: case SO_SNDTIMEO: { struct timeval tv; optlen = sizeof(tv); if (getsockopt(sock->fd(), level, optname, (char*)&tv, &optlen) != 0) { SOCKET_ERROR(sock, "unable to retrieve socket option", errno); return false; } return make_map_array( s_sec, (int)tv.tv_sec, s_usec, (int)tv.tv_usec ); } break; default: { int other_val; optlen = sizeof(other_val); if (getsockopt(sock->fd(), level, optname, (char*)&other_val, &optlen)) { SOCKET_ERROR(sock, "unable to retrieve socket option", errno); return false; } return other_val; } } not_reached(); }
void C_SecureSocket::ssl_error(int P_returnCode) { int L_ret ; L_ret = SSL_get_error(m_ssl, P_returnCode) ; if (P_returnCode <= SSL_ERROR_WANT_CONNECT) { SOCKET_ERROR(0, m_ssl_error_string[L_ret]); } else { SOCKET_ERROR(0, "SSL error " << L_ret); } }
Variant f_socket_get_option(CObjRef socket, int level, int optname) { Socket *sock = socket.getTyped<Socket>(); Array ret; socklen_t optlen; switch (optname) { case SO_LINGER: { struct linger linger_val; optlen = sizeof(linger_val); if (getsockopt(sock->fd(), level, optname, (char*)&linger_val, &optlen) != 0) { SOCKET_ERROR(sock, "unable to retrieve socket option", errno); return false; } ret.set(s_l_onoff, linger_val.l_onoff); ret.set(s_l_linger, linger_val.l_linger); } break; case SO_RCVTIMEO: case SO_SNDTIMEO: { struct timeval tv; optlen = sizeof(tv); if (getsockopt(sock->fd(), level, optname, (char*)&tv, &optlen) != 0) { SOCKET_ERROR(sock, "unable to retrieve socket option", errno); return false; } ret.set(s_sec, (int)tv.tv_sec); ret.set(s_usec, (int)tv.tv_usec); } break; default: { int other_val; optlen = sizeof(other_val); if (getsockopt(sock->fd(), level, optname, (char*)&other_val, &optlen)) { SOCKET_ERROR(sock, "unable to retrieve socket option", errno); return false; } return other_val; } } return ret; }
static bool create_new_socket(const char *&name, int port, Variant &errnum, Variant &errstr, Object &ret, Socket *&sock, double timeout) { int domain = AF_INET; int type = SOCK_STREAM; if (strncmp(name, "udp://", 6) == 0 || strncmp(name, "udg://", 6) == 0) { type = SOCK_DGRAM; name += 6; } else if (strncmp(name, "tcp://", 6) == 0) { name += 6; } else if (strncmp(name, "unix://", 7) == 0) { domain = AF_UNIX; name += 7; } sock = new Socket(socket(domain, type, 0), domain, name, port, timeout); ret = Object(sock); if (!sock->valid()) { SOCKET_ERROR(sock, "unable to create socket", errno); errnum = sock->getError(); errstr = String(Util::safe_strerror(sock->getError())); return false; } return true; }
void Comm::receive_gc () throw(socket_error) { #ifdef COMM_LISTEN struct sockaddr_in recv_addr; socklen_t addr_len = sizeof(sockaddr_in); // receive a UDP message int result = ::recvfrom(gc_sockn, &buf, UDP_BUF_SIZE, 0, (struct sockaddr*)&recv_addr, &addr_len); while (result > 0) { // handle the message handle_gc(recv_addr, &buf[0], result); // check for another one result = ::recvfrom(gc_sockn, &buf, UDP_BUF_SIZE, 0, (struct sockaddr*)&recv_addr, &addr_len); } // if an error occured (other than nonblocking EAGAIN error) if (running && result == -1 && errno != EAGAIN) { stop(); throw SOCKET_ERROR(errno); } #endif }
void Comm::send (const char *msg, int len, sockaddr_in &addr) throw(socket_error) { #ifdef COMM_SEND // send the udp message int result = -2; while (result == -2) { result = ::sendto(sockn, msg, len, 0, (struct sockaddr*)&addr, sizeof(broadcast_addr)); // except if error is blocking error if (result == -1 && errno == EAGAIN) { result = -2; usleep(100); } } // error if (result == -1) { if (errno == ENETUNREACH && broadcast_addr.sin_addr.s_addr == htonl(INADDR_BROADCAST)) // attempt to discover our specific broadcast address discover_broadcast(); else if (errno != EAGAIN) error(SOCKET_ERROR(errno)); } #endif // record last time we sent a message timer.sent_packet(); }
Variant HHVM_FUNCTION(socket_read, const Resource& socket, int length, int type /* = 0 */) { if (length <= 0) { return false; } auto sock = cast<Socket>(socket); char *tmpbuf = (char *)malloc(length + 1); int retval; if (type == PHP_NORMAL_READ) { retval = php_read(sock, tmpbuf, length, 0); } else { retval = recv(sock->fd(), tmpbuf, length, 0); } if (retval == -1) { /* if the socket is in non-blocking mode and there's no data to read, don't output any error, as this is a normal situation, and not an error */ if (errno == EAGAIN || errno == EWOULDBLOCK) { sock->setError(errno); } else { SOCKET_ERROR(sock, "unable to read from socket", errno); } free(tmpbuf); return false; } tmpbuf[retval] = '\0' ; return String(tmpbuf, retval, AttachString); }
int C_SecureSocketClient::_secure_mode() { int L_result, L_ret ; m_ssl = SSL_new(m_ssl_ctx); SSL_set_connect_state(m_ssl) ; if ((m_bio = BIO_new_socket(m_socket_id, BIO_CLOSE)) == NULL ) { SOCKET_ERROR(0, "Unable to create the BIO- client in New TLS connection"); } SSL_set_bio(m_ssl,m_bio,m_bio); L_result = SSL_connect(m_ssl) ; if ( L_result < 0 ) { if (SSL_get_error(m_ssl, L_result) == SSL_ERROR_WANT_READ) { m_state = E_SOCKET_STATE_INPROGESS ; L_ret = 0 ; } else { ssl_error(L_result); L_ret = -1 ; } } else { L_ret = 0 ; } return (L_ret); }
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; }
bool HHVM_FUNCTION(socket_bind, const Resource& socket, const String& address, int port /* = 0 */) { auto sock = cast<Socket>(socket); const char *addr = address.data(); sockaddr_storage sa_storage; struct sockaddr *sa_ptr; size_t sa_size; if (!set_sockaddr(sa_storage, sock, addr, port, sa_ptr, sa_size)) { return false; } long retval = ::bind(sock->fd(), sa_ptr, sa_size); if (retval != 0) { std::string msg = "unable to bind address"; msg += addr; msg += ":"; msg += folly::to<std::string>(port); SOCKET_ERROR(sock, msg.c_str(), errno); return false; } return true; }
static bool php_set_inet6_addr(struct sockaddr_in6 *sin6, const char *address, Socket *sock) { struct in6_addr tmp; struct addrinfo hints; struct addrinfo *addrinfo = NULL; if (inet_pton(AF_INET6, address, &tmp)) { memcpy(&(sin6->sin6_addr.s6_addr), &(tmp.s6_addr), sizeof(struct in6_addr)); } else { memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = PF_INET6; getaddrinfo(address, NULL, &hints, &addrinfo); if (!addrinfo) { SOCKET_ERROR(sock, "Host lookup failed", (-10000 - h_errno)); return false; } if (addrinfo->ai_family != PF_INET6 || addrinfo->ai_addrlen != sizeof(struct sockaddr_in6)) { raise_warning("Host lookup failed: Non AF_INET6 domain " "returned on AF_INET6 socket"); freeaddrinfo(addrinfo); return false; } memcpy(&(sin6->sin6_addr.s6_addr), ((struct sockaddr_in6*)(addrinfo->ai_addr))->sin6_addr.s6_addr, sizeof(struct in6_addr)); freeaddrinfo(addrinfo); } return true; }
Variant HHVM_FUNCTION(socket_recv, const Resource& socket, VRefParam buf, int len, int flags) { if (len <= 0) { return false; } auto sock = cast<Socket>(socket); char *recv_buf = (char *)malloc(len + 1); int retval; if ((retval = recv(sock->fd(), recv_buf, len, flags)) < 1) { free(recv_buf); buf = uninit_null(); } else { recv_buf[retval] = '\0'; buf = String(recv_buf, retval, AttachString); } if (retval == -1) { SOCKET_ERROR(sock, "unable to read from socket", errno); return false; } return retval; }
Variant f_socket_sendto(CObjRef socket, CStrRef buf, int len, int flags, CStrRef addr, int port /* = 0 */) { Socket *sock = socket.getTyped<Socket>(); if (len > buf.size()) { len = buf.size(); } int retval; switch (sock->getType()) { case AF_UNIX: { struct sockaddr_un s_un; memset(&s_un, 0, sizeof(s_un)); s_un.sun_family = AF_UNIX; snprintf(s_un.sun_path, 108, "%s", addr.data()); retval = sendto(sock->fd(), buf.data(), len, flags, (struct sockaddr *)&s_un, SUN_LEN(&s_un)); } break; case AF_INET: { struct sockaddr_in sin; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons((unsigned short) port); if (!php_set_inet_addr(&sin, addr.c_str(), sock)) { return false; } retval = sendto(sock->fd(), buf.data(), len, flags, (struct sockaddr *)&sin, sizeof(sin)); } break; case AF_INET6: { struct sockaddr_in6 sin6; memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6; sin6.sin6_port = htons((unsigned short) port); if (!php_set_inet6_addr(&sin6, addr.c_str(), sock)) { return false; } retval = sendto(sock->fd(), buf.data(), len, flags, (struct sockaddr *)&sin6, sizeof(sin6)); } break; default: raise_warning("Unsupported socket type %d", sock->getType()); return false; } if (retval == -1) { SOCKET_ERROR(sock, "unable to write to socket", errno); return false; } return retval; }
bool f_socket_listen(CObjRef socket, int backlog /* = 0 */) { Socket *sock = socket.getTyped<Socket>(); if (listen(sock->fd(), backlog) != 0) { SOCKET_ERROR(sock, "unable to listen on socket", errno); return false; } return true; }
bool f_socket_shutdown(CObjRef socket, int how /* = 0 */) { Socket *sock = socket.getTyped<Socket>(); if (shutdown(sock->fd(), how) != 0) { SOCKET_ERROR(sock, "unable to shutdown socket", errno); return false; } return true; }
bool HHVM_FUNCTION(socket_listen, const Resource& socket, int backlog /* = 0 */) { auto sock = cast<Socket>(socket); if (listen(sock->fd(), backlog) != 0) { SOCKET_ERROR(sock, "unable to listen on socket", errno); return false; } return true; }
Variant f_socket_create(int domain, int type, int protocol) { check_socket_parameters(domain, type); int socketId = socket(domain, type, protocol); if (socketId == -1) { Socket dummySock; // for setting last socket error SOCKET_ERROR((&dummySock), "Unable to create socket", errno); return false; } Socket *sock = new Socket(socketId, domain); Object ret(sock); return ret; }
Variant f_socket_write(CObjRef socket, CStrRef buffer, int length /* = 0 */) { Socket *sock = socket.getTyped<Socket>(); if (length == 0 || length > buffer.size()) { length = buffer.size(); } int retval = write(sock->fd(), buffer.data(), length); if (retval < 0) { SOCKET_ERROR(sock, "unable to write to socket", errno); return false; } return retval; }
static Socket *socket_accept_impl(CObjRef socket, struct sockaddr *addr, socklen_t *addrlen) { Socket *sock = socket.getTyped<Socket>(); Socket *new_sock = new Socket(accept(sock->fd(), addr, addrlen), sock->getType()); if (!new_sock->valid()) { SOCKET_ERROR(new_sock, "unable to accept incoming connection", errno); delete new_sock; return NULL; } return new_sock; }
Variant f_socket_send(CObjRef socket, CStrRef buf, int len, int flags) { Socket *sock = socket.getTyped<Socket>(); if (len > buf.size()) { len = buf.size(); } int retval = send(sock->fd(), buf.data(), len, flags); if (retval == -1) { SOCKET_ERROR(sock, "unable to write to socket", errno); return false; } return retval; }
Variant HHVM_FUNCTION(socket_accept, const Resource& socket) { auto sock = cast<Socket>(socket); struct sockaddr sa; socklen_t salen = sizeof(sa); auto new_sock = makeSmartPtr<Socket>( accept(sock->fd(), &sa, &salen), sock->getType()); if (!new_sock->valid()) { SOCKET_ERROR(new_sock, "unable to accept incoming connection", errno); return false; } return Variant(std::move(new_sock)); }
bool f_socket_getsockname(CObjRef socket, VRefParam address, VRefParam port /* = null */) { Socket *sock = socket.getTyped<Socket>(); sockaddr_storage sa_storage; socklen_t salen = sizeof(sockaddr_storage); struct sockaddr *sa = (struct sockaddr *)&sa_storage; if (getsockname(sock->fd(), sa, &salen) < 0) { SOCKET_ERROR(sock, "unable to retrieve peer name", errno); return false; } return get_sockaddr(sa, address, port); }
Variant f_socket_accept(CObjRef socket) { Socket *sock = socket.getTyped<Socket>(); struct sockaddr sa; socklen_t salen = sizeof(sa); Socket *new_sock = new Socket(accept(sock->fd(), &sa, &salen), sock->getType()); if (!new_sock->valid()) { SOCKET_ERROR(new_sock, "unable to accept incoming connection", errno); delete new_sock; return false; } return Object(new_sock); }
void Comm::discover_broadcast () { // run ifconfig command to discover broadcast address FILE *f = popen( "ifconfig | grep 'Bcast' | sed -e 's/.* Bcast:\\([^ ]*\\) .*/\\1/'", "r"); if (f == NULL) { error(SOCKET_ERROR(errno)); return; } // read output and result (error status) char buf[1024]; int len = fread(&buf[0], 1, 1024, f); int result = pclose(f); if (result == 0 && len > 0) { // add null character to enable processing as a normal string buf[len] = '\0'; // convert address to in_addr struct struct in_addr addr; if (inet_aton(&buf[0], &addr)) { broadcast_addr.sin_addr = addr; cout << "Using broadcast address " << buf << endl; }else error(SOCKET_ERROR(errno)); }else if (result != 0) error(SOCKET_ERROR("Failed to discover broadcast address -- command " "returned error")); else if (len <= 0) error(SOCKET_ERROR("Failed to discover broadcast address -- command " "returned no output")); }
Variant HHVM_FUNCTION(socket_create, int domain, int type, int protocol) { check_socket_parameters(domain, type); int socketId = socket(domain, type, protocol); if (socketId == -1) { SOCKET_ERROR(makeSmartPtr<Socket>(), "Unable to create socket", errno); return false; } return Variant(makeSmartPtr<Socket>(socketId, domain)); }