diff --git a/docs/Makefile.am b/docs/Makefile.am
index bcd9faa..2feec65 100644
--- a/docs/Makefile.am
+++ b/docs/Makefile.am
@@ -25,8 +25,9 @@ dist_man_MANS = \
 	libssh2_channel_forward_listen.3 \
 	libssh2_channel_forward_listen_ex.3 \
 	libssh2_channel_free.3 \
-	libssh2_channel_get_exit_signal.3 \
+	libssh2_channel_signal.3 \
 	libssh2_channel_get_exit_status.3 \
+	libssh2_channel_get_exit_signal.3 \
 	libssh2_channel_handle_extended_data.3 \
 	libssh2_channel_handle_extended_data2.3 \
 	libssh2_channel_ignore_extended_data.3 \
diff --git a/include/libssh2.h b/include/libssh2.h
index 8dc547c..88ec7bf 100644
--- a/include/libssh2.h
+++ b/include/libssh2.h
@@ -404,6 +404,7 @@ typedef struct _LIBSSH2_POLLFD {
 #define LIBSSH2_ERROR_SOCKET_RECV               -43
 #define LIBSSH2_ERROR_ENCRYPT                   -44
 #define LIBSSH2_ERROR_BAD_SOCKET                -45
+#define LIBSSH2_ERROR_INVALID_SIGNAL_NAME       -46

 /* this is a define to provide the old (<= 1.2.7) name */
 #define LIBSSH2_ERROR_BANNER_NONE LIBSSH2_ERROR_BANNER_RECV
@@ -748,6 +749,10 @@ LIBSSH2_API int libssh2_channel_flush_ex(LIBSSH2_CHANNEL *channel,
 #define libssh2_channel_flush_stderr(channel) \
  libssh2_channel_flush_ex((channel), SSH_EXTENDED_DATA_STDERR)

+LIBSSH2_API int libssh2_channel_signal(LIBSSH2_CHANNEL* channel,
+                                       const char *signame,
+                                       size_t signame_len);
+
 LIBSSH2_API int libssh2_channel_get_exit_status(LIBSSH2_CHANNEL* channel);
 LIBSSH2_API int libssh2_channel_get_exit_signal(LIBSSH2_CHANNEL* channel,
                                                 char **exitsignal,
diff --git a/src/channel.c b/src/channel.c
index 8d6fb0a..8f9e368 100644
--- a/src/channel.c
+++ b/src/channel.c
@@ -754,6 +754,111 @@ libssh2_channel_forward_accept(LIBSSH2_LISTENER *listener)
 }

 /*
+ * _libssh2_channel_signal
+ *
+ * Deliver a signal to a shell/program/subsystem.
+ */
+static int _libssh2_channel_signal(LIBSSH2_CHANNEL *channel,
+                          const char *signame, size_t signame_len)
+{
+    LIBSSH2_SESSION *session = channel->session;
+    static const char *valid_signals[] = {
+        "ABRT",
+        "ALRM",
+        "FPE",
+        "HUP",
+        "ILL",
+        "INT",
+        "KILL",
+        "PIPE",
+        "QUIT",
+        "SEGV",
+        0
+    };
+
+    int signal_is_valid = 0;
+    int i = 0;
+
+    for (i = 0; i < sizeof(valid_signals); i++) {
+        if (strcmp(signame, valid_signals[i]) == 0) {
+            signal_is_valid = 1;
+            break;
+        }
+    }
+
+    if (signal_is_valid == 0) {
+        return _libssh2_error(session, LIBSSH2_ERROR_INVALID_SIGNAL_NAME,
+            "The signal name '%s' is invalid. Must be one of the following: "
+            "ABRT, ALRM, FPE, HUP, ILL, INT, KILL, PIPE, QUIT, SEGV, TERM, "
+            "USR1, USR2.",
+            signame
+        );
+    }
+
+    if (channel->signal_state == libssh2_NB_state_idle) {
+        /*
+         * packet_type(1) + channel_id(4) + "signal"(6) + want_reply(1) +
+         * signame(signame_len)
+         */
+        channel->signal_packet_len = 1 + 4 + 6 + 1 + signame_len;
+
+        /* Zero the whole thing out */
+        memset(&channel->signal_packet_requirev_state, 0,
+               sizeof(channel->signal_packet_requirev_state));
+
+        _libssh2_debug(session, LIBSSH2_TRACE_CONN,
+            "Sending signal '%s' to channel %lu/%lu",
+            signame,
+            channel->local.id,
+            channel->remote.id);
+
+        unsigned char *s = channel->signal_packet =
+            LIBSSH2_ALLOC(session, channel->signal_packet_len);
+        if (!channel->signal_packet) {
+            return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                                  "Unable to allocate memeory "
+                                  "for signal packet");
+        }
+
+        *(s++) = SSH_MSG_CHANNEL_REQUEST;
+        _libssh2_store_u32(&s, channel->remote.id);
+        _libssh2_store_str(&s, "signal", 6);
+        *(s++) = 0x00; /* Don't reply */
+        _libssh2_store_str(&s, signame, signame_len);
+
+        channel->signal_state = libssh2_NB_state_created;
+    }
+
+    if (channel->signal_state == libssh2_NB_state_created) {
+        int rc = _libssh2_transport_send(session,
+                                     channel->signal_packet,
+                                     channel->signal_packet_len,
+                                     NULL, 0);
+        if (rc == LIBSSH2_ERROR_EAGAIN) {
+            _libssh2_error(session, rc,
+                           "Would block sending signal request");
+            return rc;
+        } else if (rc) {
+            LIBSSH2_FREE(session, channel->signal_packet);
+            channel->signal_packet = NULL;
+            channel->signal_state = libssh2_NB_state_idle;
+            return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                                  "Unable to send channel-request packet for "
+                                  "signal request");
+        }
+
+        LIBSSH2_FREE(session, channel->signal_packet);
+        channel->signal_packet = NULL;
+
+        _libssh2_htonu32(channel->signal_local_channel, channel->local.id);
+    }
+
+
+    channel->signal_state = libssh2_NB_state_idle;
+    return LIBSSH2_ERROR_NONE;
+}
+
+/*
  * channel_setenv
  *
  * Set an environment variable prior to requesting a shell/program/subsystem
@@ -1448,6 +1553,27 @@ libssh2_channel_flush_ex(LIBSSH2_CHANNEL *channel, int stream)
 }

 /*
+ * libssh2_channel_setenv_ex
+ *
+ * Set an environment variable prior to requesting a shell/program/subsystem
+ */
+LIBSSH2_API int
+libssh2_channel_signal(LIBSSH2_CHANNEL *channel,
+                          const char *signame, size_t signame_len)
+{
+    int rc;
+
+    if (!channel) {
+        return LIBSSH2_ERROR_BAD_USE;
+    }
+
+    BLOCK_ADJUST(rc, channel->session,
+                 _libssh2_channel_signal(channel, signame, signame_len));
+
+    return rc;
+}
+
+/*
  * libssh2_channel_get_exit_status
  *
  * Return the channel's program exit status. Note that the actual protocol
diff --git a/src/libssh2_priv.h b/src/libssh2_priv.h
index 4f3708d..e997f9c 100644
--- a/src/libssh2_priv.h
+++ b/src/libssh2_priv.h
@@ -366,6 +366,13 @@ struct _LIBSSH2_CHANNEL
     unsigned char setenv_local_channel[4];
     packet_requirev_state_t setenv_packet_requirev_state;

+    /* State variables used in libssh2_channel_signal() */
+    libssh2_nonblocking_states signal_state;
+    unsigned char *signal_packet;
+    size_t signal_packet_len;
+    unsigned char signal_local_channel[4];
+    packet_requirev_state_t signal_packet_requirev_state;
+
     /* State variables used in libssh2_channel_request_pty_ex()
        libssh2_channel_request_pty_size_ex() */
     libssh2_nonblocking_states reqPTY_state;
diff --git a/src/misc.c b/src/misc.c
index a9f423a..cfcf6b3 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -51,9 +51,16 @@
 #include <stdio.h>
 #include <errno.h>

-int _libssh2_error(LIBSSH2_SESSION* session, int errcode, const char* errmsg)
+int _libssh2_error(LIBSSH2_SESSION* session, int errcode, const char* format, ...)
 {
-    session->err_msg = errmsg;
+    va_list vargs;
+    char buffer[2048] = "\0";
+
+    va_start(vargs, format);
+    vsnprintf(buffer, sizeof(buffer), format, vargs);
+    va_end(vargs);
+
+    session->err_msg = buffer;
     session->err_code = errcode;
 #ifdef LIBSSH2DEBUG
     if((errcode == LIBSSH2_ERROR_EAGAIN) && !session->api_block_mode)
diff --git a/src/misc.h b/src/misc.h
index bcb7d0e..4d3ed11 100644
--- a/src/misc.h
+++ b/src/misc.h
@@ -49,7 +49,7 @@ struct list_node {
     struct list_head *head;
 };

-int _libssh2_error(LIBSSH2_SESSION* session, int errcode, const char* errmsg);
+int _libssh2_error(LIBSSH2_SESSION* session, int errcode, const char* format, ...);

 void _libssh2_list_init(struct list_head *head);

diff --git a/docs/libssh2_channel_signal.3 b/docs/libssh2_channel_signal.3
new file mode 100644
index 0000000..12ba02d
--- /dev/null
+++ b/docs/libssh2_channel_signal.3
@@ -0,0 +1,31 @@
+.TH libssh2_channel_signal 3 "4 Oct 2010" "libssh2 1.2.8" "libssh2 manual"
+.SH NAME
+libssh2_channel_signal - deliver a signal to the remote process/service
+.SH SYNOPSIS
+#include <libssh2.h>
+
+int
+libssh2_channel_signal(LIBSSH2_CHANNEL *channel, const char *signame, size_t signame_len);
+
+.SH DESCRIPTION
+\fIchannel\fP - Channel stream to deliver a signal.
+
+\fIsigname\fP - The signal name (without leading "SIG") which is one of the following (these are from [POSIX]):
+    ABRT
+    ALRM
+    FPE
+    HUP
+    ILL
+    INT
+    KILL
+    PIPE
+    QUIT
+    SEGV
+    TERM
+    USR1
+    USR2
+
+\fIsigname_len\fP - The length of signal name.
+
+.SH RETURN VALUE
+Numeric error code corresponding to the the Error Code constants.
