|  | /* 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; | 
|  | } | 
|  |  |