int zmq::tcp_connecter_t::open () { zmq_assert (s == retired_fd); // Create the socket. s = open_socket (addr->resolved.tcp_addr->family (), SOCK_STREAM, IPPROTO_TCP); #ifdef ZMQ_HAVE_WINDOWS if (s == INVALID_SOCKET) { errno = wsa_error_to_errno (WSAGetLastError ()); return -1; } #else if (s == -1) return -1; #endif // On some systems, IPv4 mapping in IPv6 sockets is disabled by default. // Switch it on in such cases. if (addr->resolved.tcp_addr->family () == AF_INET6) enable_ipv4_mapping (s); // Set the socket to non-blocking mode so that we get async connect(). unblock_socket (s); // Set the socket buffer limits for the underlying socket. if (options.sndbuf != 0) set_tcp_send_buffer (s, options.sndbuf); if (options.rcvbuf != 0) set_tcp_receive_buffer (s, options.rcvbuf); // Connect to the remote peer. int rc = ::connect ( s, addr->resolved.tcp_addr->addr (), addr->resolved.tcp_addr->addrlen ()); // Connect was successfull immediately. if (rc == 0) return 0; // Translate error codes indicating asynchronous connect has been // launched to a uniform EINPROGRESS. #ifdef ZMQ_HAVE_WINDOWS const int error_code = WSAGetLastError (); if (error_code == WSAEINPROGRESS || error_code == WSAEWOULDBLOCK) errno = EINPROGRESS; else errno = wsa_error_to_errno (error_code); #else if (errno == EINTR) errno = EINPROGRESS; #endif return -1; }
int zmq::tcp_connecter_t::open () { zmq_assert (s == retired_fd); // Create the socket. s = open_socket (addr->resolved.tcp_addr->family (), SOCK_STREAM, IPPROTO_TCP); #ifdef ZMQ_HAVE_WINDOWS if (s == INVALID_SOCKET) { wsa_error_to_errno (); return -1; } #else if (s == -1) return -1; #endif // On some systems, IPv4 mapping in IPv6 sockets is disabled by default. // Switch it on in such cases. if (addr->resolved.tcp_addr->family () == AF_INET6) enable_ipv4_mapping (s); // Set the socket to non-blocking mode so that we get async connect(). unblock_socket (s); // Connect to the remote peer. int rc = ::connect ( s, addr->resolved.tcp_addr->addr (), addr->resolved.tcp_addr->addrlen ()); // Connect was successfull immediately. if (rc == 0) return 0; // Asynchronous connect was launched. #ifdef ZMQ_HAVE_WINDOWS if (rc == SOCKET_ERROR && (WSAGetLastError () == WSAEINPROGRESS || WSAGetLastError () == WSAEWOULDBLOCK)) { errno = EAGAIN; return -1; } wsa_error_to_errno (); #else if (rc == -1 && errno == EINPROGRESS) { errno = EAGAIN; return -1; } #endif return -1; }
int zmq::tcp_listener_t::set_address (const char *protocol_, const char *addr_, int backlog_) { // IPC protocol is not supported on Windows platform. if (strcmp (protocol_, "tcp") != 0 ) { errno = EPROTONOSUPPORT; return -1; } // Convert the interface into sockaddr_in structure. int rc = resolve_ip_interface (&addr, &addr_len, addr_); if (rc != 0) return rc; // Create a listening socket. s = socket (addr.ss_family, SOCK_STREAM, IPPROTO_TCP); if (s == INVALID_SOCKET) { wsa_error_to_errno (); return -1; } // Allow reusing of the address. int flag = 1; rc = setsockopt (s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*) &flag, sizeof (int)); wsa_assert (rc != SOCKET_ERROR); // Set the non-blocking flag. u_long uflag = 1; rc = ioctlsocket (s, FIONBIO, &uflag); wsa_assert (rc != SOCKET_ERROR); // Bind the socket to the network interface and port. rc = bind (s, (struct sockaddr*) &addr, addr_len); if (rc == SOCKET_ERROR) { wsa_error_to_errno (); return -1; } // Listen for incomming connections. rc = listen (s, backlog_); if (rc == SOCKET_ERROR) { wsa_error_to_errno (); return -1; } return 0; }
int zmq::vmci_connecter_t::open () { zmq_assert (s == retired_fd); int family = this->get_ctx ()->get_vmci_socket_family (); if (family == -1) return -1; // Create the socket. s = open_socket (family, SOCK_STREAM, 0); #ifdef ZMQ_HAVE_WINDOWS if (s == INVALID_SOCKET) { errno = wsa_error_to_errno(WSAGetLastError()); return -1; } #else if (s == -1) return -1; #endif // Set the non-blocking flag. unblock_socket (s); // Connect to the remote peer. int rc = ::connect ( s, addr->resolved.vmci_addr->addr (), addr->resolved.vmci_addr->addrlen ()); // Connect was successful immediately. if (rc == 0) return 0; // Translate error codes indicating asynchronous connect has been // launched to a uniform EINPROGRESS. #ifdef ZMQ_HAVE_WINDOWS const int error_code = WSAGetLastError(); if (error_code == WSAEINPROGRESS || error_code == WSAEWOULDBLOCK) errno = EINPROGRESS; else errno = wsa_error_to_errno(error_code); #else if (errno == EINTR) errno = EINPROGRESS; #endif // Forward the error. return -1; }
int zmq::vmci_connecter_t::open () { zmq_assert (s == retired_fd); int family = this->get_ctx ()->get_vmci_socket_family (); if (family == -1) return -1; // Create the socket. s = open_socket (family, SOCK_STREAM, 0); #ifdef ZMQ_HAVE_WINDOWS if (s == INVALID_SOCKET) { errno = wsa_error_to_errno(WSAGetLastError()); return -1; } #else if (s == -1) return -1; #endif // Connect to the remote peer. int rc = ::connect ( s, addr->resolved.vmci_addr->addr (), addr->resolved.vmci_addr->addrlen ()); // Connect was successful immediately. if (rc == 0) return 0; // Forward the error. return -1; }
zmq::fd_t zmq::open_socket (int domain_, int type_, int protocol_) { int rc; // Setting this option result in sane behaviour when exec() functions // are used. Old sockets are closed and don't block TCP ports etc. #if defined ZMQ_HAVE_SOCK_CLOEXEC type_ |= SOCK_CLOEXEC; #endif #if defined ZMQ_HAVE_WINDOWS && defined WSA_FLAG_NO_HANDLE_INHERIT // if supported, create socket with WSA_FLAG_NO_HANDLE_INHERIT, such that // the race condition in making it non-inheritable later is avoided const fd_t s = WSASocket (domain_, type_, protocol_, NULL, 0, WSA_FLAG_NO_HANDLE_INHERIT); #else const fd_t s = socket (domain_, type_, protocol_); #endif if (s == retired_fd) { #ifdef ZMQ_HAVE_WINDOWS errno = wsa_error_to_errno (WSAGetLastError ()); #endif return retired_fd; } make_socket_noninheritable (s); // Socket is not yet connected so EINVAL is not a valid networking error rc = zmq::set_nosigpipe (s); errno_assert (rc == 0); return s; }
int zmq::tcp_connecter_t::open () { zmq_assert (s == retired_fd); // Create the socket. s = open_socket (addr.ss_family, SOCK_STREAM, IPPROTO_TCP); if (s == INVALID_SOCKET) { wsa_error_to_errno (); return -1; } // Set to non-blocking mode. unsigned long argp = 1; int rc = ioctlsocket (s, FIONBIO, &argp); wsa_assert (rc != SOCKET_ERROR); // Disable Nagle's algorithm. int flag = 1; rc = setsockopt (s, IPPROTO_TCP, TCP_NODELAY, (char*) &flag, sizeof (int)); wsa_assert (rc != SOCKET_ERROR); // Connect to the remote peer. rc = ::connect (s, (sockaddr*) &addr, addr_len); // Connect was successfull immediately. if (rc == 0) return 0; // Asynchronous connect was launched. if (rc == SOCKET_ERROR && (WSAGetLastError () == WSAEINPROGRESS || WSAGetLastError () == WSAEWOULDBLOCK)) { errno = EINPROGRESS; return -1; } wsa_error_to_errno (); return -1; }
int zmq::tcp_listener_t::set_address (sockaddr_in addr_, int backlog_) { this->addr = addr_; this->addr_len = sizeof(this->addr); // Create a listening socket. s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); if (s == INVALID_SOCKET) { wsa_error_to_errno (); return -1; } // Allow reusing of the address. int flag = 1; int rc = setsockopt (s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*) &flag, sizeof (int)); wsa_assert (rc != SOCKET_ERROR); // Set the non-blocking flag. u_long uflag = 1; rc = ioctlsocket (s, FIONBIO, &uflag); wsa_assert (rc != SOCKET_ERROR); // Bind the socket to the network interface and port. rc = bind (s, (struct sockaddr*) &addr, addr_len); if (rc == SOCKET_ERROR) { wsa_error_to_errno (); return -1; } // Listen for incomming connections. rc = listen (s, backlog_); if (rc == SOCKET_ERROR) { wsa_error_to_errno (); return -1; } return 0; }
int zmq::tcp_read (fd_t s_, void *data_, size_t size_) { #ifdef ZMQ_HAVE_WINDOWS const int rc = recv (s_, (char*) data_, (int) size_, 0); // If not a single byte can be read from the socket in non-blocking mode // we'll get an error (this may happen during the speculative read). if (rc == SOCKET_ERROR) { const int last_error = WSAGetLastError(); if (last_error == WSAEWOULDBLOCK) { errno = EAGAIN; } else { wsa_assert (last_error == WSAENETDOWN || last_error == WSAENETRESET || last_error == WSAECONNABORTED || last_error == WSAETIMEDOUT || last_error == WSAECONNRESET || last_error == WSAECONNREFUSED || last_error == WSAENOTCONN); errno = wsa_error_to_errno (last_error); } } return rc == SOCKET_ERROR ? -1 : rc; #else const ssize_t rc = recv (s_, data_, size_, 0); // Several errors are OK. When speculative read is being done we may not // be able to read a single byte from the socket. Also, SIGSTOP issued // by a debugging tool can result in EINTR error. if (rc == -1) { errno_assert (errno != EBADF && errno != EFAULT && errno != EINVAL && errno != ENOMEM && errno != ENOTSOCK); if (errno == EWOULDBLOCK || errno == EINTR) errno = EAGAIN; } return static_cast <int> (rc); #endif }
int zmq::tcp_listener_t::set_address (const char *addr_) { // Convert the textual address into address structure. int rc = address.resolve (addr_, true, options.ipv6); if (rc != 0) return -1; address.to_string (endpoint); if (options.use_fd != -1) { s = options.use_fd; socket->event_listening (endpoint, (int) s); return 0; } // Create a listening socket. s = open_socket (address.family (), SOCK_STREAM, IPPROTO_TCP); // IPv6 address family not supported, try automatic downgrade to IPv4. if (s == zmq::retired_fd && address.family () == AF_INET6 && errno == EAFNOSUPPORT && options.ipv6) { rc = address.resolve (addr_, true, false); if (rc != 0) return rc; s = open_socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); } #ifdef ZMQ_HAVE_WINDOWS if (s == INVALID_SOCKET) { errno = wsa_error_to_errno (WSAGetLastError ()); return -1; } #if !defined _WIN32_WCE && !defined ZMQ_HAVE_WINDOWS_UWP // On Windows, preventing sockets to be inherited by child processes. BOOL brc = SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0); win_assert (brc); #endif #else if (s == -1) return -1; #endif // On some systems, IPv4 mapping in IPv6 sockets is disabled by default. // Switch it on in such cases. if (address.family () == AF_INET6) enable_ipv4_mapping (s); // Set the IP Type-Of-Service for the underlying socket if (options.tos != 0) set_ip_type_of_service (s, options.tos); // Set the socket to loopback fastpath if configured. if (options.loopback_fastpath) tcp_tune_loopback_fast_path (s); // Bind the socket to a device if applicable if (!options.bound_device.empty ()) bind_to_device (s, options.bound_device); // Set the socket buffer limits for the underlying socket. if (options.sndbuf >= 0) set_tcp_send_buffer (s, options.sndbuf); if (options.rcvbuf >= 0) set_tcp_receive_buffer (s, options.rcvbuf); // Allow reusing of the address. int flag = 1; #ifdef ZMQ_HAVE_WINDOWS rc = setsockopt (s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char *) &flag, sizeof (int)); wsa_assert (rc != SOCKET_ERROR); #else rc = setsockopt (s, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof (int)); errno_assert (rc == 0); #endif // Bind the socket to the network interface and port. rc = bind (s, address.addr (), address.addrlen ()); #ifdef ZMQ_HAVE_WINDOWS if (rc == SOCKET_ERROR) { errno = wsa_error_to_errno (WSAGetLastError ()); goto error; } #else if (rc != 0) goto error; #endif // Listen for incoming connections. rc = listen (s, options.backlog); #ifdef ZMQ_HAVE_WINDOWS if (rc == SOCKET_ERROR) { errno = wsa_error_to_errno (WSAGetLastError ()); goto error; } #else if (rc != 0) goto error; #endif socket->event_listening (endpoint, (int) s); return 0; error: int err = errno; close (); errno = err; return -1; }
int zmq::tcp_listener_t::set_address (const char *addr_) { // Convert the textual address into address structure. int rc = address.resolve (addr_, true, options.ipv4only ? true : false); if (rc != 0) return -1; // Create a listening socket. s = open_socket (address.family (), SOCK_STREAM, IPPROTO_TCP); #ifdef ZMQ_HAVE_WINDOWS if (s == INVALID_SOCKET) errno = wsa_error_to_errno (WSAGetLastError ()); #endif // IPv6 address family not supported, try automatic downgrade to IPv4. if (address.family () == AF_INET6 && errno == EAFNOSUPPORT && !options.ipv4only) { rc = address.resolve (addr_, true, true); if (rc != 0) return rc; s = ::socket (address.family (), SOCK_STREAM, IPPROTO_TCP); } #ifdef ZMQ_HAVE_WINDOWS if (s == INVALID_SOCKET) { errno = wsa_error_to_errno (WSAGetLastError ()); return -1; } // On Windows, preventing sockets to be inherited by child processes. BOOL brc = SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0); win_assert (brc); #else if (s == -1) return -1; #endif // On some systems, IPv4 mapping in IPv6 sockets is disabled by default. // Switch it on in such cases. if (address.family () == AF_INET6) enable_ipv4_mapping (s); // Allow reusing of the address. int flag = 1; #ifdef ZMQ_HAVE_WINDOWS rc = setsockopt (s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*) &flag, sizeof (int)); wsa_assert (rc != SOCKET_ERROR); #else rc = setsockopt (s, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof (int)); errno_assert (rc == 0); #endif address.to_string (endpoint); // Bind the socket to the network interface and port. rc = bind (s, address.addr (), address.addrlen ()); #ifdef ZMQ_HAVE_WINDOWS if (rc == SOCKET_ERROR) { errno = wsa_error_to_errno (WSAGetLastError ()); return -1; } #else if (rc != 0) return -1; #endif // Listen for incomming connections. rc = listen (s, options.backlog); #ifdef ZMQ_HAVE_WINDOWS if (rc == SOCKET_ERROR) { errno = wsa_error_to_errno (WSAGetLastError ()); return -1; } #else if (rc != 0) return -1; #endif socket->monitor_event (ZMQ_EVENT_LISTENING, addr_, s); return 0; }
int zmq::make_fdpair (fd_t *r_, fd_t *w_) { #if defined ZMQ_HAVE_EVENTFD int flags = 0; #if defined ZMQ_HAVE_EVENTFD_CLOEXEC // Setting this option result in sane behaviour when exec() functions // are used. Old sockets are closed and don't block TCP ports, avoid // leaks, etc. flags |= EFD_CLOEXEC; #endif fd_t fd = eventfd (0, flags); if (fd == -1) { errno_assert (errno == ENFILE || errno == EMFILE); *w_ = *r_ = -1; return -1; } else { *w_ = *r_ = fd; return 0; } #elif defined ZMQ_HAVE_WINDOWS #if !defined _WIN32_WCE && !defined ZMQ_HAVE_WINDOWS_UWP // Windows CE does not manage security attributes SECURITY_DESCRIPTOR sd; SECURITY_ATTRIBUTES sa; memset (&sd, 0, sizeof sd); memset (&sa, 0, sizeof sa); InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION); SetSecurityDescriptorDacl (&sd, TRUE, 0, FALSE); sa.nLength = sizeof (SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = &sd; #endif // This function has to be in a system-wide critical section so that // two instances of the library don't accidentally create signaler // crossing the process boundary. // We'll use named event object to implement the critical section. // Note that if the event object already exists, the CreateEvent requests // EVENT_ALL_ACCESS access right. If this fails, we try to open // the event object asking for SYNCHRONIZE access only. HANDLE sync = NULL; // Create critical section only if using fixed signaler port // Use problematic Event implementation for compatibility if using old port 5905. // Otherwise use Mutex implementation. int event_signaler_port = 5905; if (signaler_port == event_signaler_port) { #if !defined _WIN32_WCE && !defined ZMQ_HAVE_WINDOWS_UWP sync = CreateEventW (&sa, FALSE, TRUE, L"Global\\zmq-signaler-port-sync"); #else sync = CreateEventW (NULL, FALSE, TRUE, L"Global\\zmq-signaler-port-sync"); #endif if (sync == NULL && GetLastError () == ERROR_ACCESS_DENIED) sync = OpenEventW (SYNCHRONIZE | EVENT_MODIFY_STATE, FALSE, L"Global\\zmq-signaler-port-sync"); win_assert (sync != NULL); } else if (signaler_port != 0) { wchar_t mutex_name[MAX_PATH]; #ifdef __MINGW32__ _snwprintf (mutex_name, MAX_PATH, L"Global\\zmq-signaler-port-%d", signaler_port); #else swprintf (mutex_name, MAX_PATH, L"Global\\zmq-signaler-port-%d", signaler_port); #endif #if !defined _WIN32_WCE && !defined ZMQ_HAVE_WINDOWS_UWP sync = CreateMutexW (&sa, FALSE, mutex_name); #else sync = CreateMutexW (NULL, FALSE, mutex_name); #endif if (sync == NULL && GetLastError () == ERROR_ACCESS_DENIED) sync = OpenMutexW (SYNCHRONIZE, FALSE, mutex_name); win_assert (sync != NULL); } // Windows has no 'socketpair' function. CreatePipe is no good as pipe // handles cannot be polled on. Here we create the socketpair by hand. *w_ = INVALID_SOCKET; *r_ = INVALID_SOCKET; // Create listening socket. SOCKET listener; listener = open_socket (AF_INET, SOCK_STREAM, 0); wsa_assert (listener != INVALID_SOCKET); // Set SO_REUSEADDR and TCP_NODELAY on listening socket. BOOL so_reuseaddr = 1; int rc = setsockopt (listener, SOL_SOCKET, SO_REUSEADDR, (char *) &so_reuseaddr, sizeof so_reuseaddr); wsa_assert (rc != SOCKET_ERROR); tune_socket (listener); // Init sockaddr to signaler port. struct sockaddr_in addr; memset (&addr, 0, sizeof addr); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); addr.sin_port = htons (signaler_port); // Create the writer socket. *w_ = open_socket (AF_INET, SOCK_STREAM, 0); wsa_assert (*w_ != INVALID_SOCKET); // Set TCP_NODELAY on writer socket. tune_socket (*w_); if (sync != NULL) { // Enter the critical section. DWORD dwrc = WaitForSingleObject (sync, INFINITE); zmq_assert (dwrc == WAIT_OBJECT_0 || dwrc == WAIT_ABANDONED); } // Bind listening socket to signaler port. rc = bind (listener, (const struct sockaddr *) &addr, sizeof addr); if (rc != SOCKET_ERROR && signaler_port == 0) { // Retrieve ephemeral port number int addrlen = sizeof addr; rc = getsockname (listener, (struct sockaddr *) &addr, &addrlen); } // Listen for incoming connections. if (rc != SOCKET_ERROR) rc = listen (listener, 1); // Connect writer to the listener. if (rc != SOCKET_ERROR) rc = connect (*w_, (struct sockaddr *) &addr, sizeof addr); // Accept connection from writer. if (rc != SOCKET_ERROR) *r_ = accept (listener, NULL, NULL); // Send/receive large chunk to work around TCP slow start // This code is a workaround for #1608 if (*r_ != INVALID_SOCKET) { size_t dummy_size = 1024 * 1024; // 1M to overload default receive buffer unsigned char *dummy = (unsigned char *) malloc (dummy_size); wsa_assert (dummy); int still_to_send = (int) dummy_size; int still_to_recv = (int) dummy_size; while (still_to_send || still_to_recv) { int nbytes; if (still_to_send > 0) { nbytes = ::send (*w_, (char *) (dummy + dummy_size - still_to_send), still_to_send, 0); wsa_assert (nbytes != SOCKET_ERROR); still_to_send -= nbytes; } nbytes = ::recv (*r_, (char *) (dummy + dummy_size - still_to_recv), still_to_recv, 0); wsa_assert (nbytes != SOCKET_ERROR); still_to_recv -= nbytes; } free (dummy); } // Save errno if error occurred in bind/listen/connect/accept. int saved_errno = 0; if (*r_ == INVALID_SOCKET) saved_errno = WSAGetLastError (); // We don't need the listening socket anymore. Close it. rc = closesocket (listener); wsa_assert (rc != SOCKET_ERROR); if (sync != NULL) { // Exit the critical section. BOOL brc; if (signaler_port == event_signaler_port) brc = SetEvent (sync); else brc = ReleaseMutex (sync); win_assert (brc != 0); // Release the kernel object brc = CloseHandle (sync); win_assert (brc != 0); } if (*r_ != INVALID_SOCKET) { #if !defined _WIN32_WCE && !defined ZMQ_HAVE_WINDOWS_UWP // On Windows, preventing sockets to be inherited by child processes. BOOL brc = SetHandleInformation ((HANDLE) *r_, HANDLE_FLAG_INHERIT, 0); win_assert (brc); #endif return 0; } else { // Cleanup writer if connection failed if (*w_ != INVALID_SOCKET) { rc = closesocket (*w_); wsa_assert (rc != SOCKET_ERROR); *w_ = INVALID_SOCKET; } // Set errno from saved value errno = wsa_error_to_errno (saved_errno); return -1; } #elif defined ZMQ_HAVE_OPENVMS // Whilst OpenVMS supports socketpair - it maps to AF_INET only. Further, // it does not set the socket options TCP_NODELAY and TCP_NODELACK which // can lead to performance problems. // // The bug will be fixed in V5.6 ECO4 and beyond. In the meantime, we'll // create the socket pair manually. struct sockaddr_in lcladdr; memset (&lcladdr, 0, sizeof lcladdr); lcladdr.sin_family = AF_INET; lcladdr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); lcladdr.sin_port = 0; int listener = open_socket (AF_INET, SOCK_STREAM, 0); errno_assert (listener != -1); int on = 1; int rc = setsockopt (listener, IPPROTO_TCP, TCP_NODELAY, &on, sizeof on); errno_assert (rc != -1); rc = setsockopt (listener, IPPROTO_TCP, TCP_NODELACK, &on, sizeof on); errno_assert (rc != -1); rc = bind (listener, (struct sockaddr *) &lcladdr, sizeof lcladdr); errno_assert (rc != -1); socklen_t lcladdr_len = sizeof lcladdr; rc = getsockname (listener, (struct sockaddr *) &lcladdr, &lcladdr_len); errno_assert (rc != -1); rc = listen (listener, 1); errno_assert (rc != -1); *w_ = open_socket (AF_INET, SOCK_STREAM, 0); errno_assert (*w_ != -1); rc = setsockopt (*w_, IPPROTO_TCP, TCP_NODELAY, &on, sizeof on); errno_assert (rc != -1); rc = setsockopt (*w_, IPPROTO_TCP, TCP_NODELACK, &on, sizeof on); errno_assert (rc != -1); rc = connect (*w_, (struct sockaddr *) &lcladdr, sizeof lcladdr); errno_assert (rc != -1); *r_ = accept (listener, NULL, NULL); errno_assert (*r_ != -1); close (listener); return 0; #else // All other implementations support socketpair() int sv[2]; int type = SOCK_STREAM; // Setting this option result in sane behaviour when exec() functions // are used. Old sockets are closed and don't block TCP ports, avoid // leaks, etc. #if defined ZMQ_HAVE_SOCK_CLOEXEC type |= SOCK_CLOEXEC; #endif int rc = socketpair (AF_UNIX, type, 0, sv); if (rc == -1) { errno_assert (errno == ENFILE || errno == EMFILE); *w_ = *r_ = -1; return -1; } else { // If there's no SOCK_CLOEXEC, let's try the second best option. Note that // race condition can cause socket not to be closed (if fork happens // between socket creation and this point). #if !defined ZMQ_HAVE_SOCK_CLOEXEC && defined FD_CLOEXEC rc = fcntl (sv[0], F_SETFD, FD_CLOEXEC); errno_assert (rc != -1); rc = fcntl (sv[1], F_SETFD, FD_CLOEXEC); errno_assert (rc != -1); #endif *w_ = sv[0]; *r_ = sv[1]; return 0; } #endif }
int zmq::vmci_listener_t::set_address (const char *addr_) { // Create addr on stack for auto-cleanup std::string addr (addr_); // Initialise the address structure. vmci_address_t address(this->get_ctx ()); int rc = address.resolve (addr.c_str()); if (rc != 0) return -1; // Create a listening socket. s = open_socket (this->get_ctx ()->get_vmci_socket_family (), SOCK_STREAM, 0); #ifdef ZMQ_HAVE_WINDOWS if (s == INVALID_SOCKET) { errno = wsa_error_to_errno(WSAGetLastError()); return -1; } #if !defined _WIN32_WCE // On Windows, preventing sockets to be inherited by child processes. BOOL brc = SetHandleInformation((HANDLE)s, HANDLE_FLAG_INHERIT, 0); win_assert(brc); #endif #else if (s == -1) return -1; #endif address.to_string (endpoint); // Bind the socket. rc = bind (s, address.addr (), address.addrlen ()); #ifdef ZMQ_HAVE_WINDOWS if (rc == SOCKET_ERROR) { errno = wsa_error_to_errno(WSAGetLastError()); goto error; } #else if (rc != 0) goto error; #endif // Listen for incoming connections. rc = listen (s, options.backlog); #ifdef ZMQ_HAVE_WINDOWS if (rc == SOCKET_ERROR) { errno = wsa_error_to_errno(WSAGetLastError()); goto error; } #else if (rc != 0) goto error; #endif socket->event_listening (endpoint, s); return 0; error: int err = errno; close (); errno = err; return -1; }
int zmq::tcp_connecter_t::open () { zmq_assert (s == retired_fd); // Resolve the address if (addr->resolved.tcp_addr != NULL) { delete addr->resolved.tcp_addr; addr->resolved.tcp_addr = NULL; } addr->resolved.tcp_addr = new (std::nothrow) tcp_address_t (); alloc_assert (addr->resolved.tcp_addr); int rc = addr->resolved.tcp_addr->resolve ( addr->address.c_str (), false, options.ipv6); if (rc != 0) { delete addr->resolved.tcp_addr; addr->resolved.tcp_addr = NULL; return -1; } zmq_assert (addr->resolved.tcp_addr != NULL); tcp_address_t * const tcp_addr = addr->resolved.tcp_addr; // Create the socket. s = open_socket (tcp_addr->family (), SOCK_STREAM, IPPROTO_TCP); #ifdef ZMQ_HAVE_WINDOWS if (s == INVALID_SOCKET) { errno = wsa_error_to_errno (WSAGetLastError ()); return -1; } #else if (s == -1) return -1; #endif // On some systems, IPv4 mapping in IPv6 sockets is disabled by default. // Switch it on in such cases. if (tcp_addr->family () == AF_INET6) enable_ipv4_mapping (s); // Set the IP Type-Of-Service priority for this socket if (options.tos != 0) set_ip_type_of_service (s, options.tos); // Set the socket to non-blocking mode so that we get async connect(). unblock_socket (s); // Set the socket buffer limits for the underlying socket. if (options.sndbuf >= 0) set_tcp_send_buffer (s, options.sndbuf); if (options.rcvbuf >= 0) set_tcp_receive_buffer (s, options.rcvbuf); // Set the IP Type-Of-Service for the underlying socket if (options.tos != 0) set_ip_type_of_service (s, options.tos); // Set a source address for conversations if (tcp_addr->has_src_addr ()) { rc = ::bind (s, tcp_addr->src_addr (), tcp_addr->src_addrlen ()); if (rc == -1) return -1; } // Connect to the remote peer. rc = ::connect (s, tcp_addr->addr (), tcp_addr->addrlen ()); // Connect was successfull immediately. if (rc == 0) return 0; // Translate error codes indicating asynchronous connect has been // launched to a uniform EINPROGRESS. #ifdef ZMQ_HAVE_WINDOWS const int last_error = WSAGetLastError(); if (last_error == WSAEINPROGRESS || last_error == WSAEWOULDBLOCK) errno = EINPROGRESS; else errno = wsa_error_to_errno (last_error); #else if (errno == EINTR) errno = EINPROGRESS; #endif return -1; }
int zmq::tcp_listener_t::create_socket (const char *addr_) { _s = tcp_open_socket (addr_, options, true, true, &_address); if (_s == retired_fd) { return -1; } // TODO why is this only done for the listener? make_socket_noninheritable (_s); // Allow reusing of the address. int flag = 1; int rc; #ifdef ZMQ_HAVE_WINDOWS // TODO this was changed for Windows from SO_REUSEADDRE to // SE_EXCLUSIVEADDRUSE by 0ab65324195ad70205514d465b03d851a6de051c, // so the comment above is no longer correct; also, now the settings are // different between listener and connecter with a src address. // is this intentional? rc = setsockopt (_s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, reinterpret_cast<const char *> (&flag), sizeof (int)); wsa_assert (rc != SOCKET_ERROR); #elif defined ZMQ_HAVE_VXWORKS rc = setsockopt (_s, SOL_SOCKET, SO_REUSEADDR, (char *) &flag, sizeof (int)); errno_assert (rc == 0); #else rc = setsockopt (_s, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof (int)); errno_assert (rc == 0); #endif // Bind the socket to the network interface and port. #if defined ZMQ_HAVE_VXWORKS rc = bind (_s, (sockaddr *) _address.addr (), _address.addrlen ()); #else rc = bind (_s, _address.addr (), _address.addrlen ()); #endif #ifdef ZMQ_HAVE_WINDOWS if (rc == SOCKET_ERROR) { errno = wsa_error_to_errno (WSAGetLastError ()); goto error; } #else if (rc != 0) goto error; #endif // Listen for incoming connections. rc = listen (_s, options.backlog); #ifdef ZMQ_HAVE_WINDOWS if (rc == SOCKET_ERROR) { errno = wsa_error_to_errno (WSAGetLastError ()); goto error; } #else if (rc != 0) goto error; #endif return 0; error: int err = errno; close (); errno = err; return -1; }
// Returns -1 if we could not make the socket pair successfully int zmq::signaler_t::make_fdpair (fd_t *r_, fd_t *w_) { #if defined ZMQ_HAVE_EVENTFD fd_t fd = eventfd (0, 0); if (fd == -1) { errno_assert (errno == ENFILE || errno == EMFILE); *w_ = *r_ = -1; return -1; } else { *w_ = *r_ = fd; return 0; } #elif defined ZMQ_HAVE_WINDOWS # if !defined _WIN32_WCE // Windows CE does not manage security attributes SECURITY_DESCRIPTOR sd; SECURITY_ATTRIBUTES sa; memset (&sd, 0, sizeof (sd)); memset (&sa, 0, sizeof (sa)); InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION); SetSecurityDescriptorDacl(&sd, TRUE, 0, FALSE); sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = &sd; # endif // This function has to be in a system-wide critical section so that // two instances of the library don't accidentally create signaler // crossing the process boundary. // We'll use named event object to implement the critical section. // Note that if the event object already exists, the CreateEvent requests // EVENT_ALL_ACCESS access right. If this fails, we try to open // the event object asking for SYNCHRONIZE access only. HANDLE sync = NULL; // Create critical section only if using fixed signaler port // Use problematic Event implementation for compatibility if using old port 5905. // Otherwise use Mutex implementation. int event_signaler_port = 5905; if (signaler_port == event_signaler_port) { # if !defined _WIN32_WCE sync = CreateEvent (&sa, FALSE, TRUE, TEXT ("Global\\zmq-signaler-port-sync")); # else sync = CreateEvent (NULL, FALSE, TRUE, TEXT ("Global\\zmq-signaler-port-sync")); # endif if (sync == NULL && GetLastError () == ERROR_ACCESS_DENIED) sync = OpenEvent (SYNCHRONIZE | EVENT_MODIFY_STATE, FALSE, TEXT ("Global\\zmq-signaler-port-sync")); win_assert (sync != NULL); } else if (signaler_port != 0) { TCHAR mutex_name[64]; /* VC++ v120 swprintf has been changed to conform with the ISO C standard, adding an extra character count parameter. */ _stprintf (mutex_name, TEXT ("Global\\zmq-signaler-port-%d"), signaler_port); # if !defined _WIN32_WCE sync = CreateMutex (&sa, FALSE, mutex_name); # else sync = CreateMutex (NULL, FALSE, mutex_name); # endif if (sync == NULL && GetLastError () == ERROR_ACCESS_DENIED) sync = OpenMutex (SYNCHRONIZE, FALSE, mutex_name); win_assert (sync != NULL); } // Windows has no 'socketpair' function. CreatePipe is no good as pipe // handles cannot be polled on. Here we create the socketpair by hand. *w_ = INVALID_SOCKET; *r_ = INVALID_SOCKET; // Create listening socket. SOCKET listener; listener = open_socket (AF_INET, SOCK_STREAM, 0); wsa_assert (listener != INVALID_SOCKET); // Set SO_REUSEADDR and TCP_NODELAY on listening socket. BOOL so_reuseaddr = 1; int rc = setsockopt (listener, SOL_SOCKET, SO_REUSEADDR, (char *)&so_reuseaddr, sizeof (so_reuseaddr)); wsa_assert (rc != SOCKET_ERROR); BOOL tcp_nodelay = 1; rc = setsockopt (listener, IPPROTO_TCP, TCP_NODELAY, (char *)&tcp_nodelay, sizeof (tcp_nodelay)); wsa_assert (rc != SOCKET_ERROR); // Init sockaddr to signaler port. struct sockaddr_in addr; memset (&addr, 0, sizeof (addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); addr.sin_port = htons (signaler_port); // Create the writer socket. *w_ = open_socket (AF_INET, SOCK_STREAM, 0); wsa_assert (*w_ != INVALID_SOCKET); // Set TCP_NODELAY on writer socket. rc = setsockopt (*w_, IPPROTO_TCP, TCP_NODELAY, (char *)&tcp_nodelay, sizeof (tcp_nodelay)); wsa_assert (rc != SOCKET_ERROR); if (sync != NULL) { // Enter the critical section. DWORD dwrc = WaitForSingleObject (sync, INFINITE); zmq_assert (dwrc == WAIT_OBJECT_0 || dwrc == WAIT_ABANDONED); } // Bind listening socket to signaler port. rc = bind (listener, (const struct sockaddr*) &addr, sizeof (addr)); if (rc != SOCKET_ERROR && signaler_port == 0) { // Retrieve ephemeral port number int addrlen = sizeof (addr); rc = getsockname (listener, (struct sockaddr*) &addr, &addrlen); } // Listen for incoming connections. if (rc != SOCKET_ERROR) rc = listen (listener, 1); // Connect writer to the listener. if (rc != SOCKET_ERROR) rc = connect (*w_, (struct sockaddr*) &addr, sizeof (addr)); // Accept connection from writer. if (rc != SOCKET_ERROR) *r_ = accept (listener, NULL, NULL); // Save errno if error occurred in bind/listen/connect/accept. int saved_errno = 0; if (*r_ == INVALID_SOCKET) saved_errno = WSAGetLastError (); // We don't need the listening socket anymore. Close it. closesocket (listener); if (sync != NULL) { // Exit the critical section. BOOL brc; if (signaler_port == event_signaler_port) brc = SetEvent (sync); else brc = ReleaseMutex (sync); win_assert (brc != 0); // Release the kernel object brc = CloseHandle (sync); win_assert (brc != 0); } if (*r_ != INVALID_SOCKET) { # if !defined _WIN32_WCE // On Windows, preventing sockets to be inherited by child processes. BOOL brc = SetHandleInformation ((HANDLE) *r_, HANDLE_FLAG_INHERIT, 0); win_assert (brc); # endif return 0; } else { // Cleanup writer if connection failed if (*w_ != INVALID_SOCKET) { rc = closesocket (*w_); wsa_assert (rc != SOCKET_ERROR); *w_ = INVALID_SOCKET; } // Set errno from saved value errno = wsa_error_to_errno (saved_errno); return -1; } #elif defined ZMQ_HAVE_OPENVMS // Whilst OpenVMS supports socketpair - it maps to AF_INET only. Further, // it does not set the socket options TCP_NODELAY and TCP_NODELACK which // can lead to performance problems. // // The bug will be fixed in V5.6 ECO4 and beyond. In the meantime, we'll // create the socket pair manually. struct sockaddr_in lcladdr; memset (&lcladdr, 0, sizeof (lcladdr)); lcladdr.sin_family = AF_INET; lcladdr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); lcladdr.sin_port = 0; int listener = open_socket (AF_INET, SOCK_STREAM, 0); errno_assert (listener != -1); int on = 1; int rc = setsockopt (listener, IPPROTO_TCP, TCP_NODELAY, &on, sizeof (on)); errno_assert (rc != -1); rc = setsockopt (listener, IPPROTO_TCP, TCP_NODELACK, &on, sizeof (on)); errno_assert (rc != -1); rc = bind (listener, (struct sockaddr*) &lcladdr, sizeof (lcladdr)); errno_assert (rc != -1); socklen_t lcladdr_len = sizeof (lcladdr); rc = getsockname (listener, (struct sockaddr*) &lcladdr, &lcladdr_len); errno_assert (rc != -1); rc = listen (listener, 1); errno_assert (rc != -1); *w_ = open_socket (AF_INET, SOCK_STREAM, 0); errno_assert (*w_ != -1); rc = setsockopt (*w_, IPPROTO_TCP, TCP_NODELAY, &on, sizeof (on)); errno_assert (rc != -1); rc = setsockopt (*w_, IPPROTO_TCP, TCP_NODELACK, &on, sizeof (on)); errno_assert (rc != -1); rc = connect (*w_, (struct sockaddr*) &lcladdr, sizeof (lcladdr)); errno_assert (rc != -1); *r_ = accept (listener, NULL, NULL); errno_assert (*r_ != -1); close (listener); return 0; #else // All other implementations support socketpair() int sv [2]; int rc = socketpair (AF_UNIX, SOCK_STREAM, 0, sv); if (rc == -1) { errno_assert (errno == ENFILE || errno == EMFILE); *w_ = *r_ = -1; return -1; } else { *w_ = sv [0]; *r_ = sv [1]; return 0; } #endif }
int zmq::tcp_connecter_t::open () { zmq_assert (s == retired_fd); // Resolve the address if (addr->resolved.tcp_addr != NULL) { LIBZMQ_DELETE (addr->resolved.tcp_addr); } addr->resolved.tcp_addr = new (std::nothrow) tcp_address_t (); alloc_assert (addr->resolved.tcp_addr); int rc = addr->resolved.tcp_addr->resolve (addr->address.c_str (), false, options.ipv6); if (rc != 0) { LIBZMQ_DELETE (addr->resolved.tcp_addr); return -1; } zmq_assert (addr->resolved.tcp_addr != NULL); tcp_address_t *const tcp_addr = addr->resolved.tcp_addr; // Create the socket. s = open_socket (tcp_addr->family (), SOCK_STREAM, IPPROTO_TCP); // IPv6 address family not supported, try automatic downgrade to IPv4. if (s == zmq::retired_fd && tcp_addr->family () == AF_INET6 && errno == EAFNOSUPPORT && options.ipv6) { rc = addr->resolved.tcp_addr->resolve (addr->address.c_str (), false, false); if (rc != 0) { LIBZMQ_DELETE (addr->resolved.tcp_addr); return -1; } s = open_socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); } #ifdef ZMQ_HAVE_WINDOWS if (s == INVALID_SOCKET) { errno = wsa_error_to_errno (WSAGetLastError ()); return -1; } #else if (s == -1) return -1; #endif // On some systems, IPv4 mapping in IPv6 sockets is disabled by default. // Switch it on in such cases. if (tcp_addr->family () == AF_INET6) enable_ipv4_mapping (s); // Set the IP Type-Of-Service priority for this socket if (options.tos != 0) set_ip_type_of_service (s, options.tos); // Bind the socket to a device if applicable if (!options.bound_device.empty ()) bind_to_device (s, options.bound_device); // Set the socket to non-blocking mode so that we get async connect(). unblock_socket (s); // Set the socket to loopback fastpath if configured. if (options.loopback_fastpath) tcp_tune_loopback_fast_path (s); // Set the socket buffer limits for the underlying socket. if (options.sndbuf >= 0) set_tcp_send_buffer (s, options.sndbuf); if (options.rcvbuf >= 0) set_tcp_receive_buffer (s, options.rcvbuf); // Set the IP Type-Of-Service for the underlying socket if (options.tos != 0) set_ip_type_of_service (s, options.tos); // Set a source address for conversations if (tcp_addr->has_src_addr ()) { // Allow reusing of the address, to connect to different servers // using the same source port on the client. int flag = 1; #ifdef ZMQ_HAVE_WINDOWS rc = setsockopt (s, SOL_SOCKET, SO_REUSEADDR, (const char *) &flag, sizeof (int)); wsa_assert (rc != SOCKET_ERROR); #else rc = setsockopt (s, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof (int)); errno_assert (rc == 0); #endif rc = ::bind (s, tcp_addr->src_addr (), tcp_addr->src_addrlen ()); if (rc == -1) return -1; } // Connect to the remote peer. rc = ::connect (s, tcp_addr->addr (), tcp_addr->addrlen ()); // Connect was successful immediately. if (rc == 0) { return 0; } // Translate error codes indicating asynchronous connect has been // launched to a uniform EINPROGRESS. #ifdef ZMQ_HAVE_WINDOWS const int last_error = WSAGetLastError (); if (last_error == WSAEINPROGRESS || last_error == WSAEWOULDBLOCK) errno = EINPROGRESS; else errno = wsa_error_to_errno (last_error); #else if (errno == EINTR) errno = EINPROGRESS; #endif return -1; }