Exemplo n.º 1
0
int ssh_socket_get_poll_flags(ssh_socket s) {
  int r = 0;
  if (s->poll_in != NULL && (ssh_poll_get_events (s->poll_in) & POLLIN) > 0) {
    r |= SSH_READ_PENDING;
  }
  if (s->poll_out != NULL && (ssh_poll_get_events (s->poll_out) & POLLOUT) > 0) {
    r |= SSH_WRITE_PENDING;
  }
  return r;
}
Exemplo n.º 2
0
/** \internal
 * \brief writes len bytes from buffer to socket
 */
static int ssh_socket_unbuffered_write(ssh_socket s, const void *buffer,
    uint32_t len) {
  int w = -1;

  if (s->data_except) {
    return -1;
  }
  if (s->fd_is_socket)
    w = send(s->fd_out,buffer, len, 0);
  else
    w = write(s->fd_out, buffer, len);
#ifdef _WIN32
  s->last_errno = WSAGetLastError();
#else
  s->last_errno = errno;
#endif
  s->write_wontblock = 0;
  /* Reactive the POLLOUT detector in the poll multiplexer system */
  if(s->poll_out){
      SSH_LOG(SSH_LOG_PACKET, "Enabling POLLOUT for socket");
  	ssh_poll_set_events(s->poll_out,ssh_poll_get_events(s->poll_out) | POLLOUT);
  }
  if (w < 0) {
    s->data_except = 1;
  }

  return w;
}
Exemplo n.º 3
0
/** \internal
 * \brief writes len bytes from buffer to socket
 */
static ssize_t ssh_socket_unbuffered_write(ssh_socket s,
                                           const void *buffer,
                                           uint32_t len)
{
    ssize_t w = -1;
    int flags = 0;

#ifdef MSG_NOSIGNAL
    flags |= MSG_NOSIGNAL;
#endif

    if (s->data_except) {
        return -1;
    }

    if (s->fd_is_socket) {
        w = send(s->fd, buffer, len, flags);
    } else {
        w = write(s->fd, buffer, len);
    }
#ifdef _WIN32
    s->last_errno = WSAGetLastError();
#else
    s->last_errno = errno;
#endif
    s->write_wontblock = 0;
    /* Reactive the POLLOUT detector in the poll multiplexer system */
    if (s->poll_handle) {
        SSH_LOG(SSH_LOG_PACKET, "Enabling POLLOUT for socket");
        ssh_poll_set_events(s->poll_handle,ssh_poll_get_events(s->poll_handle) | POLLOUT);
    }
    if (w < 0) {
        s->data_except = 1;
    }

    return w;
}
Exemplo n.º 4
0
/**
 * @brief  Remove events from a poll object. Non-existent are ignored.
 *         The events will also be propagated to an associated poll context.
 *
 * @param  p            Pointer to an already allocated poll object.
 * @param  events       Poll events.
 */
void ssh_poll_remove_events(ssh_poll_handle p, short events) {
    ssh_poll_set_events(p, ssh_poll_get_events(p) & ~events);
}
Exemplo n.º 5
0
/**
 * @brief  Add extra events to a poll object. Duplicates are ignored.
 *         The events will also be propagated to an associated poll context.
 *
 * @param  p            Pointer to an already allocated poll object.
 * @param  events       Poll events.
 */
void ssh_poll_add_events(ssh_poll_handle p, short events) {
    ssh_poll_set_events(p, ssh_poll_get_events(p) | events);
}
Exemplo n.º 6
0
/**
 * @brief 							SSH poll callback. This callback will be used when an event
 *                      caught on the socket.
 *
 * @param p             Poll object this callback belongs to.
 * @param fd            The raw socket.
 * @param revents       The current poll events on the socket.
 * @param userdata      Userdata to be passed to the callback function,
 *                      in this case the socket object.
 *
 * @return              0 on success, < 0 when the poll object has been removed
 *                      from its poll context.
 */
int ssh_socket_pollcallback(struct ssh_poll_handle_struct *p, socket_t fd, int revents, void *v_s){
	ssh_socket s=(ssh_socket )v_s;
	char buffer[4096];
	int r;
	int err=0;
	socklen_t errlen=sizeof(err);
	/* Do not do anything if this socket was already closed */
	if(!ssh_socket_is_open(s)){
	  return -1;
	}
	if(revents & POLLERR){
		/* Check if we are in a connecting state */
		if(s->state==SSH_SOCKET_CONNECTING){
			s->state=SSH_SOCKET_ERROR;
			getsockopt(fd,SOL_SOCKET,SO_ERROR,(void *)&err,&errlen);
			s->last_errno=err;
			ssh_socket_close(s);
			if(s->callbacks && s->callbacks->connected)
				s->callbacks->connected(SSH_SOCKET_CONNECTED_ERROR,err,
						s->callbacks->userdata);
			return -1;
		}
		/* Then we are in a more standard kind of error */
		/* force a read to get an explanation */
		revents |= POLLIN;
	}
	if(revents & POLLIN){
		s->read_wontblock=1;
		r=ssh_socket_unbuffered_read(s,buffer,sizeof(buffer));
		if(r<0){
		  if(p != NULL)
				ssh_poll_set_events(p,ssh_poll_get_events(p) & ~POLLIN);
			if(s->callbacks && s->callbacks->exception){
				s->callbacks->exception(
						SSH_SOCKET_EXCEPTION_ERROR,
						s->last_errno,s->callbacks->userdata);
			}
		}
		if(r==0){
			ssh_poll_set_events(p,ssh_poll_get_events(p) & ~POLLIN);
			if(s->callbacks && s->callbacks->exception){
				s->callbacks->exception(
						SSH_SOCKET_EXCEPTION_EOF,
						0,s->callbacks->userdata);
			}
		}
		if(r>0){
			/* Bufferize the data and then call the callback */
			buffer_add_data(s->in_buffer,buffer,r);
			if(s->callbacks && s->callbacks->data){
				r= s->callbacks->data(buffer_get_rest(s->in_buffer),
						buffer_get_rest_len(s->in_buffer),
						s->callbacks->userdata);
				buffer_pass_bytes(s->in_buffer,r);
			}
		}
	}
#ifdef _WIN32
	if(revents & POLLOUT || revents & POLLWRNORM){
#else
	if(revents & POLLOUT){
#endif
		/* First, POLLOUT is a sign we may be connected */
		if(s->state == SSH_SOCKET_CONNECTING){
			ssh_log(s->session,SSH_LOG_PACKET,"Received POLLOUT in connecting state");
			s->state = SSH_SOCKET_CONNECTED;
			ssh_poll_set_events(p,POLLOUT | POLLIN | POLLERR);
			ssh_sock_set_blocking(ssh_socket_get_fd_in(s));
			if(s->callbacks && s->callbacks->connected)
				s->callbacks->connected(SSH_SOCKET_CONNECTED_OK,0,s->callbacks->userdata);
			return 0;
		}
		/* So, we can write data */
		s->write_wontblock=1;
    ssh_poll_remove_events(p,POLLOUT);

		/* If buffered data is pending, write it */
		if(buffer_get_rest_len(s->out_buffer) > 0){
		  ssh_socket_nonblocking_flush(s);
		} else if(s->callbacks && s->callbacks->controlflow){
			/* Otherwise advertise the upper level that write can be done */
			s->callbacks->controlflow(SSH_SOCKET_FLOW_WRITEWONTBLOCK,s->callbacks->userdata);
		}
			/* TODO: Find a way to put back POLLOUT when buffering occurs */
	}
	/* Return -1 if one of the poll handlers disappeared */
	return (s->poll_in == NULL || s->poll_out == NULL) ? -1 : 0;
}

/** @internal
 * @brief returns the input poll handle corresponding to the socket,
 * creates it if it does not exist.
 * @returns allocated and initialized ssh_poll_handle object
 */
ssh_poll_handle ssh_socket_get_poll_handle_in(ssh_socket s){
	if(s->poll_in)
		return s->poll_in;
	s->poll_in=ssh_poll_new(s->fd_in,0,ssh_socket_pollcallback,s);
	if(s->fd_in == s->fd_out && s->poll_out == NULL)
    s->poll_out=s->poll_in;
	return s->poll_in;
}

/** @internal
 * @brief returns the output poll handle corresponding to the socket,
 * creates it if it does not exist.
 * @returns allocated and initialized ssh_poll_handle object
 */
ssh_poll_handle ssh_socket_get_poll_handle_out(ssh_socket s){
  if(s->poll_out)
    return s->poll_out;
  s->poll_out=ssh_poll_new(s->fd_out,0,ssh_socket_pollcallback,s);
  if(s->fd_in == s->fd_out && s->poll_in == NULL)
    s->poll_in=s->poll_out;
  return s->poll_out;
}

/** \internal
 * \brief Deletes a socket object
 */
void ssh_socket_free(ssh_socket s){
  if (s == NULL) {
    return;
  }
  ssh_socket_close(s);
  ssh_buffer_free(s->in_buffer);
  ssh_buffer_free(s->out_buffer);
  SAFE_FREE(s);
}

#ifndef _WIN32
int ssh_socket_unix(ssh_socket s, const char *path) {
  struct sockaddr_un sunaddr;
  socket_t fd;
  sunaddr.sun_family = AF_UNIX;
  snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path), "%s", path);

  fd = socket(AF_UNIX, SOCK_STREAM, 0);
  if (fd == SSH_INVALID_SOCKET) {
    ssh_set_error(s->session, SSH_FATAL,
		    "Error from socket(AF_UNIX, SOCK_STREAM, 0): %s",
		    strerror(errno));
    return -1;
  }

  if (fcntl(fd, F_SETFD, 1) == -1) {
    ssh_set_error(s->session, SSH_FATAL,
		    "Error from fcntl(fd, F_SETFD, 1): %s",
		    strerror(errno));
    close(fd);
    return -1;
  }

  if (connect(fd, (struct sockaddr *) &sunaddr,
        sizeof(sunaddr)) < 0) {
    ssh_set_error(s->session, SSH_FATAL, "Error from connect(): %s",
		    strerror(errno));
    close(fd);
    return -1;
  }
  ssh_socket_set_fd(s,fd);
  return 0;
}
#endif

/** \internal
 * \brief closes a socket
 */
void ssh_socket_close(ssh_socket s){
  if (ssh_socket_is_open(s)) {
#ifdef _WIN32
    closesocket(s->fd_in);
    /* fd_in = fd_out under win32 */
    s->last_errno = WSAGetLastError();
#else
    close(s->fd_in);
    if(s->fd_out != s->fd_in && s->fd_out != -1)
      close(s->fd_out);
    s->last_errno = errno;
#endif
    s->fd_in = s->fd_out = SSH_INVALID_SOCKET;
  }
  if(s->poll_in != NULL){
    if(s->poll_out == s->poll_in)
      s->poll_out = NULL;
    ssh_poll_free(s->poll_in);
    s->poll_in=NULL;
  }
  if(s->poll_out != NULL){
    ssh_poll_free(s->poll_out);
    s->poll_out=NULL;
  }
#ifndef _WIN32
  /* kill proxycommand child process */
  if (s->proxycommand_pid > 0){
    if (kill(s->proxycommand_pid, SIGTERM) == 0){
      s->proxycommand_pid = 0;
    }
  }
#endif
}

/**
 * @internal
 * @brief sets the file descriptor of the socket.
 * @param[out] s ssh_socket to update
 * @param[in] fd file descriptor to set
 * @warning this function updates boths the input and output
 * file descriptors
 */
void ssh_socket_set_fd(ssh_socket s, socket_t fd) {
  s->fd_in = s->fd_out = fd;
  if(s->poll_in)
  	ssh_poll_set_fd(s->poll_in,fd);
}