From cbfa74c0e909d2196e3cc3f7e7a4279d9f60b60c Mon Sep 17 00:00:00 2001 From: Donald Pillou Date: Mon, 30 Dec 2013 15:44:48 +0100 Subject: [PATCH 1/3] Avoid most in-code #ifdefs --- easywsclient.cpp | 47 +++++++++++------------------------------------ 1 file changed, 11 insertions(+), 36 deletions(-) diff --git a/easywsclient.cpp b/easywsclient.cpp index f510af9..7f7b6d7 100644 --- a/easywsclient.cpp +++ b/easywsclient.cpp @@ -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 + #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 #define WIN32_LEAN_AND_MEAN #endif @@ -62,11 +59,14 @@ #ifndef SOCKET_ERROR #define SOCKET_ERROR (-1) #endif + #define closesocket(s) ::close(s) #endif #include #include +#include "easywsclient.hpp" + namespace { // private module-only namespace socket_t hostname_connect(const std::string& hostname, int port) { @@ -92,11 +92,7 @@ socket_t hostname_connect(const std::string& hostname, int port) { if (connect(sockfd, p->ai_addr, p->ai_addrlen) != SOCKET_ERROR) { break; } -#ifdef _WIN32 closesocket(sockfd); -#else - close(sockfd); -#endif sockfd = INVALID_SOCKET; } freeaddrinfo(result); @@ -156,14 +152,6 @@ class _RealWebSocket : public easywsclient::WebSocket uint8_t masking_key[4]; }; - inline int close(socket_t sockfd) { -#ifdef _WIN32 - return ::closesocket(sockfd); -#else - return ::close(sockfd); -#endif - } - std::vector rxbuf; std::vector txbuf; @@ -194,22 +182,14 @@ class _RealWebSocket : public easywsclient::WebSocket FD_ZERO(&wfds); FD_SET(sockfd, &rfds); if (txbuf.size()) { FD_SET(sockfd, &wfds); } - #ifdef _WIN32 - select(0, &rfds, &wfds, NULL, &tv); - #else select(sockfd + 1, &rfds, &wfds, NULL, &tv); - #endif } while (true) { // FD_ISSET(0, &rfds) will be true int N = rxbuf.size(); ssize_t ret; rxbuf.resize(N + 1500); -#ifdef _WIN32 ret = recv(sockfd, (char*)&rxbuf[0] + N, 1500, 0); -#else - ret = recv(sockfd, &rxbuf[0] + N, 1500, 0); -#endif if (false) { } else if (ret < 0) { rxbuf.resize(N); @@ -217,7 +197,7 @@ class _RealWebSocket : public easywsclient::WebSocket } else if (ret == 0) { rxbuf.resize(N); - close(sockfd); + closesocket(sockfd); readyState = CLOSED; fprintf(stderr, "Connection closed!\n"); break; @@ -227,17 +207,12 @@ class _RealWebSocket : public easywsclient::WebSocket } } while (txbuf.size()) { - int ret; -#ifdef _WIN32 - ret = ::send(sockfd, (char*)&txbuf[0], txbuf.size(), 0); -#else - ret = ::send(sockfd, &txbuf[0], txbuf.size(), 0); -#endif + int ret = ::send(sockfd, (char*)&txbuf[0], txbuf.size(), 0); if (ret > 0) { txbuf.erase(txbuf.begin(), txbuf.begin() + ret); } else { break; } } if (!txbuf.size() && readyState == CLOSING) { - close(sockfd); + closesocket(sockfd); readyState = CLOSED; } } @@ -300,7 +275,7 @@ class _RealWebSocket : public easywsclient::WebSocket if (false) { } 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]; } } - 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); } else if (ws.opcode == wsheader_type::PING) { } @@ -308,7 +283,7 @@ class _RealWebSocket : public easywsclient::WebSocket else if (ws.opcode == wsheader_type::CLOSE) { 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); } } From b0366105c592d381da8a11c4d8b26062c5bb0ac2 Mon Sep 17 00:00:00 2001 From: Donald Pillou Date: Mon, 30 Dec 2013 15:45:35 +0100 Subject: [PATCH 2/3] Working example build instructions --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 73adf86..5b6c86b 100644 --- a/README.md +++ b/README.md @@ -91,11 +91,15 @@ Example node example-server.js # 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 # ...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 # Expect the output from example-client: From c5917f913ea256e9248018d2d282869000d3f344 Mon Sep 17 00:00:00 2001 From: Donald Pillou Date: Mon, 30 Dec 2013 16:32:35 +0100 Subject: [PATCH 3/3] Add send/receive error handling --- easywsclient.cpp | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/easywsclient.cpp b/easywsclient.cpp index 7f7b6d7..7fac4ef 100644 --- a/easywsclient.cpp +++ b/easywsclient.cpp @@ -37,6 +37,9 @@ typedef __int64 int64_t; typedef unsigned __int64 uint64_t; #endif + #define socketerrno WSAGetLastError() + #define SOCKET_EAGAIN_EINPROGRESS WSAEINPROGRESS + #define SOCKET_EWOULDBLOCK WSAEWOULDBLOCK #else #include #include @@ -60,6 +63,10 @@ #define SOCKET_ERROR (-1) #endif #define closesocket(s) ::close(s) + #include + #define socketerrno errno + #define SOCKET_EAGAIN_EINPROGRESS EAGAIN + #define SOCKET_EWOULDBLOCK EWOULDBLOCK #endif #include @@ -191,15 +198,15 @@ class _RealWebSocket : public easywsclient::WebSocket rxbuf.resize(N + 1500); ret = recv(sockfd, (char*)&rxbuf[0] + N, 1500, 0); if (false) { } - else if (ret < 0) { + else if (ret < 0 && (socketerrno == SOCKET_EWOULDBLOCK || socketerrno == SOCKET_EAGAIN_EINPROGRESS)) { rxbuf.resize(N); break; } - else if (ret == 0) { + else if (ret <= 0) { rxbuf.resize(N); closesocket(sockfd); readyState = CLOSED; - fprintf(stderr, "Connection closed!\n"); + fputs(ret < 0 ? "Connection error!\n" : "Connection closed!\n", stderr); break; } else { @@ -208,8 +215,19 @@ class _RealWebSocket : public easywsclient::WebSocket } while (txbuf.size()) { int ret = ::send(sockfd, (char*)&txbuf[0], txbuf.size(), 0); - if (ret > 0) { txbuf.erase(txbuf.begin(), txbuf.begin() + ret); } - else { break; } + if (false) { } // ?? + else if (ret < 0 && (socketerrno == SOCKET_EWOULDBLOCK || socketerrno == SOCKET_EAGAIN_EINPROGRESS)) { + break; + } + else if (ret <= 0) { + closesocket(sockfd); + 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) { closesocket(sockfd);