void
SharedPortEndpoint::RemoveListenerFromSelector(Selector &selector)
{
#ifdef WIN32
	if(!wake_select_dest)
		EXCEPT("SharedPortEndpoint: RemoveListenerFromSelector: Nothing registered.");
	selector.delete_fd(wake_select_dest->get_file_desc(), Selector::IO_READ);
#else
	selector.delete_fd(m_listener_sock.get_file_desc(),Selector::IO_READ);
#endif
}
Example #2
0
int
condor_write( char const *peer_description, SOCKET fd, const char *buf, int sz, int timeout, int flags, bool non_blocking )
{
	int nw = 0, nwo = 0;
	unsigned int start_time = 0, cur_time = 0;
	char tmpbuf[1];
	int nro;
	bool select_for_read = true;
	bool needs_select = true;
	char sinbuf[SINFUL_STRING_BUF_SIZE];

	if( IsDebugLevel( D_NETWORK ) ) {
		dprintf(D_NETWORK,
				"condor_write(fd=%d %s,,size=%d,timeout=%d,flags=%d,non_blocking=%d)\n",
				fd,
				not_null_peer_description(peer_description,fd,sinbuf),
				sz,
				timeout,
				flags,
				non_blocking);
	}

	/* Pre-conditions. */
	ASSERT(sz > 0);      /* Can't write buffers that are have no data */
	ASSERT(fd >= 0);     /* Need valid file descriptor */
	ASSERT(buf != NULL); /* Need valid buffer to write */

	if (non_blocking) {
#ifdef WIN32
		unsigned long mode = 1; // nonblocking mode
		if (ioctlsocket(fd, FIONBIO, &mode) < 0)
			return -1;
#else
		int fcntl_flags;
		if ( (fcntl_flags=fcntl(fd, F_GETFL)) < 0 )
			return -1;
			// set nonblocking mode
		if ( ((fcntl_flags & O_NONBLOCK) == 0) && fcntl(fd, F_SETFL, fcntl_flags | O_NONBLOCK) == -1 )
			return -1;
#endif
		nw = -2;
		while (nw == -2 || (nw == -1 && errno == EINTR)) {
			nw = send(fd, buf, sz, flags);
		}

		if ( nw <= 0 ) {
			int the_error;
			char const *the_errorstr;
#ifdef WIN32
			the_error = WSAGetLastError();
			the_errorstr = "";
#else
			the_error = errno;
			the_errorstr = strerror(the_error);
#endif
			if ( !errno_is_temporary(the_error) ) {
				dprintf( D_ALWAYS, "condor_write() failed: send() %d bytes to %s "
					"returned %d, "     
					"timeout=%d, errno=%d %s.\n",
					sz,                 
					not_null_peer_description(peer_description,fd,sinbuf),
					nw, timeout, the_error, the_errorstr );
			}
			else
			{
				nw = 0;
			}
		}
		if (nw < 0) {
			dprintf(D_NETWORK, "condor_write (non-blocking) wrote %d bytes.\n", nw);
		}       

#ifdef WIN32
		mode = 0; // reset blocking mode
		if (ioctlsocket(fd, FIONBIO, &mode) < 0)
			return -1;
#else
			// reset flags to prior value
		if ( ((fcntl_flags & O_NONBLOCK) == 0) && fcntl(fd, F_SETFL, fcntl_flags) == -1 )
			return -1;
#endif
		return nw;
	}

	Selector selector;
	selector.add_fd( fd, Selector::IO_READ );
	selector.add_fd( fd, Selector::IO_WRITE );
	selector.add_fd( fd, Selector::IO_EXCEPT );
	
	if(timeout > 0) {
		start_time = time(NULL);
		cur_time = start_time;
	}

	while( nw < sz ) {

		needs_select = true;

		if( timeout > 0 ) {
			while( needs_select ) {
				if( cur_time == 0 ) {
					cur_time = time(NULL);
				}

				if( start_time + timeout > cur_time ) {
					selector.set_timeout( (start_time + timeout) - cur_time );
				} else {
					dprintf( D_ALWAYS, "condor_write(): "
							 "timed out writing %d bytes to %s\n",
							 sz,
							 not_null_peer_description(peer_description,fd,sinbuf) );
					return -1;
				}
			
				cur_time = 0;

					// The write and except sets are added at the top of
					// this function, since we always want to select on
					// them.
				if( select_for_read ) {
						// Also, put it in the read fds, so we'll wake
						// up if the socket is closed
					selector.add_fd( fd, Selector::IO_READ );
				} else {
					selector.delete_fd( fd, Selector::IO_READ );
				}
				selector.execute();

					// unless we decide we need to select() again, we
					// want to break out of our while() loop now that
					// we've actually performed a select()
				needs_select = false;

				if ( selector.timed_out() ) {
					dprintf( D_ALWAYS, "condor_write(): "
							 "timed out writing %d bytes to %s\n",
							 sz,
							 not_null_peer_description(peer_description,fd,sinbuf) );
					return -1;
				
				} else if ( selector.signalled() ) {
					needs_select = true;
					continue;
				} else if ( selector.has_ready() ) {
					if ( selector.fd_ready( fd, Selector::IO_READ ) ) {
						dprintf(D_NETWORK, "condor_write(): socket %d is readable\n", fd);
							// see if the socket was closed
						nro = recv(fd, tmpbuf, 1, MSG_PEEK);
						if( nro == -1 ) {
							int the_error;
                            char const *the_errorstr;
#ifdef WIN32
							the_error = WSAGetLastError();
                            the_errorstr = "";
#else
							the_error = errno;
                            the_errorstr = strerror(the_error);
#endif
							if(errno_is_temporary( the_error )) {
								continue;
							}

							dprintf( D_ALWAYS, "condor_write(): "
									 "Socket closed when trying "
									 "to write %d bytes to %s, fd is %d, "
									 "errno=%d %s\n",
									 sz,
									 not_null_peer_description(peer_description,fd,sinbuf),
									 fd, the_error, the_errorstr );
							return -1;
						}

						if( ! nro ) {
							dprintf( D_ALWAYS, "condor_write(): "
									 "Socket closed when trying "
									 "to write %d bytes to %s, fd is %d\n",
									 sz,
									 not_null_peer_description(peer_description,fd,sinbuf),
									 fd );
							return -1;
						}

							/*
							  otherwise, there's real data to consume
							  on the read side, and we don't want to
							  put our fd in the readfds anymore or
							  select() will never block.  also, we
							  need to re-do the select()
							*/
						needs_select = true;
						select_for_read = false;
					}
				} else {
					dprintf( D_ALWAYS, "condor_write() failed: select() "
							 "returns %d, "
							 "writing %d bytes to %s.\n",
							 selector.select_retval(),
							 sz,
							 not_null_peer_description(peer_description,fd,sinbuf) );
					return -1;
				}
			}
		}
		start_thread_safe("send");

		nwo = send(fd, &buf[nw], sz - nw, flags);
		// Save the error value before stop_thread_safe(), as that may
		// overwrite it.
		int the_error;
#ifdef WIN32
		the_error = WSAGetLastError();
#else
		the_error = errno;
#endif

		stop_thread_safe("send");		

		if( nwo <= 0 ) {
            char const *the_errorstr;
#ifdef WIN32
            the_errorstr = "";
#else
            the_errorstr = strerror(the_error);
#endif
			if ( errno_is_temporary(the_error) ) {
				dprintf( D_FULLDEBUG, "condor_write(): "
				         "send() returned temporary error %d %s,"
						 "still trying to write %d bytes to %s\n", the_error,
						 the_errorstr, sz,
						 not_null_peer_description(peer_description,fd,sinbuf) );
				continue;
			}

			dprintf( D_ALWAYS, "condor_write() failed: send() %d bytes to %s "
					 "returned %d, "
					 "timeout=%d, errno=%d %s.\n",
					 sz,
					 not_null_peer_description(peer_description,fd,sinbuf),
					 nwo, timeout, the_error, the_errorstr );

			return -1;
		}
		
		nw += nwo;
	}

	/* POST conditions. */
	ASSERT( nw == sz ); /* Make sure that we wrote everything */
	return nw;
}