fixed #17416: Wrong default port of SocketIO connection. (#17459)

Supports SSL connection for SocketIO.
Avoid memory corruption while disconnecting SocketIO, _ws->close() has to be at the end of ‘SIOClientImpl::disconnect()’.
This commit is contained in:
James Chen 2017-03-07 15:49:38 +08:00 committed by minggo
parent 0536f6dc74
commit 1c0e56efef
2 changed files with 65 additions and 64 deletions

View File

@ -28,6 +28,7 @@
****************************************************************************/
#include "network/SocketIO.h"
#include "network/Uri.h"
#include <algorithm>
#include <sstream>
#include <iterator>
@ -345,8 +346,11 @@ class SIOClientImpl :
public WebSocket::Delegate
{
private:
int _port, _heartbeat, _timeout;
std::string _host, _sid, _uri;
int _heartbeat, _timeout;
std::string _sid;
std::string _hostAndPort;
Uri _uri;
std::string _caFilePath;
bool _connected;
SocketIOPacket::SocketIOVersion _version;
@ -355,10 +359,10 @@ private:
Map<std::string, SIOClient*> _clients;
public:
SIOClientImpl(const std::string& host, int port);
SIOClientImpl(const Uri& uri, const std::string& caFilePath);
virtual ~SIOClientImpl();
static SIOClientImpl* create(const std::string& host, int port);
static SIOClientImpl* create(const Uri& uri, const std::string& caFilePath);
virtual void onOpen(WebSocket* ws);
virtual void onMessage(WebSocket* ws, const WebSocket::Data& data);
@ -390,13 +394,13 @@ public:
//method implementations
//begin SIOClientImpl methods
SIOClientImpl::SIOClientImpl(const std::string& host, int port) :
_port(port),
_host(host),
_uri(host + ":" + StringUtils::toString(port)),
SIOClientImpl::SIOClientImpl(const Uri& uri, const std::string& caFilePath) :
_uri(uri),
_caFilePath(caFilePath),
_connected(false),
_ws(nullptr)
{
_hostAndPort = _uri.getHost() + ":" + StringUtils::toString(_uri.getPort());
}
SIOClientImpl::~SIOClientImpl()
@ -412,7 +416,13 @@ void SIOClientImpl::handshake()
CCLOGINFO("SIOClientImpl::handshake() called");
std::stringstream pre;
pre << "http://" << _uri << "/socket.io/1/?EIO=2&transport=polling&b64=true";
if (_uri.isSecure())
pre << "https://";
else
pre << "http://";
pre << _hostAndPort << "/socket.io/1/?EIO=2&transport=polling&b64=true";
HttpRequest* request = new (std::nothrow) HttpRequest();
request->setUrl(pre.str());
@ -423,6 +433,10 @@ void SIOClientImpl::handshake()
CCLOGINFO("SIOClientImpl::handshake() waiting");
if (_uri.isSecure() && !_caFilePath.empty())
{
HttpClient::getInstance()->setSSLVerification(_caFilePath);
}
HttpClient::getInstance()->send(request);
request->release();
@ -558,18 +572,23 @@ void SIOClientImpl::openSocket()
std::stringstream s;
if (_uri.isSecure())
s << "wss://";
else
s << "ws://";
switch (_version)
{
case SocketIOPacket::SocketIOVersion::V09x:
s << _uri << "/socket.io/1/websocket/" << _sid;
s << _hostAndPort << "/socket.io/1/websocket/" << _sid;
break;
case SocketIOPacket::SocketIOVersion::V10x:
s << _uri << "/socket.io/1/websocket/?EIO=2&transport=websocket&sid=" << _sid;
s << _hostAndPort << "/socket.io/1/websocket/?EIO=2&transport=websocket&sid=" << _sid;
break;
}
_ws = new (std::nothrow) WebSocket();
if (!_ws->init(*this, s.str()))
if (!_ws->init(*this, s.str(), nullptr, _caFilePath))
{
CC_SAFE_DELETE(_ws);
}
@ -605,16 +624,17 @@ void SIOClientImpl::disconnect()
Director::getInstance()->getScheduler()->unscheduleAllForTarget(this);
_ws->close();
_connected = false;
SocketIO::getInstance()->removeSocket(_uri);
SocketIO::getInstance()->removeSocket(_hostAndPort);
// Close websocket connection should be at last.
_ws->close();
}
SIOClientImpl* SIOClientImpl::create(const std::string& host, int port)
SIOClientImpl* SIOClientImpl::create(const Uri& uri, const std::string& caFilePath)
{
SIOClientImpl *s = new (std::nothrow) SIOClientImpl(host, port);
SIOClientImpl *s = new (std::nothrow) SIOClientImpl(uri, caFilePath);
if (s && s->init())
{
@ -717,7 +737,7 @@ void SIOClientImpl::onOpen(WebSocket* /*ws*/)
{
_connected = true;
SocketIO::getInstance()->addSocket(_uri, this);
SocketIO::getInstance()->addSocket(_hostAndPort, this);
if (_version == SocketIOPacket::SocketIOVersion::V10x)
{
@ -979,7 +999,7 @@ void SIOClientImpl::onClose(WebSocket* /*ws*/)
if (Director::getInstance())
Director::getInstance()->getScheduler()->unscheduleAllForTarget(this);
SocketIO::getInstance()->removeSocket(_uri);
SocketIO::getInstance()->removeSocket(_hostAndPort);
}
this->release();
@ -1121,75 +1141,47 @@ void SocketIO::destroyInstance()
SIOClient* SocketIO::connect(SocketIO::SIODelegate& delegate, const std::string& uri)
{
return SocketIO::connect(uri, delegate);
}
SIOClient* SocketIO::connect(const std::string& uri, SocketIO::SIODelegate& delegate)
{
std::string host = uri;
int port = 0;
size_t pos = 0;
return SocketIO::connect(uri, delegate, "");
}
pos = host.find("//");
if (pos != std::string::npos)
{
host.erase(0, pos+2);
}
pos = host.find(":");
if (pos != std::string::npos)
{
port = atoi(host.substr(pos+1, host.size()).c_str());
}
pos = host.find("/", 0);
std::string path = "/";
if (pos != std::string::npos)
{
path += host.substr(pos + 1, host.size());
}
pos = host.find(":");
if (pos != std::string::npos)
{
host.erase(pos, host.size());
}
else if ((pos = host.find("/")) != std::string::npos)
{
host.erase(pos, host.size());
}
SIOClient* SocketIO::connect(const std::string& uri, SocketIO::SIODelegate& delegate, const std::string& caFilePath)
{
Uri uriObj = Uri::parse(uri);
std::stringstream s;
s << host << ":" << port;
s << uriObj.getHost() << ":" << uriObj.getPort();
SIOClientImpl *socket = SocketIO::getInstance()->getSocket(s.str());
SIOClient *c = nullptr;
if(socket == nullptr)
if (socket == nullptr)
{
//create a new socket, new client, connect
socket = SIOClientImpl::create(host, port);
socket = SIOClientImpl::create(uriObj, caFilePath);
c = new (std::nothrow) SIOClient(host, port, path, socket, delegate);
c = new (std::nothrow) SIOClient(uriObj.getHost(), static_cast<int>(uriObj.getPort()), uriObj.getPath(), socket, delegate);
socket->addClient(path, c);
socket->addClient(uriObj.getPath(), c);
socket->connect();
}
else
{
//check if already connected to endpoint, handle
c = socket->getClient(path);
c = socket->getClient(uriObj.getPath());
if(c == nullptr)
{
c = new (std::nothrow) SIOClient(host, port, path, socket, delegate);
c = new (std::nothrow) SIOClient(uriObj.getHost(), static_cast<int>(uriObj.getPort()), uriObj.getPath(), socket, delegate);
socket->addClient(path, c);
socket->addClient(uriObj.getPath(), c);
socket->connectToEndpoint(path);
socket->connectToEndpoint(uriObj.getPath());
}
else
{
@ -1197,10 +1189,10 @@ SIOClient* SocketIO::connect(const std::string& uri, SocketIO::SIODelegate& dele
c->disconnect();
CCLOG("SocketIO: recreate a new socket, new client, connect");
SIOClientImpl* newSocket = SIOClientImpl::create(host, port);
SIOClient *newC = new (std::nothrow) SIOClient(host, port, path, newSocket, delegate);
SIOClientImpl* newSocket = SIOClientImpl::create(uriObj, caFilePath);
SIOClient *newC = new (std::nothrow) SIOClient(uriObj.getHost(), static_cast<int>(uriObj.getPort()), uriObj.getPath(), newSocket, delegate);
newSocket->addClient(path, newC);
newSocket->addClient(uriObj.getPath(), newC);
newSocket->connect();
return newC;

View File

@ -155,6 +155,15 @@ public:
*/
static SIOClient* connect(const std::string& uri, SocketIO::SIODelegate& delegate);
/**
* Static client creation method, similar to socketio.connect(uri) in JS.
* @param uri the URI of the socket.io server.
* @param delegate the delegate which want to receive events from the socket.io client.
* @param caFilePath The ca file path for wss connection
* @return SIOClient* an initialized SIOClient if connected successfully, otherwise nullptr.
*/
static SIOClient* connect(const std::string& uri, SocketIO::SIODelegate& delegate, const std::string& caFilePath);
/**
* Static client creation method, similar to socketio.connect(uri) in JS.
* @param delegate the delegate which want to receive events from the socket.io client.