2
* socket.c - socket functions for the library
4
* This file is part of the SSH Library
6
* Copyright (c) 2008 by Aris Adamantiadis
8
* The SSH Library is free software; you can redistribute it and/or modify
9
* it under the terms of the GNU Lesser General Public License as published by
10
* the Free Software Foundation; either version 2.1 of the License, or (at your
11
* option) any later version.
13
* The SSH Library is distributed in the hope that it will be useful, but
14
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
16
* License for more details.
18
* You should have received a copy of the GNU Lesser General Public License
19
* along with the SSH Library; see the file COPYING. If not, write to
20
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
33
#include <sys/types.h>
34
#include <sys/socket.h>
36
extern char **environ;
38
#include "libssh/priv.h"
39
#include "libssh/socket.h"
40
#include "libssh/buffer.h"
41
#include "libssh/poll.h"
42
#include "libssh/session.h"
45
/** \defgroup ssh_socket SSH Sockets
46
* \addtogroup ssh_socket
53
int data_to_read; /* reading now on socket will
57
ssh_buffer out_buffer;
64
* \brief inits the socket system (windows specific)
66
int ssh_socket_init(void) {
68
struct WSAData wsaData;
70
/* Initiates use of the Winsock DLL by a process. */
71
if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) {
82
* \brief creates a new Socket object
84
struct socket *ssh_socket_new(ssh_session session) {
87
s = malloc(sizeof(struct socket));
91
s->fd = SSH_INVALID_SOCKET;
94
s->in_buffer = buffer_new();
95
if (s->in_buffer == NULL) {
99
s->out_buffer=buffer_new();
100
if (s->out_buffer == NULL) {
101
buffer_free(s->in_buffer);
106
s->data_to_write = 0;
113
* \brief Deletes a socket object
115
void ssh_socket_free(struct socket *s){
120
buffer_free(s->in_buffer);
121
buffer_free(s->out_buffer);
126
int ssh_socket_unix(struct socket *s, const char *path) {
127
struct sockaddr_un sunaddr;
129
sunaddr.sun_family = AF_UNIX;
130
snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path), "%s", path);
132
s->fd = socket(AF_UNIX, SOCK_STREAM, 0);
133
if (s->fd == SSH_INVALID_SOCKET) {
137
if (fcntl(s->fd, F_SETFD, 1) == -1) {
139
s->fd = SSH_INVALID_SOCKET;
143
if (connect(s->fd, (struct sockaddr *) &sunaddr,
144
sizeof(sunaddr)) < 0) {
146
s->fd = SSH_INVALID_SOCKET;
155
* \brief closes a socket
157
void ssh_socket_close(struct socket *s){
158
if (ssh_socket_is_open(s)) {
161
s->last_errno = WSAGetLastError();
164
s->last_errno = errno;
166
s->fd = SSH_INVALID_SOCKET;
171
* \brief sets the file descriptor of the socket
173
void ssh_socket_set_fd(struct socket *s, socket_t fd) {
178
* \brief returns the file descriptor of the socket
180
socket_t ssh_socket_get_fd(struct socket *s) {
185
* \brief returns nonzero if the socket is open
187
int ssh_socket_is_open(struct socket *s) {
188
return s->fd != SSH_INVALID_SOCKET;
192
* \brief read len bytes from socket into buffer
194
static int ssh_socket_unbuffered_read(struct socket *s, void *buffer, uint32_t len) {
197
if (s->data_except) {
201
rc = recv(s->fd,buffer, len, 0);
203
s->last_errno = WSAGetLastError();
205
s->last_errno = errno;
217
* \brief writes len bytes from buffer to socket
219
static int ssh_socket_unbuffered_write(struct socket *s, const void *buffer,
223
if (s->data_except) {
227
w = send(s->fd,buffer, len, 0);
229
s->last_errno = WSAGetLastError();
231
s->last_errno = errno;
233
s->data_to_write = 0;
243
* \brief returns nonzero if the current socket is in the fd_set
245
int ssh_socket_fd_isset(struct socket *s, fd_set *set) {
246
if(s->fd == SSH_INVALID_SOCKET) {
249
return FD_ISSET(s->fd,set);
253
* \brief sets the current fd in a fd_set and updates the max_fd
256
void ssh_socket_fd_set(struct socket *s, fd_set *set, socket_t *max_fd) {
257
if (s->fd == SSH_INVALID_SOCKET)
263
s->fd != SSH_INVALID_SOCKET) {
269
* \brief reads blocking until len bytes have been read
271
int ssh_socket_completeread(struct socket *s, void *buffer, uint32_t len) {
274
uint32_t toread = len;
275
if(! ssh_socket_is_open(s)) {
279
while((r = ssh_socket_unbuffered_read(s, ((uint8_t*)buffer + total), toread))) {
293
/* connection closed */
298
* \brief Blocking write of len bytes
300
int ssh_socket_completewrite(struct socket *s, const void *buffer, uint32_t len) {
301
ssh_session session = s->session;
306
if(! ssh_socket_is_open(s)) {
312
written = ssh_socket_unbuffered_write(s, buffer, len);
313
if (written == 0 || written == -1) {
318
buffer = ((uint8_t*)buffer + written);
326
* \brief buffered read of data (complete)
327
* \returns SSH_OK or SSH_ERROR.
328
* \returns SSH_AGAIN in nonblocking mode
330
int ssh_socket_read(struct socket *s, void *buffer, int len){
331
ssh_session session = s->session;
336
rc = ssh_socket_wait_for_data(s, s->session, len);
342
memcpy(buffer, buffer_get_rest(s->in_buffer), len);
343
buffer_pass_bytes(s->in_buffer, len);
349
#define WRITE_BUFFERING_THRESHOLD 65536
351
* \brief buffered write of data
352
* \returns SSH_OK, or SSH_ERROR
353
* \warning has no effect on socket before a flush
355
int ssh_socket_write(struct socket *s, const void *buffer, int len) {
356
ssh_session session = s->session;
361
if (buffer_add_data(s->out_buffer, buffer, len) < 0) {
365
if (buffer_get_rest_len(s->out_buffer) > WRITE_BUFFERING_THRESHOLD) {
366
rc = ssh_socket_nonblocking_flush(s);
377
* \brief wait for data on socket
379
* \param session the ssh session
380
* \param len number of bytes to be read
381
* \returns SSH_OK bytes are available on socket
382
* \returns SSH_AGAIN need to call later for data
383
* \returns SSH_ERROR error happened
385
int ssh_socket_wait_for_data(struct socket *s, ssh_session session, uint32_t len) {
386
char buffer[4096] = {0};
395
to_read = len - buffer_get_rest_len(s->in_buffer);
402
if (session->blocking) {
403
buf = malloc(to_read);
409
r = ssh_socket_completeread(session->socket,buf,to_read);
410
if (r == SSH_ERROR || r == 0) {
411
ssh_set_error(session, SSH_FATAL,
412
(r == 0) ? "Connection closed by remote host" :
413
"Error reading socket");
414
ssh_socket_close(session->socket);
422
if (buffer_add_data(s->in_buffer,buf,to_read) < 0) {
434
/* nonblocking read */
436
/* internally sets data_to_read */
437
r = ssh_socket_poll(s, &can_write, &except);
438
if (r < 0 || !s->data_to_read) {
443
/* read as much as we can */
444
if (ssh_socket_is_open(session->socket)) {
445
r = ssh_socket_unbuffered_read(session->socket, buffer, sizeof(buffer));
451
ssh_set_error(session, SSH_FATAL,
452
(r == 0) ? "Connection closed by remote host" :
453
"Error reading socket");
454
ssh_socket_close(session->socket);
461
if (buffer_add_data(s->in_buffer,buffer, (uint32_t) r) < 0) {
465
} while(buffer_get_rest_len(s->in_buffer) < len);
471
/* ssh_socket_poll */
472
int ssh_socket_poll(struct socket *s, int *writeable, int *except) {
473
ssh_session session = s->session;
479
if (!ssh_socket_is_open(s)) {
488
if (!s->data_to_read) {
489
fd->events |= POLLIN;
491
if (!s->data_to_write) {
492
fd->events |= POLLOUT;
494
/* do not do poll if fd->events is empty, we already know the response */
496
/* Make the call, and listen for errors */
497
rc = ssh_poll(fd, 1, 0);
499
ssh_set_error(session, SSH_FATAL, "poll(): %s", strerror(errno));
505
if (!s->data_to_read) {
506
s->data_to_read = fd->revents & POLLIN;
508
if (!s->data_to_write) {
509
s->data_to_write = fd->revents & POLLOUT;
511
if (!s->data_except) {
512
s->data_except = fd->revents & POLLERR;
515
*except = s->data_except;
516
*writeable = s->data_to_write;
519
return (s->data_to_read || (buffer_get_rest_len(s->in_buffer) > 0));
523
* \brief nonblocking flush of the output buffer
525
int ssh_socket_nonblocking_flush(struct socket *s) {
526
ssh_session session = s->session;
533
/* internally sets data_to_write */
534
if (ssh_socket_poll(s, &can_write, &except) < 0) {
539
if (!ssh_socket_is_open(s)) {
541
/* FIXME use ssh_socket_get_errno */
542
ssh_set_error(session, SSH_FATAL,
543
"Writing packet: error on socket (or connection closed): %s",
550
while(s->data_to_write && buffer_get_rest_len(s->out_buffer) > 0) {
551
if (ssh_socket_is_open(s)) {
552
w = ssh_socket_unbuffered_write(s, buffer_get_rest(s->out_buffer),
553
buffer_get_rest_len(s->out_buffer));
562
/* FIXME use ssh_socket_get_errno() */
563
ssh_set_error(session, SSH_FATAL,
564
"Writing packet: error on socket (or connection closed): %s",
571
buffer_pass_bytes(s->out_buffer, w);
572
/* refresh the socket status */
573
if (ssh_socket_poll(session->socket, &can_write, &except) < 0) {
579
/* Is there some data pending? */
580
if (buffer_get_rest_len(s->out_buffer) > 0) {
585
/* all data written */
592
* \brief locking flush of the output packet buffer
594
int ssh_socket_blocking_flush(struct socket *s) {
595
ssh_session session = s->session;
599
if (!ssh_socket_is_open(s)) {
606
if (s->data_except) {
611
if (buffer_get_rest_len(s->out_buffer) == 0) {
616
if (ssh_socket_completewrite(s, buffer_get_rest(s->out_buffer),
617
buffer_get_rest_len(s->out_buffer)) != SSH_OK) {
620
/* FIXME use the proper errno */
621
ssh_set_error(session, SSH_FATAL,
622
"Writing packet: error on socket (or connection closed): %s",
629
if (buffer_reinit(s->out_buffer) < 0) {
635
return SSH_OK; // no data pending
638
void ssh_socket_set_towrite(struct socket *s) {
639
s->data_to_write = 1;
642
void ssh_socket_set_toread(struct socket *s) {
646
void ssh_socket_set_except(struct socket *s) {
650
int ssh_socket_data_available(struct socket *s) {
651
return s->data_to_read;
654
int ssh_socket_data_writable(struct socket *s) {
655
return s->data_to_write;
658
int ssh_socket_get_status(struct socket *s) {
661
if (s->data_to_read) {
662
r |= SSH_READ_PENDING;
665
if (s->data_except) {
666
r |= SSH_CLOSED_ERROR;
675
* @brief executes a command and redirect input and outputs
676
* @param command command to execute
677
* @param in input file descriptor
678
* @param out output file descriptor
680
void ssh_execute_command(const char *command, socket_t in, socket_t out){
681
const char *args[]={"/bin/sh","-c",command,NULL};
682
/* redirect in and out to stdin, stdout and stderr */
688
execve(args[0],(char * const *)args,(char * const *)environ);
694
* @brief Open a socket on a ProxyCommand
695
* This call will always be nonblocking.
696
* @param s socket to connect.
697
* @param command Command to execute.
698
* @returns SSH_OK socket is being connected.
699
* @returns SSH_ERROR error while executing the command.
702
socket_t ssh_socket_connect_proxycommand(ssh_session session,
703
const char *command){
707
socketpair(AF_UNIX,SOCK_STREAM,0,fd);
710
ssh_execute_command(command,fd[1],fd[1]);
713
ssh_log(session,SSH_LOG_PROTOCOL,"ProxyCommand connection pipe: [%d,%d]",fd[0],fd[1]);
722
/* vim: set ts=2 sw=2 et cindent: */