Skip to content

Commit

Permalink
Windows support (no TLS yet)
Browse files Browse the repository at this point in the history
  • Loading branch information
Benjamin Sergeant committed Oct 9, 2018
1 parent 88c2e1f commit 1680575
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 44 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ If the remote end (server) breaks the connection, the code will try to perpetual
2. Compile the example C++ code. `sh build.sh`
3. Install node.js from [here](https://nodejs.org/en/download/).
4. Type `npm install` to install the node.js dependencies. Then `node broadcast-server.js` to run the server.
5. Bring up a second terminal. `env USER=bob ./cmd_websocket_chat`
6. Bring up a third terminal. `env USER=bill ./cmd_websocket_chat`
5. Bring up a second terminal. `./cmd_websocket_chat bob`
6. Bring up a third terminal. `./cmd_websocket_chat bill`
7. Start typing things in any of those terminals. Hopefully you should see your message being received on the other end.

## C++ code organization
Expand Down
19 changes: 12 additions & 7 deletions examples/chat/cmd_websocket_chat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <sstream>
#include <queue>
#include <ixwebsocket/IXWebSocket.h>
#include <ixwebsocket/IXSocket.h>

#include "nlohmann/json.hpp"

Expand Down Expand Up @@ -158,13 +159,10 @@ namespace
_webSocket.send(encodeMessage(text));
}

void interactiveMain()
void interactiveMain(const std::string& user)
{
std::string user(getenv("USER"));

WebSocketChat webSocketChat(user);

std::cout << "Type Ctrl-D to exit prompt..." << std::endl;
WebSocketChat webSocketChat(user);
webSocketChat.start();

while (true)
Expand All @@ -186,8 +184,15 @@ namespace
}
}

int main()
int main(int argc, char** argv)
{
interactiveMain();
std::string user("user");
if (argc == 2)
{
user = argv[1];
}

Socket::init();
interactiveMain(user);
return 0;
}
103 changes: 78 additions & 25 deletions ixwebsocket/IXSocket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,32 @@

#include "IXSocket.h"

#include <netdb.h>
#include <netinet/tcp.h>
#ifdef _WIN32
# include <basetsd.h>
# include <WinSock2.h>
# include <ws2def.h>
# include <WS2tcpip.h>
# include <io.h>
#else
# include <unistd.h>
# include <errno.h>
# include <netdb.h>
# include <netinet/tcp.h>
# include <sys/socket.h>
# include <sys/time.h>
# include <sys/select.h>
# include <sys/stat.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <assert.h>
#include <stdint.h>
#include <sys/select.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/types.h>

#include <algorithm>

//
// Linux/Android has a special type of virtual files. select(2) will react
Expand All @@ -35,7 +45,7 @@
// cf Android/Kernel table here
// https://android.stackexchange.com/questions/51651/which-android-runs-which-linux-kernel
//
#ifndef __APPLE__
#ifdef __linux__
# include <sys/eventfd.h>
#endif

Expand All @@ -51,7 +61,7 @@ namespace ix
_sockfd(-1),
_eventfd(-1)
{
#ifndef __APPLE__
#ifdef __linux__
_eventfd = eventfd(0, 0);
assert(_eventfd != -1 && "Panic - eventfd not functioning on this platform");
#endif
Expand All @@ -61,14 +71,14 @@ namespace ix
{
close();

#ifndef __APPLE__
#ifdef __linux__
::close(_eventfd);
#endif
}

bool connectToAddress(const struct addrinfo *address,
int& sockfd,
std::string& errMsg)
bool Socket::connectToAddress(const struct addrinfo *address,
int& sockfd,
std::string& errMsg)
{
sockfd = -1;

Expand All @@ -84,7 +94,7 @@ namespace ix
int maxRetries = 3;
for (int i = 0; i < maxRetries; ++i)
{
if (connect(fd, address->ai_addr, address->ai_addrlen) != -1)
if (::connect(fd, address->ai_addr, address->ai_addrlen) != -1)
{
sockfd = fd;
return true;
Expand All @@ -94,7 +104,7 @@ namespace ix
if (errno != EINTR) break;
}

::close(fd);
closeSocket(fd);
sockfd = -1;
errMsg = strerror(errno);
return false;
Expand Down Expand Up @@ -142,7 +152,13 @@ namespace ix
{
int flag = 1;
setsockopt(_sockfd, IPPROTO_TCP, TCP_NODELAY, (char*) &flag, sizeof(flag)); // Disable Nagle's algorithm

#ifdef _WIN32
unsigned long nonblocking = 1;
ioctlsocket(_sockfd, FIONBIO, &nonblocking);
#else
fcntl(_sockfd, F_SETFL, O_NONBLOCK); // make socket non blocking
#endif

#ifdef SO_NOSIGPIPE
int value = 1;
Expand All @@ -163,12 +179,12 @@ namespace ix
FD_ZERO(&rfds);
FD_SET(_sockfd, &rfds);

#ifndef __APPLE__
#ifdef __linux__
FD_SET(_eventfd, &rfds);
#endif

int sockfd = _sockfd;
int nfds = std::max(sockfd, _eventfd);
int nfds = (std::max)(sockfd, _eventfd);
select(nfds + 1, &rfds, nullptr, nullptr, nullptr);

onPollCallback();
Expand All @@ -191,7 +207,7 @@ namespace ix
{
#ifdef __APPLE__
wakeUpFromPollApple();
#else
#elif defined(__linux__)
wakeUpFromPollLinux();
#endif
}
Expand All @@ -202,7 +218,7 @@ namespace ix
{
std::lock_guard<std::mutex> lock(_socketMutex);

#ifndef __APPLE__
#ifdef __linux__
if (_eventfd == -1)
{
return false; // impossible to use this socket if eventfd is broken
Expand All @@ -219,7 +235,7 @@ namespace ix

if (_sockfd == -1) return;

::close(_sockfd);
closeSocket(_sockfd);
_sockfd = -1;
}

Expand All @@ -245,7 +261,44 @@ namespace ix
flags = MSG_NOSIGNAL;
#endif

return (int) ::recv(_sockfd, buffer, length, flags);
return (int) ::recv(_sockfd, (char*) buffer, length, flags);
}

int Socket::getErrno() const
{
#ifdef _WIN32
return WSAGetLastError();
#else
return errno;
#endif
}

void Socket::closeSocket(int fd)
{
#ifdef _WIN32
closesocket(fd);
#else
::close(fd);
#endif
}

bool Socket::init()
{
#ifdef _WIN32
INT rc;
WSADATA wsaData;

rc = WSAStartup(MAKEWORD(2, 2), &wsaData);
return rc != 0;
#else
return true;
#endif
}

void Socket::cleanup()
{
#ifdef _WIN32
WSACleanup();
#endif
}
}
19 changes: 16 additions & 3 deletions ixwebsocket/IXSocket.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include <mutex>
#include <atomic>

struct addrinfo;

namespace ix
{
class Socket {
Expand All @@ -20,9 +22,9 @@ namespace ix
Socket();
virtual ~Socket();

static int hostname_connect(const std::string& hostname,
int port,
std::string& errMsg);
int hostname_connect(const std::string& hostname,
int port,
std::string& errMsg);
void configure();

virtual void poll(const OnPollCallback& onPollCallback);
Expand All @@ -38,13 +40,24 @@ namespace ix
virtual int send(const std::string& buffer);
virtual int recv(void* buffer, size_t length);

int getErrno() const;
static bool init(); // Required on Windows to initialize WinSocket
static void cleanup(); // Required on Windows to cleanup WinSocket

protected:
void wakeUpFromPollApple();
void wakeUpFromPollLinux();

void closeSocket(int fd);

std::atomic<int> _sockfd;
int _eventfd;
std::mutex _socketMutex;

private:
bool connectToAddress(const struct addrinfo *address,
int& sockfd,
std::string& errMsg);
};

}
14 changes: 7 additions & 7 deletions ixwebsocket/IXWebSocketTransport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
# endif
#endif

#include <unistd.h>
#include <errno.h>
// #include <unistd.h>
#include <string.h>
#include <stdlib.h>

#include <cstdlib>
#include <vector>
Expand Down Expand Up @@ -273,12 +273,12 @@ namespace ix {
{
int N = (int) _rxbuf.size();

ssize_t ret;
int ret;
_rxbuf.resize(N + 1500);
ret = _socket->recv((char*)&_rxbuf[0] + N, 1500);

if (ret < 0 && (errno == EWOULDBLOCK ||
errno == EAGAIN)) {
if (ret < 0 && (_socket->getErrno() == EWOULDBLOCK ||
_socket->getErrno() == EAGAIN)) {
_rxbuf.resize(N);
break;
}
Expand Down Expand Up @@ -575,8 +575,8 @@ namespace ix {
{
int ret = _socket->send((char*)&_txbuf[0], _txbuf.size());

if (ret < 0 && (errno == EWOULDBLOCK ||
errno == EAGAIN))
if (ret < 0 && (_socket->getErrno() == EWOULDBLOCK ||
_socket->getErrno() == EAGAIN))
{
break;
}
Expand Down

0 comments on commit 1680575

Please sign in to comment.