diff --git a/plugins/websockets/Makefile.in b/plugins/websockets/Makefile.in
index ffd9483..4bbb87b 100644
--- a/plugins/websockets/Makefile.in
+++ b/plugins/websockets/Makefile.in
@@ -3,7 +3,7 @@ CFLAGS	= $CFLAGS
 LDFLAGS = $LDFLAGS
 DEFS    = $DEFS
 INCDIR  = ../../src/include
-WS_OBJECTS = ws.o request.o base64.o sha1.o
+WS_OBJECTS = ws.o request.o base64.o sha1.o echo.o
 
 all: monkey-websockets.so
 
diff --git a/plugins/websockets/echo.c b/plugins/websockets/echo.c
new file mode 100644
index 0000000..304f8d1
--- /dev/null
+++ b/plugins/websockets/echo.c
@@ -0,0 +1,40 @@
+
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/*  Monkey HTTP Daemon
+ *  ------------------
+ *  Copyright (C) 2001-2012, Eduardo Silva P.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include "echo.h"
+#include "ws.h"
+
+int ws_echo_write_callback(int sockfd, unsigned char *payload_data, uint64_t payload_len)
+{
+    int n;
+
+    /* Just send it out */
+    n = ws_send_data(sockfd, 1, 0, 0, 0, WS_FRAME_TEXT, 
+        0, payload_len, NULL, payload_data);
+    if (n < 0) {
+        return -1;
+    }
+
+    return 0;
+}
diff --git a/plugins/websockets/echo.h b/plugins/websockets/echo.h
new file mode 100644
index 0000000..ac8daff
--- /dev/null
+++ b/plugins/websockets/echo.h
@@ -0,0 +1,27 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/*  Monkey HTTP Daemon
+ *  ------------------
+ *  Copyright (C) 2001-2012, Eduardo Silva P.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef MK_WEBSOCKET_ECHO_H
+#define MK_WEBSOCKET_ECHO_H
+
+int ws_echo_write_callback(int, unsigned char *, uint64_t);
+
+#endif
diff --git a/plugins/websockets/request.c b/plugins/websockets/request.c
index 41dc294..ad81cbe 100644
--- a/plugins/websockets/request.c
+++ b/plugins/websockets/request.c
@@ -29,7 +29,8 @@
 /* Create a ws_request node */
 struct mk_ws_request *mk_ws_request_create(int socket_fd,
                                            struct client_session *cs,
-                                           struct session_request *sr)
+                                           struct session_request *sr,
+                                           unsigned int subprotocol_id)
 {
     struct mk_ws_request *new;
 
@@ -37,6 +38,9 @@ struct mk_ws_request *mk_ws_request_create(int socket_fd,
     new->socket_fd = socket_fd;
     new->cs = cs;
     new->sr = sr;
+    new->subprotocol_id = subprotocol_id;
+    new->payload = NULL;
+    new->payload_len = 0;
 
     return new;
 }
diff --git a/plugins/websockets/request.h b/plugins/websockets/request.h
index 871f8f5..fdd194a 100644
--- a/plugins/websockets/request.h
+++ b/plugins/websockets/request.h
@@ -29,6 +29,13 @@ struct mk_ws_request
 {
     int socket_fd;
 
+    /* Websocket subprotocol */
+    unsigned int subprotocol_id;
+
+    /* Payload data */
+    unsigned char *payload;
+    uint64_t payload_len;
+
     /* Client request data */
     struct client_session *cs;
     struct session_request *sr;
@@ -39,7 +46,8 @@ struct mk_ws_request
 void mk_ws_request_init();
 struct mk_ws_request *mk_ws_request_create(int socket_fd,
                                            struct client_session *cs,
-                                           struct session_request *sr);
+                                           struct session_request *sr,
+                                           unsigned int subprotocol_id);
 
 void mk_ws_request_add(struct mk_ws_request *pr);
 struct mk_ws_request *mk_ws_request_get(int socket);
diff --git a/plugins/websockets/ws.c b/plugins/websockets/ws.c
index 0b917eb..6274e30 100644
--- a/plugins/websockets/ws.c
+++ b/plugins/websockets/ws.c
@@ -27,6 +27,7 @@
 #include <stdio.h>
 #include <stdint.h>
 #include <errno.h>
+#include <string.h>
 
 /* Networking - I/O*/
 #include <fcntl.h>
@@ -42,6 +43,7 @@
 #include "base64.h"
 #include "request.h"
 #include "ws.h"
+#include "echo.h"
 
 MONKEY_PLUGIN("websocket",          /* shortname */
               "Web Sockets",        /* name */ 
@@ -49,8 +51,23 @@ MONKEY_PLUGIN("websocket",          /* shortname */
               MK_PLUGIN_STAGE_30);  /* hook for thread context call */
 
 
+struct ws_subprotocol
+{
+    char *name;
+    unsigned int id;
+    unsigned int name_len;
+
+    int (*event_write_callback)(int, unsigned char *, uint64_t);
+};
+
+#define WS_SUBPROTOCOL_NUM 2
+static struct ws_subprotocol subprotocol_list[WS_SUBPROTOCOL_NUM] = {
+    {"/websockets", 0, 11, NULL},
+    {"/echo", 1, 5, NULL},
+};
+
 int ws_handler(int socket, struct client_session *cs, struct session_request *sr,
-               struct plugin *plugin)
+               struct plugin *plugin, unsigned int subprotocol_id)
 {
     int len;
     size_t out_len;
@@ -144,7 +161,7 @@ int ws_handler(int socket, struct client_session *cs, struct session_request *sr
         mk_api->mem_free(encoded_accept);
         
         /* Register node in main list */
-        wr_node = mk_ws_request_create(socket, cs, sr);
+        wr_node = mk_ws_request_create(socket, cs, sr, subprotocol_id);
         mk_ws_request_add(wr_node);
 
         /* Register socket with plugin events interface */
@@ -159,6 +176,54 @@ int ws_handler(int socket, struct client_session *cs, struct session_request *sr
     return MK_PLUGIN_RET_CONTINUE;
 }
 
+int ws_send_data(int sockfd,
+                unsigned int fin,
+                unsigned int rsv1,
+                unsigned int rsv2,
+                unsigned int rsv3,
+                unsigned int opcode,
+                unsigned int frame_mask,
+                uint64_t payload_len,
+                unsigned char *frame_masking_key,
+                unsigned char *payload_data)
+{
+    unsigned char buf[256];
+    unsigned int offset = 0;
+    int n;
+
+    memset(buf, 0, sizeof(buf));
+    buf[0] |= ((fin << 7) | (rsv1 << 6) | (rsv2 << 5) | (rsv3 << 4) | opcode);
+
+    if (payload_len < 126) {
+        buf[1] |= ((frame_mask << 7) | payload_len);
+        offset = 2;
+    }
+    else if (payload_len >= 126 && payload_len <= 0xFFFF) {
+        buf[1] |= ((frame_mask << 7) | 126);
+        buf[2] = payload_len >> 8;
+        buf[3] = payload_len & 0x0F;
+        offset = 4;
+    }
+    else {
+        buf[1] |= ((frame_mask << 7) | 127);
+        memcpy(buf + 2, &payload_len, 8);
+        offset = 10;
+    }
+
+    if (frame_mask) {
+        memcpy(buf + offset, frame_masking_key, WS_FRAME_MASK_LEN);
+        offset += WS_FRAME_MASK_LEN;
+    }
+
+    memcpy(buf + offset, payload_data, payload_len);
+
+    n = mk_api->socket_send(sockfd, buf, offset + payload_len);
+    if (n <= 0) {
+        return -1;
+    }
+
+    return n;
+}
 
 /* _MKP_EVENTs */
 int _mkp_event_read(int sockfd)
@@ -168,13 +233,10 @@ int _mkp_event_read(int sockfd)
     unsigned int frame_size = 0;
     unsigned int frame_opcode = 0;
     unsigned int frame_mask = 0;
-    unsigned int frame_payload = 0;    
-    unsigned char frame_masking_key[256];
+    unsigned char *frame_payload;
+    unsigned char frame_masking_key[WS_FRAME_MASK_LEN];
     uint64_t payload_length = 0;
-    unsigned int payload_size = 0;
-    unsigned int mask_key_init = 0;
-    unsigned char data[256];
-
+    unsigned int masking_key_offset = 0;
     struct mk_ws_request *wr;
 
     wr = mk_ws_request_get(sockfd);
@@ -194,16 +256,18 @@ int _mkp_event_read(int sockfd)
     frame_size    = n;
     frame_opcode  = buf[0] & 0x0f;
     frame_mask    = CHECK_BIT(buf[1], 7);
-    frame_payload = buf[1] & 0x7f;
+    payload_length = buf[1] & 0x7f;
 
-    if (frame_payload == 126) {
+    if (payload_length == 126) {
         payload_length = buf[2] * 256 + buf[3];
+        masking_key_offset = 4;
     }
-    else if (frame_payload == 127) { 
+    else if (payload_length == 127) {
         memcpy(&payload_length, buf + 2, 8);
+        masking_key_offset = 10;
     }
     else {
-        payload_length = frame_payload;
+        masking_key_offset = 2;
     }
 
     
@@ -217,43 +281,70 @@ int _mkp_event_read(int sockfd)
     printf("Op Code\t%i\n", frame_opcode);
     printf("Mask ?\t%i\n", frame_mask);
     printf("Frame Size\t%i\n", frame_size);
-    printf("Frame Payload\t%i\n", frame_payload);
-    printf("Payload Value\t%i\n", (unsigned int) payload_length);
-    printf("Payload Size\t%i\n", (unsigned int) payload_size);
+    printf("Payload Length\t%i\n", (unsigned int) payload_length);
+    printf("Mask Key Offset\t%i\n", (unsigned int) masking_key_offset);
     fflush(stdout);
 #endif
 
-    memset(data, '\0', sizeof(data));
+    wr->payload_len = payload_length;
+    wr->payload = mk_api->mem_alloc(256);
+    memset(wr->payload, '\0', sizeof(wr->payload));
+
     if (frame_mask) {
-        mask_key_init = 2 + payload_size;
-        memcpy(&frame_masking_key, buf + mask_key_init, WS_FRAME_MASK_LEN);
+        memcpy(frame_masking_key, buf + masking_key_offset, WS_FRAME_MASK_LEN);
 
-        if (payload_size != (frame_size - (mask_key_init + WS_FRAME_MASK_LEN))) {
+        if (payload_length != (frame_size - (masking_key_offset + WS_FRAME_MASK_LEN))) {
             //mk_err("Invalid frame size: %i", (frame_size - (mask_key_init + WS_FRAME_MASK_LEN)));
             /* FIXME: Send error, frame size does not cover the payload size */
             //return MK_PLUGIN_RET_EVENT_CLOSE;
         }
 
-        memcpy(&data, buf + mask_key_init + WS_FRAME_MASK_LEN, payload_length);
-        for (i=0; i < payload_length; i++) {
-            data[i] = data[i] ^ frame_masking_key[i % 4];
+        /* Unmasking the frame payload */
+        frame_payload = buf + masking_key_offset + WS_FRAME_MASK_LEN;
+        for (i = 0; i < payload_length; i++) {
+            wr->payload[i] = frame_payload[i] ^ frame_masking_key[i & 0x03];
         }
     }
     else {
-        memcpy(&data, buf + 2 + payload_size, payload_length); 
+        // There is no masking key, get to the frame payload
+        frame_payload = buf + masking_key_offset;
+        memcpy(wr->payload, frame_payload, payload_length);
     }
 
 #ifdef TRACE
-    if (frame_opcode == 1) printf("Data:\n\"%s\"\n", data);
+    if (frame_opcode == 1) printf("Data:\n\"%s\"\n", wr->data);
 #endif
 
     return MK_PLUGIN_RET_EVENT_OWNED;
 }
 
+int _mkp_event_write(int sockfd)
+{
+    struct mk_ws_request *wr;
+
+    wr = mk_ws_request_get(sockfd);
+    if (!wr){
+        PLUGIN_TRACE("[FD %i] this FD is not a WebSocket Frame", sockfd);
+        return MK_PLUGIN_RET_EVENT_NEXT;
+    }
+
+    if (wr->payload_len == 0 || wr->payload == NULL)
+        return MK_PLUGIN_RET_EVENT_OWNED;
+
+    subprotocol_list[wr->subprotocol_id].event_write_callback(sockfd,
+        wr->payload, wr->payload_len); 
+
+    mk_api->mem_free(wr->payload);
+    wr->payload_len = 0;
+
+    return MK_PLUGIN_RET_EVENT_OWNED;
+}
 
 int _mkp_init(void **api, char *confdir)
 {
     mk_api = *api;
+    
+    subprotocol_list[1].event_write_callback = ws_echo_write_callback;
 
     return 0;
 }
@@ -271,15 +362,19 @@ void _mkp_core_thctx()
 int _mkp_stage_30(struct plugin *plugin, struct client_session *cs, 
                   struct session_request *sr)
 {
+    int i;
+
     PLUGIN_TRACE("[FD %i] STAGE 30", cs->socket);
 
     /* Do websocket stuff just for the defined path */
-    if (sr->uri_processed.len == sizeof(WS_PATH) - 1 &&
-        strncmp(sr->uri_processed.data, WS_PATH, 
-                sizeof(WS_PATH) - 1) == 0) {
+    for (i = 0; i < WS_SUBPROTOCOL_NUM; i++) {
 
-        return ws_handler(cs->socket, cs, sr, plugin);
-    }
+        if (sr->uri_processed.len == subprotocol_list[i].name_len &&
+                strncmp(sr->uri_processed.data, subprotocol_list[i].name, 
+                    subprotocol_list[i].name_len) == 0) {
 
+            return ws_handler(cs->socket, cs, sr, plugin, subprotocol_list[i].id);
+        }
+    }
     return MK_PLUGIN_RET_NOT_ME;
 }
diff --git a/plugins/websockets/ws.h b/plugins/websockets/ws.h
index 3d47ef4..66dce41 100644
--- a/plugins/websockets/ws.h
+++ b/plugins/websockets/ws.h
@@ -42,11 +42,33 @@
 #define WS_RESP_CONNECTION         "Connection: Upgrade"
 #define WS_RESP_WS_ACCEPT          "Sec-WebSocket-Accept: "
 
+/* Frame Opcode */
+#define WS_FRAME_CONTINUE   0x00
+#define WS_FRAME_TEXT       0x01
+#define WS_FRAME_BINARY     0x02
+
+#define WS_FRAME_CTL_CLOSE  0x08
+#define WS_FRAME_CTL_PING   0x09
+#define WS_FRAME_CTL_PONG   0x0a
+
 /* Framing macros */
-#define WS_FRAME_MASK_LEN          4
+#define WS_FRAME_MASK_LEN       4
 
 #define CHECK_BIT(var, pos) !!((var) & (1 << (pos)))
 
 /* SHA1 stuff */
 #define SHA1_DIGEST_LEN            20
+
+
+int ws_send_data(int sockfd,
+                unsigned int fin,
+                unsigned int rsv1,
+                unsigned int rsv2,
+                unsigned int rsv3,
+                unsigned int opcode,
+                unsigned int frame_mask,
+                uint64_t payload_len,
+                unsigned char *frame_masking_key,
+                unsigned char *payload_data);
+
 #endif
