For webRTC clients to connect to each other, you need ICE. Although STUN and TURN, which you do not need for such a test, are part of this, even without these helpers, you still need to use ICE to tell the other end to which the IP / port / protocol is connected.
There are two ways to do this: Google "trickle ice", where the SDP (response / offer) is transmitted without any ICE candidates. Then they are transferred along a separate signal layer and added as they are detected. This speeds up the connection process because ICE takes time and some later ICE candidates may not be needed.
The classic method is to wait until all ICE candidates have been collected, and then generate SDP with those already included.
I changed your latest version to do this: http://pastebin.com/g2YVvrRd
You also need to wait for the datachannel / connection to become available before you can use it, so I moved the sending of the message to the onopen channel event.
Significant changes in the source code:
Interface callbacks have been removed from Host.prototype.createOffer and Guest.prototype.createAnswer, instead we attach the provided callback function to the corresponding objects for later use.
self.cb = cb;
The host and guest have an additional ICE handler for PeerConnection:
var self = this; this.peer.onicecandidate = function (event) {
For the guest user, self.offer becomes self.answer
Interface handler $ ("# submitAnswer"). click () no longer sends a message, but is sent when the datanel is ready in the onopen event defined in setChannelEvents ().
channel.onopen = function () { console.log('** channel.onopen'); channel.send('hello world!'); };