diff options
Diffstat (limited to 'ssh/server.c')
-rw-r--r-- | ssh/server.c | 83 |
1 files changed, 74 insertions, 9 deletions
diff --git a/ssh/server.c b/ssh/server.c index ed578c4..cdc3dbd 100644 --- a/ssh/server.c +++ b/ssh/server.c @@ -12,6 +12,7 @@ #include <signal.h> #include <sys/socket.h> #include <sys/stat.h> +#include <arpa/inet.h> #include <libssh/server.h> #include <libssh/callbacks.h> #include "util.h" @@ -169,6 +170,16 @@ static ssh_channel chan_open_request_cb(ssh_session session, void *tdata_) { static int backend_data_cb(int fd, int revents, void *tdata_) { struct thread_data *tdata = (struct thread_data*)tdata_; + if (revents & (POLLERR|POLLHUP|POLLNVAL)) { + char descr[64] = ""; + if (revents & POLLERR) strcat(descr, "|POLLERR"); + if (revents & POLLHUP) strcat(descr, "|POLLHUP"); + if (revents & POLLNVAL) strcat(descr, "|POLLNVAL"); + printf("[%d] %s on backend\n", tdata->thread_id, descr + 1); + close(fd); + tdata->should_close = true; + } + if (revents & POLLIN) { char buffer[1024]; ssize_t nr = read(fd, buffer, sizeof buffer); @@ -184,16 +195,55 @@ static int backend_data_cb(int fd, int revents, void *tdata_) { return 0; } - if (ssh_channel_write(tdata->channel, buffer, nr) != SSH_OK) { - printf("[%d] Error writing to ssh channel: %s\n", tdata->thread_id, ssh_get_error(tdata->channel)); - tdata->should_close = true; - return 0; + int cursor = 0; + while (cursor < nr) { + int nw = ssh_channel_write(tdata->channel, buffer + cursor, nr - cursor); + if (nw == SSH_ERROR) { + printf("[%d] Error writing to ssh channel: %s\n", tdata->thread_id, ssh_get_error(tdata->channel)); + tdata->should_close = true; + return 0; + } + cursor += nw; } } return 0; } +static void print_addrinfo(FILE *stream, const struct addrinfo *info) { + if (info->ai_family == AF_INET) fprintf(stream, "inet "); + else if (info->ai_family == AF_INET6) fprintf(stream, "inet6 "); + else fprintf(stream, "(family=%d) ", info->ai_family); + + if (info->ai_socktype == SOCK_STREAM) fprintf(stream, "stream "); + else if (info->ai_socktype == SOCK_DGRAM) fprintf(stream, "datagram "); + else fprintf(stream, "(socktype=%d) ", info->ai_socktype); + + if (info->ai_protocol == IPPROTO_TCP) fprintf(stream, "TCP "); + else if (info->ai_protocol == IPPROTO_UDP) fprintf(stream, "UDP "); + else fprintf(stream, "(protocol=%d) ", info->ai_protocol); + + bool success = false; + if (info->ai_family == AF_INET) { + char addrbuf[INET_ADDRSTRLEN]; + struct sockaddr_in *sin = (struct sockaddr_in*)info->ai_addr; + if (inet_ntop(AF_INET, &sin->sin_addr, addrbuf, INET_ADDRSTRLEN)) { + fprintf(stream, "%s\n", addrbuf); + success = true; + } + } else if (info->ai_family == AF_INET6) { + char addrbuf[INET6_ADDRSTRLEN]; + struct sockaddr_in6 *sin = (struct sockaddr_in6*)info->ai_addr; + if (inet_ntop(AF_INET6, &sin->sin6_addr, addrbuf, INET6_ADDRSTRLEN)) { + fprintf(stream, "%s\n", addrbuf); + success = true; + } + } + if (!success) { + fprintf(stream, "(unknown address format: %s)\n", strerror(errno)); + } +} + // Returns whether successful. static bool lookup_backend(const char *host, int port, struct addrinfo *dst) { char port_string[16]; @@ -203,7 +253,7 @@ static bool lookup_backend(const char *host, int port, struct addrinfo *dst) { memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; + hints.ai_flags = AI_ADDRCONFIG; struct addrinfo *result; int ret = getaddrinfo(host, port_string, &hints, &result); @@ -215,27 +265,41 @@ static bool lookup_backend(const char *host, int port, struct addrinfo *dst) { int last_failure = 0; bool success = false; - for (struct addrinfo *item = result; item; item = item->ai_next) { + for (struct addrinfo *item = result; item; ) { + printf("lookup_backend: option "); + print_addrinfo(stdout, item); + int sock = socket(item->ai_family, item->ai_socktype, item->ai_protocol); if (sock == -1) { last_failure = errno; + printf(" socket() failure: %s\n", strerror(last_failure)); continue; } int ret = connect(sock, item->ai_addr, item->ai_addrlen); + last_failure = errno; close(sock); if (ret == 0) { + printf(" success!\n"); success = true; + // Free the rest of the linked list, keeping this item intact. + freeaddrinfo(item->ai_next); *dst = *item; dst->ai_next = NULL; break; } else { - last_failure = errno; + printf(" connect() failure: %s\n", strerror(last_failure)); } - } - freeaddrinfo(result); + printf(" next=%p\n", item->ai_next); + + // Free this element in the linked list, but preserve (and switch to) the tail. + struct addrinfo *next = item->ai_next; + item->ai_next = NULL; + freeaddrinfo(item); + item = next; + } if (success) { return true; @@ -323,6 +387,7 @@ static void* thread_entry(void *tdata_) { } cleanup: + if (tdata->backend_fd != -1) close(tdata->backend_fd); if (event) ssh_event_free(event); if (tdata->channel) { ssh_channel_close(tdata->channel); |