Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
cd ./usrsctp/usrsctplib/ && make
cd ../../
cd examples/websocket_client/cpslib/
make
cd ../../../
cmake -DUSRSCTP_LIBRARY=./usrsctp/usrsctplib/.libs/libusrsctp.so.1 -DUSRSCTP_INCLUDE_DIR=./usrsctp/usrsctplib -DSPDLOG_INCLUDE_DIR="./spdlog/include/" -DDISABLE_SPDLOG=off -DCMAKE_BUILD_TYPE=Debug
make
23 changes: 22 additions & 1 deletion examples/websocket_client/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,26 @@ add_executable(testclient
testclient.cpp
WebSocketWrapper.cpp
WebSocketWrapper.hpp)

target_link_libraries(testclient rtcdcpp)

add_executable(testclientoffer
json/json.h
json/json-forwards.h
easywsclient.cpp
easywsclient.hpp
jsoncpp.cpp
testclient_offer.cpp
WebSocketWrapper.cpp
WebSocketWrapper.hpp)
target_link_libraries(testclientoffer rtcdcpp)

add_executable(testclientanswer
json/json.h
json/json-forwards.h
easywsclient.cpp
easywsclient.hpp
jsoncpp.cpp
testclient_answer.cpp
WebSocketWrapper.cpp
WebSocketWrapper.hpp)
target_link_libraries(testclientanswer rtcdcpp)
101 changes: 101 additions & 0 deletions examples/websocket_client/testclient_answer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/**
* Simple WebRTC test client.
*/

#include "WebSocketWrapper.hpp"
#include "json/json.h"

#include <rtcdcpp/PeerConnection.hpp>
#include <rtcdcpp/Logging.hpp>

#include <iostream>

using namespace rtcdcpp;

int main(void) {
#ifndef SPDLOG_DISABLED
auto console_sink = std::make_shared<spdlog::sinks::ansicolor_stdout_sink_mt>();
spdlog::create("rtcdcpp.PeerConnection", console_sink);
spdlog::create("rtcdcpp.SCTP", console_sink);
spdlog::create("rtcdcpp.Nice", console_sink);
spdlog::create("rtcdcpp.DTLS", console_sink);
spdlog::set_level(spdlog::level::debug);
#endif

WebSocketWrapper ws("ws://localhost:5000/channel/test");
std::shared_ptr<PeerConnection> pc;
std::shared_ptr<DataChannel> dc;

if (!ws.Initialize()) {
std::cout << "WebSocket connection failed\n";
return 0;
}

RTCConfiguration config;
config.ice_servers.emplace_back(RTCIceServer{"stun3.l.google.com", 19302});

bool running = true;

ChunkQueue messages;

std::function<void(std::string)> onMessage = [&messages](std::string msg) {
messages.push(std::shared_ptr<Chunk>(new Chunk((const void *)msg.c_str(), msg.length())));
};

std::function<void(PeerConnection::IceCandidate)> onLocalIceCandidate = [&ws](PeerConnection::IceCandidate candidate) {
Json::Value jsonCandidate;
jsonCandidate["type"] = "candidate";
jsonCandidate["msg"]["candidate"] = candidate.candidate;
jsonCandidate["msg"]["sdpMid"] = candidate.sdpMid;
jsonCandidate["msg"]["sdpMLineIndex"] = candidate.sdpMLineIndex;

Json::StreamWriterBuilder wBuilder;
ws.Send(Json::writeString(wBuilder, jsonCandidate));
};

std::function<void(std::shared_ptr<DataChannel> channel)> onDataChannel = [&dc](std::shared_ptr<DataChannel> channel) {
std::cout << "Hey cool, got a data channel\n";
dc = channel;
dc->SendString("Hello from native code");
//dc->Close();
};

ws.SetOnMessage(onMessage);
ws.Start();
ws.Send("{\"type\": \"client_connected\", \"msg\": {}}");

Json::Reader reader;
Json::StreamWriterBuilder msgBuilder;

while (running) {
ChunkPtr cur_msg = messages.wait_and_pop();
std::string msg((const char *)cur_msg->Data(), cur_msg->Length());
std::cout << msg << "\n";
Json::Value root;
if (reader.parse(msg, root)) {
std::cout << "Got msg of type: " << root["type"] << "\n";
if (root["type"] == "offer") {
std::cout << "Time to get the rtc party started\n";
pc = std::make_shared<PeerConnection>(config, onLocalIceCandidate, onDataChannel);

pc->ParseOffer(root["msg"]["sdp"].asString());
Json::Value answer;
answer["type"] = "answer";
answer["msg"]["sdp"] = pc->GenerateAnswer();
answer["msg"]["type"] = "answer";

std::cout << "Sending Answer: " << answer << "\n";
ws.Send(Json::writeString(msgBuilder, answer));
} else if (root["type"] == "candidate") {
pc->SetRemoteIceCandidate("a=" + root["msg"]["candidate"].asString());
}
} else {
std::cout << "Json parse failed"
<< "\n";
}
}

ws.Close();

return 0;
}
115 changes: 115 additions & 0 deletions examples/websocket_client/testclient_offer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/**
* Simple WebRTC test client.
* Cpp to JavaScript
*/

#include "WebSocketWrapper.hpp"
#include "json/json.h"

#include <rtcdcpp/PeerConnection.hpp>
#include <rtcdcpp/Logging.hpp>

#include <iostream>

using namespace rtcdcpp;

void OnStrMsg(std::string s){
std::cout << s << "\n" ;
}
int main(void) {
#ifndef SPDLOG_DISABLED
auto console_sink = std::make_shared<spdlog::sinks::ansicolor_stdout_sink_mt>();
spdlog::create("rtcdcpp.PeerConnection", console_sink);
spdlog::create("rtcdcpp.SCTP", console_sink);
spdlog::create("rtcdcpp.Nice", console_sink);
spdlog::create("rtcdcpp.DTLS", console_sink);
spdlog::set_level(spdlog::level::debug);
#endif

WebSocketWrapper ws("ws://localhost:5000/channel/test");
std::shared_ptr<PeerConnection> pc;
std::shared_ptr<DataChannel> dc;

if (!ws.Initialize()) {
std::cout << "WebSocket connection failed\n";
return 0;
}

RTCConfiguration config;
config.ice_servers.emplace_back(RTCIceServer{"stun3.l.google.com", 19302});

bool running = true;

ChunkQueue messages;

std::function<void(std::string)> onMessage = [&messages](std::string msg) {
messages.push(std::shared_ptr<Chunk>(new Chunk((const void *)msg.c_str(), msg.length())));
};

std::function<void(PeerConnection::IceCandidate)> onLocalIceCandidate = [&ws](PeerConnection::IceCandidate candidate) {
Json::Value jsonCandidate;
jsonCandidate["type"] = "candidate";
jsonCandidate["msg"]["candidate"] = candidate.candidate;
jsonCandidate["msg"]["sdpMid"] = candidate.sdpMid;
jsonCandidate["msg"]["sdpMLineIndex"] = candidate.sdpMLineIndex;

Json::StreamWriterBuilder wBuilder;
ws.Send(Json::writeString(wBuilder, jsonCandidate));
};

std::function<void(std::shared_ptr<DataChannel> channel)> onDataChannel = [&dc](std::shared_ptr<DataChannel> channel) {
std::cout << "Hey cool, got a data channel\n";
dc = channel;
dc->SendString("Hello from native code");
dc->SetOnStringMsgCallback(OnStrMsg);
// dc->Close();
};

ws.SetOnMessage(onMessage);
ws.Start();
ws.Send("{\"type\": \"client_connected\", \"msg\": {}}");

Json::Reader reader;
Json::StreamWriterBuilder msgBuilder;
Json::Value jsonOffer;
pc = std::make_shared<PeerConnection>(config, onLocalIceCandidate, onDataChannel);
pc->CreateDataChannel("testchannel","");
std::string offer = pc->GenerateOffer();

jsonOffer["type"] = "offer";
std::cout << "offer" << offer ;
jsonOffer["msg"]["sdp"] = offer;
Json::StreamWriterBuilder wBuilder;
ws.Send(Json::writeString(wBuilder, jsonOffer));
while (running) {
ChunkPtr cur_msg = messages.wait_and_pop();
std::string msg((const char *)cur_msg->Data(), cur_msg->Length());
//std::cout << msg << "\n";
Json::Value root;
if (reader.parse(msg, root)) {
std::cout << "Got msg of type: " << root["type"] << "\n";
if (root["type"] == "answer") {
std::cout << "Time to get the rtc party started\n";
// pc = std::make_shared<PeerConnection>(config, onLocalIceCandidate, onDataChannel);
std::cout << "remote answer sdp as string : " << root["msg"]["sdp"].asString()<< "\n";
pc->ParseOffer(root["msg"]["sdp"].asString());
// Json::Value answer;
// answer["type"] = "answer";
// answer["msg"]["sdp"] = pc->GenerateAnswer();
// answer["msg"]["type"] = "answer";

// std::cout << "Sending Answer: " << answer << "\n";
// ws.Send(Json::writeString(msgBuilder, answer));
} else if (root["type"] == "candidate") {
pc->SetRemoteIceCandidate("a=" + root["msg"]["candidate"].asString());
}
} else {
std::cout << "Json parse failed"
<< "\n";
}
}

ws.Close();

return 0;
}
6 changes: 3 additions & 3 deletions include/rtcdcpp/DataChannel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ namespace rtcdcpp {
#define DATA_CHANNEL_PARTIAL_RELIABLE_TIMED 0x02
#define DATA_CHANNEL_PARTIAL_RELIABLE_TIMED_UNORDERED 0x82

typedef struct {
typedef struct __attribute__((packed, aligned(1))) {
uint8_t msg_type;
uint8_t chan_type;
uint16_t priority;
Expand All @@ -80,7 +80,7 @@ class DataChannel {
uint8_t chan_type;
std::string label;
std::string protocol;

uint32_t reliability;
// TODO: Priority field

std::function<void()> open_cb;
Expand All @@ -97,7 +97,7 @@ class DataChannel {
void OnError(std::string description);

public:
DataChannel(PeerConnection *pc, uint16_t stream_id, uint8_t chan_type, std::string label, std::string protocol);
DataChannel(PeerConnection *pc, uint16_t stream_id, uint8_t chan_type, std::string label, std::string protocol, uint32_t reliability);
virtual ~DataChannel();

/**
Expand Down
9 changes: 8 additions & 1 deletion include/rtcdcpp/PeerConnection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ struct RTCConfiguration {
};

class PeerConnection {
friend class DTLSWrapper;
public:
struct IceCandidate {
IceCandidate(const std::string &candidate, const std::string &sdpMid, int sdpMLineIndex)
Expand All @@ -80,6 +81,11 @@ class PeerConnection {
*/
void ParseOffer(std::string offer_sdp);

/**
* Generate Offer SDP
*/
std::string GenerateOffer();

/**
* Generate Answer SDP
*/
Expand All @@ -103,7 +109,7 @@ class PeerConnection {
* TODO: Handle creating data channels before generating SDP, so that the
* data channel is created as part of the connection process.
*/
// std::shared_ptr<DataChannel> CreateDataChannel(std::string label);
std::shared_ptr<DataChannel> CreateDataChannel(std::string label, std::string protocol="", uint8_t chan_type=DATA_CHANNEL_RELIABLE, uint32_t reliability=0);

/**
* Notify when remote party creates a DataChannel.
Expand Down Expand Up @@ -150,6 +156,7 @@ class PeerConnection {

// DataChannel message parsing
void HandleNewDataChannel(ChunkPtr chunk, uint16_t sid);
void HandleDataChannelAck(uint16_t sid);
void HandleStringMessage(ChunkPtr chunk, uint16_t sid);
void HandleBinaryMessage(ChunkPtr chunk, uint16_t sid);

Expand Down
19 changes: 19 additions & 0 deletions include/rtcdcpp/SCTPWrapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,28 @@ class SCTPWrapper {

// Handle a decrypted SCTP packet
void DTLSForSCTP(ChunkPtr chunk);

void SendACK(uint8_t chan_type, uint32_t reliability);
void CreateDCForSCTP(std::string label, std::string protocol="", uint8_t chan_type = DATA_CHANNEL_RELIABLE, uint32_t reliability = 0);

dc_open_msg *data;
uint16_t sid;
std::string label;
std::string protocol;

dc_open_msg* GetDataChannelData();
uint16_t GetSid();
std::string GetProtocol();
std::string GetLabel();
void SetDataChannelSID(uint16_t sid);

// Send a message to the remote connection
// Note, this will cause 1+ DTLSEncrypt callback calls
void GSForSCTP(ChunkPtr chunk, uint16_t sid, uint32_t ppid);

private:
// PeerConnection *peer_connection;
uint32_t reliability;
bool started{false};
struct socket *sock;
uint16_t local_port;
Expand All @@ -76,6 +91,10 @@ class SCTPWrapper {
std::mutex connectMtx;
std::condition_variable connectCV;

bool readyDataChannel{false};
std::mutex createDCMtx;
std::condition_variable createDC;

ChunkQueue send_queue;
ChunkQueue recv_queue;

Expand Down
1 change: 1 addition & 0 deletions spdlog
Submodule spdlog added at 15af51
8 changes: 5 additions & 3 deletions src/DTLSWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,11 @@ bool DTLSWrapper::Initialize() {

void DTLSWrapper::Start() {
SPDLOG_TRACE(logger, "Start(): Starting handshake - {}", std::this_thread::get_id());

// XXX: We can never be the server (sdp always returns active, not passive)
SSL_set_connect_state(ssl);
if (peer_connection->role == peer_connection->Server) {
SSL_set_accept_state(ssl); // This is for role server.
} else {
SSL_set_connect_state(ssl);
}
uint8_t buf[4192];
SSL_do_handshake(ssl);
while (BIO_ctrl_pending(out_bio) > 0) {
Expand Down
4 changes: 2 additions & 2 deletions src/DataChannel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@

namespace rtcdcpp {

DataChannel::DataChannel(PeerConnection *pc, uint16_t stream_id, uint8_t chan_type, std::string label, std::string protocol)
: pc(pc), stream_id(stream_id), chan_type(chan_type), label(label), protocol(protocol) {
DataChannel::DataChannel(PeerConnection *pc, uint16_t stream_id, uint8_t chan_type, std::string label, std::string protocol, uint32_t reliability)
: pc(pc), stream_id(stream_id), chan_type(chan_type), label(label), protocol(protocol), reliability(reliability) {
// XXX: Default-noop callbacks
open_cb = []() { ; }; // XXX: I love and hate that this is valid c++
str_msg_cb = [](std::string x) { ; };
Expand Down
Loading