og-qstat/qserver.c
Steven Hartland 546fed9a83
fix(hexen2): player details (#115)
Fix Hexen 2 player details by enabling next_player_info flow.

Also:
* Extract code send code into send_packet_raw and use in all send
  methods. This enables easy conversion of callers using send(...)
  to use a version which supports packet debugging.

Fixes #114
2021-10-09 19:02:53 +01:00

146 lines
3.1 KiB
C

/*
* qstat
* by Steve Jankowski
*
* qserver functions
* Copyright 2004 Ludwig Nussel
*
* Licensed under the Artistic License, see LICENSE.txt for license terms
*/
#include "qstat.h"
#include "qserver.h"
#include "debug.h"
#ifndef _WIN32
#include <sys/socket.h>
#include <netinet/in.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
// TODO: get rid of this and use send_packet instead, remove n_requests hack from a2s
query_status_t
qserver_send_initial(struct qserver *server, const char *data, size_t len)
{
query_status_t status;
status = send_packet_raw(server, data, len);
if ((server->retry1 == n_retries) || server->flags & FLAG_BROADCAST) {
gettimeofday(&server->packet_time1, NULL);
} else {
server->n_retries++;
}
server->retry1--;
server->n_packets++;
return (status);
}
query_status_t
qserver_send(struct qserver *server, const char *data, size_t len)
{
query_status_t status;
status = send_packet_raw(server, data, len);
server->retry1 = n_retries - 1;
gettimeofday(&server->packet_time1, NULL);
server->n_requests++;
server->n_packets++;
return (status);
}
int
send_broadcast(struct qserver *server, const char *pkt, size_t pktlen)
{
struct sockaddr_in addr;
addr.sin_family = AF_INET;
if (no_port_offset || server->flags & TF_NO_PORT_OFFSET) {
addr.sin_port = htons(server->port);
} else {
addr.sin_port = htons((unsigned short)(server->port + server->type->port_offset));
}
addr.sin_addr.s_addr = server->ipaddr;
memset(&(addr.sin_zero), 0, sizeof(addr.sin_zero));
return (sendto(server->fd, (const char *)pkt, pktlen, 0, (struct sockaddr *)&addr, sizeof(addr)));
}
int
register_send(struct qserver *server)
{
if ((server->retry1 == n_retries) || server->flags & FLAG_BROADCAST) {
server->n_requests++;
} else {
server->n_retries++;
}
// New request so reset the sent time. This ensures
// that we record an accurate ping time even on retry
gettimeofday(&server->packet_time1, NULL);
server->retry1--;
server->n_packets++;
return (INPROGRESS);
}
query_status_t
send_packet_raw(struct qserver *server, const char *data, size_t len)
{
debug(2, "[%s] send", server->type->type_prefix);
if (4 <= get_debug_level()) {
output_packet(server, data, len, 1);
}
if (data) {
int ret;
if (server->flags & FLAG_BROADCAST) {
ret = send_broadcast(server, data, len);
} else {
ret = send(server->fd, data, len, 0);
}
if (ret == SOCKET_ERROR) {
return (send_error(server, ret));
}
}
return (INPROGRESS);
}
query_status_t
send_packet(struct qserver *server, const char *data, size_t len)
{
query_status_t rc;
rc = send_packet_raw(server, data, len);
if (rc == SYS_ERROR) {
return (rc);
}
return (register_send(server));
}
query_status_t
send_error(struct qserver *server, int rc)
{
unsigned int ipaddr = ntohl(server->ipaddr);
const char *errstr = strerror(errno);
fprintf(stderr, "Error on %d.%d.%d.%d: %s, skipping ...\n",
(ipaddr >> 24) & 0xff,
(ipaddr >> 16) & 0xff,
(ipaddr >> 8) & 0xff,
ipaddr & 0xff,
errstr
);
return (SYS_ERROR);
}