$ git clone https://socialnetwork.ion.nu/socialnetwork-web.git
commit 18fd27d8c090f04980b03d21f2fdc0aa94110354
Author: Alicia <...>
Date:   Sun Jun 4 22:51:05 2017 +0200

    Lots of little fixes:
    moved adaptforjs.patch out into jsglue.c
    made libraries build properly
    fixed squeezeandcomment.sh so it doesn't break .js files
    fixed the conversion to and from javascript Blobs
    use document.domain for the websocket connection

diff --git a/Makefile b/Makefile
index f17b755..7d4533f 100644
--- a/Makefile
+++ b/Makefile
@@ -5,8 +5,11 @@ GMPVERSION=6.1.2
 NETTLEVERSION=3.3
 GNUTLSVERSION=3.5.12
 SOCIALNETWORKREVISION=9e11beb56de1c867b1339fef577c97c2ac619d59
+REVISION=$(shell git log | sed -n -e 's/^commit //p;q')
+JSLIBS=$(shell PKG_CONFIG_PATH=toolchain/usr/lib/pkgconfig pkg-config --libs gnutls nettle hogweed) -lgmp
+JSCFLAGS=$(shell PKG_CONFIG_PATH=toolchain/usr/lib/pkgconfig pkg-config --cflags gnutls)
 
-all: webpeer socialnetwork/libsocial.js
+all: webpeer libsocial.js
 
 webpeer: daemon.o webpeer.o
  $(CC) $^ $(LIBS) -o $@
@@ -14,9 +17,12 @@ webpeer: daemon.o webpeer.o
 toolchain/usr/bin/emcc: emscripten-$(EMSCRIPTVERSION).tar.gz emscripten-fastcomp-$(EMSCRIPTVERSION).tar.gz emscripten-fastcomp-clang-$(EMSCRIPTVERSION).tar.gz
  ./buildtoolchain.sh '$(EMSCRIPTVERSION)'
 
-socialnetwork/libsocial.js: toolchain/usr/bin/emcc
+toolchain/usr/lib/libsocial.so: toolchain/usr/bin/emcc
  ./buildlibs.sh '$(GMPVERSION)' '$(NETTLEVERSION)' '$(GNUTLSVERSION)'
- ./squeezeandcomment.sh '$@' 'This code was built from gmp $(GMPVERSION), nettle $(NETTLEVERSION), gnutls $(GNUTLSVERSION) and socialnetwork git revision $(SOCIALNETWORKREVISION) using emscripten (fastcomp) $(EMSCRIPTVERSION)'
+
+libsocial.js: jsglue.c toolchain/usr/lib/libsocial.so
+ toolchain/usr/bin/emcc -O3 -s EXPORTED_FUNCTIONS="['_social_init','_peer_handlesocket','_peer_new_unique','_websockproxy_read','_websockproxy_setwrite','_jsglue_addfile']" -s RESERVED_FUNCTION_POINTERS=1 -s NO_EXIT_RUNTIME=1 -s NODEJS_CATCH_EXIT=0 -s EXPORTED_RUNTIME_METHODS="['ccall','cwrap']" -s INVOKE_RUN=0 $(JSCFLAGS) $^ $(JSLIBS) -o $@
+ ./squeezeandcomment.sh '$@' 'This code was built from gmp $(GMPVERSION), nettle $(NETTLEVERSION), gnutls $(GNUTLSVERSION) and socialnetwork git revision $(SOCIALNETWORKREVISION) with tweaks from socialnetwork-web git revision $(REVISION) using emscripten (fastcomp) $(EMSCRIPTVERSION)'
 
 # Download all external sources we'll need
 download:
diff --git a/adaptforjs.patch b/adaptforjs.patch
deleted file mode 100644
index f4b14c7..0000000
--- a/adaptforjs.patch
+++ /dev/null
@@ -1,272 +0,0 @@
-diff --git a/Makefile b/Makefile
-index 62667e9..0450b1e 100644
---- a/Makefile
-+++ b/Makefile
-@@ -1,12 +1,11 @@
--LIBS=$(shell pkg-config --libs gnutls)
--CFLAGS=-g3 -Wall $(shell pkg-config --cflags gnutls)
-+LIBS=$(shell pkg-config --libs gnutls nettle hogweed) -lgmp -O3
-+CFLAGS=-O3 -Wall $(shell pkg-config --cflags gnutls)
- PREFIX=/usr

--all: socialtest libsocial.so libsocial.pc
-+all: libsocial.js

--libsocial.so: CFLAGS+=-fPIC
--libsocial.so: social.o peer.o update.o udpstream.o
-- $(CC) -shared $^ $(LIBS) -o $@
-+libsocial.js: social.o peer.o update.o udpstream.o
-+ $(CC) -shared $^ $(LIBS) -s EXPORTED_FUNCTIONS="['_social_init','_peer_handlesocket','_peer_new_unique']" -s RESERVED_FUNCTION_POINTERS=1 -o $@

- libsocial.pc:
-  echo 'prefix=$(PREFIX)' > libsocial.pc
-diff --git a/peer.c b/peer.c
-index 7d02247..e918944 100644
---- a/peer.c
-+++ b/peer.c
-@@ -211,19 +211,14 @@ void peer_init(const char* keypath)
-   if(!privkey)
-   {
-     gnutls_x509_privkey_init(&privkey);
--    struct stat st;
-+//    struct stat st;
-     char loadfailed=1;
--    if(!stat(keypath, &st))
-     {
-       gnutls_datum_t keydata;
--      keydata.size=st.st_size;
--      keydata.data=malloc(st.st_size);
--      int f=open(keypath, O_RDONLY);
--      read(f, keydata.data, st.st_size);
--      close(f);
-+      keydata.size=strlen(keypath);
-+      keydata.data=keypath;
-       // TODO: Allow encrypted keys, using _import2()
-       if(!gnutls_x509_privkey_import2(privkey, &keydata, GNUTLS_X509_FMT_PEM, 0, GNUTLS_PKCS_PLAIN)){loadfailed=0;}
--      free(keydata.data);
-     }
-     if(loadfailed)
-     {
-@@ -232,12 +227,13 @@ void peer_init(const char* keypath)
-       gnutls_x509_privkey_generate(privkey, GNUTLS_PK_RSA, 3072, 0);
- // printf("Done\n");
-       // TODO: Allow exporting encrypted key, using _export2_pkcs8() I think
--      gnutls_datum_t keydata;
--      gnutls_x509_privkey_export2(privkey, GNUTLS_X509_FMT_PEM, &keydata);
--      int f=open(keypath, O_WRONLY|O_TRUNC|O_CREAT, 0600);
--      write(f, keydata.data, keydata.size);
--      close(f);
--      gnutls_free(keydata.data);
-+// TODO: Return this to the user, somewhere (or to the server, if password-protecting it is secure enough for that and the user registers a username to tie it to)
-+//      gnutls_datum_t keydata;
-+//      gnutls_x509_privkey_export2(privkey, GNUTLS_X509_FMT_PEM, &keydata);
-+//      int f=open(keypath, O_WRONLY|O_TRUNC|O_CREAT, 0600);
-+//      write(f, keydata.data, keydata.size);
-+//      close(f);
-+//      gnutls_free(keydata.data);
-     }
-     size_t size=ID_SIZE;
-     gnutls_x509_privkey_get_key_id(privkey, GNUTLS_KEYID_USE_SHA256, peer_id, &size);
-@@ -390,7 +386,7 @@ void peer_bootstrap(int sock, const char* peerlist)
- #define readordie(x,y,z) {ssize_t r=gnutls_record_recv(x->tls,y,z); if(z && r<1){peer_disconnect(x, 0); continue;}}
- void peer_handlesocket(int sock) // Incoming data
- {
--  udpstream_readsocket(sock); // If it locks up here we're probably missing a bootstrap node
-+//  udpstream_readsocket(sock); // If it locks up here we're probably missing a bootstrap node
-   struct peer* peer;
-   while((peer=findpending()))
-   {
-diff --git a/social.c b/social.c
-index 6c05f24..171e7a8 100644
---- a/social.c
-+++ b/social.c
-@@ -66,6 +66,7 @@ static void user_save(struct user* user)

- static void user_load(struct user* user)
- {
-+/*
-   // Load user data (only pubkey atm), but spare pubkey if it's already set
-   if(!user->pubkey)
-   {
-@@ -96,6 +97,7 @@ static void user_load(struct user* user)
-     read(f, buf, size);
-     social_update_parse(user, buf, size);
-   }
-+*/
- }

- static struct user* user_new(const unsigned char id[ID_SIZE])
-diff --git a/udpstream.c b/udpstream.c
-index ba57da5..3b232f9 100644
---- a/udpstream.c
-+++ b/udpstream.c
-@@ -61,6 +61,7 @@ struct udpstream
-   unsigned int buflen;
-   unsigned char state;
-   time_t timestamp;
-+  uint16_t wsseq;
- // TODO: add void pointer to keep relevant application data? plus a function to free it if the connection is closed or abandoned as stale
- };

-@@ -83,6 +84,7 @@ static struct udpstream* stream_new(int sock, struct sockaddr* addr, socklen_t a
-   stream->buflen=0;
-   stream->state=0; // Start new streams as invalid, need to init
-   stream->timestamp=time(0);
-+  stream->wsseq=0;
-   ++streamcount;
-   streams=realloc(streams, sizeof(void*)*streamcount);
-   streams[streamcount-1]=stream;
-@@ -102,6 +104,7 @@ struct udpstream* udpstream_find(struct sockaddr* addr, socklen_t addrlen)
-   return 0;
- }

-+/*
- static ssize_t stream_send(struct udpstream* stream, uint8_t type, uint16_t seq, uint32_t size, const void* buf)
- {
- // TODO: Include a checksum in the header?
-@@ -137,6 +140,7 @@ static void udpstream_requestresend(struct udpstream* stream, uint16_t seq)
-   if(!missedcount){return;}
-   stream_send(stream, TYPE_RESEND, 0, missedcount*sizeof(uint16_t), missed);
- }
-+*/

- static void stream_free(struct udpstream* stream)
- {
-@@ -167,10 +171,12 @@ struct udpstream* udpstream_new(int sock, struct sockaddr* addr, socklen_t addrl
- {
-   struct udpstream* stream=stream_new(sock, addr, addrlen);
-   stream->state=STATE_INIT; // If we're creating the stream we're the ones initializing it
--  stream_send(stream, TYPE_INIT, 0, 0, 0);
-+// TODO: Notify webpeer so it'll initiate the connection? I guess the TLS handshake takes care of that
-+//  stream_send(stream, TYPE_INIT, 0, 0, 0);
-   return stream;
- }

-+/*
- void udpstream_readsocket(int sock)
- {
-   time_t now=time(0);
-@@ -288,14 +294,16 @@ fprintf(stderr, "TODO: resend packets\n");
-     }
-   }
- }
-+*/

- struct udpstream* udpstream_poll(void)
- {
--  time_t now=time(0);
-+//  time_t now=time(0);
-   unsigned int i;
-   for(i=0; i<streamcount; ++i)
-   {
-     // Check for state changes
-+// TODO: Webpeer needs to send status changes like this over the websocket and libsocialjs.js needs to pass it along to libsocial
-     if(streams[i]->state&STATE_CLOSED){return streams[i];}
-     // Check for the next packet in the order
-     unsigned int i2;
-@@ -303,6 +311,7 @@ struct udpstream* udpstream_poll(void)
-     {
-       if(streams[i]->recvpackets[i2].seq==streams[i]->inseq){return streams[i];}
-     }
-+/*
-     // Send ping if it's been 20 seconds without any data, unless we already sent one
-     if(streams[i]->timestamp+20<now && !(streams[i]->state&STATE_PING))
-     {
-@@ -320,6 +329,7 @@ struct udpstream* udpstream_poll(void)
-         return streams[i];
-       }
-     }
-+*/
-   }
-   return 0;
- }
-@@ -355,8 +365,10 @@ ssize_t udpstream_read(struct udpstream* stream, void* buf, size_t size)
-   return -1;
- }

-+void(*websockproxy_write)(struct sockaddr*, socklen_t, const void*, size_t);
- ssize_t udpstream_write(struct udpstream* stream, const void* buf, size_t size)
- {
-+/*
-   if(stream->state&(STATE_CLOSED|STATE_CLOSING)){return 0;} // EOF, TODO: -1 and EBADFD for STATE_CLOSING?
- // TODO: abort and return negative if sentpacketcount is too high? EWOULDBLOCK?
-   ++stream->sentpacketcount;
-@@ -367,6 +379,8 @@ ssize_t udpstream_write(struct udpstream* stream, const void* buf, size_t size)
-   memcpy(stream->sentpackets[stream->sentpacketcount-1].buf, buf, size);
-   stream_send(stream, TYPE_PAYLOAD, stream->outseq, size, buf);
-   ++stream->outseq;
-+*/
-+  websockproxy_write(&stream->addr, stream->addrlen, buf, size);
-   return size;
- }

-@@ -380,11 +394,31 @@ int udpstream_getsocket(struct udpstream* stream){return stream->sock;}

- void udpstream_close(struct udpstream* stream)
- {
--  if(stream->state&STATE_CLOSED) // Closed by peer, just free it
--  {
-+//  if(stream->state&STATE_CLOSED) // Closed by peer, just free it
-+//  {
-     stream_free(stream);
-+/*
-   }else{
-     stream->state|=STATE_CLOSING;
-     stream_send(stream, TYPE_CLOSE, 0, 0, 0);
-   }
-+*/
-+}
-+
-+void websockproxy_setwrite(void(*writefunc)(struct sockaddr*, socklen_t, const void*, size_t))
-+{
-+  websockproxy_write=writefunc;
-+}
-+void websockproxy_read(struct sockaddr* addr, socklen_t addrlen, const void* buf, size_t payloadsize)
-+{
-+  // Find the stream
-+  struct udpstream* stream=udpstream_find(addr, addrlen);
-+  if(!stream){stream=stream_new(-1, addr, addrlen);}
-+  // Add to list of parsed packets
-+  ++stream->recvpacketcount;
-+  stream->recvpackets=realloc(stream->recvpackets, sizeof(struct packet)*stream->recvpacketcount);
-+  stream->recvpackets[stream->recvpacketcount-1].seq=(stream->wsseq++);
-+  stream->recvpackets[stream->recvpacketcount-1].buf=malloc(payloadsize);
-+  stream->recvpackets[stream->recvpacketcount-1].buflen=payloadsize;
-+  memcpy(stream->recvpackets[stream->recvpacketcount-1].buf, buf, payloadsize);
- }
-diff --git a/update.c b/update.c
-index aa69d92..8ad78dc 100644
---- a/update.c
-+++ b/update.c
-@@ -26,6 +26,7 @@
- #include "social.h"
- #include "update.h"

-+/*
- static void mkdirp(char* path)
- {
-   char* next=path;
-@@ -38,6 +39,7 @@ static void mkdirp(char* path)
-     slash[0]='/';
-   }
- }
-+*/

- void social_update_write(struct buffer* buf, struct update* update)
- {
-@@ -109,6 +111,7 @@ void social_update_sign(struct update* update)

- void social_update_save(struct user* user, struct update* update)
- {
-+/*
-   char path[strlen(social_prefix)+strlen("/updates/0")+ID_SIZE*2];
-   sprintf(path, "%s/updates/"PEERFMT, social_prefix, PEERARG(user->id));
-   mkdirp(path);
-@@ -124,6 +127,7 @@ void social_update_save(struct user* user, struct update* update)
-   buffer_deinit(buf);
-   close(f);
- // TODO: Is it bad to close and reopen a file in rapid succession? if it is maybe we should implement some kind of cache for cases where we're saving many updates fast, like receiving someone else's updates for the first time
-+*/
- }

- struct update* social_update_getfield(struct user* user, const char* name)
diff --git a/buildlibs.sh b/buildlibs.sh
index 7191795..993b6d0 100755
--- a/buildlibs.sh
+++ b/buildlibs.sh
@@ -17,7 +17,7 @@
 prefix="`pwd`/toolchain/usr"
 export PATH="${prefix}/bin:${PATH}"
 export PKG_CONFIG_PATH="${prefix}/lib/pkgconfig"
-export CFLAGS='-O3' # TODO: Make sure these didn't break anything
+export CFLAGS='-O3'
 export LDFLAGS='-O3'
 GMPVERSION="$1"
 NETTLEVERSION="$2"
@@ -29,35 +29,50 @@ tar -xJf "../gmp-${GMPVERSION}.tar.xz"
 cd "gmp-${GMPVERSION}"
 mkdir -p build
 cd build
-emconfigure ../configure --prefix="$prefix" --disable-static --enable-shared --disable-assembly
+emconfigure ../configure --prefix="$prefix" --disable-static --enable-shared --disable-assembly ABI=32 ac_cv_sizeof_mp_limb_t=4
 make
 make install
 cd ../..
+
 # nettle
 tar -xzf "../nettle-${NETTLEVERSION}.tar.gz"
 cd "nettle-${NETTLEVERSION}"
 # Remove emscripten-incompatible options
 sed -i -e 's/ -ggdb3//' configure
-# Work around broken macros
-sed -i -e 's/#if !/#ifndef /' camellia-internal.h camellia-absorb.c
-sed -i -e 's/#if /#ifdef /' camellia-crypt-internal.c
 # Work around emscripten limitations with fopen in configure
 sed -i -e 's/FILE *\* *f *= *fopen *( *\("[^"]*"\)/#include <unistd.h>\n#include <fcntl.h>\nint fd=open(\1, O_WRONLY|O_CREAT|O_TRUNC, 0644);\nFILE*f=fdopen(fd/' configure
 mkdir -p build
 cd build
-emconfigure ../configure --prefix="$prefix" --disable-static --enable-shared --disable-assembler --disable-documentation LDFLAGS="-L${prefix}/lib -I${prefix}/include" CFLAGS="-I${prefix}/include"
-sed -i -e 's/^#define SIZEOF[^ ]* $/&4/' config.h
+emconfigure ../configure --prefix="$prefix" --disable-static --enable-shared --disable-assembler --disable-documentation LDFLAGS="-L${prefix}/lib -I${prefix}/include" CFLAGS="-I${prefix}/include" ac_cv_sizeof_char=1 ac_cv_sizeof_int=4 ac_cv_sizeof_long=4 ac_cv_sizeof_short=2 ac_cv_sizeof_size_t=4 ac_cv_sizeof_voidp=4
 make GMP_NUMB_BITS=32
 make install
 cd ../..
+
 # gnutls
 tar -xJf "../gnutls-${GNUTLSVERSION}.tar.xz"
 cd "gnutls-${GNUTLSVERSION}"
 mkdir -p build
 cd build
-emconfigure ../configure --prefix="$prefix" --disable-static --enable-shared --with-included-libtasn1 --disable-hardware-acceleration --disable-dtls-srtp-support --disable-srp-authentication --disable-psk-authentication --disable-openpgp-authentication --disable-ocsp --disable-openssl-compatibility --disable-nls --disable-libdane --without-tpm --without-p11-kit --disable-tests --disable-cxx --disable-tools --with-included-unistring --with-zlib LDFLAGS="-L${prefix}/lib"
+emconfigure ../configure --prefix="$prefix" --disable-static --enable-shared --with-included-libtasn1 --disable-hardware-acceleration --disable-dtls-srtp-support --disable-srp-authentication --disable-psk-authentication --disable-openpgp-authentication --disable-ocsp --disable-openssl-compatibility --disable-nls --disable-libdane --without-tpm --without-p11-kit --disable-tests --disable-cxx --disable-tools --with-included-unistring --with-zlib ac_cv_sizeof_char_p=4 ac_cv_sizeof_long=4 ac_cv_sizeof_short=2 ac_cv_sizeof_unsigned_int=4 ac_cv_sizeof_unsigned_long_int=4 ac_cv_sizeof_void_p=4 LDFLAGS="-L${prefix}/lib"
 make
 make install defexec_DATA=
+
+# socialnetwork
 cd ../../../socialnetwork
-git apply ../adaptforjs.patch
-emmake make
+# Get rid of code and structures that were needed for UDP, add some stuff needed for websockets
+if [ ! -e .patched ]; then
+  sed -i -e 's|^ *stream_send|// &|
+s/if(.*timestamp.*/if(0)/
+s|^[^/].*sentpacket|// &|
+s|^static\(.* stream_new(\)|\1|
+/stream_send.*TYPE_PAYLOAD/a websockproxy_write(&stream->addr, stream->addrlen, buf, size);
+/time_t timestamp;/a uint16_t wsseq;
+/stream=malloc/a stream->wsseq=0;' udpstream.c
+  sed -i -e 's|^ *udpstream_readsocket|// &|' peer.c
+  touch .patched
+fi
+# Expose internal structures that we need to interact with to inject packets from websockets
+mkdir -p "${prefix}/include/libsocial"
+sed -n -e '/^struct [^()*]*$/,/^}/p' udpstream.c > "${prefix}/include/libsocial/udpstream_private.h"
+emmake make PREFIX="$prefix" CC='emcc -include ../jsglue.h -O3'
+emmake make install PREFIX="$prefix"
diff --git a/jsglue.c b/jsglue.c
new file mode 100644
index 0000000..5dcee29
--- /dev/null
+++ b/jsglue.c
@@ -0,0 +1,135 @@
+/*
+    socialnetwork-web, peer-to-peer social network web client
+    Copyright (C) 2017  alicia@ion.nu
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Affero General Public License version 3
+    as published by the Free Software Foundation.
+
+    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 Affero General Public License for more details.
+
+    You should have received a copy of the GNU Affero General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <time.h>
+#include <sys/socket.h>
+#include <libsocial/udpstream_private.h>
+#include <libsocial/udpstream.h>
+#include "jsglue.h"
+extern struct udpstream* stream_new(int sock, struct sockaddr* addr, socklen_t addrlen);
+
+struct file
+{
+  char* name;
+  void* content;
+  size_t size;
+};
+
+struct fileinfo
+{
+  struct file* file;
+  unsigned int pos;
+};
+
+static struct file* files=0;
+static unsigned int filecount=0;
+static struct fileinfo* fds=0;
+static unsigned int fdcount=0;
+
+static struct file* getfile(const char* path)
+{
+  unsigned int i;
+  for(i=0; i<filecount; ++i)
+  {
+    if(!strcmp(files[i].name, path)){return &files[i];}
+  }
+  return 0;
+}
+
+ssize_t jsglue_read(int fd, void* buf, size_t size)
+{
+  if(fd<0){return -1;}
+  if(size>fds[fd].file->size-fds[fd].pos){size=fds[fd].file->size-fds[fd].pos;}
+  memcpy(buf, fds[fd].file->content+fds[fd].pos, size);
+  return size;
+}
+
+ssize_t jsglue_write(int fd, const void* buf, size_t size)
+{
+// TODO: Writing
+  return size;
+}
+
+int jsglue_open(const char* path, int flags, mode_t mode)
+{
+  struct file* f=getfile(path);
+  if(!f){return -1;}
+  unsigned int i;
+  for(i=0; i<fdcount; ++i)
+  {
+    if(!fds[i].file){break;}
+  }
+  if(i==fdcount)
+  {
+    fds=realloc(fds, (++fdcount)*sizeof(struct fileinfo));
+  }
+  fds[i].file=f;
+  fds[i].pos=0;
+  return i;
+}
+
+int jsglue_stat(const char* path, struct stat* st)
+{
+  struct file* f=getfile(path);
+  if(!f){return 1;}
+  st->st_size=f->size;
+  return 0;
+}
+
+void jsglue_close(int fd)
+{
+  fds[fd].file=0;
+}
+
+void jsglue_addfile(const char* path, const void* data, size_t size)
+{
+  struct file* f=getfile(path);
+  if(!f) // New file
+  {
+    ++filecount;
+    files=realloc(files, filecount*sizeof(struct file));
+    f=&files[filecount-1];
+  }else{ // Overwrite old
+    free(f->name);
+    free(f->content);
+  }
+  f->name=strdup(path);
+  f->content=malloc(size);
+  memcpy(f->content, data, size);
+  f->size=size;
+}
+
+void(*websockproxy_write)(struct sockaddr*, socklen_t, const void*, size_t);
+void websockproxy_setwrite(void(*writefunc)(struct sockaddr*, socklen_t, const void*, size_t))
+{
+  websockproxy_write=writefunc;
+}
+void websockproxy_read(struct sockaddr* addr, socklen_t addrlen, const void* buf, size_t payloadsize)
+{
+  // Find the stream
+  struct udpstream* stream=udpstream_find(addr, addrlen);
+  if(!stream){stream=stream_new(-1, addr, addrlen);}
+  // Add to list of parsed packets
+  ++stream->recvpacketcount;
+  stream->recvpackets=realloc(stream->recvpackets, sizeof(struct packet)*stream->recvpacketcount);
+  stream->recvpackets[stream->recvpacketcount-1].seq=(stream->wsseq++);
+  stream->recvpackets[stream->recvpacketcount-1].buf=malloc(payloadsize);
+  stream->recvpackets[stream->recvpacketcount-1].buflen=payloadsize;
+  memcpy(stream->recvpackets[stream->recvpacketcount-1].buf, buf, payloadsize);
+}
diff --git a/jsglue.h b/jsglue.h
new file mode 100644
index 0000000..bfb578c
--- /dev/null
+++ b/jsglue.h
@@ -0,0 +1,34 @@
+/*
+    socialnetwork-web, peer-to-peer social network web client
+    Copyright (C) 2017  alicia@ion.nu
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Affero General Public License version 3
+    as published by the Free Software Foundation.
+
+    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 Affero General Public License for more details.
+
+    You should have received a copy of the GNU Affero General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include <unistd.h> // Include it first because we're going to override some functions from there, but don't want to get any mess from the declarations
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+
+#define read(fd,buf,size) jsglue_read(fd,buf,size)
+#define write(fd,buf,size) jsglue_write(fd,buf,size)
+#define open(path,flags,...) jsglue_open(path,flags,0)
+#define stat(path,st) jsglue_stat(path,st)
+#define close(fd) jsglue_close(fd)
+#define mkdir(path,mode) 0 // Screw directories :)
+
+extern ssize_t jsglue_read(int fd, void* buf, size_t size);
+extern ssize_t jsglue_write(int fd, const void* buf, size_t size);
+extern int jsglue_open(const char* path, int flags, mode_t mode);
+extern int jsglue_stat(const char* path, struct stat* st);
+extern void jsglue_close(int fd);
+extern void(*websockproxy_write)(struct sockaddr*, socklen_t, const void*, size_t);
diff --git a/libsocialjs.js b/libsocialjs.js
index eb75271..f30807e 100644
--- a/libsocialjs.js
+++ b/libsocialjs.js
@@ -17,8 +17,8 @@
 var connection;
 function websockwrite(addr, addrlen, buf, size)
 {
-  addr=new Blob(Module.HEAP8.subarray(addr, addr+addrlen));
-  buf=new Blob(Module.HEAP8.subarray(buf, buf+size));
+  addr=new Blob([Module.HEAP8.subarray(addr, addr+addrlen)]);
+  buf=new Blob([Module.HEAP8.subarray(buf, buf+size)]);
   connection.send(addr);
   connection.send(buf);
 }
@@ -31,28 +31,33 @@ var firstpacket=true;
 function handlenet(data)
 {
   var f=new FileReader();
-  f.readAsArrayBuffer(data.data);
-  data=new Int8Array(f.result);
-  if(firstpacket) // Bootstrap
-  {
-    firstpacket=false;
-    // TODO: Read lengths and pass subarrays until we reach the end of the array. length=data[pos]*256+data[pos+1]
-    peer_new_unique(-1, data, data.length);
-    return;
-  }
-  if(websockproxy_to)
+  f.onload=function()
   {
-    websockproxy_read(websockproxy_to, websockproxy_to.length, data, data.length);
-    _peer_handlesocket(-1); // Handle whatever we just received
-  }else{websockproxy_to=data;}
+    data=new Int8Array(f.result);
+    if(firstpacket) // Bootstrap
+    {
+      firstpacket=false;
+      // TODO: Read lengths and pass subarrays until we reach the end of the array. length=data[pos]*256+data[pos+1]
+      peer_new_unique(-1, data, data.length);
+      return;
+    }
+    if(websockproxy_to)
+    {
+      websockproxy_read(websockproxy_to, websockproxy_to.length, data, data.length);
+      _peer_handlesocket(-1); // Handle whatever we just received
+      websockproxy_to=false;
+    }else{websockproxy_to=data;}
+  };
+  f.readAsArrayBuffer(data.data);
 }
 function init(privkey)
 {
   websockproxy_read=Module.cwrap('websockproxy_read', null, ['array', 'number', 'array', 'number']);
   peer_new_unique=Module.cwrap('peer_new_unique', 'array', ['number', 'array', 'number']);
   _websockproxy_setwrite(Runtime.addFunction(websockwrite));
-  connection=new WebSocket('wss://127.0.0.1:5000/', 'socialwebsock-0.1');
+  Module.ccall('jsglue_addfile', null, ['string', 'string', 'number'], ['privkey.pem', privkey, privkey.length]);
+  Module.ccall('social_init', null, ['string', 'string'], ['privkey.pem', '']);
+  connection=new WebSocket('wss://'+document.domain+':5000/', 'socialwebsock-0.1');
   connection.onmessage=handlenet;
   connection.onclose=function(){alert('The connection to the server was lost.');};
-  Module.ccall('social_init', null, ['string', 'string'], [privkey, '']);
 }
diff --git a/squeezeandcomment.sh b/squeezeandcomment.sh
index c8bd3df..ae4498f 100755
--- a/squeezeandcomment.sh
+++ b/squeezeandcomment.sh
@@ -1,8 +1,10 @@
 #!/bin/sh
 file="$1"
+cp "$file" "${file}.unsqueezed"
 comment="$2"
 base="`basename "$file"`"
-sed -i -e '/^$/d;/^\/\//d' "$file" # Probably safe
+sed -i -e 's|// .*||; /^$/d' "$file" # Probably safe
+sed -i -e 's/throw new[^};]*;\?/;/g' "$file" # Don't waste space on error messages
 tr -d '\r\n' < "$file" > ".tmp.${base}" # Not so safe
 mv ".tmp.${base}" "$file"
 sed -i -e "1i// ${comment}" "$file" # 100% safe
diff --git a/webpeer.c b/webpeer.c
index 06bbe25..6ccad71 100644
--- a/webpeer.c
+++ b/webpeer.c
@@ -40,8 +40,7 @@ void webpeer(int sock)
   struct sockaddr_in bootstrapaddr={
     .sin_family=AF_INET,
     .sin_addr.s_addr=0x100007f,
-    .sin_port=htons(4000),
-    0
+    .sin_port=htons(4000)
   };
   websock_write(conn, &bootstrapaddr, sizeof(bootstrapaddr), WEBSOCK_BINARY);
   // Listen to client and udpstream socket and pass messages back and forth (client handles the TLS within the udpstream)