Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F140428
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
15 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/Makefile b/Makefile
index b0e89ce..9807776 100644
--- a/Makefile
+++ b/Makefile
@@ -1,74 +1,74 @@
MIX = mix
MYHTMLEX_CFLAGS = -g -O2 -std=c99 -pedantic -Wcomment -Wall
# we need to compile position independent code
MYHTMLEX_CFLAGS += -fpic -DPIC
# For some reason __erl_errno is undefined unless _REENTRANT is defined
MYHTMLEX_CFLAGS += -D_REENTRANT
# myhtmlex is using stpcpy, as defined in gnu string.h
# MYHTMLEX_CFLAGS += -D_GNU_SOURCE
# base on the same posix c source as myhtml
# MYHTMLEX_CFLAGS += -D_POSIX_C_SOURCE=199309
# turn warnings into errors
# MYHTMLEX_CFLAGS += -Werror
# ignore unused variables
# MYHTMLEX_CFLAGS += -Wno-unused-variable
# ignore unused parameter warnings
MYHTMLEX_CFLAGS += -Wno-unused-parameter
# set erlang include path
ERLANG_PATH = $(shell erl -eval 'io:format("~s", [lists:concat([code:root_dir(), "/erts-", erlang:system_info(version)])])' -s init stop -noshell)
MYHTMLEX_CFLAGS += -I$(ERLANG_PATH)/include
# expecting myhtml as a submodule in c_src/
# that way we can pin a version and package the whole thing in hex
# hex does not allow for non-app related dependencies.
MYHTML_PATH = c_src/myhtml
MYHTML_STATIC = $(MYHTML_PATH)/lib/libmyhtml_static.a
MYHTMLEX_CFLAGS += -I$(MYHTML_PATH)/include
# that would be used for a dynamically linked build
# MYHTMLEX_CFLAGS += -L$(MYHTML_PATH)/lib
MYHTMLEX_LDFLAGS = -shared
# C-Node
ERL_INTERFACE = $(wildcard $(ERLANG_PATH)/../lib/erl_interface-*)
CNODE_CFLAGS = $(MYHTMLEX_CFLAGS)
CNODE_CFLAGS += -L$(ERL_INTERFACE)/lib
CNODE_CFLAGS += -I$(ERL_INTERFACE)/include
CNODE_CFLAGS += -lerl_interface -lei
# platform specific
UNAME = $(shell uname -s)
ifeq ($(wilcard Makefile.$(UNAME)),)
include Makefile.$(UNAME)
endif
.PHONY: all
all: myhtmlex
myhtmlex: priv/myhtmlex.so
$(MIX) compile
$(MYHTML_STATIC): $(MYHTML_PATH)
$(MAKE) -C $(MYHTML_PATH) library
priv/myhtmlex.so: c_src/myhtmlex.c $(MYHTML_STATIC)
$(CC) $(MYHTMLEX_CFLAGS) $(MYHTMLEX_LDFLAGS) -o $@ $< $(MYHTML_STATIC)
priv/cclient: c_src/cclient.c $(MYHTML_STATIC)
- $(CC) $(CNODE_CFLAGS) -o $@ $< $(MYHTML_STATIC)
+ $(CC) -o $@ $< $(MYHTML_STATIC) $(CNODE_CFLAGS)
clean: clean-myhtml
$(RM) -r priv/myhtmlex*
$(RM) priv/cclient
$(RM) myhtmlex-*.tar
$(RM) -r package-test
clean-myhtml:
$(MAKE) -C $(MYHTML_PATH) clean
publish: clean
$(MIX) hex.publish
diff --git a/c_src/cserver.c b/c_src/cserver.c
deleted file mode 100644
index 6ca69ed..0000000
--- a/c_src/cserver.c
+++ /dev/null
@@ -1,500 +0,0 @@
-#include <stdlib.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <pthread.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <errno.h>
-
-#include "erl_interface.h"
-#include "ei.h"
-
-#include <myhtml/myhtml.h>
-#include <myhtml/mynamespace.h>
-
-#define BUFFER_SIZE 1000
-
-typedef struct _binding_t {
- int fd;
- int port;
- ErlConnect conn;
-} binding_t;
-
-typedef struct _thread_state_t {
- int fd;
- int idx;
- char *node;
-
- myhtml_tree_t* tree;
-} thread_state_t;
-
-typedef struct _prefab_t {
- ETERM* atom_nil;
- ETERM* atom_comment;
- ETERM* empty_list;
-} prefab_t;
-
-binding_t
-bind_any_port();
-void
-accept_loop(binding_t* binding);
-void
-*thread_receive_messages(void*); // receives thread_state_t* state
-void
-handle_emsg(thread_state_t* state, ErlMessage* emsg);
-void
-handle_send(thread_state_t* state, ErlMessage* emsg);
-ETERM*
-decode(thread_state_t* state, ErlMessage* emsg, ETERM* bin, ETERM* args);
-ETERM*
-build_tree(prefab_t* prefab, myhtml_tree_t* tree, myhtml_tree_node_t* node, unsigned char* parse_flags);
-ETERM*
-build_node_children(prefab_t* prefab, myhtml_tree_t* tree, myhtml_tree_node_t* parent, unsigned char* parse_flags);
-ETERM*
-build_node_attrs(prefab_t* prefab, myhtml_tree_t* tree, myhtml_tree_node_t* node);
-ETERM*
-err_term(const char* error_atom);
-
-static int TIDX = 0; // thread index
-
-const unsigned char FLAG_HTML_ATOMS = 1 << 0;
-const unsigned char FLAG_NIL_SELF_CLOSING = 1 << 1;
-const unsigned char FLAG_COMMENT_TUPLE3 = 1 << 2;
-
-int main(int argc, char **argv) {
- if (argc != 4 || !strcmp(argv[1],"-h") || !strcmp(argv[1],"--help")) {
- printf("\nUsage: ./priv/cnode_server <sname> <hostname> <cookie>\n\n");
- printf(" sname the short name you want this c-node to connect as\n");
- printf(" hostname the hostname\n");
- printf(" cookie the authentication cookie\n");
- return 0;
- }
-
- char *sname = argv[1];
- char *hostname = argv[2];
- char *cookie = argv[3];
- /* gethostname(hostname, 256); */
- char full_name[1024];
- stpcpy(stpcpy(stpcpy(full_name, sname), "@"), hostname);
-
- struct in_addr addr;
- addr.s_addr = htonl(INADDR_ANY);
-
- // initialize all of Erl_Interface
- erl_init(NULL, 0);
-
- printf("initialising %s\n", full_name); fflush(stdout);
- if ( erl_connect_xinit(hostname, sname, full_name, &addr, cookie, 0) == -1 )
- erl_err_quit("error erl_connect_init");
-
- // create a listen socket
- binding_t binding = bind_any_port();
- if (binding.fd < 0)
- erl_err_quit("error bind_any_port");
-
- // publish our port
- if (erl_publish(binding.port) == -1)
- erl_err_quit("error erl_publish");
-
- // signal to stdout that we are ready, do not fflush yet
- printf("%s ready\n", full_name);
-
- // accept loop
- accept_loop(&binding);
-}
-
-void
-accept_loop(binding_t* binding)
-{
- thread_state_t* state;
- pthread_t thread;
- pthread_attr_t attr;
- int fd;
- ErlConnect conn;
- myhtml_t* myhtml = myhtml_create();
- myhtml_init(myhtml, MyHTML_OPTIONS_DEFAULT, 1, 0);
-
- // now it is really time to flush stdout
- fflush(stdout);
-
- // initialising phtread attributes
- if (pthread_attr_init(&attr)) {
- fprintf(stderr, "error while init pthread attr struct\n\r"); fflush(stderr);
- return; // TODO: DIE
- }
- if ((pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED))) {
- fprintf(stderr, "error while setting pthread attributes\n\r"); fflush(stderr);
- return; // TODO: DIE
- }
-
- // spawn a new thread for each connected erlang client
- for(;;) {
- while((fd = erl_accept(binding->fd, &conn)) == ERL_ERROR)
- fprintf(stderr, "error accepting connection\n"); fflush(stderr);
-
- if((state = (thread_state_t*)malloc(sizeof(thread_state_t))) == NULL) {
- fprintf(stderr, "error allocating memory for new thread\n"); fflush(stderr);
- return; // TODO: DIE
- }
-
- if((state->node = (char*)malloc(strlen(conn.nodename)+1)) == NULL) {
- fprintf(stderr, "error allocating memory for new state\n"); fflush(stderr);
- return; // TODO: DIE
- }
-
- state->fd = fd;
- state->idx = TIDX;
- strcpy(state->node, binding->conn.nodename);
- state->tree = myhtml_tree_create();
- myhtml_tree_init(state->tree, myhtml);
-
- printf("node joined\n"); fflush(stdout);
- if (pthread_create(&thread, &attr, thread_receive_messages, state)) {
- fprintf(stderr, "error pthread_create\n\r"); fflush(stderr);
- return; // TODO: DIE
- }
- TIDX++;
- }
-
- return;
-}
-
-void
-*thread_receive_messages(void *arg)
-{
- thread_state_t *state = (thread_state_t*)arg;
- bool looping = true;
- /* unsigned char buffer[BUFFER_SIZE]; */
- ErlMessage emsg;
- // TODO: get erl_xreceive_msg to work
- // making use of reallocatable buffer sizes
- /* unsigned char **bufferpp; */
- /* int *buffer_size; */
- /* buffer_size = malloc(sizeof(int)); */
- /* *buffer_size = BUFFER_SIZE; */
- /* *bufferpp = malloc(*buffer_size); */
- int buffer_size = BUFFER_SIZE;
- unsigned char* bufferpp = (unsigned char*)malloc(BUFFER_SIZE);
-
- while (looping) {
- // erl_xreceive_msg adapts the buffer width
- switch( erl_xreceive_msg(state->fd, &bufferpp, &buffer_size, &emsg) )
- // erl_receive_msg, uses a fixed buffer width
- /* switch( erl_receive_msg(state->fd, buffer, BUFFER_SIZE, &emsg) ) */
- {
- case ERL_TICK:
- // ignore
- break;
- case ERL_ERROR:
- // On failure, the function returns ERL_ERROR and sets erl_errno to one of:
- //
- // EMSGSIZE
- // Buffer is too small.
- // ENOMEM
- // No more memory is available.
- // EIO
- // I/O error.
- //
- // TODO: what is the correct reaction?
- looping = false;
- break;
- default:
- handle_emsg(state, &emsg);
- }
- }
-
- free(state->node);
- free(state);
- printf("lost node\n"); fflush(stdout);
- return 0;
-}
-
-void
-handle_emsg(thread_state_t* state, ErlMessage* emsg)
-{
- switch(emsg->type)
- {
- case ERL_REG_SEND:
- case ERL_SEND:
- handle_send(state, emsg);
- break;
- case ERL_LINK:
- case ERL_UNLINK:
- break;
- case ERL_EXIT:
- break;
- }
- // its our responsibility to free these pointers
- erl_free_compound(emsg->msg);
- erl_free_compound(emsg->to);
- erl_free_compound(emsg->from);
-}
-
-void
-handle_send(thread_state_t* state, ErlMessage* emsg)
-{
- ETERM *decode_pattern = erl_format("{decode, Bin, Args}");
- ETERM *response;
-
- if (erl_match(decode_pattern, emsg->msg))
- {
- ETERM *bin = erl_var_content(decode_pattern, "Bin");
- ETERM *args = erl_var_content(decode_pattern, "Args");
-
- response = decode(state, emsg, bin, args);
-
- // free allocated resources
- erl_free_term(bin);
- erl_free_term(args);
- }
- else
- {
- response = err_term("unknown_call");
- return;
- }
-
- // send response
- erl_send(state->fd, emsg->from, response);
-
- // free allocated resources
- erl_free_compound(response);
- erl_free_term(decode_pattern);
-
- // free the free-list
- erl_eterm_release();
-
- return;
-}
-
-ETERM*
-err_term(const char* error_atom)
-{
- /* ETERM* tuple2[] = {erl_mk_atom("error"), erl_mk_atom(error_atom)}; */
- /* return erl_mk_tuple(tuple2, 2); */
- return erl_format("{error, ~w}", erl_mk_atom(error_atom));
-}
-
-ETERM*
-decode(thread_state_t* state, ErlMessage* emsg, ETERM* bin, ETERM* args)
-{
- unsigned char parse_flags = 0;
- prefab_t prefab;
-
- // prepare reusable prefab terms
- prefab.atom_nil = erl_mk_atom("nil");
- prefab.atom_comment = erl_mk_atom("comment");
- prefab.empty_list = erl_mk_empty_list();
-
- if (!ERL_IS_BINARY(bin) || !ERL_IS_LIST(args))
- {
- return err_term("badarg");
- }
-
- // get contents of binary argument
- char* binary = (char*)ERL_BIN_PTR(bin);
- size_t binary_len = ERL_BIN_SIZE(bin);
-
- // parse tree
- mystatus_t status = myhtml_parse(state->tree, MyENCODING_UTF_8, binary, binary_len);
- if (status != MyHTML_STATUS_OK)
- {
- return err_term("myhtml_parse_failed");
- }
-
- // build tree
- myhtml_tree_node_t *root = myhtml_tree_get_document(state->tree);
- return build_tree(&prefab, state->tree, myhtml_node_last_child(root), &parse_flags);
-}
-
-ETERM*
-build_tree(prefab_t* prefab, myhtml_tree_t* tree, myhtml_tree_node_t* node, unsigned char* parse_flags)
-{
- ETERM* result;
- myhtml_tag_id_t tag_id = myhtml_node_tag_id(node);
- /* myhtml_namespace_t tag_ns = myhtml_node_namespace(node); */
-
- if (tag_id == MyHTML_TAG__TEXT)
- {
- size_t text_len;
- const char* node_text = myhtml_node_text(node, &text_len);
- result = erl_mk_binary(node_text, text_len);
- }
- else if (tag_id == MyHTML_TAG__COMMENT)
- {
- size_t comment_len;
- const char* node_comment = myhtml_node_text(node, &comment_len);
- ETERM* comment = erl_mk_binary(node_comment, comment_len);
-
- if (*parse_flags & FLAG_COMMENT_TUPLE3)
- {
- /* ETERM* tuple3[] = {prefab->atom_comment, prefab->empty_list, comment}; */
- /* result = erl_mk_tuple(tuple3, 3); */
- result = erl_format("{comment, [], ~w}", comment);
- }
- else
- {
- /* ETERM* tuple2[] = {prefab->atom_comment, comment}; */
- /* result = erl_mk_tuple(tuple2, 2); */
- result = erl_format("{comment, ~w}", comment);
- }
- }
- else
- {
- ETERM* tag;
- ETERM* attrs;
- ETERM* children;
-
- // get name of tag
- size_t tag_name_len;
- const char *tag_name = myhtml_tag_name_by_id(tree, tag_id, &tag_name_len);
- // get namespace of tag
- /* size_t tag_ns_len; */
- /* const char *tag_ns_name_ptr = myhtml_namespace_name_by_id(tag_ns, &tag_ns_len); */
- /* char *tag_ns_buffer; */
- /* char buffer [tag_ns_len + tag_name_len + 1]; */
- /* char *tag_string = buffer; */
- /* size_t tag_string_len; */
-
- tag = erl_mk_binary(tag_name, tag_name_len);
-
- // attributes
- attrs = build_node_attrs(prefab, tree, node);
-
- // children
- children = build_node_children(prefab, tree, node, parse_flags);
-
- /* ETERM* tuple3[] = {tag, attrs, children}; */
- /* result = erl_mk_tuple(tuple3, 3); */
- result = erl_format("{~w, ~w, ~w}", tag, attrs, children);
- }
-
- return result;
-}
-
-ETERM*
-build_node_children(prefab_t* prefab, myhtml_tree_t* tree, myhtml_tree_node_t* parent, unsigned char* parse_flags)
-{
- if (myhtml_node_is_close_self(parent) && (*parse_flags & FLAG_NIL_SELF_CLOSING))
- {
- /* prefab->atom_nil; */
- return erl_mk_atom("nil");
- }
-
- myhtml_tree_node_t* child = myhtml_node_last_child(parent);
- if (child == NULL)
- {
- if (myhtml_node_is_void_element(parent) && (*parse_flags & FLAG_NIL_SELF_CLOSING))
- {
- /* return prefab->atom_nil; */
- return erl_mk_atom("nil");
- }
- /* else */
- /* { */
- /* return prefab->empty_list; */
- /* } */
- }
-
- ETERM* list = erl_mk_empty_list();
-
- while (child)
- {
- ETERM* node_tuple = build_tree(prefab, tree, child, parse_flags);
- list = erl_cons(node_tuple, list);
-
- // get previous child, building the list from reverse
- child = myhtml_node_prev(child);
- }
-
- return list;
-}
-
-ETERM*
-build_node_attrs(prefab_t* prefab, myhtml_tree_t* tree, myhtml_tree_node_t* node)
-{
- myhtml_tree_attr_t* attr = myhtml_node_attribute_last(node);
-
- /* if (attr == NULL) */
- /* { */
- /* return prefab->empty_list; */
- /* } */
-
- ETERM* list = erl_mk_empty_list();
-
- while (attr)
- {
- ETERM* name;
- ETERM* value;
- ETERM* attr_tuple;
-
- size_t attr_name_len;
- const char *attr_name = myhtml_attribute_key(attr, &attr_name_len);
- size_t attr_value_len;
- const char *attr_value = myhtml_attribute_value(attr, &attr_value_len);
-
- if (attr_value) {
- value = erl_mk_binary(attr_value, attr_value_len);
- } else {
- value = erl_mk_binary(attr_name, attr_name_len);
- }
- name = erl_mk_binary(attr_name, attr_name_len);
-
- /* ETERM* tuple2[] = {name, value}; */
- /* attr_tuple = erl_mk_tuple(tuple2, 2); */
- attr_tuple = erl_format("{~w, ~w}", name, value);
-
- list = erl_cons(attr_tuple, list);
-
- // get prev attribute, building the list from reverse
- attr = myhtml_attribute_prev(attr);
- }
-
- return list;
-}
-
-binding_t
-bind_any_port()
-{
- int port = 40000;
- binding_t result;
- result.fd = -1;
- struct sockaddr_in addr;
- int on = 1;
- int bind_result;
-
- if ((result.fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
- {
- return result;
- }
-
- setsockopt(result.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
-
- memset((void*) &addr, 0, (size_t) sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = htonl(INADDR_ANY);
- addr.sin_port = htons(port);
-
- while(
- (bind_result = bind(result.fd, (struct sockaddr*) &addr, sizeof(addr))) < 0
- && errno == EADDRINUSE
- )
- {
- port++;
- addr.sin_port = htons(port);
- }
- if (bind_result < 0)
- {
- return result;
- }
- else
- {
- result.port = port;
-
- listen(result.fd, 5);
-
- return result;
- }
-}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sun, Jan 19, 8:37 PM (1 d, 20 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
55441
Default Alt Text
(15 KB)
Attached To
Mode
R16 fast_html
Attached
Detach File
Event Timeline
Log In to Comment