start implementing the messages for connecting to pvpgn servers
This commit is contained in:
parent
ea96b7c5dd
commit
843bccdd42
2 changed files with 233 additions and 0 deletions
|
@ -236,6 +236,7 @@ set(network_SRCS
|
||||||
src/network/netconnect.cpp
|
src/network/netconnect.cpp
|
||||||
src/network/network.cpp
|
src/network/network.cpp
|
||||||
src/network/netsockets.cpp
|
src/network/netsockets.cpp
|
||||||
|
src/network/online_service.cpp
|
||||||
)
|
)
|
||||||
source_group(network FILES ${network_SRCS})
|
source_group(network FILES ${network_SRCS})
|
||||||
|
|
||||||
|
|
232
src/network/online_service.cpp
Normal file
232
src/network/online_service.cpp
Normal file
|
@ -0,0 +1,232 @@
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <iostream>
|
||||||
|
#include <ostream>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#ifdef USE_WIN32
|
||||||
|
#include <winsock2.h>
|
||||||
|
#else
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "assert.h"
|
||||||
|
|
||||||
|
#include "network/netsockets.h"
|
||||||
|
|
||||||
|
class BNCSBuf {
|
||||||
|
public:
|
||||||
|
BNCSBuf(uint8_t id) {
|
||||||
|
// Every BNCS message has the same header:
|
||||||
|
// (UINT8) Always 0xFF
|
||||||
|
// (UINT8) Message ID
|
||||||
|
// (UINT16) Message length, including this header
|
||||||
|
// (VOID) Message data
|
||||||
|
this->sz = 16;
|
||||||
|
this->buf = (uint8_t*) calloc(sizeof(uint8_t), this->sz);
|
||||||
|
this->pos = 0;
|
||||||
|
serialize8(0xff);
|
||||||
|
serialize8(id);
|
||||||
|
this->length_pos = pos;
|
||||||
|
serialize16((uint16_t)0);
|
||||||
|
};
|
||||||
|
~BNCSBuf() {
|
||||||
|
free(buf);
|
||||||
|
};
|
||||||
|
|
||||||
|
void serialize32(uint32_t data) {
|
||||||
|
ensureSpace(sizeof(data));
|
||||||
|
uint32_t *view = reinterpret_cast<uint32_t *>(buf + pos);
|
||||||
|
*view = htonl(data);
|
||||||
|
pos += sizeof(data);
|
||||||
|
};
|
||||||
|
void serialize32(int32_t data) {
|
||||||
|
ensureSpace(sizeof(data));
|
||||||
|
int32_t *view = reinterpret_cast<int32_t *>(buf + pos);
|
||||||
|
*view = htonl(data);
|
||||||
|
pos += sizeof(data);
|
||||||
|
};
|
||||||
|
void serialize16(uint16_t data) {
|
||||||
|
ensureSpace(sizeof(data));
|
||||||
|
uint16_t *view = reinterpret_cast<uint16_t *>(buf + pos);
|
||||||
|
*view = htons(data);
|
||||||
|
pos += sizeof(data);
|
||||||
|
};
|
||||||
|
void serialize16(int16_t data) {
|
||||||
|
ensureSpace(sizeof(data));
|
||||||
|
uint16_t *view = reinterpret_cast<uint16_t *>(buf + pos);
|
||||||
|
*view = htons(data);
|
||||||
|
pos += sizeof(data);
|
||||||
|
};
|
||||||
|
void serialize8(uint8_t data) {
|
||||||
|
ensureSpace(sizeof(data));
|
||||||
|
*(buf + pos) = data;
|
||||||
|
pos++;
|
||||||
|
};
|
||||||
|
void serialize(const char* str, int len) {
|
||||||
|
ensureSpace(len);
|
||||||
|
memcpy(buf + pos, str, len);
|
||||||
|
pos += len;
|
||||||
|
};
|
||||||
|
void serialize(const char* str) {
|
||||||
|
int len = strlen(str);
|
||||||
|
ensureSpace(len);
|
||||||
|
memcpy(buf + pos, str, len);
|
||||||
|
pos += len;
|
||||||
|
};
|
||||||
|
uint8_t *getBuffer() {
|
||||||
|
// insert length to make it a valid buffer
|
||||||
|
uint16_t *view = reinterpret_cast<uint16_t *>(buf + length_pos);
|
||||||
|
*view = htons(pos);
|
||||||
|
return buf;
|
||||||
|
};
|
||||||
|
int getLength() {
|
||||||
|
return pos;
|
||||||
|
};
|
||||||
|
private:
|
||||||
|
void ensureSpace(size_t required) {
|
||||||
|
if (pos + required < sz) {
|
||||||
|
sz = sz * 2;
|
||||||
|
buf = (uint8_t*) realloc(buf, sz);
|
||||||
|
assert(buf != NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *buf;
|
||||||
|
int sz;
|
||||||
|
int pos;
|
||||||
|
int length_pos;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Context;
|
||||||
|
class NetworkState {
|
||||||
|
public:
|
||||||
|
virtual ~NetworkState() {};
|
||||||
|
virtual void doOneStep(Context *ctx) = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int send(Context *ctx, BNCSBuf *buf);
|
||||||
|
};
|
||||||
|
|
||||||
|
class Context {
|
||||||
|
public:
|
||||||
|
Context() {
|
||||||
|
this->udpSocket = new CUDPSocket();
|
||||||
|
this->tcpSocket = new CTCPSocket();
|
||||||
|
this->state = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
~Context() {
|
||||||
|
if (state != NULL) {
|
||||||
|
delete state;
|
||||||
|
}
|
||||||
|
delete udpSocket;
|
||||||
|
delete tcpSocket;
|
||||||
|
}
|
||||||
|
|
||||||
|
CUDPSocket *getUDPSocket() { return udpSocket; }
|
||||||
|
|
||||||
|
CTCPSocket *getTCPSocket() { return tcpSocket; }
|
||||||
|
|
||||||
|
void doOneStep() { this->state->doOneStep(this); }
|
||||||
|
|
||||||
|
void setState(NetworkState* newState) {
|
||||||
|
assert (newState != this->state);
|
||||||
|
if (this->state != NULL) {
|
||||||
|
delete this->state;
|
||||||
|
}
|
||||||
|
this->state = newState;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
NetworkState *state;
|
||||||
|
CUDPSocket *udpSocket;
|
||||||
|
CTCPSocket *tcpSocket;
|
||||||
|
};
|
||||||
|
|
||||||
|
int NetworkState::send(Context *ctx, BNCSBuf *buf) {
|
||||||
|
return ctx->getTCPSocket()->Send(buf->getBuffer(), buf->getLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
class DisconnectedState : public NetworkState {
|
||||||
|
public:
|
||||||
|
DisconnectedState(std::string message) {
|
||||||
|
this->message = message;
|
||||||
|
this->hasPrinted = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual void doOneStep(Context *ctx) {
|
||||||
|
if (!hasPrinted) {
|
||||||
|
std::cout << message << std::endl;
|
||||||
|
hasPrinted = true;
|
||||||
|
}
|
||||||
|
// the end
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool hasPrinted;
|
||||||
|
std::string message;
|
||||||
|
};
|
||||||
|
|
||||||
|
class C2S_SID_AUTH_INFO : public NetworkState {
|
||||||
|
virtual void doOneStep(Context *ctx) {
|
||||||
|
BNCSBuf buffer(0x50);
|
||||||
|
// (UINT32) Protocol ID
|
||||||
|
buffer.serialize32(0x00);
|
||||||
|
// (UINT32) Platform code
|
||||||
|
buffer.serialize("IX86", 4);
|
||||||
|
// (UINT32) Product code
|
||||||
|
buffer.serialize("W2BN", 4);
|
||||||
|
// (UINT32) Version byte
|
||||||
|
buffer.serialize32(0x4f);
|
||||||
|
// (UINT32) Language code
|
||||||
|
buffer.serialize32(0x00);
|
||||||
|
// (UINT32) Local IP
|
||||||
|
buffer.serialize32(0x00);
|
||||||
|
// (UINT32) Time zone bias
|
||||||
|
buffer.serialize32(0x00);
|
||||||
|
// (UINT32) MPQ locale ID
|
||||||
|
buffer.serialize32(0x00);
|
||||||
|
// (UINT32) User language ID
|
||||||
|
buffer.serialize32(0x00);
|
||||||
|
// (STRING) Country abbreviation
|
||||||
|
buffer.serialize("USA");
|
||||||
|
// (STRING) Country
|
||||||
|
buffer.serialize("United States");
|
||||||
|
|
||||||
|
send(ctx, &buffer);
|
||||||
|
// ctx->setState(new S2C_PING());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ProtoByteState : public NetworkState {
|
||||||
|
virtual void doOneStep(Context *ctx) {
|
||||||
|
ctx->getTCPSocket()->Send("\x1", 1); // use game protocol
|
||||||
|
ctx->setState(new C2S_SID_AUTH_INFO());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConnectState : public NetworkState {
|
||||||
|
virtual void doOneStep(Context *ctx) {
|
||||||
|
CHost host("127.0.0.1", 6112); // TODO: parameterize
|
||||||
|
ctx->getTCPSocket()->Open(host);
|
||||||
|
if (ctx->getTCPSocket()->IsValid() == false) {
|
||||||
|
ctx->setState(new DisconnectedState("TCP open failed"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ctx->getTCPSocket()->Connect(host) == false) {
|
||||||
|
ctx->setState(new DisconnectedState("TCP connect failed"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ctx->setState(new ProtoByteState());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static void goOnline() {
|
||||||
|
Context *ctx = new Context();
|
||||||
|
ctx->setState(new ConnectState());
|
||||||
|
while (true) {
|
||||||
|
ctx->doOneStep();
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue