assaultfish/engine/net/src/socket.c
2026-01-08 00:35:00 +09:00

200 lines
4 KiB
C

#include <gbnet.h>
#include <zlib.h>
#define CHUNK 512
int gbnet_packet_send(int fd, gbnet_packet_t* packet) {
int r;
gbnet_packet_header_t h;
int len = 0;
unsigned char* data = NULL;
if(packet->header.length > 0) {
z_stream strm;
int in = packet->header.length;
int seek = 0;
int flush = 0;
unsigned char buf[CHUNK];
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
if(deflateInit(&strm, Z_DEFAULT_COMPRESSION) != Z_OK) return 0;
do {
strm.avail_in = in <= CHUNK ? in : CHUNK;
strm.next_in = ((unsigned char*)packet->data) + seek;
flush = in <= CHUNK ? Z_FINISH : Z_NO_FLUSH;
do {
int have;
strm.avail_out = CHUNK;
strm.next_out = buf;
deflate(&strm, flush);
have = CHUNK - strm.avail_out;
if(data == NULL) {
data = malloc(have);
memcpy(data, buf, have);
} else {
unsigned char* old = data;
data = malloc(len + have);
memcpy(data, old, len);
memcpy(data + len, buf, have);
free(data);
}
len += have;
} while(strm.avail_out == 0);
seek += CHUNK;
} while(flush != Z_FINISH);
deflateEnd(&strm);
}
memcpy(&h, &packet->header, sizeof(h));
h.length = htons(len);
r = gbnet_fd_send(fd, &h, sizeof(h));
if(r != sizeof(h)) return 0;
if(data != NULL) {
r = gbnet_fd_send(fd, data, len);
if(r != sizeof(h)) {
free(data);
return 0;
}
free(data);
}
return sizeof(h) + len;
}
int gbnet_packet_recv(int fd, gbnet_packet_t* packet) {
gbnet_packet_header_t h;
if(gbnet_fd_recv(fd, &h, sizeof(h), 500) != sizeof(h)) {
packet->data = NULL;
return 0;
}
memcpy(&packet->header, &h, sizeof(h));
packet->header.length = ntohs(packet->header.length);
packet->data = NULL;
if(packet->header.length > 0) {
unsigned char* data = malloc(packet->header.length);
z_stream strm;
int in = packet->header.length;
int ret;
int seek = 0;
int len = 0;
unsigned char buf[CHUNK];
if(gbnet_fd_recv(fd, data, packet->header.length, 50) != packet->header.length) {
free(data);
return 0;
}
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = 0;
strm.next_in = Z_NULL;
if(inflateInit(&strm) != Z_OK) {
free(data);
return 0;
}
do {
strm.avail_in = in <= CHUNK ? in : CHUNK;
strm.next_in = data + seek;
do {
int have;
strm.avail_out = CHUNK;
strm.next_out = buf;
ret = inflate(&strm, Z_NO_FLUSH);
if(ret == Z_NEED_DICT || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR) {
inflateEnd(&strm);
if(packet->data != NULL) {
free(packet->data);
packet->data = NULL;
}
free(data);
return 0;
}
have = CHUNK - strm.avail_out;
if(packet->data == NULL) {
packet->data = malloc(have);
memcpy(packet->data, buf, have);
} else {
unsigned char* old = packet->data;
packet->data = malloc(len + have);
memcpy(packet->data, old, len);
memcpy(packet->data + len, buf, have);
free(packet->data);
}
len += have;
} while(strm.avail_out == 0);
} while(ret != Z_STREAM_END);
inflateEnd(&strm);
free(data);
packet->header.length = len;
}
return sizeof(h) + packet->header.length;
}
int gbnet_fd_send(int fd, const void* buf, int length) {
struct pollfd pfd;
pfd.fd = fd;
pfd.events = POLLOUT | POLLPRI;
poll(&pfd, 1, 0);
if(!(pfd.revents & POLLOUT)) return 0;
return send(fd, buf, length, 0);
}
int gbnet_fd_recv(int fd, void* buf, int length, int to) {
struct pollfd pfd;
int ret;
unsigned char* b = buf;
int i = 0;
time_t t = time(NULL);
pfd.fd = fd;
pfd.events = POLLIN | POLLPRI;
while(i < length) {
/* i think 500 is reasonable timeout. no? */
ret = poll(&pfd, 1, to);
if((time(NULL) - t) >= 5) return i; /* we waited enough! kill the connection */
if(ret <= 0) return i;
ret = recv(fd, &b[i], 1, 0);
if(ret < 1) return i;
i++;
}
return i;
}