blob: 1a7fc28b62a685dd55f2505d9e4106880d6378e3 [file] [log] [blame] [raw]
/* Minecraft Interprocess Management Client
* Copyright 2015-2020 Rivoreo
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/
#include "packet.h"
#include <unistd.h>
#include "syncrw.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
int send_packet_get_version(int fd) {
uint32_t length = 1;
struct mcipm_packet *packet = malloc(4 + length);
if(!packet) {
fputs("send_packet_get_version: out of memory\n", stderr);
return -1;
}
packet->length = length;
packet->type = MCIPM_GET_VERSION;
if(sync_write(fd, packet, 4 + length) < 0) {
perror("send_packet_get_version: write");
return -1;
}
return 0;
}
int send_packet_get_entities(int fd, const void *selectors, size_t selectors_len, unsigned int selector_count) {
uint32_t length = 1 + 2 + selectors_len;
struct mcipm_packet *packet = malloc(4 + length);
if(!packet) {
fputs("send_packet_get_entities: out of memory\n", stderr);
return -1;
}
packet->length = length;
packet->type = MCIPM_GET_ENTITIES;
*(uint16_t *)packet->data = selector_count;
memcpy(packet->data + 2, selectors, selectors_len);
if(sync_write(fd, packet, 4 + length) < 0) {
perror("send_packet_get_entities: write");
return -1;
}
return 0;
}
int send_packet_kill_entity(int fd, const char *world_id_name, long int entity_id) {
size_t world_id_name_len = strlen(world_id_name);
if(world_id_name_len > 255) {
fprintf(stderr, "send_packet_kill_entity: world_id_name too long (%zu>255)\n", world_id_name_len);
return -1;
}
uint32_t length = 1 + 1 + world_id_name_len + 1 + 4;
struct mcipm_packet *packet = malloc(4 + length);
if(!packet) {
fputs("send_packet_kill_entity: out of memory\n", stderr);
return -1;
}
packet->length = length;
packet->type = MCIPM_KILL_ENTITY;
uint8_t *p = packet->data;
*p++ = world_id_name_len;
memcpy(p, world_id_name, world_id_name_len);
p += world_id_name_len;
*p++ = MCIPM_KILL_ENTITY_BY_ID;
*(uint32_t *)p = entity_id;
if(sync_write(fd, packet, 4 + length) < 0) {
perror("send_packet_kill_entity: write");
return -1;
}
return 0;
}
int receive_packet(int fd, struct mcipm_packet **packet, int blocking_read) {
uint32_t length;
int s;
if(blocking_read) s = sync_read(fd, &length, sizeof length);
else do {
s = read(fd, &length, sizeof length);
} while(s < 0 && errno == EINTR);
if(s < 0) return GET_PACKET_ERROR;
if(!s) return GET_PACKET_EOF;
if(s < sizeof length) return blocking_read ? GET_PACKET_EOF : GET_PACKET_SHORT_READ;
if(length < 1) return GET_PACKET_TOO_SMALL;
if(length > MCIPM_PACKET_MAX_LENGTH) return GET_PACKET_TOO_LARGE;
*packet = malloc(sizeof length + length);
if(!*packet) return GET_PACKET_OUT_OF_MEMORY;
(*packet)->length = length;
if(blocking_read) s = sync_read(fd, (char *)*packet + sizeof length, length);
else do {
s = read(fd, (char *)*packet + sizeof length, length);
} while(s < 0 && errno == EINTR);
int r = 0;
//syslog(LOG_DEBUG, "*length = %u, s = %d", (unsigned int)*length, s);
if(s < 0) r = GET_PACKET_ERROR;
else if(!s) r = GET_PACKET_EOF;
else if(s < length) r = blocking_read ? GET_PACKET_EOF : GET_PACKET_SHORT_READ;
if(r) free(*packet);
return r;
}