Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Implement more of stream to half half of echo tcp server
  • Loading branch information
creationix committed Mar 8, 2012
1 parent bd28419 commit 828cd02
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 11 deletions.
16 changes: 8 additions & 8 deletions src/helpers.h
Expand Up @@ -2,16 +2,16 @@
#define LUV_HELPERS_H

/* Helper macro to check the return value of uv calls and throw errors */
#define UV_CALL(uv_func, ...) \
if (uv_func(__VA_ARGS__)) { \
uv_err_t err = uv_last_error(uv_default_loop()); \
JS_ReportError(cx, "##uv_func: %s", uv_strerror(err)); \
return JS_FALSE; \
#define UV_CALL(uv_func, ...) \
if (uv_func(__VA_ARGS__)) { \
uv_err_t err = uv_last_error(uv_default_loop()); \
JS_ReportError(cx, "%s: %s", #uv_func, uv_strerror(err)); \
return JS_FALSE; \
}

#define LUV_REF(cx, obj) \
(luv_ref_t*)malloc(sizeof(luv_ref_t)); \
ref->cx = cx; \
#define LUV_REF(cx, obj) \
(luv_ref_t*)malloc(sizeof(luv_ref_t)); \
ref->cx = cx; \
ref->obj = obj;

#endif
107 changes: 107 additions & 0 deletions src/luv_stream.c
Expand Up @@ -20,8 +20,115 @@ static JSBool luv_write(JSContext *cx, unsigned argc, jsval *vp) {
return JS_TRUE;
}

static void luv_on_connection(uv_stream_t* server, int status) {
luv_ref_t* ref;
ref = (luv_ref_t*)server->data;
if (!luv_call_callback(ref->cx, ref->obj, "onConnection", 0, NULL)) {
/* TODO: report properly */
printf("Error in onConnection callback\n");
}
}

static JSBool luv_listen(JSContext* cx, unsigned argc, jsval *vp) {
JSObject* this = JS_THIS_OBJECT(cx, vp);
uv_stream_t* stream;
stream = (uv_stream_t*)JS_GetPrivate(this);

int backlog;
JSObject* callback;
if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "io", &backlog, &callback)) {
return JS_FALSE;
}

if (!luv_store_callback(cx, this, "onConnection", callback)) return JS_FALSE;

UV_CALL(uv_listen, stream, backlog, luv_on_connection);

JS_SET_RVAL(cx, vp, JSVAL_VOID);
return JS_TRUE;
}

static JSBool luv_accept(JSContext* cx, unsigned argc, jsval *vp) {
JSObject* this = JS_THIS_OBJECT(cx, vp);
uv_stream_t* server;
uv_stream_t* client;
server = (uv_stream_t*)JS_GetPrivate(this);

JSObject* obj;
if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "o", &obj)) {
return JS_FALSE;
}
client = (uv_stream_t*)JS_GetPrivate(obj);

UV_CALL(uv_accept, server, client);

JS_SET_RVAL(cx, vp, JSVAL_VOID);
return JS_TRUE;
}

static uv_buf_t luv_on_alloc(uv_handle_t* handle, size_t suggested_size) {
uv_buf_t buf;
buf.base = malloc(suggested_size);
buf.len = suggested_size;
return buf;
}

static void luv_on_read(uv_stream_t* stream, ssize_t nread, uv_buf_t buf) {
printf("luv_on_read\n");
luv_ref_t* ref;
ref = (luv_ref_t*)stream->data;

if (nread >= 0) {
jsval chunk[1] = { STRING_TO_JSVAL(JS_NewStringCopyN(ref->cx, buf.base, nread)) };

if (!luv_call_callback(ref->cx, ref->obj, "onData", 1, chunk)) {
/* TODO: report properly */
printf("Error in onData callback\n");
}

} else {
uv_err_t err = uv_last_error(uv_default_loop());
if (err.code == UV_EOF) {
printf("EOF\n");
} else {
/*
TODO: Implement close
uv_close((uv_handle_t*)handle, luv_on_close);
*/
uv_err_t err = uv_last_error(uv_default_loop());
/*
TODO: Proper error handling
*/
printf("luv_on_read: %s\n", uv_strerror(err));
}
}

free(buf.base);
}

static JSBool luv_read_start(JSContext* cx, unsigned argc, jsval* vp) {
JSObject* this = JS_THIS_OBJECT(cx, vp);
uv_stream_t* stream;
stream = (uv_stream_t*)JS_GetPrivate(this);

JSObject* callback;
if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "o", &callback)) {
return JS_FALSE;
}

if (!luv_store_callback(cx, this, "onData", callback)) return JS_FALSE;

UV_CALL(uv_read_start, stream, luv_on_alloc, luv_on_read);

JS_SET_RVAL(cx, vp, JSVAL_VOID);
return JS_TRUE;
}

static JSFunctionSpec Stream_methods[] = {
JS_FS("write", luv_write, 0, JSPROP_ENUMERATE),
JS_FS("listen", luv_listen, 0, JSPROP_ENUMERATE),
JS_FS("accept", luv_accept, 0, JSPROP_ENUMERATE),
JS_FS("readStart", luv_read_start, 0, JSPROP_ENUMERATE),
JS_FS_END
};

Expand Down
1 change: 1 addition & 0 deletions src/luv_stream.h
Expand Up @@ -3,6 +3,7 @@

#include "jsapi.h"
#include "luv_handle.h"
#include "helpers.h"

JSObject* Stream_prototype;

Expand Down
14 changes: 11 additions & 3 deletions src/luv_tcp.c
Expand Up @@ -18,6 +18,10 @@ static JSBool Tcp_constructor(JSContext *cx, unsigned argc, jsval *vp) {
uv_tcp_init(uv_default_loop(), handle);
JS_SetPrivate(obj, handle);

/* Store a reference to the object in the handle */
luv_ref_t* ref = LUV_REF(cx, obj);
handle->data = ref;

JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj));
return JS_TRUE;
}
Expand All @@ -32,11 +36,15 @@ static JSBool luv_tcp_bind(JSContext *cx, unsigned argc, jsval *vp) {
uv_tcp_t* handle;
handle = (uv_tcp_t*)JS_GetInstancePrivate(cx, this, &Tcp_class, NULL);

/* TODO: don't hardcode */
const char* host = "0.0.0.0";
int port = 8080;

JSString* str;
int port;
if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "Si", &str, &port)) {
return JS_FALSE;
}
char *host = JS_EncodeString(cx, str);
struct sockaddr_in address = uv_ip4_addr(host, port);
JS_free(cx, host);

UV_CALL(uv_tcp_bind, handle, address);

Expand Down
16 changes: 16 additions & 0 deletions test-tcp.js
@@ -0,0 +1,16 @@
var p = require('utils').prettyPrint;

var Tcp = require('uv').Tcp;

var server = new Tcp();
server.bind("0.0.0.0", 1337);
server.listen(128, function () {
var client = new Tcp();
server.accept(client);
client.readStart(function (chunk) {
p("onRead", chunk);
});
p("Connection!", client);
});

p(server);
File renamed without changes.

0 comments on commit 828cd02

Please sign in to comment.