mirror of https://github.com/basinserver/basin/
split up work
This commit is contained in:
parent
7f6fa031b6
commit
b0b43eed0b
|
@ -23,8 +23,6 @@ size_t tick_counter;
|
|||
struct config* cfg;
|
||||
struct mempool* global_pool;
|
||||
struct logsess* delog;
|
||||
struct hashmap* players;
|
||||
struct queue* playersToLoad;
|
||||
pthread_mutex_t glob_tick_mut;
|
||||
pthread_cond_t glob_tick_cond;
|
||||
struct hashmap* server_map;
|
||||
|
|
|
@ -1274,9 +1274,11 @@ struct packet {
|
|||
union pkts data;
|
||||
};
|
||||
|
||||
ssize_t readPacket(struct connection* conn, unsigned char* buf, size_t buflen, struct packet* packet);
|
||||
struct packet* packet_new(struct mempool* pool, int32_t id);
|
||||
|
||||
ssize_t writePacket(struct connection* conn, struct packet* packet);
|
||||
ssize_t packet_read(struct connection* conn, unsigned char* buf, size_t buflen, struct packet* packet);
|
||||
|
||||
ssize_t packet_write(struct connection* conn, struct packet* packet);
|
||||
|
||||
void freePacket(int state, int dir, struct packet* packet);
|
||||
|
|
@ -26,6 +26,9 @@ struct server {
|
|||
struct world* endworld;
|
||||
struct list* worlds;
|
||||
struct queue* prepared_connections;
|
||||
struct hashmap* players;
|
||||
// struct queue* playersToLoad;
|
||||
|
||||
};
|
||||
|
||||
//TODO: make this an option
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Author: root
|
||||
*/
|
||||
|
||||
#include "packet.h"
|
||||
#include "basin/packet.h"
|
||||
#include <basin/inventory.h>
|
||||
#include <basin/globals.h>
|
||||
#include "basin/network.h"
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Author: root
|
||||
*/
|
||||
|
||||
#include "packet.h"
|
||||
#include "basin/packet.h"
|
||||
#include <basin/basin.h>
|
||||
#include <basin/network.h>
|
||||
#include <basin/queue.h>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Author: root
|
||||
*/
|
||||
|
||||
#include "packet.h"
|
||||
#include "basin/packet.h"
|
||||
#include <basin/basin.h>
|
||||
#include <basin/queue.h>
|
||||
#include <basin/game.h>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Author: root
|
||||
*/
|
||||
|
||||
#include "packet.h"
|
||||
#include "basin/packet.h"
|
||||
#include <basin/network.h>
|
||||
#include <basin/globals.h>
|
||||
#include <basin/item.h>
|
||||
|
|
|
@ -0,0 +1,254 @@
|
|||
//
|
||||
// Created by p on 4/14/19.
|
||||
//
|
||||
|
||||
#include "login_stage_handler.h"
|
||||
#include <basin/connection.h>
|
||||
#include <basin/network.h>
|
||||
#include <basin/packet.h>
|
||||
#include <basin/globals.h>
|
||||
#include <basin/version.h>
|
||||
#include <avuna/string.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <netdb.h>
|
||||
|
||||
int handle_packet_handshake(struct connection* conn, struct packet* packet) {
|
||||
conn->host_ip = str_dup(packet->data.handshake_server.handshake.server_address, 0, conn->pool);
|
||||
conn->host_port = packet->data.handshake_server.handshake.server_port;
|
||||
conn->protocolVersion = (uint32_t) packet->data.handshake_server.handshake.protocol_version;
|
||||
if ((packet->data.handshake_server.handshake.protocol_version < MC_PROTOCOL_VERSION_MIN || packet->data.handshake_server.handshake.protocol_version > MC_PROTOCOL_VERSION_MAX) && packet->data.handshake_server.handshake.next_state != STATE_STATUS) return -2;
|
||||
if (packet->data.handshake_server.handshake.next_state == STATE_STATUS) {
|
||||
conn->protocol_state = STATE_STATUS;
|
||||
} else if (packet->data.handshake_server.handshake.next_state == STATE_LOGIN) {
|
||||
conn->protocol_state = STATE_LOGIN;
|
||||
} else return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int handle_packet_status(struct connection* conn, struct packet* packet) {
|
||||
if (packet->id == PKT_STATUS_SERVER_REQUEST) {
|
||||
struct packet* resp = packet_new(packet->pool, PKT_STATUS_CLIENT_RESPONSE);
|
||||
resp->data.status_client.response.json_response = pmalloc(packet->pool, 1000);
|
||||
resp->data.status_client.response.json_response[999] = 0;
|
||||
snprintf(resp->data.status_client.response.json_response, 999, "{\"version\":{\"name\":\"1.11.2\",\"protocol\":%i},\"players\":{\"max\":%lu,\"online\":%lu},\"description\":{\"text\":\"%s\"}}", MC_PROTOCOL_VERSION_MIN, conn->server->max_players, conn->server->players->entry_count, conn->server->motd);
|
||||
if (packet_write(conn, resp) < 0) return 1;
|
||||
} else if (packet->id == PKT_STATUS_SERVER_PING) {
|
||||
struct packet* resp = packet_new(packet->pool, PKT_STATUS_CLIENT_PONG);
|
||||
if (packet_write(conn, resp) < 0) return 1;
|
||||
conn->disconnect = 1;
|
||||
} else return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void encrypt_free(EVP_CIPHER_CTX* ctx) {
|
||||
unsigned char final[256];
|
||||
int throw_away = 0;
|
||||
EVP_EncryptFinal_ex(ctx, final, &throw_away);
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
}
|
||||
|
||||
void decrypt_free(EVP_CIPHER_CTX* ctx) {
|
||||
unsigned char final[256];
|
||||
int throw_away = 0;
|
||||
EVP_DecryptFinal_ex(ctx, final, &throw_away);
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
}
|
||||
|
||||
int handle_encryption_response(struct connection* conn, struct packet* packet) {
|
||||
if (conn->verifyToken == 0 || packet->data.login_server.encryptionresponse.shared_secret_length > 162 || packet->data.login_server.encryptionresponse.verify_token_length > 162) goto rete;
|
||||
unsigned char decSecret[162];
|
||||
int secLen = RSA_private_decrypt(packet->data.login_server.encryptionresponse.shared_secret_length, packet->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(packet->data.login_server.encryptionresponse.verify_token_length, packet->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;
|
||||
memcpy(conn->shared_secret, decSecret, 16);
|
||||
uint8_t pubkey[162];
|
||||
memcpy(pubkey, public_rsa_publickey, 162);
|
||||
uint8_t hash[20];
|
||||
SHA_CTX context;
|
||||
SHA1_Init(&context);
|
||||
SHA1_Update(&context, decSecret, 16);
|
||||
SHA1_Update(&context, pubkey, 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->online_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;
|
||||
json_parse(&json, data);
|
||||
struct json_object* tmp = json_get(&json, "id");
|
||||
if (tmp == NULL || tmp->type != JSON_STRING) {
|
||||
freeJSON(&json);
|
||||
goto merr;
|
||||
}
|
||||
char* id = trim(tmp->data.string);
|
||||
tmp = json_get(&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;
|
||||
conn->aes_ctx_enc = EVP_CIPHER_CTX_new();
|
||||
if (conn->aes_ctx_enc == NULL) goto rete;
|
||||
//EVP_CIPHER_CTX_set_padding(conn->aes_ctx_enc, 0);
|
||||
if (EVP_EncryptInit_ex(conn->aes_ctx_enc, EVP_aes_128_cfb8(), NULL, conn->sharedSecret, conn->sharedSecret) != 1) goto rete;
|
||||
if (conn->aes_ctx_enc != NULL) {
|
||||
phook(conn->pool, encrypt_free, conn->aes_ctx_enc);
|
||||
}
|
||||
|
||||
conn->aes_ctx_dec = EVP_CIPHER_CTX_new();
|
||||
if (conn->aes_ctx_dec == NULL) goto rete;
|
||||
//EVP_CIPHER_CTX_set_padding(conn->aes_ctx_dec, 0);
|
||||
if (EVP_DecryptInit_ex(conn->aes_ctx_dec, EVP_aes_128_cfb8(), NULL, conn->sharedSecret, conn->sharedSecret) != 1) goto rete;
|
||||
if (conn->aes_ctx_dec != NULL) {
|
||||
phook(conn->pool, decrypt_free, conn->aes_ctx_dec);
|
||||
}
|
||||
|
||||
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 (packet_write(conn, &rep) < 0) goto rete;
|
||||
conn->disconnect = 1;
|
||||
goto ret;
|
||||
}
|
||||
}
|
||||
|
||||
int handle_login_start(struct connection* conn, struct packet* packet) {
|
||||
if (conn->server->online_mode) {
|
||||
if (conn->verifyToken) {
|
||||
return 1;
|
||||
}
|
||||
conn->online_username = pxfer(packet->pool, conn->pool, packet->data.login_server.loginstart.name);
|
||||
struct packet* resp = packet_new(packet->pool, PKT_LOGIN_CLIENT_ENCRYPTIONREQUEST);
|
||||
resp->data.login_client.encryptionrequest.server_id = "";
|
||||
resp->data.login_client.encryptionrequest.public_key = public_rsa_publickey;
|
||||
resp->data.login_client.encryptionrequest.public_key_length = 162;
|
||||
conn->verifyToken = rand(); // TODO: better RNG
|
||||
if (conn->verifyToken == 0) conn->verifyToken = 1;
|
||||
resp->data.login_client.encryptionrequest.verify_token = (uint8_t*) &conn->verifyToken;
|
||||
resp->data.login_client.encryptionrequest.verify_token_length = 4;
|
||||
if (packet_write(conn, resp) < 0) {
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
int bad_name = 0;
|
||||
char* name_trimmed = str_trim(packet->data.login_server.loginstart.name);
|
||||
size_t trimmed_length = strlen(name_trimmed);
|
||||
if (trimmed_length > 16 || trimmed_length < 2) bad_name = 2;
|
||||
if (!bad_name) {
|
||||
BEGIN_HASHMAP_ITERATION (players)
|
||||
struct player* player = (struct player*) value;
|
||||
if (streq_nocase(name_trimmed, player->name)) {
|
||||
bad_name = 1;
|
||||
goto pbn;
|
||||
}
|
||||
END_HASHMAP_ITERATION (players)
|
||||
pbn: ;
|
||||
}
|
||||
if (bad_name) {
|
||||
struct packet* resp = packet_new(packet->pool, PKT_LOGIN_CLIENT_DISCONNECT);
|
||||
resp->id = PKT_LOGIN_CLIENT_DISCONNECT;
|
||||
resp->data.login_client.disconnect.reason = bad_name == 2 ? "{\"text\": \"Invalid name!\"}" : "{\"text\", \"You are already in the server!\"}";
|
||||
if (packet_write(conn, resp) < 0) {
|
||||
return 1;
|
||||
}
|
||||
conn->disconnect = 1;
|
||||
return 0;
|
||||
}
|
||||
if (work_joinServer(conn, name_trimmed, NULL)) goto rete;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int handle_packet_login(struct connection* conn, struct packet* packet) {
|
||||
if (packet->id == PKT_LOGIN_SERVER_ENCRYPTIONRESPONSE) {
|
||||
return handle_encryption_response(conn, packet);
|
||||
} else if (packet->id == PKT_LOGIN_SERVER_LOGINSTART) {
|
||||
return handle_login_start(conn, packet);
|
||||
} else return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
//
|
||||
// Created by p on 4/14/19.
|
||||
//
|
||||
|
||||
#ifndef BASIN_LOGIN_STAGE_HANDLER_H
|
||||
#define BASIN_LOGIN_STAGE_HANDLER_H
|
||||
|
||||
#include <basin/connection.h>
|
||||
#include <basin/packet.h>
|
||||
|
||||
int handle_packet_handshake(struct connection* conn, struct packet* packet);
|
||||
|
||||
int handle_packet_login(struct connection* conn, struct packet* packet);
|
||||
|
||||
int handle_packet_status(struct connection* conn, struct packet* packet);
|
||||
|
||||
#endif //BASIN_LOGIN_STAGE_HANDLER_H
|
|
@ -275,9 +275,10 @@ struct server* server_load(struct config_node* server) {
|
|||
list_append(serv->worlds, serv->overworld);
|
||||
//add_collection(worlds, nether);
|
||||
//add_collection(worlds, endworld);
|
||||
serv-> players = hashmap_thread_new(32, global_pool);
|
||||
// playersToLoad = queue_new(0, 1, global_pool);
|
||||
|
||||
hashmap_put(server_map, serv->name, serv);
|
||||
struct accept_param* param = pmalloc(serv->pool, sizeof(struct accept_param));
|
||||
param->server = serv;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
|
@ -354,8 +355,6 @@ int main(int argc, char* argv[]) {
|
|||
return -1;
|
||||
}
|
||||
globalChunkQueue = queue_new(0, 1, global_pool);
|
||||
players = hashmap_thread_new(32, global_pool);
|
||||
playersToLoad = queue_new(0, 1, global_pool);
|
||||
init_materials();
|
||||
acclog(delog, "Materials Initialized");
|
||||
init_blocks();
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
#include "accept.h"
|
||||
#include "packet.h"
|
||||
#include "basin/packet.h"
|
||||
#include <basin/nbt.h>
|
||||
#include <basin/network.h>
|
||||
#include <avuna/pmem.h>
|
||||
|
|
13
src/packet.c
13
src/packet.c
|
@ -1,7 +1,7 @@
|
|||
|
||||
|
||||
|
||||
#include "packet.h"
|
||||
#include "basin/packet.h"
|
||||
#include <basin/globals.h>
|
||||
#include <basin/inventory.h>
|
||||
#include <basin/network.h>
|
||||
|
@ -26,13 +26,20 @@
|
|||
#include <time.h>
|
||||
#include <math.h>
|
||||
|
||||
struct packet* packet_new(struct mempool* pool, int32_t id) {
|
||||
struct packet* packet = pcalloc(pool, sizeof(struct packet));
|
||||
packet->pool = pool;
|
||||
packet->id = id;
|
||||
return packet;
|
||||
}
|
||||
|
||||
#define ADRX if(rx == 0) goto rer;pbuf += rx;ps -= rx;
|
||||
#define ADX(x) pbuf += x;ps -= x;
|
||||
#define CPS(x) if(ps < x) goto rer;
|
||||
#define CPS_OPT(x) if(ps >= x) {
|
||||
#define ENS(x) if(ps-pi < x) { ps += (x > 256 ? x + 1024 : 1024); pktbuf = prealloc(packet->pool, pktbuf - 10, ps + 10) + 10; }
|
||||
|
||||
ssize_t readPacket(struct connection* conn, unsigned char* buf, size_t buflen, struct packet* packet) {
|
||||
ssize_t packet_read(struct connection* conn, unsigned char* buf, size_t buflen, struct packet* packet) {
|
||||
void* pktbuf = buf;
|
||||
int32_t pktlen = (int32_t) buflen;
|
||||
if (conn->compression_state >= 0) {
|
||||
|
@ -549,7 +556,7 @@ ssize_t readPacket(struct connection* conn, unsigned char* buf, size_t buflen, s
|
|||
return buflen;
|
||||
}
|
||||
|
||||
ssize_t writePacket(struct connection* conn, struct packet* packet) {
|
||||
ssize_t packet_write(struct connection* conn, struct packet* packet) {
|
||||
if (conn->protocol_state == STATE_PLAY && packet->id == PKT_PLAY_CLIENT_CHUNKDATA) {
|
||||
if (!isChunkLoaded(conn->player->world, packet->data.play_client.chunkdata.cx, packet->data.play_client.chunkdata.cz)) return 0;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
#include "accept.h"
|
||||
#include "packet.h"
|
||||
#include "basin/packet.h"
|
||||
#include <basin/network.h>
|
||||
#include <basin/inventory.h>
|
||||
#include <basin/queue.h>
|
||||
|
|
446
src/work.c
446
src/work.c
|
@ -7,7 +7,8 @@
|
|||
|
||||
#include "work.h"
|
||||
#include "accept.h"
|
||||
#include "packet.h"
|
||||
#include "basin/packet.h"
|
||||
#include "login_stage_handler.h"
|
||||
#include <basin/network.h>
|
||||
#include <basin/globals.h>
|
||||
#include <basin/connection.h>
|
||||
|
@ -18,6 +19,7 @@
|
|||
#include <basin/block.h>
|
||||
#include <basin/item.h>
|
||||
#include <basin/version.h>
|
||||
#include <basin/profile.h>
|
||||
#include <avuna/json.h>
|
||||
#include <avuna/streams.h>
|
||||
#include <avuna/queue.h>
|
||||
|
@ -39,35 +41,6 @@
|
|||
#include <sys/ioctl.h>
|
||||
#include <avuna/util.h>
|
||||
|
||||
void closeConn(struct work_param* param, struct conn* conn) {
|
||||
close(conn->fd);
|
||||
if (rem_collection(param->conns, conn)) {
|
||||
errlog(param->logsess, "Failed to delete connection properly! This is bad!");
|
||||
}
|
||||
if (conn->player != NULL) {
|
||||
broadcastf("yellow", "%s has left the server!", conn->player->name);
|
||||
conn->player->defunct = 1;
|
||||
conn->player->conn = NULL;
|
||||
}
|
||||
if (conn->aes_ctx_enc != NULL) {
|
||||
char final[256];
|
||||
int csl2 = 0;
|
||||
EVP_EncryptFinal_ex(conn->aes_ctx_enc, final, &csl2);
|
||||
EVP_CIPHER_CTX_free(conn->aes_ctx_enc);
|
||||
}
|
||||
if (conn->aes_ctx_dec != NULL) {
|
||||
char final[256];
|
||||
int csl2 = 0;
|
||||
EVP_DecryptFinal_ex(conn->aes_ctx_dec, final, &csl2);
|
||||
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->readDecBuffer != NULL) xfree(conn->readDecBuffer);
|
||||
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;
|
||||
|
@ -101,7 +74,7 @@ int work_joinServer(struct conn* conn, char* username, char* uuids) {
|
|||
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;
|
||||
if (packet_write(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.);
|
||||
|
@ -117,26 +90,26 @@ int work_joinServer(struct conn* conn, char* username, char* uuids) {
|
|||
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;
|
||||
if (packet_write(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 rx2 = writeVarInt(5, rep.data.play_client.pluginmessage.data);
|
||||
memcpy(rep.data.play_client.pluginmessage.data + rx2, "Basin", 5);
|
||||
rep.data.play_client.pluginmessage.data_size = rx2 + 5;
|
||||
if (writePacket(conn, &rep) < 0) return 1;
|
||||
if (packet_write(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;
|
||||
if (packet_write(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;
|
||||
if (packet_write(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;
|
||||
if (packet_write(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;
|
||||
|
@ -145,7 +118,7 @@ int work_joinServer(struct conn* conn, char* username, char* uuids) {
|
|||
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;
|
||||
if (packet_write(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;
|
||||
|
@ -192,11 +165,11 @@ int work_joinServer(struct conn* conn, char* username, char* uuids) {
|
|||
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;
|
||||
if (packet_write(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;
|
||||
if (packet_write(conn, &rep) < 0) return 1;
|
||||
add_collection(playersToLoad, player);
|
||||
broadcastf("yellow", "%s has joined the server!", player->name);
|
||||
const char* mip = NULL;
|
||||
|
@ -256,379 +229,44 @@ int connection_read(struct netmgr_connection* netmgr_conn, uint8_t* read_buf, si
|
|||
|
||||
struct packet* packet = pmalloc(packet_pool, sizeof(struct packet));
|
||||
packet->pool = packet_pool;
|
||||
ssize_t read_packet_length = readPacket(conn, packet_buf, (size_t) length, packet);
|
||||
ssize_t read_packet_length = packet_read(conn, packet_buf, (size_t) length, packet);
|
||||
|
||||
if (read_packet_length == -1) goto rete;
|
||||
int os = conn->state;
|
||||
struct packet rep;
|
||||
int df = 0;
|
||||
if (conn->state == STATE_HANDSHAKE && packet->id == PKT_HANDSHAKE_SERVER_HANDSHAKE) {
|
||||
conn->host_ip = xstrdup(packet->data.handshake_server.handshake.server_address, 0);
|
||||
conn->host_port = packet->data.handshake_server.handshake.server_port;
|
||||
conn->protocolVersion = packet->data.handshake_server.handshake.protocol_version;
|
||||
if ((packet->data.handshake_server.handshake.protocol_version < MC_PROTOCOL_VERSION_MIN || packet->data.handshake_server.handshake.protocol_version > MC_PROTOCOL_VERSION_MAX) && packet->data.handshake_server.handshake.next_state != STATE_STATUS) return -2;
|
||||
if (packet->data.handshake_server.handshake.next_state == STATE_STATUS) {
|
||||
conn->state = STATE_STATUS;
|
||||
} else if (packet->data.handshake_server.handshake.next_state == STATE_LOGIN) {
|
||||
conn->state = STATE_LOGIN;
|
||||
} else goto rete;
|
||||
} else if (conn->state == STATE_STATUS) {
|
||||
if (packet->id == PKT_STATUS_SERVER_REQUEST) {
|
||||
rep.id = PKT_STATUS_CLIENT_RESPONSE;
|
||||
rep.data.status_client.response.json_response = xmalloc(1000);
|
||||
rep.data.status_client.response.json_response[999] = 0;
|
||||
snprintf(rep.data.status_client.response.json_response, 999, "{\"version\":{\"name\":\"1.11.2\",\"protocol\":%i},\"players\":{\"max\":%i,\"online\":%i},\"description\":{\"text\":\"%s\"}}", MC_PROTOCOL_VERSION_MIN, max_players, players->entry_count, motd);
|
||||
if (writePacket(conn, &rep) < 0) goto rete;
|
||||
xfree(rep.data.status_client.response.json_response);
|
||||
} else if (packet->id == PKT_STATUS_SERVER_PING) {
|
||||
rep.id = PKT_STATUS_CLIENT_PONG;
|
||||
if (writePacket(conn, &rep) < 0) goto rete;
|
||||
conn->state = -1;
|
||||
} else goto rete;
|
||||
} else if (conn->state == STATE_LOGIN) {
|
||||
if (packet->id == PKT_LOGIN_SERVER_ENCRYPTIONRESPONSE) {
|
||||
if (conn->verifyToken == 0 || packet->data.login_server.encryptionresponse.shared_secret_length > 162 || packet->data.login_server.encryptionresponse.verify_token_length > 162) goto rete;
|
||||
unsigned char decSecret[162];
|
||||
int secLen = RSA_private_decrypt(packet->data.login_server.encryptionresponse.shared_secret_length, packet->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(packet->data.login_server.encryptionresponse.verify_token_length, packet->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;
|
||||
memcpy(conn->sharedSecret, decSecret, 16);
|
||||
uint8_t pubkey[162];
|
||||
memcpy(pubkey, public_rsa_publickey, 162);
|
||||
uint8_t hash[20];
|
||||
SHA_CTX context;
|
||||
SHA1_Init(&context);
|
||||
SHA1_Update(&context, decSecret, 16);
|
||||
SHA1_Update(&context, pubkey, 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;
|
||||
json_parse(&json, data);
|
||||
struct json_object* tmp = json_get(&json, "id");
|
||||
if (tmp == NULL || tmp->type != JSON_STRING) {
|
||||
freeJSON(&json);
|
||||
goto merr;
|
||||
}
|
||||
char* id = trim(tmp->data.string);
|
||||
tmp = json_get(&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;
|
||||
conn->aes_ctx_enc = EVP_CIPHER_CTX_new();
|
||||
if (conn->aes_ctx_enc == NULL) goto rete;
|
||||
//EVP_CIPHER_CTX_set_padding(conn->aes_ctx_enc, 0);
|
||||
if (EVP_EncryptInit_ex(conn->aes_ctx_enc, EVP_aes_128_cfb8(), NULL, conn->sharedSecret, conn->sharedSecret) != 1) goto rete;
|
||||
conn->aes_ctx_dec = EVP_CIPHER_CTX_new();
|
||||
if (conn->aes_ctx_dec == NULL) goto rete;
|
||||
//EVP_CIPHER_CTX_set_padding(conn->aes_ctx_dec, 0);
|
||||
if (EVP_DecryptInit_ex(conn->aes_ctx_dec, EVP_aes_128_cfb8(), NULL, conn->sharedSecret, conn->sharedSecret) != 1) 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 (packet->id == PKT_LOGIN_SERVER_LOGINSTART) {
|
||||
if (online_mode) {
|
||||
if (conn->verifyToken) goto rete;
|
||||
conn->onll_username = xstrdup(packet->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(packet->data.login_server.loginstart.name);
|
||||
size_t rnal = strlen(rna);
|
||||
if (rnal > 16 || rnal < 2) bn = 2;
|
||||
if (!bn) {
|
||||
BEGIN_HASHMAP_ITERATION (players)
|
||||
struct player* player = (struct player*) value;
|
||||
if (streq_nocase(rna, player->name)) {
|
||||
bn = 1;
|
||||
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;
|
||||
goto ret;
|
||||
}
|
||||
if (work_joinServer(conn, rna, NULL)) goto rete;
|
||||
}
|
||||
if (read_packet_length == -1) goto ret_error;
|
||||
if (conn->protocol_state == STATE_HANDSHAKE && packet->id == PKT_HANDSHAKE_SERVER_HANDSHAKE) {
|
||||
if (handle_packet_handshake(conn, packet)) {
|
||||
goto ret_error;
|
||||
}
|
||||
} else if (conn->state == STATE_PLAY) {
|
||||
add_queue(conn->player->incomingPacket, packet);
|
||||
df = 1;
|
||||
} else if (conn->protocol_state == STATE_STATUS) {
|
||||
if (handle_packet_status(conn, packet)) {
|
||||
goto ret_error;
|
||||
}
|
||||
} else if (conn->protocol_state == STATE_LOGIN) {
|
||||
if (handle_packet_login(conn, packet)) {
|
||||
goto ret_error;
|
||||
}
|
||||
} else if (conn->protocol_state == STATE_PLAY) {
|
||||
queue_push(conn->player->incomingPacket, packet);
|
||||
} else {
|
||||
goto ret_error;
|
||||
}
|
||||
beginProfilerSection("movebuf");
|
||||
memmove(abuf, abuf + length + ls, asze - length - ls);
|
||||
asze -= length + ls;
|
||||
if (abuf == conn->readBuffer) conn->readBuffer_size = asze;
|
||||
else if (abuf == conn->readDecBuffer) conn->readDecBuffer_size = asze;
|
||||
endProfilerSection("movebuf");
|
||||
goto ret;
|
||||
rete: ;
|
||||
if (!df) {
|
||||
freePacket(os, 0, packet);
|
||||
xfree(packet);
|
||||
}
|
||||
return -1;
|
||||
ret_error: ;
|
||||
pfree(packet->pool);
|
||||
return 1;
|
||||
ret: ;
|
||||
if (!df) {
|
||||
freePacket(os, 0, packet);
|
||||
xfree(packet);
|
||||
}
|
||||
pfree(packet->pool);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void connection_on_closed(struct netmgr_connection* conn) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
void run_work(struct work_param* param) {
|
||||
if (pipe(param->pipes) != 0) {
|
||||
printf("Failed to create pipe! %s\n", strerror(errno));
|
||||
return;
|
||||
void connection_on_closed(struct netmgr_connection* netmgr_conn) {
|
||||
struct connection* conn = netmgr_conn->extra;
|
||||
if (conn->player != NULL) {
|
||||
broadcastf("yellow", "%s has left the server!", conn->player->name);
|
||||
conn->player->defunct = 1;
|
||||
conn->player->conn = NULL;
|
||||
}
|
||||
unsigned char wb;
|
||||
unsigned char* mbuf = xmalloc(1024);
|
||||
while (1) {
|
||||
pthread_rwlock_rdlock(¶m->conns->data_mutex);
|
||||
size_t cc = param->conns->count;
|
||||
struct pollfd fds[cc + 1];
|
||||
struct conn* conns[cc];
|
||||
int fdi = 0;
|
||||
for (int i = 0; i < param->conns->size; i++) {
|
||||
if (param->conns->data[i] != NULL) {
|
||||
conns[fdi] = (param->conns->data[i]);
|
||||
struct conn* conn = conns[fdi];
|
||||
fds[fdi].fd = conns[fdi]->fd;
|
||||
fds[fdi].events = POLLIN | ((conn->writeBuffer_size > 0 || (conn->player != NULL && conn->player->outgoingPacket->size > 0)) ? POLLOUT : 0);
|
||||
fds[fdi++].revents = 0;
|
||||
if (fdi == cc) break;
|
||||
}
|
||||
}
|
||||
pthread_rwlock_unlock(¶m->conns->data_mutex);
|
||||
fds[cc].fd = param->pipes[0];
|
||||
fds[cc].events = POLLIN;
|
||||
fds[cc].revents = 0;
|
||||
int cp = poll(fds, cc + 1, -1);
|
||||
if (cp < 0) {
|
||||
printf("Poll error in worker thread! %s\n", strerror(errno));
|
||||
} else if (cp == 0) continue;
|
||||
else if ((fds[cc].revents & POLLIN) == POLLIN) {
|
||||
if (read(param->pipes[0], &wb, 1) < 1) printf("Error reading from pipe, infinite loop COULD happen here.\n");
|
||||
if (cp-- == 1) continue;
|
||||
}
|
||||
for (int i = 0; i < cc; i++) {
|
||||
int re = fds[i].revents;
|
||||
struct conn* conn = conns[i];
|
||||
if ((re & POLLERR) == POLLERR) {
|
||||
//printf("POLLERR in worker poll! This is bad!\n");
|
||||
closeConn(param, conn);
|
||||
conn = NULL;
|
||||
goto cont;
|
||||
}
|
||||
if ((re & POLLHUP) == POLLHUP) {
|
||||
closeConn(param, conn);
|
||||
conn = NULL;
|
||||
goto cont;
|
||||
}
|
||||
if ((re & POLLNVAL) == POLLNVAL) {
|
||||
printf("Invalid FD in worker poll! This is bad!\n");
|
||||
closeConn(param, conn);
|
||||
conn = NULL;
|
||||
goto cont;
|
||||
}
|
||||
if ((re & POLLIN) == POLLIN) {
|
||||
size_t tr = 0;
|
||||
ioctl(fds[i].fd, FIONREAD, &tr);
|
||||
unsigned char* loc;
|
||||
if (conn->readBuffer == NULL) {
|
||||
conn->readBuffer = xmalloc(tr); // TODO: max upload?
|
||||
conn->readBuffer_size = tr;
|
||||
loc = conn->readBuffer;
|
||||
} else {
|
||||
conn->readBuffer_size += tr;
|
||||
conn->readBuffer = xrealloc(conn->readBuffer, conn->readBuffer_size);
|
||||
loc = conn->readBuffer + conn->readBuffer_size - tr;
|
||||
}
|
||||
ssize_t r = 0;
|
||||
if (r == 0 && tr == 0) { // nothing to read, but wont block.
|
||||
ssize_t x = read(fds[i].fd, loc + r, tr - r);
|
||||
if (x <= 0) {
|
||||
closeConn(param, conn);
|
||||
conn = NULL;
|
||||
goto cont;
|
||||
}
|
||||
r += x;
|
||||
}
|
||||
while (r < tr) {
|
||||
ssize_t x = read(fds[i].fd, loc + r, tr - r);
|
||||
if (x <= 0) {
|
||||
closeConn(param, conn);
|
||||
conn = NULL;
|
||||
goto cont;
|
||||
}
|
||||
r += x;
|
||||
}
|
||||
int p = 0;
|
||||
p = handleRead(conn, param, fds[i].fd);
|
||||
if (p == 1) {
|
||||
goto cont;
|
||||
}
|
||||
}
|
||||
if ((re & POLLOUT) == POLLOUT && conn != NULL) {
|
||||
if (conn->player != NULL) {
|
||||
struct packet* wp = pop_nowait_queue(conn->player->outgoingPacket);
|
||||
while (wp != NULL) {
|
||||
int wr = writePacket(conn, wp);
|
||||
if (wr == -1) {
|
||||
closeConn(param, conn);
|
||||
conn = NULL;
|
||||
goto cont;
|
||||
}
|
||||
freePacket(conn->state, 1, wp);
|
||||
xfree(wp);
|
||||
wp = pop_nowait_queue(conn->player->outgoingPacket);
|
||||
}
|
||||
//printf("%s WBS: %lu\n", conn->player->name, conn->writeBuffer_size);
|
||||
}
|
||||
ssize_t mtr = write(fds[i].fd, conn->writeBuffer, conn->writeBuffer_size);
|
||||
if (mtr < 0 && errno != EAGAIN) {
|
||||
closeConn(param, conn);
|
||||
conn = NULL;
|
||||
goto cont;
|
||||
} else if (mtr < 0) {
|
||||
goto cont;
|
||||
} else if (mtr < conn->writeBuffer_size) {
|
||||
memmove(conn->writeBuffer, conn->writeBuffer + mtr, conn->writeBuffer_size - mtr);
|
||||
conn->writeBuffer_size -= mtr;
|
||||
if (conn->writeBuffer_capacity > conn->writeBuffer_size + 1024 * 1024) {
|
||||
conn->writeBuffer = xrealloc(conn->writeBuffer, conn->writeBuffer_size);
|
||||
conn->writeBuffer_capacity = conn->writeBuffer_size;
|
||||
}
|
||||
} else {
|
||||
conn->writeBuffer_size = 0;
|
||||
conn->writeBuffer_capacity = 0;
|
||||
xfree(conn->writeBuffer);
|
||||
conn->writeBuffer = NULL;
|
||||
}
|
||||
}
|
||||
if (conn->state == -1 && conn->writeBuffer_size == 0) {
|
||||
closeConn(param, conn);
|
||||
conn = NULL;
|
||||
}
|
||||
cont: ;
|
||||
if (conn != NULL && conn->disconnect) {
|
||||
closeConn(param, conn);
|
||||
conn = NULL;
|
||||
}
|
||||
if (--cp == 0) break;
|
||||
}
|
||||
}
|
||||
xfree(mbuf);
|
||||
pthread_cancel (pthread_self());}
|
||||
pfree(conn->pool);
|
||||
|
||||
}
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
#include "basin/network.h"
|
||||
#include "packet.h"
|
||||
#include "basin/packet.h"
|
||||
#include <basin/game.h>
|
||||
#include <basin/block.h>
|
||||
#include <basin/queue.h>
|
||||
|
|
Loading…
Reference in New Issue