mirror of https://github.com/basinserver/basin/
Encryption/online mode wip
This commit is contained in:
parent
6a29bcc777
commit
e6b7887024
|
@ -12,7 +12,7 @@ threads = 30
|
|||
max-players = 20
|
||||
motd = A Minecraft Server
|
||||
level-seed =
|
||||
online-mode = false
|
||||
online-mode = true
|
||||
white-list = false
|
||||
spawn-animals = true
|
||||
spawn-npcs = true
|
||||
|
|
|
@ -42,11 +42,16 @@ void run_accept(struct accept_param* param) {
|
|||
c->writeBuffer_capacity = 0;
|
||||
c->comp = -1;
|
||||
c->state = 0;
|
||||
c->onll_username = NULL;
|
||||
c->disconnect = 0;
|
||||
c->host_ip = NULL;
|
||||
c->player = NULL;
|
||||
c->host_port = 0;
|
||||
c->protocolVersion = 0;
|
||||
c->verifyToken = 0;
|
||||
c->aes_ctx_enc = NULL;
|
||||
c->aes_ctx_dec = NULL;
|
||||
memset(c->sharedSecret, 0, 16);
|
||||
if (poll(&spfd, 1, -1) < 0) {
|
||||
printf("Error while polling server: %s\n", strerror(errno));
|
||||
xfree(c);
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
#include <sys/socket.h>
|
||||
#include "work.h"
|
||||
#include <netinet/ip6.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/aes.h>
|
||||
|
||||
struct accept_param {
|
||||
int server_fd;
|
||||
|
@ -41,6 +43,11 @@ struct conn {
|
|||
struct player* player;
|
||||
int disconnect;
|
||||
uint32_t protocolVersion;
|
||||
uint32_t verifyToken;
|
||||
char* onll_username;
|
||||
uint8_t sharedSecret[16];
|
||||
EVP_CIPHER_CTX* aes_ctx_enc;
|
||||
EVP_CIPHER_CTX* aes_ctx_dec;
|
||||
};
|
||||
|
||||
void run_accept(struct accept_param* param);
|
||||
|
|
|
@ -13,6 +13,94 @@
|
|||
#include <stdlib.h>
|
||||
#include "world.h"
|
||||
|
||||
/*
|
||||
|
||||
#define ENT_PLAYER 0
|
||||
#define ENT_ITEM 1
|
||||
#define ENT_XP_ORB 2
|
||||
#define ENT_AREA_EFFECT_CLOUD 3
|
||||
#define ENT_ELDER_GUARDIAN 4
|
||||
#define ENT_WITHER_SKELETON 5
|
||||
#define ENT_STRAY 6
|
||||
#define ENT_EGG 7
|
||||
#define ENT_LEASH_KNOT 8
|
||||
#define ENT_PAINTING 9
|
||||
#define ENT_ARROW 10
|
||||
#define ENT_SNOWBALL 11
|
||||
#define ENT_FIREBALL 12
|
||||
#define ENT_SMALL_FIREBALL 13
|
||||
#define ENT_ENDER_PEARL 14
|
||||
#define ENT_EYE_OF_ENDER_SIGNAL 15
|
||||
#define ENT_POTION 16
|
||||
#define ENT_XP_BOTTLE 17
|
||||
#define ENT_ITEM_FRAME 18
|
||||
#define ENT_WITHER_SKULL 19
|
||||
#define ENT_TNT 20
|
||||
#define ENT_FALLING_BLOCK 21
|
||||
#define ENT_FIREWORKS_ROCKET 22
|
||||
#define ENT_HUSK 23
|
||||
#define ENT_SPECTRAL_ARROW 24
|
||||
#define ENT_SHULKER_BULLET 25
|
||||
#define ENT_DRAGON_FIREBALL 26
|
||||
#define ENT_ZOMBIE_VILLAGER 27
|
||||
#define ENT_SKELETON_HORSE 28
|
||||
#define ENT_ZOMBIE_HORSE 29
|
||||
#define ENT_ARMOR_STAND 30
|
||||
#define ENT_DONKEY 31
|
||||
#define ENT_MULE 32
|
||||
#define ENT_EVOCATION_FANGS 33
|
||||
#define ENT_EVOCATION_ILLAGER 34
|
||||
#define ENT_VEX 35
|
||||
#define ENT_VINDICATION_ILLAGER 36
|
||||
#define ENT_COMMANDBLOCK_MINECART 40
|
||||
#define ENT_BOAT 41
|
||||
#define ENT_MINECART 42
|
||||
#define ENT_CHEST_MINECART 43
|
||||
#define ENT_FURNACE_MINECART 44
|
||||
#define ENT_TNT_MINECART 45
|
||||
#define ENT_HOPPER_MINECART 46
|
||||
#define ENT_SPAWNER_MINECART 47
|
||||
#define ENT_CREEPER 50
|
||||
#define ENT_SKELETON 51
|
||||
#define ENT_SPIDER 52
|
||||
#define ENT_GIANT 53
|
||||
#define ENT_ZOMBIE 54
|
||||
#define ENT_SLIME 55
|
||||
#define ENT_GHAST 56
|
||||
#define ENT_ZOMBIE_PIGMAN 57
|
||||
#define ENT_ENDERMAN 58
|
||||
#define ENT_CAVE_SPIDER 59
|
||||
#define ENT_SILVERFISH 60
|
||||
#define ENT_BLAZE 61
|
||||
#define ENT_MAGMA_CUBE 62
|
||||
#define ENT_ENDER_DRAGON 63
|
||||
#define ENT_WITHER 64
|
||||
#define ENT_BAT 65
|
||||
#define ENT_WITCH 66
|
||||
#define ENT_ENDERMITE 67
|
||||
#define ENT_GUARDIAN 68
|
||||
#define ENT_SHULKER 69
|
||||
#define ENT_PIG 90
|
||||
#define ENT_SHEEP 91
|
||||
#define ENT_COW 92
|
||||
#define ENT_CHICKEN 93
|
||||
#define ENT_SQUID 94
|
||||
#define ENT_WOLF 95
|
||||
#define ENT_MOOSHROOM 96
|
||||
#define ENT_SNOWMAN 97
|
||||
#define ENT_OCELOT 98
|
||||
#define ENT_VILLAGER_GOLEM 99
|
||||
#define ENT_HORSE 100
|
||||
#define ENT_RABBIT 101
|
||||
#define ENT_POLAR_BEAR 102
|
||||
#define ENT_LLAMA 103
|
||||
#define ENT_LLAMA_SPIT 104
|
||||
#define ENT_VILLAGER 120
|
||||
#define ENT_ENDER_CRYSTAL 200
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#define ENT_UNDEFINED 1
|
||||
#define ENT_PLAYER 2
|
||||
#define ENT_CREEPER 3
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "queue.h"
|
||||
#include "profile.h"
|
||||
#include "plugin.h"
|
||||
#include <openssl/rand.h>
|
||||
|
||||
void main_tick() {
|
||||
pthread_cond_broadcast (&glob_tick_cond);
|
||||
|
@ -116,7 +117,9 @@ int main(int argc, char* argv[]) {
|
|||
signal(SIGPIPE, SIG_IGN);
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
srand(ts.tv_sec * 1000000 + ts.tv_nsec / 1000);
|
||||
size_t us = ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
|
||||
srand(us);
|
||||
RAND_seed(&us, sizeof(size_t));
|
||||
printf("Loading %s %s\n", DAEMON_NAME, VERSION);
|
||||
#ifdef DEBUG
|
||||
printf("Running in Debug mode!\n");
|
||||
|
@ -204,6 +207,8 @@ int main(int argc, char* argv[]) {
|
|||
printf("Commands Initialized\n");
|
||||
init_plugins();
|
||||
printf("Plugins Initialized\n");
|
||||
init_encryption();
|
||||
printf("Encryption Initialized\n");
|
||||
for (int i = 0; i < servsl; i++) {
|
||||
struct cnode* serv = servs[i];
|
||||
const char* bind_mode = getConfigValue(serv, "bind-mode");
|
||||
|
|
|
@ -23,6 +23,31 @@
|
|||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include "network.h"
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
void init_encryption() {
|
||||
public_rsa = RSA_new();
|
||||
BIGNUM* pn = BN_new();
|
||||
if (BN_set_word(pn, RSA_F4) != 1) {
|
||||
printf("Error generating RSA BIGNUM!\n");
|
||||
return;
|
||||
}
|
||||
if (RSA_generate_key_ex(public_rsa, 1024, pn, NULL) != 1) {
|
||||
printf("Error generating RSA keypair!\n");
|
||||
return;
|
||||
}
|
||||
size_t s = i2d_RSA_PUBKEY(public_rsa, &public_rsa_publickey);
|
||||
if (s != 162) {
|
||||
printf("[WARNING] RSA Public Key size was not 162! Size = %lu\n", s);
|
||||
}
|
||||
OpenSSL_add_all_algorithms();
|
||||
SSL_load_error_strings();
|
||||
SSL_library_init();
|
||||
const SSL_METHOD* method = SSLv23_client_method();
|
||||
mojang_ctx = SSL_CTX_new(method);
|
||||
}
|
||||
|
||||
void swapEndian(void* dou, size_t ss) {
|
||||
uint8_t* pxs = (uint8_t*) dou;
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "accept.h"
|
||||
#include "inventory.h"
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
struct packet;
|
||||
|
||||
|
@ -29,6 +30,12 @@ struct entity_metadata {
|
|||
size_t metadata_size;
|
||||
};
|
||||
|
||||
RSA* public_rsa;
|
||||
uint8_t* public_rsa_publickey;
|
||||
SSL_CTX* mojang_ctx;
|
||||
|
||||
void init_encryption();
|
||||
|
||||
void swapEndian(void* dou, size_t ss);
|
||||
|
||||
int getVarIntSize(int32_t input);
|
||||
|
|
|
@ -35,24 +35,42 @@ ssize_t readPacket(struct conn* conn, unsigned char* buf, size_t buflen, struct
|
|||
void* pktbuf = buf;
|
||||
int32_t pktlen = buflen;
|
||||
int tf = 0;
|
||||
if (conn->aes_ctx_dec != NULL) {
|
||||
if (EVP_DecryptInit_ex(conn->aes_ctx_dec, EVP_aes_128_cfb8(), NULL, conn->sharedSecret, conn->sharedSecret) != 1) return -1;
|
||||
int csl = pktlen + 32; // 16 extra just in case
|
||||
void* edata = xmalloc(csl);
|
||||
if (EVP_DecryptUpdate(conn->aes_ctx_dec, edata, &csl, pktbuf, pktlen) != 1) {
|
||||
xfree(edata);
|
||||
goto rer;
|
||||
}
|
||||
int csl2 = 0;
|
||||
if (EVP_DecryptFinal_ex(conn->aes_ctx_dec, edata + csl, &csl2) != 1) {
|
||||
xfree(edata);
|
||||
goto rer;
|
||||
}
|
||||
csl += csl2;
|
||||
pktbuf = edata;
|
||||
pktlen = csl;
|
||||
tf = 1;
|
||||
}
|
||||
if (conn->comp >= 0) {
|
||||
int32_t dl = 0;
|
||||
int rx = readVarInt(&dl, pktbuf, pktlen);
|
||||
if (rx == 0) return -1;
|
||||
if (rx == 0) goto rer;
|
||||
pktlen -= rx;
|
||||
pktbuf += rx;
|
||||
if (dl > 0 && pktlen > 0) {
|
||||
pktlen = dl;
|
||||
void* decmpbuf = malloc(dl);
|
||||
void* decmpbuf = xmalloc(dl);
|
||||
z_stream strm;
|
||||
strm.zalloc = Z_NULL;
|
||||
strm.zfree = Z_NULL;
|
||||
strm.opaque = Z_NULL;
|
||||
int dr = 0;
|
||||
if ((dr = inflateInit(&strm)) != Z_OK) {
|
||||
free(decmpbuf);
|
||||
xfree(decmpbuf);
|
||||
printf("Compression initialization error!\n");
|
||||
return -1;
|
||||
goto rer;
|
||||
}
|
||||
strm.avail_in = pktlen;
|
||||
strm.next_in = pktbuf;
|
||||
|
@ -61,9 +79,9 @@ ssize_t readPacket(struct conn* conn, unsigned char* buf, size_t buflen, struct
|
|||
do {
|
||||
dr = inflate(&strm, Z_FINISH);
|
||||
if (dr == Z_STREAM_ERROR) {
|
||||
free(decmpbuf);
|
||||
xfree(decmpbuf);
|
||||
printf("Compression Read Error\n");
|
||||
return -1;
|
||||
goto rer;
|
||||
}
|
||||
strm.avail_out = pktlen - strm.total_out;
|
||||
strm.next_out = decmpbuf + strm.total_out;
|
||||
|
@ -543,6 +561,7 @@ ssize_t readPacket(struct conn* conn, unsigned char* buf, size_t buflen, struct
|
|||
}
|
||||
goto rx;
|
||||
rer: ;
|
||||
if (tf) xfree(pktbuf);
|
||||
return -1;
|
||||
rx: ;
|
||||
if (tf) xfree(pktbuf);
|
||||
|
@ -1920,14 +1939,14 @@ ssize_t writePacket(struct conn* conn, struct packet* packet) {
|
|||
pi += writeVarInt(packet->data.login_client.encryptionrequest.public_key_length, pktbuf + pi);
|
||||
//public_key
|
||||
ENS(packet->data.login_client.encryptionrequest.public_key_length)
|
||||
memcpy(pktbuf + pi, &packet->data.login_client.encryptionrequest.public_key, packet->data.login_client.encryptionrequest.public_key_length);
|
||||
memcpy(pktbuf + pi, packet->data.login_client.encryptionrequest.public_key, packet->data.login_client.encryptionrequest.public_key_length);
|
||||
pi += packet->data.login_client.encryptionrequest.public_key_length;
|
||||
//verify_token_length
|
||||
ENS(4)
|
||||
pi += writeVarInt(packet->data.login_client.encryptionrequest.verify_token_length, pktbuf + pi);
|
||||
//verify_token
|
||||
ENS(packet->data.login_client.encryptionrequest.verify_token_length)
|
||||
memcpy(pktbuf + pi, &packet->data.login_client.encryptionrequest.verify_token, packet->data.login_client.encryptionrequest.verify_token_length);
|
||||
memcpy(pktbuf + pi, packet->data.login_client.encryptionrequest.verify_token, packet->data.login_client.encryptionrequest.verify_token_length);
|
||||
pi += packet->data.login_client.encryptionrequest.verify_token_length;
|
||||
} else if (id == PKT_LOGIN_CLIENT_LOGINSUCCESS) {
|
||||
//uuid
|
||||
|
@ -1962,27 +1981,26 @@ ssize_t writePacket(struct conn* conn, struct packet* packet) {
|
|||
}
|
||||
strm.avail_in = pi;
|
||||
strm.next_in = pktbuf;
|
||||
void* cdata = malloc(16384);
|
||||
size_t cc = pi + 32;
|
||||
void* cdata = xmalloc(cc);
|
||||
size_t ts = 0;
|
||||
size_t cc = 16384;
|
||||
strm.avail_out = cc - ts;
|
||||
strm.next_out = cdata + ts;
|
||||
do {
|
||||
dr = deflate(&strm, Z_FINISH);
|
||||
ts = strm.total_out;
|
||||
if (ts >= cc) {
|
||||
cc = ts + 16384;
|
||||
cdata = realloc(cdata, cc);
|
||||
cc = ts + 1024;
|
||||
cdata = xrealloc(cdata, cc);
|
||||
}
|
||||
if (dr == Z_STREAM_ERROR) {
|
||||
free(cdata);
|
||||
xfree(cdata);
|
||||
return -1;
|
||||
}
|
||||
strm.avail_out = cc - ts;
|
||||
strm.next_out = cdata + ts;
|
||||
} while (strm.avail_out == 0);
|
||||
deflateEnd(&strm);
|
||||
cdata = xrealloc(cdata, ts); // shrink
|
||||
preps += writeVarInt(ts + getVarIntSize(pi), prep + preps);
|
||||
preps += writeVarInt(pi, prep + preps);
|
||||
wrt = cdata;
|
||||
|
@ -1997,7 +2015,63 @@ ssize_t writePacket(struct conn* conn, struct packet* packet) {
|
|||
wrt = pktbuf;
|
||||
wrt_s = pi;
|
||||
}
|
||||
//TODO: encrypt
|
||||
if (conn->aes_ctx_enc != NULL) {
|
||||
if (EVP_EncryptInit_ex(conn->aes_ctx_enc, EVP_aes_128_cfb8(), NULL, conn->sharedSecret, conn->sharedSecret) != 1) {
|
||||
wrt_s = -1;
|
||||
goto rret;
|
||||
}
|
||||
int csl = wrt_s + 32; // 16 extra just in case
|
||||
void* edata = xcalloc(csl);
|
||||
if (EVP_EncryptUpdate(conn->aes_ctx_enc, edata, &csl, wrt, wrt_s) != 1) {
|
||||
xfree(edata);
|
||||
wrt_s = -1;
|
||||
goto rret;
|
||||
}
|
||||
int csl2 = 0;
|
||||
if (EVP_EncryptFinal_ex(conn->aes_ctx_enc, edata + csl, &csl2) != 1) {
|
||||
xfree(edata);
|
||||
wrt_s = -1;
|
||||
goto rret;
|
||||
}
|
||||
csl += csl2;
|
||||
void* owrt = wrt;
|
||||
size_t owrts = wrt_s;
|
||||
//xfree(wrt);
|
||||
if (!frp) pktbuf = NULL;
|
||||
wrt = edata;
|
||||
wrt_s = csl;
|
||||
//
|
||||
if (EVP_DecryptInit_ex(conn->aes_ctx_dec, EVP_aes_128_cfb8(), NULL, conn->sharedSecret, conn->sharedSecret) != 1) return -1;
|
||||
csl = wrt_s + 32; // 16 extra just in case
|
||||
edata = xcalloc(csl);
|
||||
if (EVP_DecryptUpdate(conn->aes_ctx_dec, edata, &csl, wrt, wrt_s) != 1) {
|
||||
xfree(edata);
|
||||
wrt_s = -1;
|
||||
goto rret;
|
||||
}
|
||||
csl2 = 0;
|
||||
if (EVP_DecryptFinal_ex(conn->aes_ctx_dec, edata + csl, &csl2) != 1) {
|
||||
xfree(edata);
|
||||
wrt_s = -1;
|
||||
goto rret;
|
||||
}
|
||||
csl += csl2;
|
||||
if (csl != owrts) {
|
||||
printf("length mismatch! %i != %i\n", csl, owrts);
|
||||
} else {
|
||||
printf("original data: ");
|
||||
for (int i = 0; i < owrts; i++) {
|
||||
printf("%02X", ((uint8_t*) owrt)[i]);
|
||||
}
|
||||
printf("\ndec/enc data: ");
|
||||
for (int i = 0; i < csl; i++) {
|
||||
printf("%02X", ((uint8_t*) edata)[i]);
|
||||
}
|
||||
printf("\n%s\n", memeq(owrt, owrts, edata, csl) ? "equal!" : "not equal!");
|
||||
}
|
||||
xfree(owrt);
|
||||
xfree(edata);
|
||||
}
|
||||
if (conn->writeBuffer == NULL) {
|
||||
conn->writeBuffer = xmalloc(preps);
|
||||
memcpy(conn->writeBuffer, prep, preps);
|
||||
|
@ -2017,6 +2091,7 @@ ssize_t writePacket(struct conn* conn, struct packet* packet) {
|
|||
}
|
||||
memcpy(conn->writeBuffer + conn->writeBuffer_size, wrt, wrt_s);
|
||||
conn->writeBuffer_size += wrt_s;
|
||||
rret: ;
|
||||
if (frp) xfree(wrt);
|
||||
xfree(pktbuf);
|
||||
return wrt_s;
|
||||
|
|
|
@ -1082,9 +1082,9 @@ struct pkt_login_client_disconnect {
|
|||
struct pkt_login_client_encryptionrequest {
|
||||
char* server_id;
|
||||
int32_t public_key_length;
|
||||
int8_t* public_key;
|
||||
uint8_t* public_key;
|
||||
int32_t verify_token_length;
|
||||
int8_t* verify_token;
|
||||
uint8_t* verify_token;
|
||||
};
|
||||
|
||||
#define PKT_LOGIN_CLIENT_LOGINSUCCESS 2
|
||||
|
@ -1110,9 +1110,9 @@ struct pkt_login_server_loginstart {
|
|||
|
||||
struct pkt_login_server_encryptionresponse {
|
||||
int32_t shared_secret_length;
|
||||
int8_t* shared_secret;
|
||||
uint8_t* shared_secret;
|
||||
int32_t verify_token_length;
|
||||
int8_t* verify_token;
|
||||
uint8_t* verify_token;
|
||||
};
|
||||
|
||||
union pkt_handshake_client {
|
||||
|
|
444
basin/src/work.c
444
basin/src/work.c
|
@ -32,6 +32,11 @@
|
|||
#include "item.h"
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <netdb.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include "version.h"
|
||||
#include "json.h"
|
||||
|
||||
void closeConn(struct work_param* param, struct conn* conn) {
|
||||
close(conn->fd);
|
||||
|
@ -43,12 +48,160 @@ void closeConn(struct work_param* param, struct conn* conn) {
|
|||
conn->player->defunct = 1;
|
||||
conn->player->conn = NULL;
|
||||
}
|
||||
if (conn->aes_ctx_enc != NULL) EVP_CIPHER_CTX_free(conn->aes_ctx_enc);
|
||||
if (conn->aes_ctx_dec != NULL) EVP_CIPHER_CTX_free(conn->aes_ctx_dec);
|
||||
if (conn->host_ip != NULL) xfree(conn->host_ip);
|
||||
if (conn->readBuffer != NULL) xfree(conn->readBuffer);
|
||||
if (conn->writeBuffer != NULL) xfree(conn->writeBuffer);
|
||||
if (conn->onll_username != NULL) xfree(conn->onll_username);
|
||||
xfree(conn);
|
||||
}
|
||||
|
||||
int work_joinServer(struct conn* conn, char* username, char* uuids) {
|
||||
struct packet rep;
|
||||
rep.id = PKT_LOGIN_CLIENT_LOGINSUCCESS;
|
||||
rep.data.login_client.loginsuccess.username = username;
|
||||
struct uuid uuid;
|
||||
unsigned char* uuidx = (unsigned char*) &uuid;
|
||||
if (uuids == NULL) {
|
||||
if (!online_mode) return 1;
|
||||
MD5_CTX context;
|
||||
MD5_Init(&context);
|
||||
MD5_Update(&context, username, strlen(username));
|
||||
MD5_Final(uuidx, &context);
|
||||
} else {
|
||||
if (strlen(uuids) != 32) return 1;
|
||||
char ups[17];
|
||||
memcpy(ups, uuids, 16);
|
||||
ups[16] = 0;
|
||||
uuid.uuid1 = strtoll(ups, NULL, 16);
|
||||
memcpy(ups, uuids + 16, 16);
|
||||
uuid.uuid2 = strtoll(ups, NULL, 16);
|
||||
}
|
||||
rep.data.login_client.loginsuccess.uuid = xmalloc(38);
|
||||
snprintf(rep.data.login_client.loginsuccess.uuid, 10, "%08X-", ((uint32_t*) uuidx)[0]);
|
||||
snprintf(rep.data.login_client.loginsuccess.uuid + 9, 6, "%04X-", ((uint16_t*) uuidx)[2]);
|
||||
snprintf(rep.data.login_client.loginsuccess.uuid + 14, 6, "%04X-", ((uint16_t*) uuidx)[3]);
|
||||
snprintf(rep.data.login_client.loginsuccess.uuid + 19, 6, "%04X-", ((uint16_t*) uuidx)[4]);
|
||||
snprintf(rep.data.login_client.loginsuccess.uuid + 24, 9, "%08X", ((uint32_t*) (uuidx + 4))[2]);
|
||||
snprintf(rep.data.login_client.loginsuccess.uuid + 32, 5, "%04X", ((uint16_t*) uuidx)[7]);
|
||||
if (writePacket(conn, &rep) < 0) return 1;
|
||||
xfree(rep.data.login_client.loginsuccess.uuid);
|
||||
conn->state = STATE_PLAY;
|
||||
struct entity* ep = newEntity(nextEntityID++, (double) overworld->spawnpos.x + .5, (double) overworld->spawnpos.y, (double) overworld->spawnpos.z + .5, ENT_PLAYER, 0., 0.);
|
||||
struct player* player = newPlayer(ep, xstrdup(rep.data.login_client.loginsuccess.username, 1), uuid, conn, 0); // TODO default gamemode
|
||||
player->protocolVersion = conn->protocolVersion;
|
||||
conn->player = player;
|
||||
put_hashmap(players, player->entity->id, player);
|
||||
rep.id = PKT_PLAY_CLIENT_JOINGAME;
|
||||
rep.data.play_client.joingame.entity_id = ep->id;
|
||||
rep.data.play_client.joingame.gamemode = player->gamemode;
|
||||
rep.data.play_client.joingame.dimension = overworld->dimension;
|
||||
rep.data.play_client.joingame.difficulty = difficulty;
|
||||
rep.data.play_client.joingame.max_players = max_players;
|
||||
rep.data.play_client.joingame.level_type = overworld->levelType;
|
||||
rep.data.play_client.joingame.reduced_debug_info = 0; // TODO
|
||||
if (writePacket(conn, &rep) < 0) return 1;
|
||||
rep.id = PKT_PLAY_CLIENT_PLUGINMESSAGE;
|
||||
rep.data.play_client.pluginmessage.channel = "MC|Brand";
|
||||
rep.data.play_client.pluginmessage.data = xmalloc(16);
|
||||
int rx = writeVarInt(5, rep.data.play_client.pluginmessage.data);
|
||||
memcpy(rep.data.play_client.pluginmessage.data + rx, "Basin", 5);
|
||||
rep.data.play_client.pluginmessage.data_size = rx + 5;
|
||||
if (writePacket(conn, &rep) < 0) return 1;
|
||||
xfree(rep.data.play_client.pluginmessage.data);
|
||||
rep.id = PKT_PLAY_CLIENT_SERVERDIFFICULTY;
|
||||
rep.data.play_client.serverdifficulty.difficulty = difficulty;
|
||||
if (writePacket(conn, &rep) < 0) return 1;
|
||||
rep.id = PKT_PLAY_CLIENT_SPAWNPOSITION;
|
||||
memcpy(&rep.data.play_client.spawnposition.location, &overworld->spawnpos, sizeof(struct encpos));
|
||||
if (writePacket(conn, &rep) < 0) return 1;
|
||||
rep.id = PKT_PLAY_CLIENT_PLAYERABILITIES;
|
||||
rep.data.play_client.playerabilities.flags = 0; // TODO: allows flying, remove
|
||||
rep.data.play_client.playerabilities.flying_speed = 0.05;
|
||||
rep.data.play_client.playerabilities.field_of_view_modifier = .1;
|
||||
if (writePacket(conn, &rep) < 0) return 1;
|
||||
rep.id = PKT_PLAY_CLIENT_PLAYERPOSITIONANDLOOK;
|
||||
rep.data.play_client.playerpositionandlook.x = ep->x;
|
||||
rep.data.play_client.playerpositionandlook.y = ep->y;
|
||||
rep.data.play_client.playerpositionandlook.z = ep->z;
|
||||
rep.data.play_client.playerpositionandlook.yaw = ep->yaw;
|
||||
rep.data.play_client.playerpositionandlook.pitch = ep->pitch;
|
||||
rep.data.play_client.playerpositionandlook.flags = 0x0;
|
||||
rep.data.play_client.playerpositionandlook.teleport_id = 0;
|
||||
if (writePacket(conn, &rep) < 0) return 1;
|
||||
rep.id = PKT_PLAY_CLIENT_PLAYERLISTITEM;
|
||||
pthread_rwlock_rdlock(&players->data_mutex);
|
||||
rep.data.play_client.playerlistitem.action_id = 0;
|
||||
rep.data.play_client.playerlistitem.number_of_players = players->entry_count + 1;
|
||||
rep.data.play_client.playerlistitem.players = xmalloc(rep.data.play_client.playerlistitem.number_of_players * sizeof(struct listitem_player));
|
||||
size_t px = 0;
|
||||
BEGIN_HASHMAP_ITERATION (players)
|
||||
struct player* plx = (struct player*) value;
|
||||
if (px < rep.data.play_client.playerlistitem.number_of_players) {
|
||||
memcpy(&rep.data.play_client.playerlistitem.players[px].uuid, &plx->uuid, sizeof(struct uuid));
|
||||
rep.data.play_client.playerlistitem.players[px].action.addplayer.name = xstrdup(plx->name, 0);
|
||||
rep.data.play_client.playerlistitem.players[px].action.addplayer.number_of_properties = 0;
|
||||
rep.data.play_client.playerlistitem.players[px].action.addplayer.properties = NULL;
|
||||
rep.data.play_client.playerlistitem.players[px].action.addplayer.gamemode = plx->gamemode;
|
||||
rep.data.play_client.playerlistitem.players[px].action.addplayer.ping = 0; // TODO
|
||||
rep.data.play_client.playerlistitem.players[px].action.addplayer.has_display_name = 0;
|
||||
rep.data.play_client.playerlistitem.players[px].action.addplayer.display_name = NULL;
|
||||
px++;
|
||||
}
|
||||
if (player == plx) continue;
|
||||
struct packet* pkt = xmalloc(sizeof(struct packet));
|
||||
pkt->id = PKT_PLAY_CLIENT_PLAYERLISTITEM;
|
||||
pkt->data.play_client.playerlistitem.action_id = 0;
|
||||
pkt->data.play_client.playerlistitem.number_of_players = 1;
|
||||
pkt->data.play_client.playerlistitem.players = xmalloc(sizeof(struct listitem_player));
|
||||
memcpy(&pkt->data.play_client.playerlistitem.players->uuid, &player->uuid, sizeof(struct uuid));
|
||||
pkt->data.play_client.playerlistitem.players->action.addplayer.name = xstrdup(player->name, 0);
|
||||
pkt->data.play_client.playerlistitem.players->action.addplayer.number_of_properties = 0;
|
||||
pkt->data.play_client.playerlistitem.players->action.addplayer.properties = NULL;
|
||||
pkt->data.play_client.playerlistitem.players->action.addplayer.gamemode = player->gamemode;
|
||||
pkt->data.play_client.playerlistitem.players->action.addplayer.ping = 0; // TODO
|
||||
pkt->data.play_client.playerlistitem.players->action.addplayer.has_display_name = 0;
|
||||
pkt->data.play_client.playerlistitem.players->action.addplayer.display_name = NULL;
|
||||
add_queue(plx->outgoingPacket, pkt);
|
||||
flush_outgoing(plx);
|
||||
END_HASHMAP_ITERATION (players)
|
||||
pthread_rwlock_unlock(&players->data_mutex);
|
||||
memcpy(&rep.data.play_client.playerlistitem.players[px].uuid, &player->uuid, sizeof(struct uuid));
|
||||
rep.data.play_client.playerlistitem.players[px].action.addplayer.name = xstrdup(player->name, 0);
|
||||
rep.data.play_client.playerlistitem.players[px].action.addplayer.number_of_properties = 0;
|
||||
rep.data.play_client.playerlistitem.players[px].action.addplayer.properties = NULL;
|
||||
rep.data.play_client.playerlistitem.players[px].action.addplayer.gamemode = player->gamemode;
|
||||
rep.data.play_client.playerlistitem.players[px].action.addplayer.ping = 0; // TODO
|
||||
rep.data.play_client.playerlistitem.players[px].action.addplayer.has_display_name = 0;
|
||||
rep.data.play_client.playerlistitem.players[px].action.addplayer.display_name = NULL;
|
||||
px++;
|
||||
if (writePacket(conn, &rep) < 0) return 1;
|
||||
rep.id = PKT_PLAY_CLIENT_TIMEUPDATE;
|
||||
rep.data.play_client.timeupdate.time_of_day = overworld->time;
|
||||
rep.data.play_client.timeupdate.world_age = overworld->age;
|
||||
if (writePacket(conn, &rep) < 0) return 1;
|
||||
add_collection(playersToLoad, player);
|
||||
//broadcastf("yellow", "%s has joined the server!", player->name);
|
||||
const char* mip = NULL;
|
||||
char tip[48];
|
||||
if (conn->addr.sin6_family == AF_INET) {
|
||||
struct sockaddr_in *sip4 = (struct sockaddr_in*) &conn->addr;
|
||||
mip = inet_ntop(AF_INET, &sip4->sin_addr, tip, 48);
|
||||
} else if (conn->addr.sin6_family == AF_INET6) {
|
||||
struct sockaddr_in6 *sip6 = (struct sockaddr_in6*) &conn->addr;
|
||||
if (memseq((unsigned char*) &sip6->sin6_addr, 10, 0) && memseq((unsigned char*) &sip6->sin6_addr + 10, 2, 0xff)) {
|
||||
mip = inet_ntop(AF_INET, ((unsigned char*) &sip6->sin6_addr) + 12, tip, 48);
|
||||
} else mip = inet_ntop(AF_INET6, &sip6->sin6_addr, tip, 48);
|
||||
} else if (conn->addr.sin6_family == AF_LOCAL) {
|
||||
mip = "UNIX";
|
||||
} else {
|
||||
mip = "UNKNOWN";
|
||||
}
|
||||
printf("Player '%s' has joined with IP '%s'\n", player->name, mip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int handleRead(struct conn* conn, struct work_param* param, int fd) {
|
||||
if (conn->disconnect) return 0;
|
||||
while (conn->readBuffer != NULL && conn->readBuffer_size > 0) {
|
||||
|
@ -96,10 +249,145 @@ int handleRead(struct conn* conn, struct work_param* param, int fd) {
|
|||
conn->state = -1;
|
||||
} else goto rete;
|
||||
} else if (conn->state == STATE_LOGIN) {
|
||||
if (inp->id == PKT_LOGIN_SERVER_LOGINSTART) {
|
||||
if (inp->id == PKT_LOGIN_SERVER_ENCRYPTIONRESPONSE) {
|
||||
if (conn->verifyToken == 0 || inp->data.login_server.encryptionresponse.shared_secret_length > 162 || inp->data.login_server.encryptionresponse.verify_token_length > 162) goto rete;
|
||||
unsigned char decSecret[162];
|
||||
int secLen = RSA_private_decrypt(inp->data.login_server.encryptionresponse.shared_secret_length, inp->data.login_server.encryptionresponse.shared_secret, decSecret, public_rsa, RSA_PKCS1_PADDING);
|
||||
if (secLen != 16) goto rete;
|
||||
unsigned char decVerifyToken[162];
|
||||
int vtLen = RSA_private_decrypt(inp->data.login_server.encryptionresponse.verify_token_length, inp->data.login_server.encryptionresponse.verify_token, decVerifyToken, public_rsa, RSA_PKCS1_PADDING);
|
||||
if (vtLen != 4) goto rete;
|
||||
uint32_t vt = *((uint32_t*) decVerifyToken);
|
||||
if (vt != conn->verifyToken) goto rete;
|
||||
uint8_t hash[20];
|
||||
SHA_CTX context;
|
||||
SHA1_Init(&context);
|
||||
SHA1_Update(&context, decSecret, 16);
|
||||
SHA1_Update(&context, public_rsa_publickey, 162);
|
||||
SHA1_Final(hash, &context);
|
||||
int m = 0;
|
||||
if (hash[0] & 0x80) {
|
||||
m = 1;
|
||||
for (int i = 0; i < 20; i++) {
|
||||
hash[i] = ~hash[i];
|
||||
}
|
||||
(hash[19])++;
|
||||
}
|
||||
char fhash[32];
|
||||
char* fhash2 = fhash + 1;
|
||||
for (int i = 0; i < 20; i++) {
|
||||
snprintf(fhash + 1 + (i * 2), 3, "%02X", hash[i]);
|
||||
}
|
||||
for (int i = 1; i < 41; i++) {
|
||||
if (fhash[i] == '0') fhash2++;
|
||||
else break;
|
||||
}
|
||||
fhash2--;
|
||||
if (m) fhash2[0] = '-';
|
||||
else fhash2++;
|
||||
struct sockaddr_in sin;
|
||||
struct hostent *host = gethostbyname("sessionserver.mojang.com");
|
||||
if (host != NULL) {
|
||||
struct in_addr **adl = (struct in_addr **) host->h_addr_list;
|
||||
if (adl[0] != NULL) {
|
||||
sin.sin_addr.s_addr = adl[0]->s_addr;
|
||||
} else goto merr;
|
||||
} else goto merr;
|
||||
sin.sin_port = htons(443);
|
||||
sin.sin_family = AF_INET;
|
||||
int mfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
SSL* sct = NULL;
|
||||
int initssl = 0;
|
||||
int val = 0;
|
||||
if (mfd < 0) goto merr;
|
||||
if (connect(mfd, (struct sockaddr*) &sin, sizeof(struct sockaddr_in))) goto merr;
|
||||
sct = SSL_new(mojang_ctx);
|
||||
SSL_set_connect_state(sct);
|
||||
SSL_set_fd(sct, mfd);
|
||||
if (SSL_connect(sct) != 1) goto merr;
|
||||
else initssl = 1;
|
||||
char cbuf[4096];
|
||||
int tl = snprintf(cbuf, 1024, "GET /session/minecraft/hasJoined?username=%s&serverId=%s HTTP/1.1\r\nHost: sessionserver.mojang.com\r\nUser-Agent: Basin " VERSION "\r\nConnection: close\r\n\r\n", conn->onll_username, fhash2);
|
||||
int tw = 0;
|
||||
while (tw < tl) {
|
||||
int r = SSL_write(sct, cbuf, tl);
|
||||
if (r <= 0) goto merr;
|
||||
else tw += r;
|
||||
}
|
||||
tw = 0;
|
||||
int r = 0;
|
||||
while ((r = SSL_read(sct, cbuf + tw, 4095 - tw)) > 0) {
|
||||
tw += r;
|
||||
}
|
||||
cbuf[tw] = 0;
|
||||
char* data = strstr(cbuf, "\r\n\r\n");
|
||||
if (data == NULL) goto merr;
|
||||
data += 4;
|
||||
struct json_object json;
|
||||
parseJSON(&json, data);
|
||||
struct json_object* tmp = getJSONValue(&json, "id");
|
||||
if (tmp == NULL || tmp->type != JSON_STRING) {
|
||||
freeJSON(&json);
|
||||
goto merr;
|
||||
}
|
||||
char* id = trim(tmp->data.string);
|
||||
tmp = getJSONValue(&json, "name");
|
||||
if (tmp == NULL || tmp->type != JSON_STRING) {
|
||||
freeJSON(&json);
|
||||
goto merr;
|
||||
}
|
||||
char* name = trim(tmp->data.string);
|
||||
size_t sl = strlen(name);
|
||||
if (sl < 2 || sl > 16) {
|
||||
freeJSON(&json);
|
||||
goto merr;
|
||||
}
|
||||
BEGIN_HASHMAP_ITERATION (players)
|
||||
struct player* player = (struct player*) value;
|
||||
if (streq_nocase(name, player->name)) {
|
||||
kickPlayer(player, "You have logged in from another location!");
|
||||
goto pbn2;
|
||||
}
|
||||
END_HASHMAP_ITERATION (players)
|
||||
pbn2: ;
|
||||
val = 1;
|
||||
memcpy(conn->sharedSecret, decSecret, 16);
|
||||
conn->aes_ctx_enc = EVP_CIPHER_CTX_new();
|
||||
if (conn->aes_ctx_enc == NULL) goto rete;
|
||||
conn->aes_ctx_dec = EVP_CIPHER_CTX_new();
|
||||
if (conn->aes_ctx_dec == NULL) goto rete;
|
||||
if (work_joinServer(conn, name, id)) {
|
||||
freeJSON(&json);
|
||||
if (initssl) SSL_shutdown(sct);
|
||||
if (mfd >= 0) close(mfd);
|
||||
if (sct != NULL) SSL_free(sct);
|
||||
goto rete;
|
||||
}
|
||||
freeJSON(&json);
|
||||
merr: ;
|
||||
if (initssl) SSL_shutdown(sct);
|
||||
if (mfd >= 0) close(mfd);
|
||||
if (sct != NULL) SSL_free(sct);
|
||||
if (!val) {
|
||||
rep.id = PKT_LOGIN_CLIENT_DISCONNECT;
|
||||
rep.data.login_client.disconnect.reason = xstrdup("{\"text\": \"There was an unresolvable issue with the Mojang sessionserver! Please try again.\"}", 0);
|
||||
if (writePacket(conn, &rep) < 0) goto rete;
|
||||
conn->disconnect = 1;
|
||||
goto ret;
|
||||
}
|
||||
} else if (inp->id == PKT_LOGIN_SERVER_LOGINSTART) {
|
||||
if (online_mode) {
|
||||
//TODO
|
||||
return -1;
|
||||
if (conn->verifyToken) goto rete;
|
||||
conn->onll_username = xstrdup(inp->data.login_server.loginstart.name, 0);
|
||||
rep.id = PKT_LOGIN_CLIENT_ENCRYPTIONREQUEST;
|
||||
rep.data.login_client.encryptionrequest.server_id = "";
|
||||
rep.data.login_client.encryptionrequest.public_key = public_rsa_publickey;
|
||||
rep.data.login_client.encryptionrequest.public_key_length = 162;
|
||||
conn->verifyToken = rand();
|
||||
if (conn->verifyToken == 0) conn->verifyToken = 1;
|
||||
rep.data.login_client.encryptionrequest.verify_token = (uint8_t*) &conn->verifyToken;
|
||||
rep.data.login_client.encryptionrequest.verify_token_length = 4;
|
||||
if (writePacket(conn, &rep) < 0) goto rete;
|
||||
} else {
|
||||
int bn = 0;
|
||||
char* rna = trim(inp->data.login_server.loginstart.name);
|
||||
|
@ -110,161 +398,19 @@ int handleRead(struct conn* conn, struct work_param* param, int fd) {
|
|||
struct player* player = (struct player*) value;
|
||||
if (streq_nocase(rna, player->name)) {
|
||||
bn = 1;
|
||||
break;
|
||||
goto pbn;
|
||||
}
|
||||
END_HASHMAP_ITERATION (players)
|
||||
pbn: ;
|
||||
}
|
||||
if (bn) {
|
||||
rep.id = PKT_LOGIN_CLIENT_DISCONNECT;
|
||||
rep.data.login_client.disconnect.reason = xstrdup(bn == 2 ? "{\"text\": \"Invalid name!\"}" : "{\"text\", \"You are already in the server!\"}", 0);
|
||||
if (writePacket(conn, &rep) < 0) goto rete;
|
||||
conn->disconnect = 1;
|
||||
return 0;
|
||||
goto ret;
|
||||
}
|
||||
rep.id = PKT_LOGIN_CLIENT_LOGINSUCCESS;
|
||||
rep.data.login_client.loginsuccess.username = rna;
|
||||
struct uuid uuid;
|
||||
unsigned char* uuidx = (unsigned char*) &uuid;
|
||||
MD5_CTX context;
|
||||
MD5_Init(&context);
|
||||
MD5_Update(&context, rna, strlen(rna));
|
||||
MD5_Final(uuidx, &context);
|
||||
rep.data.login_client.loginsuccess.uuid = xmalloc(38);
|
||||
snprintf(rep.data.login_client.loginsuccess.uuid, 10, "%08X-", ((uint32_t*) uuidx)[0]);
|
||||
snprintf(rep.data.login_client.loginsuccess.uuid + 9, 6, "%04X-", ((uint16_t*) uuidx)[2]);
|
||||
snprintf(rep.data.login_client.loginsuccess.uuid + 14, 6, "%04X-", ((uint16_t*) uuidx)[3]);
|
||||
snprintf(rep.data.login_client.loginsuccess.uuid + 19, 6, "%04X-", ((uint16_t*) uuidx)[4]);
|
||||
snprintf(rep.data.login_client.loginsuccess.uuid + 24, 9, "%08X", ((uint32_t*) (uuidx + 4))[2]);
|
||||
snprintf(rep.data.login_client.loginsuccess.uuid + 32, 5, "%04X", ((uint16_t*) uuidx)[7]);
|
||||
if (writePacket(conn, &rep) < 0) goto rete;
|
||||
xfree(rep.data.login_client.loginsuccess.uuid);
|
||||
conn->state = STATE_PLAY;
|
||||
struct entity* ep = newEntity(nextEntityID++, (double) overworld->spawnpos.x + .5, (double) overworld->spawnpos.y, (double) overworld->spawnpos.z + .5, ENT_PLAYER, 0., 0.);
|
||||
struct player* player = newPlayer(ep, xstrdup(rep.data.login_client.loginsuccess.username, 1), uuid, conn, 0); // TODO default gamemode
|
||||
player->protocolVersion = conn->protocolVersion;
|
||||
conn->player = player;
|
||||
put_hashmap(players, player->entity->id, player);
|
||||
rep.id = PKT_PLAY_CLIENT_JOINGAME;
|
||||
rep.data.play_client.joingame.entity_id = ep->id;
|
||||
rep.data.play_client.joingame.gamemode = player->gamemode;
|
||||
rep.data.play_client.joingame.dimension = overworld->dimension;
|
||||
rep.data.play_client.joingame.difficulty = difficulty;
|
||||
rep.data.play_client.joingame.max_players = max_players;
|
||||
rep.data.play_client.joingame.level_type = overworld->levelType;
|
||||
rep.data.play_client.joingame.reduced_debug_info = 0; // TODO
|
||||
if (writePacket(conn, &rep) < 0) goto rete;
|
||||
rep.id = PKT_PLAY_CLIENT_PLUGINMESSAGE;
|
||||
rep.data.play_client.pluginmessage.channel = "MC|Brand";
|
||||
rep.data.play_client.pluginmessage.data = xmalloc(16);
|
||||
int rx = writeVarInt(5, rep.data.play_client.pluginmessage.data);
|
||||
memcpy(rep.data.play_client.pluginmessage.data + rx, "Basin", 5);
|
||||
rep.data.play_client.pluginmessage.data_size = rx + 5;
|
||||
if (writePacket(conn, &rep) < 0) goto rete;
|
||||
xfree(rep.data.play_client.pluginmessage.data);
|
||||
rep.id = PKT_PLAY_CLIENT_SERVERDIFFICULTY;
|
||||
rep.data.play_client.serverdifficulty.difficulty = difficulty;
|
||||
if (writePacket(conn, &rep) < 0) goto rete;
|
||||
rep.id = PKT_PLAY_CLIENT_SPAWNPOSITION;
|
||||
memcpy(&rep.data.play_client.spawnposition.location, &overworld->spawnpos, sizeof(struct encpos));
|
||||
if (writePacket(conn, &rep) < 0) goto rete;
|
||||
rep.id = PKT_PLAY_CLIENT_PLAYERABILITIES;
|
||||
rep.data.play_client.playerabilities.flags = 0; // TODO: allows flying, remove
|
||||
rep.data.play_client.playerabilities.flying_speed = 0.05;
|
||||
rep.data.play_client.playerabilities.field_of_view_modifier = .1;
|
||||
if (writePacket(conn, &rep) < 0) goto rete;
|
||||
rep.id = PKT_PLAY_CLIENT_PLAYERPOSITIONANDLOOK;
|
||||
rep.data.play_client.playerpositionandlook.x = ep->x;
|
||||
rep.data.play_client.playerpositionandlook.y = ep->y;
|
||||
rep.data.play_client.playerpositionandlook.z = ep->z;
|
||||
rep.data.play_client.playerpositionandlook.yaw = ep->yaw;
|
||||
rep.data.play_client.playerpositionandlook.pitch = ep->pitch;
|
||||
rep.data.play_client.playerpositionandlook.flags = 0x0;
|
||||
rep.data.play_client.playerpositionandlook.teleport_id = 0;
|
||||
if (writePacket(conn, &rep) < 0) goto rete;
|
||||
rep.id = PKT_PLAY_CLIENT_PLAYERLISTITEM;
|
||||
pthread_rwlock_rdlock(&players->data_mutex);
|
||||
rep.data.play_client.playerlistitem.action_id = 0;
|
||||
rep.data.play_client.playerlistitem.number_of_players = players->entry_count + 1;
|
||||
rep.data.play_client.playerlistitem.players = xmalloc(rep.data.play_client.playerlistitem.number_of_players * sizeof(struct listitem_player));
|
||||
size_t px = 0;
|
||||
BEGIN_HASHMAP_ITERATION (players)
|
||||
struct player* plx = (struct player*) value;
|
||||
if (px < rep.data.play_client.playerlistitem.number_of_players) {
|
||||
memcpy(&rep.data.play_client.playerlistitem.players[px].uuid, &plx->uuid, sizeof(struct uuid));
|
||||
rep.data.play_client.playerlistitem.players[px].action.addplayer.name = xstrdup(plx->name, 0);
|
||||
rep.data.play_client.playerlistitem.players[px].action.addplayer.number_of_properties = 0;
|
||||
rep.data.play_client.playerlistitem.players[px].action.addplayer.properties = NULL;
|
||||
rep.data.play_client.playerlistitem.players[px].action.addplayer.gamemode = plx->gamemode;
|
||||
rep.data.play_client.playerlistitem.players[px].action.addplayer.ping = 0; // TODO
|
||||
rep.data.play_client.playerlistitem.players[px].action.addplayer.has_display_name = 0;
|
||||
rep.data.play_client.playerlistitem.players[px].action.addplayer.display_name = NULL;
|
||||
px++;
|
||||
}
|
||||
if (player == plx) continue;
|
||||
struct packet* pkt = xmalloc(sizeof(struct packet));
|
||||
pkt->id = PKT_PLAY_CLIENT_PLAYERLISTITEM;
|
||||
pkt->data.play_client.playerlistitem.action_id = 0;
|
||||
pkt->data.play_client.playerlistitem.number_of_players = 1;
|
||||
pkt->data.play_client.playerlistitem.players = xmalloc(sizeof(struct listitem_player));
|
||||
memcpy(&pkt->data.play_client.playerlistitem.players->uuid, &player->uuid, sizeof(struct uuid));
|
||||
pkt->data.play_client.playerlistitem.players->action.addplayer.name = xstrdup(player->name, 0);
|
||||
pkt->data.play_client.playerlistitem.players->action.addplayer.number_of_properties = 0;
|
||||
pkt->data.play_client.playerlistitem.players->action.addplayer.properties = NULL;
|
||||
pkt->data.play_client.playerlistitem.players->action.addplayer.gamemode = player->gamemode;
|
||||
pkt->data.play_client.playerlistitem.players->action.addplayer.ping = 0; // TODO
|
||||
pkt->data.play_client.playerlistitem.players->action.addplayer.has_display_name = 0;
|
||||
pkt->data.play_client.playerlistitem.players->action.addplayer.display_name = NULL;
|
||||
add_queue(plx->outgoingPacket, pkt);
|
||||
flush_outgoing(plx);
|
||||
END_HASHMAP_ITERATION (players)
|
||||
pthread_rwlock_unlock(&players->data_mutex);
|
||||
memcpy(&rep.data.play_client.playerlistitem.players[px].uuid, &player->uuid, sizeof(struct uuid));
|
||||
rep.data.play_client.playerlistitem.players[px].action.addplayer.name = xstrdup(player->name, 0);
|
||||
rep.data.play_client.playerlistitem.players[px].action.addplayer.number_of_properties = 0;
|
||||
rep.data.play_client.playerlistitem.players[px].action.addplayer.properties = NULL;
|
||||
rep.data.play_client.playerlistitem.players[px].action.addplayer.gamemode = player->gamemode;
|
||||
rep.data.play_client.playerlistitem.players[px].action.addplayer.ping = 0; // TODO
|
||||
rep.data.play_client.playerlistitem.players[px].action.addplayer.has_display_name = 0;
|
||||
rep.data.play_client.playerlistitem.players[px].action.addplayer.display_name = NULL;
|
||||
px++;
|
||||
if (writePacket(conn, &rep) < 0) goto rete;
|
||||
rep.id = PKT_PLAY_CLIENT_TIMEUPDATE;
|
||||
rep.data.play_client.timeupdate.time_of_day = overworld->time;
|
||||
rep.data.play_client.timeupdate.world_age = overworld->age;
|
||||
if (writePacket(conn, &rep) < 0) goto rete;
|
||||
add_collection(playersToLoad, player);
|
||||
//broadcastf("yellow", "%s has joined the server!", player->name);
|
||||
const char* mip = NULL;
|
||||
char tip[48];
|
||||
if (conn->addr.sin6_family == AF_INET) {
|
||||
struct sockaddr_in *sip4 = (struct sockaddr_in*) &conn->addr;
|
||||
mip = inet_ntop(AF_INET, &sip4->sin_addr, tip, 48);
|
||||
} else if (conn->addr.sin6_family == AF_INET6) {
|
||||
struct sockaddr_in6 *sip6 = (struct sockaddr_in6*) &conn->addr;
|
||||
if (memseq((unsigned char*) &sip6->sin6_addr, 10, 0) && memseq((unsigned char*) &sip6->sin6_addr + 10, 2, 0xff)) {
|
||||
mip = inet_ntop(AF_INET, ((unsigned char*) &sip6->sin6_addr) + 12, tip, 48);
|
||||
} else mip = inet_ntop(AF_INET6, &sip6->sin6_addr, tip, 48);
|
||||
} else if (conn->addr.sin6_family == AF_LOCAL) {
|
||||
mip = "UNIX";
|
||||
} else {
|
||||
mip = "UNKNOWN";
|
||||
}
|
||||
printf("Player '%s' has joined with IP '%s'\n", player->name, mip);
|
||||
/*for (int x = -9; x < 10; x++) {
|
||||
for (int z = -9; z < 10; z++) {
|
||||
struct chunk* ch = getChunk(overworld, x + (int32_t) ep->x / 16, z + (int32_t) ep->z / 16);
|
||||
if (ch != NULL) {
|
||||
struct packet* pkt = xmalloc(sizeof(struct packet));
|
||||
pkt->id = PKT_PLAY_CLIENT_CHUNKDATA;
|
||||
pkt->data.play_client.chunkdata.data = ch;
|
||||
pkt->data.play_client.chunkdata.ground_up_continuous = 1;
|
||||
pkt->data.play_client.chunkdata.number_of_block_entities = 0;
|
||||
pkt->data.play_client.chunkdata.block_entities = NULL;
|
||||
add_queue(player->conn->outgoingPacket, pkt);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
if (work_joinServer(conn, rna, NULL)) goto rete;
|
||||
}
|
||||
}
|
||||
} else if (conn->state == STATE_PLAY) {
|
||||
|
|
Loading…
Reference in New Issue