mirror of
https://github.com/lxsang/ant-http
synced 2024-12-26 00:38:21 +01:00
add websocket support, remote terminal as example
This commit is contained in:
parent
725deacf9f
commit
eb63cd0fa4
21
Makefile
21
Makefile
@ -1,6 +1,13 @@
|
||||
CC=gcc
|
||||
EXT=dylib
|
||||
SERVER=plugin_manager.o plugins/ini.o http_server.o plugins/dictionary.o plugins/sha1.o plugins/utils.o
|
||||
SERVER=plugin_manager.o \
|
||||
plugins/ini.o \
|
||||
http_server.o \
|
||||
plugins/dictionary.o \
|
||||
plugins/base64.o \
|
||||
plugins/sha1.o \
|
||||
plugins/ws.o \
|
||||
plugins/utils.o
|
||||
SERVERLIB=-lpthread -ldl
|
||||
UNAME_S := $(shell uname -s)
|
||||
ifeq ($(UNAME_S),Linux)
|
||||
@ -15,7 +22,15 @@ CFLAGS=-W -Wall -g -std=c99 -D DEBUG -D USE_DB $(PF_FLAG)
|
||||
#-lsocket
|
||||
PLUGINS= dummy.$(EXT) fileman.$(EXT) pluginsman.$(EXT) wterm.$(EXT) nodedaemon.$(EXT) cookiex.$(EXT)
|
||||
|
||||
PLUGINSDEP = plugins/ini.o plugins/plugin.o plugins/dbhelper.o plugins/dictionary.o plugins/utils.o plugins/list.o plugins/sha1.o
|
||||
PLUGINSDEP = plugins/ini.o \
|
||||
plugins/plugin.o \
|
||||
plugins/dbhelper.o \
|
||||
plugins/dictionary.o \
|
||||
plugins/base64.o \
|
||||
plugins/utils.o \
|
||||
plugins/ws.o \
|
||||
plugins/sha1.o \
|
||||
plugins/list.o
|
||||
PLUGINLIBS = -lsqlite3
|
||||
|
||||
main: httpd plugins
|
||||
@ -40,7 +55,7 @@ plugins: $(PLUGINS)
|
||||
clean: sclean pclean
|
||||
|
||||
sclean:
|
||||
rm -f *.o build/httpd
|
||||
rm -f *.o $(BUILDIRD)/httpd
|
||||
pclean:
|
||||
rm -rf $(BUILDIRD)/plugins/* plugins/*.o
|
||||
-for file in plugins/* ;do \
|
||||
|
BIN
build/.DS_Store
vendored
BIN
build/.DS_Store
vendored
Binary file not shown.
BIN
build/htdocs/.DS_Store
vendored
BIN
build/htdocs/.DS_Store
vendored
Binary file not shown.
@ -194,7 +194,36 @@ var Terminal = (function () {
|
||||
return TerminalConstructor
|
||||
}());
|
||||
var wtermobj;
|
||||
var nest_callback;
|
||||
var socket = new WebSocket("ws://127.0.0.1:9191/wterm?q=test");
|
||||
//ws.binaryType = 'arraybuffer';
|
||||
socket.onopen = function(){}
|
||||
//{
|
||||
// Web Socket is connected, send data using send()
|
||||
// var msg = "Lorem Ipsum ";
|
||||
// ws.send(msg);
|
||||
//ws.send(array);
|
||||
// alert("Message is sent...");
|
||||
//};
|
||||
|
||||
socket.onmessage = function (e) {
|
||||
if(wtermobj)
|
||||
{
|
||||
wtermobj.print(e.data);
|
||||
var par = $("#wterm");
|
||||
par.animate({
|
||||
scrollTop: par.get(0).scrollHeight
|
||||
}, 0);
|
||||
wtermobj.input("antd> ",nest_callback);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
socket.onclose = function()
|
||||
{
|
||||
// websocket is closed.
|
||||
alert("Connection is closed...");
|
||||
};
|
||||
var wterm_config = {
|
||||
name: 'wterm_layout',
|
||||
panels: [
|
||||
@ -210,25 +239,13 @@ var wterm_config = {
|
||||
{
|
||||
wtermobj = new Terminal();
|
||||
wtermobj.setTextSize(11);
|
||||
var nest_callback = function(data)
|
||||
nest_callback = function(data)
|
||||
{
|
||||
if(data.length>0)
|
||||
{
|
||||
//send to server
|
||||
var webtty = new EventSource('/wterm?cmd='+data);
|
||||
webtty.onmessage = function (e) {
|
||||
wtermobj.print(e.data);
|
||||
var par = $("#wterm");
|
||||
par.animate({
|
||||
scrollTop: par.get(0).scrollHeight
|
||||
}, 0);
|
||||
};
|
||||
webtty.onerror = function(e)
|
||||
{
|
||||
// finish the command
|
||||
webtty.close();
|
||||
wtermobj.input("antd> ",nest_callback);
|
||||
}
|
||||
//alert("sent " + data);
|
||||
socket.send(data);
|
||||
//alert("sent "+data);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
75
build/htdocs/term/index.html
Normal file
75
build/htdocs/term/index.html
Normal file
@ -0,0 +1,75 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<title>term.js</title>
|
||||
<style>
|
||||
html {
|
||||
background: #555;
|
||||
}
|
||||
h1 {
|
||||
margin-bottom: 20px;
|
||||
font: 20px/1.5 sans-serif;
|
||||
}
|
||||
|
||||
.terminal {
|
||||
float: left;
|
||||
border: #000 solid 5px;
|
||||
font-family: "DejaVu Sans Mono", "Liberation Mono", monospace;
|
||||
font-size: 11px;
|
||||
color: #f0f0f0;
|
||||
background: #000;
|
||||
}
|
||||
.terminal-cursor {
|
||||
color: #000;
|
||||
background: #f0f0f0;
|
||||
}
|
||||
|
||||
</style>
|
||||
<script src="term/term.js"></script>
|
||||
<body>
|
||||
<h1>Terminal</h1>
|
||||
</body>
|
||||
<script>
|
||||
window.onload = function() {
|
||||
String.prototype.replaceAll = function(search, replacement) {
|
||||
var target = this;
|
||||
return target.replace(new RegExp(search, 'g'), replacement);
|
||||
};
|
||||
|
||||
var socket = new WebSocket("ws://127.0.0.1:9191/wterm?q=test");
|
||||
var term = null;
|
||||
socket.onopen = function(){
|
||||
term = new Terminal({
|
||||
cols: 80,
|
||||
rows: 24,
|
||||
useStyle: true,
|
||||
screenKeys: true,
|
||||
cursorBlink: false
|
||||
});
|
||||
term.on('data', function(data) {
|
||||
socket.send(data);
|
||||
});
|
||||
term.on('title', function(title) {
|
||||
document.title = title;
|
||||
});
|
||||
term.open(document.body);
|
||||
term.write('\x1b[31mWelcome to term.js!\x1b[m\r\n');
|
||||
};
|
||||
socket.onmessage = function (e) {
|
||||
if(term && e.data)
|
||||
{
|
||||
term.write(e.data.replaceAll("\n","\r\n"));
|
||||
}
|
||||
};
|
||||
socket.onclose = function()
|
||||
{
|
||||
// websocket is closed.
|
||||
alert("Connection is closed...");
|
||||
};
|
||||
window.onbeforeunload = function(e) {
|
||||
if(socket) socket.close();
|
||||
};
|
||||
|
||||
};
|
||||
</script>
|
||||
</html>
|
||||
|
5977
build/htdocs/term/term.js
Normal file
5977
build/htdocs/term/term.js
Normal file
File diff suppressed because it is too large
Load Diff
@ -42,14 +42,45 @@ dictionary decode_request(int client,const char* method,const char* query)
|
||||
char * token;
|
||||
if(strcmp(method,"GET") == 0)
|
||||
{
|
||||
// this for check if web socket is enabled
|
||||
int ws= 0;
|
||||
char* ws_key = NULL;
|
||||
while((line = read_line(client)) && strcmp("\r\n",line))
|
||||
{
|
||||
token = strsep(&line,":");
|
||||
trim(token,' ');
|
||||
if(token != NULL &&strcasecmp(token,"Cookie") == 0)
|
||||
{
|
||||
if(!cookie) cookie = decode_cookie(line);
|
||||
}
|
||||
else if(token != NULL && strcasecmp(token,"Upgrade") == 0)
|
||||
{
|
||||
// verify that the connection is upgrade to websocket
|
||||
trim(line, ' ');
|
||||
trim(line, '\n');
|
||||
trim(line, '\r');
|
||||
if(line != NULL && strcasecmp(line,"websocket") == 0)
|
||||
ws = 1;
|
||||
} else if(token != NULL && strcasecmp(token,"Sec-WebSocket-Key") == 0)
|
||||
{
|
||||
// get the key from the client
|
||||
trim(line, ' ');
|
||||
trim(line, '\n');
|
||||
trim(line, '\r');
|
||||
ws_key = strdup(line);
|
||||
}
|
||||
}
|
||||
request = decode_url_request(query);
|
||||
if(ws && ws_key != NULL)
|
||||
{
|
||||
ws_confirm_request(client, ws_key);
|
||||
free(ws_key);
|
||||
// insert wsocket flag to request
|
||||
// plugin should handle this ugrade connection
|
||||
// not the server
|
||||
if(!request) request = dict();
|
||||
dput(request,"__web_socket__","1");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -122,6 +153,40 @@ void __px(const char* data,int size)
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
/**
|
||||
* Send header to the client to confirm
|
||||
* that the websocket is accepted by
|
||||
* our server
|
||||
*/
|
||||
void ws_confirm_request(int client, const char* key)
|
||||
{
|
||||
char buf[256];
|
||||
char rkey[128];
|
||||
char sha_d[20];
|
||||
char base64[64];
|
||||
strcpy(rkey,key);
|
||||
strcat(rkey,WS_MAGIC_STRING);
|
||||
//printf("RESPONDKEY '%s'\n", rkey);
|
||||
SHA1_CTX context;
|
||||
SHA1_Init(&context);
|
||||
SHA1_Update(&context, rkey, strlen(rkey));
|
||||
SHA1_Final(&context, sha_d);
|
||||
Base64encode(base64, sha_d, 20);
|
||||
//printf("Base 64 '%s'\n", base64);
|
||||
// send accept to client
|
||||
sprintf(buf, "HTTP/1.1 101 Switching Protocols\r\n");
|
||||
send(client, buf, strlen(buf), 0);
|
||||
sprintf(buf, "Upgrade: websocket\r\n");
|
||||
send(client, buf, strlen(buf), 0);
|
||||
sprintf(buf, "Connection: Upgrade\r\n");
|
||||
send(client, buf, strlen(buf), 0);
|
||||
sprintf(buf, "Sec-WebSocket-Accept: %s\r\n",base64);
|
||||
send(client, buf, strlen(buf), 0);
|
||||
sprintf(buf, "\r\n");
|
||||
send(client, buf, strlen(buf), 0);
|
||||
|
||||
LOG("%s\n", "Websocket is now enabled for plugin");
|
||||
}
|
||||
/**
|
||||
* Decode the cookie header to a dictionary
|
||||
* @param client The client socket
|
||||
|
@ -7,7 +7,7 @@
|
||||
#define FORM_MULTI_PART "multipart/form-data"
|
||||
#define APP_JSON "application/json"
|
||||
#define PLUGIN_HANDLER "handler"
|
||||
|
||||
#define WS_MAGIC_STRING "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
|
||||
struct plugin_entry {
|
||||
struct plugin_entry *next;
|
||||
char *pname;
|
||||
@ -22,6 +22,7 @@ void unload_all_plugin();
|
||||
void unload_plugin(struct plugin_entry*);
|
||||
void unload_plugin_by_name(const char*);
|
||||
void * plugin_from_file(char* name);
|
||||
void ws_confirm_request(int, const char*);
|
||||
char* post_url_decode(int client,int len);
|
||||
dictionary decode_url_request(const char* query);
|
||||
dictionary decode_request(int client,const char* method,const char* query);
|
||||
|
BIN
plugins/.DS_Store
vendored
BIN
plugins/.DS_Store
vendored
Binary file not shown.
@ -270,3 +270,7 @@ void unknow(int client)
|
||||
html(client);
|
||||
__t(client,"404 API not found");
|
||||
}
|
||||
int ws_enable(dictionary dic)
|
||||
{
|
||||
return (dic != NULL && R_INT(dic,"__web_socket__") == 1);
|
||||
}
|
@ -7,6 +7,7 @@
|
||||
#include "dictionary.h"
|
||||
#include "list.h"
|
||||
#include "ini.h"
|
||||
#include "ws.h"
|
||||
|
||||
#define SERVER_NAME "antd"
|
||||
#define IS_POST(method) (strcmp(method,"POST")== 0)
|
||||
@ -62,3 +63,4 @@ void clear_cookie(int, dictionary);
|
||||
/*Default function for plugin*/
|
||||
void handler(int, const char*,const char*,dictionary);
|
||||
void unknow(int);
|
||||
int ws_enable(dictionary);
|
||||
|
44
plugins/rterm/rterm.c
Normal file
44
plugins/rterm/rterm.c
Normal file
@ -0,0 +1,44 @@
|
||||
#include "../plugin.h"
|
||||
|
||||
#define TEXT "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."
|
||||
void pexit()
|
||||
{
|
||||
|
||||
}
|
||||
void handler(int cl, const char* m, const char* rqp, dictionary rq)
|
||||
{
|
||||
//html(cl);
|
||||
ws_msg_header_t* h = NULL;
|
||||
if(ws_enable(rq))
|
||||
{
|
||||
printf("Doc: %s\n","Websocket is available" );
|
||||
while(1)
|
||||
{
|
||||
h = ws_read_header(cl);
|
||||
if(h)
|
||||
{
|
||||
if(h->opcode == WS_CLOSE)
|
||||
{
|
||||
printf("WARNING: Connection close\n");
|
||||
break;
|
||||
}
|
||||
else if(h->opcode == WS_TEXT)
|
||||
{
|
||||
char buff[1025];
|
||||
int l;
|
||||
while((l = ws_read_data(cl,h,1024,buff)) != -1)
|
||||
{
|
||||
buff[l] = '\0';
|
||||
printf("Received:%d '%s'\n", l, buff);
|
||||
}
|
||||
ws_t(cl, TEXT);
|
||||
ws_t(cl, "test");
|
||||
}
|
||||
|
||||
free(h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("Child process exit\n");
|
||||
}
|
@ -261,5 +261,5 @@ void digest_to_hex(const uint8_t digest[SHA1_DIGEST_SIZE], char *output)
|
||||
//sprintf(c, " ");
|
||||
//c += 1;
|
||||
}
|
||||
//*(c - 1) = '\0';
|
||||
*c = '\0';
|
||||
}
|
@ -37,6 +37,7 @@ THE SOFTWARE.
|
||||
#include <time.h>
|
||||
#include <stdint.h>
|
||||
#include "sha1.h"
|
||||
#include "base64.h"
|
||||
|
||||
#define LEFTROTATE(x, c) (((x) << (c)) | ((x) >> (32 - (c))))
|
||||
#define EQU(a,b) (strcmp(a,b) == 0)
|
||||
|
199
plugins/ws.c
Normal file
199
plugins/ws.c
Normal file
@ -0,0 +1,199 @@
|
||||
#include "ws.h"
|
||||
|
||||
/**
|
||||
* Read a frame header
|
||||
* based on this header, we'll decide
|
||||
* the appropriate handle for frame data
|
||||
*/
|
||||
ws_msg_header_t * ws_read_header(int client)
|
||||
{
|
||||
|
||||
uint8_t byte;
|
||||
uint8_t bytes[8];
|
||||
ws_msg_header_t* header = (ws_msg_header_t*) malloc(sizeof(*header));
|
||||
|
||||
// get first byte
|
||||
if(recv(client, &byte, sizeof(byte), 0) <0) goto fail;
|
||||
if(BITV(byte,6) || BITV(byte,5) || BITV(byte,4)) goto fail;// all RSV bit must be 0
|
||||
|
||||
//printf("FIN: %d, RSV1: %d, RSV2: %d, RSV3:%d, opcode:%d\n", BITV(byte,7), BITV(byte,6), BITV(byte,5), BITV(byte,4),(byte & 0x0F) );
|
||||
// find and opcode
|
||||
header->fin = BITV(byte,7);
|
||||
header->opcode = (byte & 0x0F);
|
||||
|
||||
// get next byte
|
||||
if(recv(client, &byte, sizeof(byte), 0) <0) goto fail;
|
||||
|
||||
//printf("MASK: %d paylen:%d\n", BITV(byte,7), (byte & 0x7F));
|
||||
// check mask bit, should be 1
|
||||
if(!BITV(byte,7))
|
||||
{
|
||||
// close the connection with protocol error
|
||||
ws_close(client, 1002);
|
||||
goto fail;
|
||||
}
|
||||
// get the data length of the frame
|
||||
int len = (byte & 0x7F);
|
||||
if(len <= 125)
|
||||
{
|
||||
header->plen = len;
|
||||
} else if(len == 126)
|
||||
{
|
||||
if(recv(client,bytes, 2*sizeof(uint8_t), 0) <0) goto fail;
|
||||
header->plen = (bytes[0]<<8) + bytes[1];
|
||||
|
||||
} else
|
||||
{
|
||||
//read only last 4 byte
|
||||
if(recv(client,bytes, 8*sizeof(uint8_t), 0) <0) goto fail;
|
||||
header->plen = (bytes[4]<<24) + (bytes[5]<<16) + (bytes[6] << 8) + bytes[7] ;
|
||||
}
|
||||
//printf("len: %d\n", header->plen);
|
||||
// last step is to get the maskey
|
||||
if(recv(client,header->mask_key, 4*sizeof(uint8_t), 0) <0) goto fail;
|
||||
//printf("key 0: %d key 1: %d key2:%d, key3: %d\n",header->mask_key[0],header->mask_key[1],header->mask_key[2], header->mask_key[3] );
|
||||
|
||||
// check wheather it is a ping or a close message
|
||||
// process it and return NULL
|
||||
//otherwise return the header
|
||||
//return the header
|
||||
switch(header->opcode){
|
||||
case WS_CLOSE: // client requests to close the connection
|
||||
// send back a close message
|
||||
ws_close(client,1000);
|
||||
//goto fail;
|
||||
break;
|
||||
|
||||
case WS_PING: // client send a ping
|
||||
// send back a pong message
|
||||
pong(client,header->plen);
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
return header;
|
||||
|
||||
fail:
|
||||
free(header);
|
||||
return NULL;
|
||||
|
||||
}
|
||||
/**
|
||||
* Read data from client
|
||||
* and unmask data using the key
|
||||
*/
|
||||
int ws_read_data(int client, ws_msg_header_t* header, int len, uint8_t* data)
|
||||
{
|
||||
// if len == -1 ==> read all remaining data to 'data';
|
||||
if(header->plen == 0) return 0;
|
||||
int dlen = (len==-1 || len > header->plen)?header->plen:len;
|
||||
if((dlen = recv(client,data, dlen, 0)) <0) return -1;
|
||||
header->plen = header->plen - dlen;
|
||||
// unmask received data
|
||||
for(int i = 0; i < dlen; ++i)
|
||||
data[i] = data[i]^ header->mask_key[i%4];
|
||||
|
||||
return dlen;
|
||||
}
|
||||
void _send_header(int client, ws_msg_header_t header)
|
||||
{
|
||||
uint8_t byte = 0;
|
||||
uint8_t bytes[8];
|
||||
for(int i=0; i< 8; i++) bytes[i] = 0;
|
||||
//first byte |FIN|000|opcode|
|
||||
byte = (header.fin << 7) + header.opcode;
|
||||
send(client, &byte, 1, 0);
|
||||
// second byte, payload length
|
||||
// mask = 0
|
||||
if(header.plen <= 125)
|
||||
{
|
||||
byte = header.plen;
|
||||
send(client, &byte, 1, 0);
|
||||
}
|
||||
else if(header.plen < 65536) // 16 bits
|
||||
{
|
||||
byte = 126;
|
||||
bytes[0] = (header.plen) >> 8;
|
||||
bytes[1] = (header.plen) & 0x00FF;
|
||||
send(client, &byte, 1, 0);
|
||||
send(client, &bytes, 2, 0);
|
||||
}
|
||||
else // > 16 bits
|
||||
{
|
||||
byte = 127;
|
||||
bytes[4] = (header.plen) >> 24;
|
||||
bytes[5] = ((header.plen)>>16) & 0x00FF;
|
||||
bytes[6] = ((header.plen)>>8) & 0x00FF;
|
||||
bytes[7] = (header.plen) & 0x00FF;
|
||||
send(client, &byte, 1, 0);
|
||||
send(client, &bytes, 8, 0);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* send a text data frame to client
|
||||
*/
|
||||
void ws_t(int client, const char* data)
|
||||
{
|
||||
ws_msg_header_t header;
|
||||
header.fin = 1;
|
||||
header.opcode = WS_TEXT;
|
||||
header.plen = strlen(data);
|
||||
_send_header(client,header);
|
||||
send(client, data, header.plen,0);
|
||||
}
|
||||
/**
|
||||
* send a binary data fram to client
|
||||
* not tested yet, but should work
|
||||
*/
|
||||
void ws_b(int client, uint8_t* data, int l)
|
||||
{
|
||||
ws_msg_header_t header;
|
||||
header.fin = 1;
|
||||
header.opcode = WS_BIN;
|
||||
header.plen = l;
|
||||
_send_header(client,header);
|
||||
send(client, data, header.plen,0);
|
||||
}
|
||||
/**
|
||||
* Not tested yet
|
||||
* but should work
|
||||
*/
|
||||
void pong(int client, int len)
|
||||
{
|
||||
ws_msg_header_t pheader;
|
||||
pheader.fin = 1;
|
||||
pheader.opcode = WS_PONG;
|
||||
pheader.plen = len;
|
||||
uint8_t data[len];
|
||||
if(recv(client,data, len, 0) < 0) return;
|
||||
_send_header(client, pheader);
|
||||
send(client, data, len, 0);
|
||||
}
|
||||
/*
|
||||
* Not tested yet, but should work
|
||||
*/
|
||||
void ws_close(int client, unsigned int status)
|
||||
{
|
||||
ws_msg_header_t header;
|
||||
header.fin = 1;
|
||||
header.opcode = WS_CLOSE;
|
||||
header.plen = 2;
|
||||
uint8_t bytes[2];
|
||||
bytes[0] = status >> 8;
|
||||
bytes[1] = status & 0xFF;
|
||||
_send_header(client, header);
|
||||
send(client,bytes,2,0);
|
||||
}
|
||||
int ws_status(int client)
|
||||
{
|
||||
fd_set sk;
|
||||
FD_ZERO(&sk);
|
||||
FD_SET(0, &sk);
|
||||
FD_SET(client, &sk);
|
||||
int result = select(client + 1, sk, NULL, NULL, NULL);
|
||||
if(result == 1)
|
||||
{
|
||||
return FD_ISSET(client, &sk);
|
||||
}
|
||||
return result;
|
||||
}
|
28
plugins/ws.h
Normal file
28
plugins/ws.h
Normal file
@ -0,0 +1,28 @@
|
||||
#ifndef WS_H
|
||||
#define WS_H
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define BITV(v,i) ((v & (1 << i)) >> i)
|
||||
#define WS_TEXT 0x1
|
||||
#define WS_BIN 0x2
|
||||
#define WS_CLOSE 0x8
|
||||
#define WS_PING 0x9
|
||||
#define WS_PONG 0xA
|
||||
typedef struct{
|
||||
uint8_t fin;
|
||||
uint8_t opcode;
|
||||
unsigned int plen;
|
||||
uint8_t mask_key[4];
|
||||
} ws_msg_header_t;
|
||||
|
||||
ws_msg_header_t * ws_read_header(int);
|
||||
void ws_t(int , const char* );
|
||||
void ws_b(int , uint8_t* data, int);
|
||||
void ws_close(int, unsigned int);
|
||||
void pong(int client, int len);
|
||||
int ws_read_data(int , ws_msg_header_t*, int, uint8_t*);
|
||||
int ws_status(int);
|
||||
#endif
|
@ -1,88 +1,191 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/wait.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <termios.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <string.h>
|
||||
#include "../plugin.h"
|
||||
|
||||
void init();
|
||||
call __init__ = init;
|
||||
|
||||
void init()
|
||||
{
|
||||
|
||||
}
|
||||
void pexit()
|
||||
{
|
||||
|
||||
}
|
||||
void handler(int cl, const char* m, const char* rqp, dictionary rq)
|
||||
{
|
||||
ws_msg_header_t* h = NULL;
|
||||
if(ws_enable(rq))
|
||||
{
|
||||
|
||||
int read_buf(int fd, char*buf,int size)
|
||||
int fdm, fds;
|
||||
int rc;
|
||||
char buff[1024];
|
||||
|
||||
// Check arguments
|
||||
fdm = posix_openpt(O_RDWR);
|
||||
if (fdm < 0)
|
||||
{
|
||||
int i = 0;
|
||||
char c = '\0';
|
||||
int n;
|
||||
while ((i < size - 1) && (c != '\n'))
|
||||
{
|
||||
n = read(fd, &c, 1);
|
||||
if (n > 0)
|
||||
{
|
||||
buf[i] = c;
|
||||
i++;
|
||||
LOG("Error %d on posix_openpt()\n", errno);
|
||||
ws_close(cl, 1011);
|
||||
return ;
|
||||
}
|
||||
|
||||
rc = grantpt(fdm);
|
||||
if (rc != 0)
|
||||
{
|
||||
LOG("Error %d on grantpt()\n", errno);
|
||||
ws_close(cl, 1011);
|
||||
return ;
|
||||
}
|
||||
|
||||
rc = unlockpt(fdm);
|
||||
if (rc != 0)
|
||||
{
|
||||
LOG( "Error %d on unlockpt()\n", errno);
|
||||
ws_close(cl, 1011);
|
||||
return ;
|
||||
}
|
||||
|
||||
// Open the slave side ot the PTY
|
||||
fds = open(ptsname(fdm), O_RDWR);
|
||||
|
||||
// Create the child process
|
||||
if (fork())
|
||||
{
|
||||
fd_set fd_in;
|
||||
|
||||
// FATHER
|
||||
|
||||
// Close the slave side of the PTY
|
||||
close(fds);
|
||||
int max_fdm;
|
||||
while (1)
|
||||
{
|
||||
FD_ZERO(&fd_in);
|
||||
//FD_SET(0, &fd_in);
|
||||
FD_SET(fdm, &fd_in);
|
||||
FD_SET(cl,&fd_in);
|
||||
max_fdm = fdm>cl?fdm:cl;
|
||||
rc = select(max_fdm + 1, &fd_in, NULL, NULL, NULL);
|
||||
switch(rc)
|
||||
{
|
||||
case -1 :
|
||||
LOG("Error %d on select()\n", errno);
|
||||
ws_close(cl, 1011);
|
||||
return;
|
||||
|
||||
default :
|
||||
{
|
||||
// If data is on websocket side
|
||||
if (FD_ISSET(cl, &fd_in))
|
||||
{
|
||||
h = ws_read_header(cl);
|
||||
if(h)
|
||||
{
|
||||
if(h->opcode == WS_CLOSE)
|
||||
{
|
||||
LOG("%s\n","Websocket: connection closed");
|
||||
write(fdm, "exit\n", 5);
|
||||
return;
|
||||
}
|
||||
else if(h->opcode == WS_TEXT)
|
||||
{
|
||||
int l;
|
||||
while((l = ws_read_data(cl,h,sizeof(buff),buff)) > 0)
|
||||
{
|
||||
//buff[l] = '\0';
|
||||
write(fdm, buff, l);
|
||||
//ws_t(cl,buff);
|
||||
}
|
||||
/*if(l == -1)
|
||||
{
|
||||
printf("EXIT FROM CLIENT \n");
|
||||
write(fdm, "exit\n", 5);
|
||||
return;
|
||||
}*/
|
||||
}
|
||||
|
||||
free(h);
|
||||
}
|
||||
else if(n == -1) return n;
|
||||
else
|
||||
c = '\n';
|
||||
}
|
||||
buf[i] = '\0';
|
||||
return i;
|
||||
}
|
||||
void handler(int client, const char* m, const char* rqp, dictionary rq)
|
||||
{
|
||||
textstream(client);
|
||||
int filedes[2];
|
||||
char* code = R_STR(rq, "cmd");
|
||||
if(!code) return;
|
||||
if(pipe(filedes) == -1)
|
||||
write(fdm, "exit\n", 5);
|
||||
ws_close(cl,1000);
|
||||
}
|
||||
}
|
||||
// If data on master side of PTY
|
||||
if (FD_ISSET(fdm, &fd_in))
|
||||
{
|
||||
perror("pipe");
|
||||
//rc = read(fdm, buff, sizeof(buff));
|
||||
if ( (rc = read(fdm, buff,sizeof(buff)-1)) > 0)
|
||||
{
|
||||
// Send data to websocket
|
||||
buff[rc] = '\0';
|
||||
ws_t(cl,buff);
|
||||
} else
|
||||
{
|
||||
if (rc < 0)
|
||||
{
|
||||
LOG("Error %d on read standard input. Exit now\n", errno);
|
||||
write(fdm, "exit\n", 5);
|
||||
ws_close(cl,1011);
|
||||
return;
|
||||
}
|
||||
pid_t pid = fork();
|
||||
if(pid == -1)
|
||||
}
|
||||
}
|
||||
//printf("DONE\n");
|
||||
}
|
||||
} // End switch
|
||||
} // End while
|
||||
}
|
||||
else
|
||||
{
|
||||
perror("folk");
|
||||
return;
|
||||
} else if(pid == 0)
|
||||
{
|
||||
while ((dup2(filedes[1], STDOUT_FILENO) == -1) && (errno == EINTR)) {}
|
||||
close(filedes[1]);
|
||||
close(filedes[0]);
|
||||
// executecomand
|
||||
system(code);
|
||||
//perror("execl");
|
||||
struct termios slave_orig_term_settings; // Saved terminal settings
|
||||
struct termios new_term_settings; // Current terminal settings
|
||||
|
||||
// CHILD
|
||||
|
||||
// Close the master side of the PTY
|
||||
close(fdm);
|
||||
|
||||
// Save the defaults parameters of the slave side of the PTY
|
||||
//rc = tcgetattr(fds, &slave_orig_term_settings);
|
||||
|
||||
// Set RAW mode on slave side of PTY
|
||||
//new_term_settings = slave_orig_term_settings;
|
||||
//cfmakeraw (&new_term_settings);
|
||||
//tcsetattr (fds, TCSANOW, &new_term_settings);
|
||||
|
||||
// The slave side of the PTY becomes the standard input and outputs of the child process
|
||||
// we use cook mode here
|
||||
close(0); // Close standard input (current terminal)
|
||||
close(1); // Close standard output (current terminal)
|
||||
close(2); // Close standard error (current terminal)
|
||||
|
||||
dup(fds); // PTY becomes standard input (0)
|
||||
dup(fds); // PTY becomes standard output (1)
|
||||
dup(fds); // PTY becomes standard error (2)
|
||||
|
||||
// Now the original file descriptor is useless
|
||||
close(fds);
|
||||
|
||||
// Make the current process a new session leader
|
||||
setsid();
|
||||
|
||||
// As the child is a session leader, set the controlling terminal to be the slave side of the PTY
|
||||
// (Mandatory for programs like the shell to make them manage correctly their outputs)
|
||||
ioctl(0, TIOCSCTTY, 1);
|
||||
|
||||
//system("/bin/bash");
|
||||
system("sudo login");
|
||||
// if Error...
|
||||
ws_close(cl,1000);
|
||||
//LOG("%s\n","Terminal exit");
|
||||
_exit(1);
|
||||
}
|
||||
close(filedes[1]);
|
||||
char buffer[1024];
|
||||
while (1) {
|
||||
ssize_t count = read_buf(filedes[0],buffer, sizeof(buffer));
|
||||
if (count == -1) {
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
} else {
|
||||
perror("read");
|
||||
return;
|
||||
}
|
||||
} else if (count == 0) {
|
||||
break;
|
||||
} else {
|
||||
__t(client,"data:%s\n",buffer);
|
||||
//handle_child_process_output(buffer, count);
|
||||
}
|
||||
}
|
||||
close(filedes[0]);
|
||||
wait(0);
|
||||
free(code);
|
||||
printf("Child process exit\n");
|
||||
|
||||
LOG("%s\n","All processes exit");
|
||||
}
|
Loading…
Reference in New Issue
Block a user