|
|
@@ -104,8 +104,10 @@ struct ggs_req { |
|
|
|
TAILQ_ENTRY(ggs_req) r_next; |
|
|
|
}; |
|
|
|
|
|
|
|
static TAILQ_HEAD(ggs_reqqueue, ggs_req) procqueue = TAILQ_HEAD_INITIALIZER(procqueue); |
|
|
|
static TAILQ_HEAD(ggs_sessqueue, ggs_sess_cache) session_cache = TAILQ_HEAD_INITIALIZER(session_cache); |
|
|
|
static TAILQ_HEAD(ggs_reqqueue, ggs_req) procqueue = |
|
|
|
TAILQ_HEAD_INITIALIZER(procqueue); |
|
|
|
static TAILQ_HEAD(ggs_sessqueue, ggs_sess_cache) session_cache = |
|
|
|
TAILQ_HEAD_INITIALIZER(session_cache); |
|
|
|
static sem_t nconn_sem; |
|
|
|
static pthread_mutex_t procqueue_mtx; |
|
|
|
|
|
|
@@ -196,6 +198,22 @@ tcp_connect(const char *host, const char *service, int af) |
|
|
|
return sd; |
|
|
|
} |
|
|
|
|
|
|
|
static int |
|
|
|
get_open_flags() |
|
|
|
{ |
|
|
|
|
|
|
|
switch (flags) { |
|
|
|
case G_GATE_FLAG_READONLY: |
|
|
|
return LIBSSH2_FXF_READ; |
|
|
|
|
|
|
|
case G_GATE_FLAG_WRITEONLY: |
|
|
|
return LIBSSH2_FXF_WRITE; |
|
|
|
|
|
|
|
default: |
|
|
|
return LIBSSH2_FXF_READ|LIBSSH2_FXF_WRITE; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static struct ggs_connection |
|
|
|
make_connection(void) |
|
|
|
{ |
|
|
@@ -209,7 +227,8 @@ make_connection(void) |
|
|
|
sockfd = tcp_connect(hostname, sshport, 0); |
|
|
|
if (sockfd == -1) { |
|
|
|
if (errno == ENOENT) |
|
|
|
g_gate_xlog("tcp_connect: failed to lookup %s", hostname); |
|
|
|
g_gate_xlog("tcp_connect: failed to lookup %s", |
|
|
|
hostname); |
|
|
|
g_gate_xlog("tcp_connect: %s.", strerror(errno)); |
|
|
|
} |
|
|
|
|
|
|
@@ -218,11 +237,10 @@ make_connection(void) |
|
|
|
if (session == NULL) |
|
|
|
libssh2_errorx(session, "libssh2_session_init"); |
|
|
|
|
|
|
|
if (g_gate_verbose) { |
|
|
|
//libssh2_trace(session, LIBSSH2_TRACE_SOCKET|LIBSSH2_TRACE_TRANS|LIBSSH2_TRACE_KEX|LIBSSH2_TRACE_AUTH|LIBSSH2_TRACE_CONN|LIBSSH2_TRACE_SFTP|LIBSSH2_TRACE_ERROR|LIBSSH2_TRACE_PUBLICKEY); |
|
|
|
libssh2_trace(session, LIBSSH2_TRACE_SOCKET|LIBSSH2_TRACE_KEX|LIBSSH2_TRACE_AUTH|LIBSSH2_TRACE_CONN|LIBSSH2_TRACE_SFTP|LIBSSH2_TRACE_ERROR|LIBSSH2_TRACE_PUBLICKEY); |
|
|
|
//libssh2_trace(session, LIBSSH2_TRACE_KEX|LIBSSH2_TRACE_AUTH|LIBSSH2_TRACE_CONN|LIBSSH2_TRACE_SFTP|LIBSSH2_TRACE_ERROR|LIBSSH2_TRACE_PUBLICKEY); |
|
|
|
} |
|
|
|
if (g_gate_verbose) |
|
|
|
libssh2_trace(session, LIBSSH2_TRACE_SOCKET|LIBSSH2_TRACE_KEX| |
|
|
|
LIBSSH2_TRACE_AUTH|LIBSSH2_TRACE_CONN|LIBSSH2_TRACE_SFTP| |
|
|
|
LIBSSH2_TRACE_ERROR|LIBSSH2_TRACE_PUBLICKEY); |
|
|
|
|
|
|
|
/* XXX - libssh2_session_flag to enable compression */ |
|
|
|
|
|
|
@@ -247,7 +265,8 @@ make_connection(void) |
|
|
|
|
|
|
|
g_gate_log(LOG_DEBUG, "trying identity file: %s", identityfile); |
|
|
|
|
|
|
|
rc = libssh2_userauth_publickey_fromfile(session, username, pubkeyfile, identityfile, NULL); |
|
|
|
rc = libssh2_userauth_publickey_fromfile(session, username, pubkeyfile, |
|
|
|
identityfile, NULL); |
|
|
|
//rc = libssh2_userauth_password(session, "freebsd", "freebsd"); |
|
|
|
if (rc) { |
|
|
|
g_gate_log(LOG_ERR, "identity file: %s", identityfile); |
|
|
@@ -260,7 +279,7 @@ make_connection(void) |
|
|
|
if (sftp_session == NULL) |
|
|
|
g_gate_xlog("libssh2_sftp_init"); |
|
|
|
|
|
|
|
handle = libssh2_sftp_open(sftp_session, imgpath, LIBSSH2_FXF_READ|LIBSSH2_FXF_WRITE, 0); |
|
|
|
handle = libssh2_sftp_open(sftp_session, imgpath, get_open_flags(), 0); |
|
|
|
if (handle == NULL) { |
|
|
|
g_gate_log(LOG_ERR, "image file: %s", imgpath); |
|
|
|
libssh2_errorx(session, "libssh2_sftp_open"); |
|
|
@@ -291,7 +310,8 @@ mediachg(void *arg __unused) |
|
|
|
.gctl_mediasize = mediasize, |
|
|
|
}; |
|
|
|
g_gate_ioctl(G_GATE_CMD_MODIFY, &ggiom); |
|
|
|
g_gate_log(LOG_DEBUG, "updated ggate%d mediasize to %zd", unit, mediasize); |
|
|
|
g_gate_log(LOG_DEBUG, "updated ggate%d mediasize to %zd", unit, |
|
|
|
mediasize); |
|
|
|
|
|
|
|
return NULL; |
|
|
|
} |
|
|
@@ -407,7 +427,8 @@ req_thread(void *arg __unused) |
|
|
|
} |
|
|
|
|
|
|
|
static int |
|
|
|
process_pending(struct ggs_reqqueue *req_pending, struct ggs_sessqueue *sessqueue) |
|
|
|
process_pending(struct ggs_reqqueue *req_pending, |
|
|
|
struct ggs_sessqueue *sessqueue) |
|
|
|
{ |
|
|
|
struct ggs_req *greq, *greq2; |
|
|
|
char *errmsg; |
|
|
@@ -421,27 +442,40 @@ process_pending(struct ggs_reqqueue *req_pending, struct ggs_sessqueue *sessqueu |
|
|
|
again: |
|
|
|
switch (greq->r_ggio.gctl_cmd) { |
|
|
|
case BIO_READ: |
|
|
|
g_gate_log(LOG_DEBUG, "sftp_read(%p): %d(%d), rem: %d", greq, greq->r_ggio.gctl_offset, greq->r_ggio.gctl_length, greq->r_ggio.gctl_length - greq->r_bufoff); |
|
|
|
g_gate_log(LOG_DEBUG, "sftp_read(%p): %d(%d), rem: %d", |
|
|
|
greq, greq->r_ggio.gctl_offset, |
|
|
|
greq->r_ggio.gctl_length, |
|
|
|
greq->r_ggio.gctl_length - greq->r_bufoff); |
|
|
|
if (greq->r_didseek == 0) { |
|
|
|
libssh2_sftp_seek64(greq->r_handle, greq->r_ggio.gctl_offset); |
|
|
|
libssh2_sftp_seek64(greq->r_handle, |
|
|
|
greq->r_ggio.gctl_offset); |
|
|
|
greq->r_didseek = 1; |
|
|
|
} |
|
|
|
rc = libssh2_sftp_read(greq->r_handle, (char *)greq->r_ggio.gctl_data + greq->r_bufoff, greq->r_ggio.gctl_length - greq->r_bufoff); |
|
|
|
rc = libssh2_sftp_read(greq->r_handle, |
|
|
|
(char *)greq->r_ggio.gctl_data + greq->r_bufoff, |
|
|
|
greq->r_ggio.gctl_length - greq->r_bufoff); |
|
|
|
g_gate_log(LOG_DEBUG, "sftp_read ret: %d", rc); |
|
|
|
if (rc < 0 && rc != LIBSSH2_ERROR_EAGAIN) |
|
|
|
g_gate_log(LOG_ERR, "libssh2_sftp_read"); |
|
|
|
break; |
|
|
|
|
|
|
|
case BIO_WRITE: |
|
|
|
g_gate_log(LOG_DEBUG, "sftp_write(%p): %d(%d), rem: %d", greq, greq->r_ggio.gctl_offset, greq->r_ggio.gctl_length, greq->r_ggio.gctl_length - greq->r_bufoff); |
|
|
|
g_gate_log(LOG_DEBUG, "sftp_write(%p): %d(%d), rem: %d", |
|
|
|
greq, greq->r_ggio.gctl_offset, |
|
|
|
greq->r_ggio.gctl_length, |
|
|
|
greq->r_ggio.gctl_length - greq->r_bufoff); |
|
|
|
if (greq->r_didseek == 0) { |
|
|
|
libssh2_sftp_seek64(greq->r_handle, greq->r_ggio.gctl_offset); |
|
|
|
libssh2_sftp_seek64(greq->r_handle, |
|
|
|
greq->r_ggio.gctl_offset); |
|
|
|
greq->r_didseek = 1; |
|
|
|
} |
|
|
|
rc = libssh2_sftp_write(greq->r_handle, (char *)greq->r_ggio.gctl_data + greq->r_bufoff, greq->r_ggio.gctl_length - greq->r_bufoff); |
|
|
|
rc = libssh2_sftp_write(greq->r_handle, |
|
|
|
(char *)greq->r_ggio.gctl_data + greq->r_bufoff, |
|
|
|
greq->r_ggio.gctl_length - greq->r_bufoff); |
|
|
|
g_gate_log(LOG_DEBUG, "sftp_write ret: %d", rc); |
|
|
|
if (rc < 0 && rc != LIBSSH2_ERROR_EAGAIN) |
|
|
|
libssh2_errorx(greq->r_ssh_session, "libssh2_sftp_write"); |
|
|
|
libssh2_errorx(greq->r_ssh_session, |
|
|
|
"libssh2_sftp_write"); |
|
|
|
break; |
|
|
|
|
|
|
|
case BIO_FLUSH: |
|
|
@@ -461,8 +495,10 @@ again: |
|
|
|
goto completeio; |
|
|
|
|
|
|
|
default: |
|
|
|
libssh2_session_last_error(greq->r_ssh_session, &errmsg, NULL, 0); |
|
|
|
g_gate_log(LOG_ERR, "sftp_flush(%p) ret %d: %s", greq, rc, errmsg); |
|
|
|
libssh2_session_last_error(greq->r_ssh_session, |
|
|
|
&errmsg, NULL, 0); |
|
|
|
g_gate_log(LOG_ERR, "sftp_flush(%p) ret %d: %s", |
|
|
|
greq, rc, errmsg); |
|
|
|
greq->r_ggio.gctl_error = EIO; |
|
|
|
goto completeio; |
|
|
|
} |
|
|
@@ -471,7 +507,8 @@ again: |
|
|
|
|
|
|
|
default: |
|
|
|
rc = 0; |
|
|
|
g_gate_log(LOG_ERR, "unhandled op: %d", greq->r_ggio.gctl_cmd); |
|
|
|
g_gate_log(LOG_ERR, "unhandled op: %d", |
|
|
|
greq->r_ggio.gctl_cmd); |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
@@ -479,7 +516,10 @@ again: |
|
|
|
didwork = 1; |
|
|
|
greq->r_bufoff += rc; |
|
|
|
|
|
|
|
/* try again on partial read/write, might have more data pending */ |
|
|
|
/* |
|
|
|
* try again on partial read/write, |
|
|
|
* might have more data pending |
|
|
|
*/ |
|
|
|
if ((off_t)greq->r_bufoff != greq->r_ggio.gctl_length) |
|
|
|
goto again; |
|
|
|
} |
|
|
@@ -487,10 +527,12 @@ again: |
|
|
|
if ((off_t)greq->r_bufoff == greq->r_ggio.gctl_length) { |
|
|
|
/* complete */ |
|
|
|
completeio: |
|
|
|
g_gate_log(LOG_DEBUG, "cmd complete: seq: %d, cmd: %d", greq->r_ggio.gctl_seq, greq->r_ggio.gctl_cmd); |
|
|
|
g_gate_log(LOG_DEBUG, "cmd complete: seq: %d, cmd: %d", |
|
|
|
greq->r_ggio.gctl_seq, greq->r_ggio.gctl_cmd); |
|
|
|
g_gate_ioctl(G_GATE_CMD_DONE, &greq->r_ggio); |
|
|
|
TAILQ_REMOVE(req_pending, greq, r_next); |
|
|
|
TAILQ_INSERT_HEAD(sessqueue, greq->r_sesscache, sc_next); |
|
|
|
TAILQ_INSERT_HEAD(sessqueue, greq->r_sesscache, |
|
|
|
sc_next); |
|
|
|
free(greq->r_ggio.gctl_data); |
|
|
|
free(greq); |
|
|
|
|
|
|
@@ -562,7 +604,8 @@ proc_thread(void *arg __unused) |
|
|
|
FD_ZERO(&fdexcep); |
|
|
|
|
|
|
|
dir = libssh2_session_block_directions(session); |
|
|
|
if (dir & LIBSSH2_SESSION_BLOCK_INBOUND || gsc_pending != NULL) |
|
|
|
if (dir & LIBSSH2_SESSION_BLOCK_INBOUND || |
|
|
|
gsc_pending != NULL) |
|
|
|
FD_SET(sockfd, &fdread); |
|
|
|
if (dir & LIBSSH2_SESSION_BLOCK_OUTBOUND) |
|
|
|
FD_SET(sockfd, &fdwrite); |
|
|
@@ -571,24 +614,30 @@ proc_thread(void *arg __unused) |
|
|
|
FD_SET(popfd, &fdread); |
|
|
|
maxfd = MAX(popfd, sockfd); |
|
|
|
|
|
|
|
#if 0 |
|
|
|
/* we need to be kj */ |
|
|
|
if (gsc_pending != NULL) |
|
|
|
FD_SET(sockfd, &fdread); |
|
|
|
#endif |
|
|
|
|
|
|
|
g_gate_log(LOG_DEBUG, "selecting: %s %s, read: sockfd: %d, popfd: %d, write: sockfd: %d", (dir & LIBSSH2_SESSION_BLOCK_INBOUND) ? "inbound" : "", (dir & LIBSSH2_SESSION_BLOCK_OUTBOUND) ? "outbound" : "", FD_ISSET(sockfd, &fdread), FD_ISSET(popfd, &fdread), FD_ISSET(sockfd, &fdwrite)); |
|
|
|
g_gate_log(LOG_DEBUG, "selecting: %s %s, " \ |
|
|
|
"read: sockfd: %d, popfd: %d, write: sockfd: %d", |
|
|
|
(dir & LIBSSH2_SESSION_BLOCK_INBOUND) ? "inbound" : |
|
|
|
"", (dir & LIBSSH2_SESSION_BLOCK_OUTBOUND) ? |
|
|
|
"outbound" : "", FD_ISSET(sockfd, &fdread), |
|
|
|
FD_ISSET(popfd, &fdread), |
|
|
|
FD_ISSET(sockfd, &fdwrite)); |
|
|
|
to = (struct timeval){ .tv_sec = 1, .tv_usec = 1000 }; |
|
|
|
(void)to; |
|
|
|
rc = select(maxfd + 1, &fdread, &fdwrite, &fdexcep, NULL); |
|
|
|
rc = select(maxfd + 1, &fdread, &fdwrite, &fdexcep, |
|
|
|
NULL); |
|
|
|
switch (rc) { |
|
|
|
case -1: |
|
|
|
g_gate_log(LOG_ERR, "%s: select failed: %s", __func__, |
|
|
|
strerror(errno)); |
|
|
|
g_gate_log(LOG_ERR, "%s: select failed: %s", |
|
|
|
__func__, strerror(errno)); |
|
|
|
break; |
|
|
|
case 0: |
|
|
|
default: |
|
|
|
g_gate_log(LOG_DEBUG, "select: %d, read: sockfd: %d, popfd: %d, write: sockfd: %d", rc, FD_ISSET(sockfd, &fdread), FD_ISSET(popfd, &fdread), FD_ISSET(sockfd, &fdwrite)); |
|
|
|
g_gate_log(LOG_DEBUG, "select: %d, " \ |
|
|
|
"read: sockfd: %d, popfd: %d, " \ |
|
|
|
"write: sockfd: %d", rc, |
|
|
|
FD_ISSET(sockfd, &fdread), |
|
|
|
FD_ISSET(popfd, &fdread), |
|
|
|
FD_ISSET(sockfd, &fdwrite)); |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
@@ -623,30 +672,38 @@ procreq: |
|
|
|
if (gsc == NULL) { |
|
|
|
if (gsc_pending == NULL) { |
|
|
|
/* need new session */ |
|
|
|
g_gate_log(LOG_DEBUG, "need new session"); |
|
|
|
gsc_pending = malloc(sizeof *gsc); |
|
|
|
gsc_pending->sc_ssh_session = session; |
|
|
|
g_gate_log(LOG_DEBUG, |
|
|
|
"need new session"); |
|
|
|
gsc_pending = |
|
|
|
malloc(sizeof *gsc); |
|
|
|
gsc_pending->sc_ssh_session = |
|
|
|
session; |
|
|
|
gsc_pending->sc_session = NULL; |
|
|
|
gsc_pending->sc_handle = NULL; |
|
|
|
} |
|
|
|
|
|
|
|
/* put back request */ |
|
|
|
error = pthread_mutex_lock(&procqueue_mtx); |
|
|
|
error = |
|
|
|
pthread_mutex_lock(&procqueue_mtx); |
|
|
|
assert(error == 0); |
|
|
|
TAILQ_INSERT_HEAD(&procqueue, greq, r_next); |
|
|
|
error = pthread_mutex_unlock(&procqueue_mtx); |
|
|
|
TAILQ_INSERT_HEAD(&procqueue, greq, |
|
|
|
r_next); |
|
|
|
error = pthread_mutex_unlock( |
|
|
|
&procqueue_mtx); |
|
|
|
assert(error == 0); |
|
|
|
|
|
|
|
break; |
|
|
|
} else { |
|
|
|
/* process request */ |
|
|
|
TAILQ_REMOVE(&session_cache, gsc, sc_next); |
|
|
|
TAILQ_REMOVE(&session_cache, gsc, |
|
|
|
sc_next); |
|
|
|
greq->r_sesscache = gsc; |
|
|
|
gsc = NULL; |
|
|
|
|
|
|
|
greq->r_bufoff = 0; |
|
|
|
|
|
|
|
TAILQ_INSERT_TAIL(&req_pending, greq, r_next); |
|
|
|
TAILQ_INSERT_TAIL(&req_pending, greq, |
|
|
|
r_next); |
|
|
|
|
|
|
|
greq = NULL; |
|
|
|
} |
|
|
@@ -657,20 +714,26 @@ procreq: |
|
|
|
/* we are creating a new session */ |
|
|
|
if (gsc_pending->sc_session == NULL) { |
|
|
|
didwork = 1; |
|
|
|
gsc_pending->sc_session = libssh2_sftp_init(session); |
|
|
|
gsc_pending->sc_session = |
|
|
|
libssh2_sftp_init(session); |
|
|
|
} |
|
|
|
|
|
|
|
if (gsc_pending->sc_session != NULL) { |
|
|
|
didwork = 1; |
|
|
|
gsc_pending->sc_handle = libssh2_sftp_open(gsc_pending->sc_session, "fstest/data.img", LIBSSH2_FXF_READ|LIBSSH2_FXF_WRITE, 0); |
|
|
|
gsc_pending->sc_handle = libssh2_sftp_open( |
|
|
|
gsc_pending->sc_session, "fstest/data.img", |
|
|
|
get_open_flags(), 0); |
|
|
|
} |
|
|
|
|
|
|
|
g_gate_log(LOG_DEBUG, "pending: session: %p, handle: %p", gsc_pending->sc_session, gsc_pending->sc_handle); |
|
|
|
g_gate_log(LOG_DEBUG, |
|
|
|
"pending: session: %p, handle: %p", |
|
|
|
gsc_pending->sc_session, gsc_pending->sc_handle); |
|
|
|
|
|
|
|
/* we have a fully initalized entry, use it */ |
|
|
|
if (gsc_pending->sc_handle != NULL) { |
|
|
|
g_gate_log(LOG_DEBUG, "new session created"); |
|
|
|
TAILQ_INSERT_HEAD(&session_cache, gsc_pending, sc_next); |
|
|
|
TAILQ_INSERT_HEAD(&session_cache, gsc_pending, |
|
|
|
sc_next); |
|
|
|
gsc_pending = NULL; |
|
|
|
didwork = 1; |
|
|
|
goto procreq; |
|
|
@@ -692,13 +755,15 @@ ggatessh_makepidfile(void) |
|
|
|
|
|
|
|
if (!g_gate_verbose) { |
|
|
|
if (ggatessh_pidfile == NULL) { |
|
|
|
asprintf(&ggatessh_pidfile, _PATH_VARRUN "/ggatessh.ggate%d.pid", unit); |
|
|
|
asprintf(&ggatessh_pidfile, |
|
|
|
_PATH_VARRUN "/ggatessh.ggate%d.pid", unit); |
|
|
|
err(EXIT_FAILURE, "Cannot allocate memory for pidfile"); |
|
|
|
} |
|
|
|
pfh = pidfile_open(ggatessh_pidfile, 0600, &otherpid); |
|
|
|
if (pfh == NULL) { |
|
|
|
if (errno == EEXIST) { |
|
|
|
errx(EXIT_FAILURE, "Daemon already running, pid: %jd.", |
|
|
|
errx(EXIT_FAILURE, |
|
|
|
"Daemon already running, pid: %jd.", |
|
|
|
(intmax_t)otherpid); |
|
|
|
} |
|
|
|
err(EXIT_FAILURE, "Cannot open/create pidfile"); |
|
|
@@ -824,7 +889,8 @@ g_gatessh_create(void) |
|
|
|
ggioc.gctl_maxcount = queue_size; |
|
|
|
ggioc.gctl_timeout = timeout; |
|
|
|
ggioc.gctl_unit = unit; |
|
|
|
snprintf(ggioc.gctl_info, sizeof(ggioc.gctl_info), "%s@%s:%s", username, hostname, imgpath); |
|
|
|
snprintf(ggioc.gctl_info, sizeof(ggioc.gctl_info), "%s@%s:%s", |
|
|
|
username, hostname, imgpath); |
|
|
|
g_gate_ioctl(G_GATE_CMD_CREATE, &ggioc); |
|
|
|
if (unit == -1) { |
|
|
|
printf("%s%u\n", G_GATE_PROVIDER_NAME, ggioc.gctl_unit); |
|
|
@@ -865,7 +931,8 @@ g_gatessh_rescue(void) |
|
|
|
|
|
|
|
error = pthread_create(&mediatd, NULL, mediachg, NULL); |
|
|
|
if (error != 0) |
|
|
|
g_gate_xlog("unable to create mediasize change thread", strerror(errno)); |
|
|
|
g_gate_xlog("unable to create mediasize change thread", |
|
|
|
strerror(errno)); |
|
|
|
|
|
|
|
g_gatessh_loop(); |
|
|
|
} |
|
|
|