Merge pull request #25 from donpillou/errorHandling
send/recv error handling, avoid in-code #ifdefs, update README with build instructions
This commit is contained in:
@@ -91,11 +91,15 @@ Example
|
|||||||
node example-server.js
|
node example-server.js
|
||||||
|
|
||||||
# Build and launch the client:
|
# Build and launch the client:
|
||||||
g++ example-client.cpp -o example-client
|
g++ -c easywsclient.cpp -o easywsclient.o
|
||||||
|
g++ -c example-client.cpp -o example-client.o
|
||||||
|
g++ example-client.o easywsclient.o -o example-client
|
||||||
./example-client
|
./example-client
|
||||||
|
|
||||||
# ...or build and launch a C++11 client:
|
# ...or build and launch a C++11 client:
|
||||||
g++ -std=gnu++0x example-client-cpp11.cpp -o example-client-cpp11
|
g++ -std=gnu++0x -c easywsclient.cpp -o easywsclient.o
|
||||||
|
g++ -std=gnu++0x -c example-client-cpp11.cpp -o example-client-cpp11.o
|
||||||
|
g++ example-client-cpp11.o easywsclient.o -o example-client-cpp11
|
||||||
./example-client-cpp11
|
./example-client-cpp11
|
||||||
|
|
||||||
# Expect the output from example-client:
|
# Expect the output from example-client:
|
||||||
|
|||||||
+34
-41
@@ -1,11 +1,8 @@
|
|||||||
#ifdef _MSC_VER
|
|
||||||
// _CRT_SECURE_NO_WARNINGS for sscanf errors in MSVC2013 Express
|
|
||||||
#define _CRT_SECURE_NO_WARNINGS
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "easywsclient.hpp"
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
|
||||||
|
#define _CRT_SECURE_NO_WARNINGS // _CRT_SECURE_NO_WARNINGS for sscanf errors in MSVC2013 Express
|
||||||
|
#endif
|
||||||
#ifndef WIN32_LEAN_AND_MEAN
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#endif
|
#endif
|
||||||
@@ -40,6 +37,9 @@
|
|||||||
typedef __int64 int64_t;
|
typedef __int64 int64_t;
|
||||||
typedef unsigned __int64 uint64_t;
|
typedef unsigned __int64 uint64_t;
|
||||||
#endif
|
#endif
|
||||||
|
#define socketerrno WSAGetLastError()
|
||||||
|
#define SOCKET_EAGAIN_EINPROGRESS WSAEINPROGRESS
|
||||||
|
#define SOCKET_EWOULDBLOCK WSAEWOULDBLOCK
|
||||||
#else
|
#else
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
@@ -62,11 +62,18 @@
|
|||||||
#ifndef SOCKET_ERROR
|
#ifndef SOCKET_ERROR
|
||||||
#define SOCKET_ERROR (-1)
|
#define SOCKET_ERROR (-1)
|
||||||
#endif
|
#endif
|
||||||
|
#define closesocket(s) ::close(s)
|
||||||
|
#include <errno.h>
|
||||||
|
#define socketerrno errno
|
||||||
|
#define SOCKET_EAGAIN_EINPROGRESS EAGAIN
|
||||||
|
#define SOCKET_EWOULDBLOCK EWOULDBLOCK
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "easywsclient.hpp"
|
||||||
|
|
||||||
namespace { // private module-only namespace
|
namespace { // private module-only namespace
|
||||||
|
|
||||||
socket_t hostname_connect(const std::string& hostname, int port) {
|
socket_t hostname_connect(const std::string& hostname, int port) {
|
||||||
@@ -92,11 +99,7 @@ socket_t hostname_connect(const std::string& hostname, int port) {
|
|||||||
if (connect(sockfd, p->ai_addr, p->ai_addrlen) != SOCKET_ERROR) {
|
if (connect(sockfd, p->ai_addr, p->ai_addrlen) != SOCKET_ERROR) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#ifdef _WIN32
|
|
||||||
closesocket(sockfd);
|
closesocket(sockfd);
|
||||||
#else
|
|
||||||
close(sockfd);
|
|
||||||
#endif
|
|
||||||
sockfd = INVALID_SOCKET;
|
sockfd = INVALID_SOCKET;
|
||||||
}
|
}
|
||||||
freeaddrinfo(result);
|
freeaddrinfo(result);
|
||||||
@@ -156,14 +159,6 @@ class _RealWebSocket : public easywsclient::WebSocket
|
|||||||
uint8_t masking_key[4];
|
uint8_t masking_key[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
inline int close(socket_t sockfd) {
|
|
||||||
#ifdef _WIN32
|
|
||||||
return ::closesocket(sockfd);
|
|
||||||
#else
|
|
||||||
return ::close(sockfd);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<uint8_t> rxbuf;
|
std::vector<uint8_t> rxbuf;
|
||||||
std::vector<uint8_t> txbuf;
|
std::vector<uint8_t> txbuf;
|
||||||
|
|
||||||
@@ -194,32 +189,24 @@ class _RealWebSocket : public easywsclient::WebSocket
|
|||||||
FD_ZERO(&wfds);
|
FD_ZERO(&wfds);
|
||||||
FD_SET(sockfd, &rfds);
|
FD_SET(sockfd, &rfds);
|
||||||
if (txbuf.size()) { FD_SET(sockfd, &wfds); }
|
if (txbuf.size()) { FD_SET(sockfd, &wfds); }
|
||||||
#ifdef _WIN32
|
|
||||||
select(0, &rfds, &wfds, NULL, &tv);
|
|
||||||
#else
|
|
||||||
select(sockfd + 1, &rfds, &wfds, NULL, &tv);
|
select(sockfd + 1, &rfds, &wfds, NULL, &tv);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
while (true) {
|
while (true) {
|
||||||
// FD_ISSET(0, &rfds) will be true
|
// FD_ISSET(0, &rfds) will be true
|
||||||
int N = rxbuf.size();
|
int N = rxbuf.size();
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
rxbuf.resize(N + 1500);
|
rxbuf.resize(N + 1500);
|
||||||
#ifdef _WIN32
|
|
||||||
ret = recv(sockfd, (char*)&rxbuf[0] + N, 1500, 0);
|
ret = recv(sockfd, (char*)&rxbuf[0] + N, 1500, 0);
|
||||||
#else
|
|
||||||
ret = recv(sockfd, &rxbuf[0] + N, 1500, 0);
|
|
||||||
#endif
|
|
||||||
if (false) { }
|
if (false) { }
|
||||||
else if (ret < 0) {
|
else if (ret < 0 && (socketerrno == SOCKET_EWOULDBLOCK || socketerrno == SOCKET_EAGAIN_EINPROGRESS)) {
|
||||||
rxbuf.resize(N);
|
rxbuf.resize(N);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (ret == 0) {
|
else if (ret <= 0) {
|
||||||
rxbuf.resize(N);
|
rxbuf.resize(N);
|
||||||
close(sockfd);
|
closesocket(sockfd);
|
||||||
readyState = CLOSED;
|
readyState = CLOSED;
|
||||||
fprintf(stderr, "Connection closed!\n");
|
fputs(ret < 0 ? "Connection error!\n" : "Connection closed!\n", stderr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -227,17 +214,23 @@ class _RealWebSocket : public easywsclient::WebSocket
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (txbuf.size()) {
|
while (txbuf.size()) {
|
||||||
int ret;
|
int ret = ::send(sockfd, (char*)&txbuf[0], txbuf.size(), 0);
|
||||||
#ifdef _WIN32
|
if (false) { } // ??
|
||||||
ret = ::send(sockfd, (char*)&txbuf[0], txbuf.size(), 0);
|
else if (ret < 0 && (socketerrno == SOCKET_EWOULDBLOCK || socketerrno == SOCKET_EAGAIN_EINPROGRESS)) {
|
||||||
#else
|
break;
|
||||||
ret = ::send(sockfd, &txbuf[0], txbuf.size(), 0);
|
}
|
||||||
#endif
|
else if (ret <= 0) {
|
||||||
if (ret > 0) { txbuf.erase(txbuf.begin(), txbuf.begin() + ret); }
|
closesocket(sockfd);
|
||||||
else { break; }
|
readyState = CLOSED;
|
||||||
|
fputs(ret < 0 ? "Connection error!\n" : "Connection closed!\n", stderr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
txbuf.erase(txbuf.begin(), txbuf.begin() + ret);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!txbuf.size() && readyState == CLOSING) {
|
if (!txbuf.size() && readyState == CLOSING) {
|
||||||
close(sockfd);
|
closesocket(sockfd);
|
||||||
readyState = CLOSED;
|
readyState = CLOSED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -300,7 +293,7 @@ class _RealWebSocket : public easywsclient::WebSocket
|
|||||||
if (false) { }
|
if (false) { }
|
||||||
else if (ws.opcode == wsheader_type::TEXT_FRAME && ws.fin) {
|
else if (ws.opcode == wsheader_type::TEXT_FRAME && ws.fin) {
|
||||||
if (ws.mask) { for (size_t i = 0; i != ws.N; ++i) { rxbuf[i+ws.header_size] ^= ws.masking_key[i&0x3]; } }
|
if (ws.mask) { for (size_t i = 0; i != ws.N; ++i) { rxbuf[i+ws.header_size] ^= ws.masking_key[i&0x3]; } }
|
||||||
std::string data(rxbuf.begin()+ws.header_size, rxbuf.begin()+ws.header_size+ws.N);
|
std::string data(rxbuf.begin()+ws.header_size, rxbuf.begin()+ws.header_size+(size_t)ws.N);
|
||||||
callable((const std::string) data);
|
callable((const std::string) data);
|
||||||
}
|
}
|
||||||
else if (ws.opcode == wsheader_type::PING) { }
|
else if (ws.opcode == wsheader_type::PING) { }
|
||||||
@@ -308,7 +301,7 @@ class _RealWebSocket : public easywsclient::WebSocket
|
|||||||
else if (ws.opcode == wsheader_type::CLOSE) { close(); }
|
else if (ws.opcode == wsheader_type::CLOSE) { close(); }
|
||||||
else { fprintf(stderr, "ERROR: Got unexpected WebSocket message.\n"); close(); }
|
else { fprintf(stderr, "ERROR: Got unexpected WebSocket message.\n"); close(); }
|
||||||
|
|
||||||
rxbuf.erase(rxbuf.begin(), rxbuf.begin() + ws.header_size+ws.N);
|
rxbuf.erase(rxbuf.begin(), rxbuf.begin() + ws.header_size+(size_t)ws.N);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user