respondd: first implementation of request queue
This commit is contained in:
parent
0a6411b56b
commit
d05c2e3813
|
@ -41,6 +41,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
|
@ -48,6 +49,8 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
#define QUEUE_RING_LEN 8
|
||||||
|
#define REQUEST_MAXLEN 256
|
||||||
|
|
||||||
struct provider_list {
|
struct provider_list {
|
||||||
struct provider_list *next;
|
struct provider_list *next;
|
||||||
|
@ -57,6 +60,7 @@ struct provider_list {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct request_type {
|
struct request_type {
|
||||||
|
// points to the corresponding provider_list for this request in the chained list
|
||||||
struct provider_list *providers;
|
struct provider_list *providers;
|
||||||
|
|
||||||
struct json_object *cache;
|
struct json_object *cache;
|
||||||
|
@ -64,10 +68,24 @@ struct request_type {
|
||||||
int64_t cache_timeout;
|
int64_t cache_timeout;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct request_task {
|
||||||
|
struct sockaddr_storage client_addr;
|
||||||
|
socklen_t client_addrlen;
|
||||||
|
char request[REQUEST_MAXLEN];
|
||||||
|
bool unprocessed;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct request_queue {
|
||||||
|
struct request_task *pop_task;
|
||||||
|
struct request_task *push_task;
|
||||||
|
struct request_task task_ring[QUEUE_RING_LEN];
|
||||||
|
};
|
||||||
|
|
||||||
static int64_t now;
|
static int64_t now;
|
||||||
static struct hsearch_data htab;
|
static struct hsearch_data htab;
|
||||||
|
|
||||||
|
void process_request(int sock, char *input, struct sockaddr_in *addr, socklen_t addrlen);
|
||||||
|
|
||||||
|
|
||||||
static struct json_object * merge_json(struct json_object *a, struct json_object *b);
|
static struct json_object * merge_json(struct json_object *a, struct json_object *b);
|
||||||
|
|
||||||
|
@ -165,6 +183,45 @@ static const struct respondd_provider_info * get_providers(const char *filename)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool queue_push_request(struct request_queue *q, char* req,
|
||||||
|
struct sockaddr *addr, socklen_t addrlen) {
|
||||||
|
|
||||||
|
// prevent ringbuffer overflow
|
||||||
|
if (q->push_task->unprocessed)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// store the request
|
||||||
|
strcpy(q->push_task->request, req);
|
||||||
|
memcpy(&q->push_task->client_addr, addr, addrlen);
|
||||||
|
q->push_task->client_addrlen = addrlen;
|
||||||
|
q->push_task->unprocessed = true;
|
||||||
|
|
||||||
|
if (q->push_task++ > &q->task_ring[QUEUE_RING_LEN-1])
|
||||||
|
q->push_task = &q->task_ring[0];
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void queue_process_request(struct request_queue *q, int sock) {
|
||||||
|
struct request_task *current_task = q->pop_task;
|
||||||
|
|
||||||
|
if (!current_task->unprocessed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
process_request(
|
||||||
|
sock,
|
||||||
|
current_task->request,
|
||||||
|
(struct sockaddr_in *) ¤t_task->client_addr,
|
||||||
|
current_task->client_addrlen
|
||||||
|
);
|
||||||
|
|
||||||
|
current_task->unprocessed = false;
|
||||||
|
|
||||||
|
// go on to next task
|
||||||
|
if (q->pop_task++ > &q->task_ring[QUEUE_RING_LEN-1])
|
||||||
|
q->pop_task = &q->task_ring[0];
|
||||||
|
}
|
||||||
|
|
||||||
static void load_cache_time(struct request_type *r, const char *name) {
|
static void load_cache_time(struct request_type *r, const char *name) {
|
||||||
r->cache = NULL;
|
r->cache = NULL;
|
||||||
r->cache_time = 0;
|
r->cache_time = 0;
|
||||||
|
@ -320,17 +377,19 @@ static struct json_object * handle_request(char *request, bool *compress) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the return value indicates whether there was a request
|
||||||
static void serve(int sock) {
|
static bool serve(struct request_queue *queue, int sock) {
|
||||||
char input[256];
|
char input[REQUEST_MAXLEN];
|
||||||
const char *output = NULL;
|
ssize_t input_bytes;
|
||||||
ssize_t input_bytes, output_bytes;
|
|
||||||
struct sockaddr_in6 addr;
|
struct sockaddr_in6 addr;
|
||||||
socklen_t addrlen = sizeof(addr);
|
socklen_t addrlen = sizeof(addr);
|
||||||
bool compress;
|
|
||||||
|
|
||||||
input_bytes = recvfrom(sock, input, sizeof(input)-1, 0, (struct sockaddr *)&addr, &addrlen);
|
input_bytes = recvfrom(sock, input, sizeof(input)-1, 0, (struct sockaddr *)&addr, &addrlen);
|
||||||
|
|
||||||
|
// Timeout
|
||||||
|
if (input_bytes < 0 && errno == EWOULDBLOCK)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (input_bytes < 0) {
|
if (input_bytes < 0) {
|
||||||
perror("recvfrom failed");
|
perror("recvfrom failed");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
@ -338,6 +397,16 @@ static void serve(int sock) {
|
||||||
|
|
||||||
input[input_bytes] = 0;
|
input[input_bytes] = 0;
|
||||||
|
|
||||||
|
// TODO: only multicast requests should be queued
|
||||||
|
queue_push_request(queue, input, (struct sockaddr *)&addr, addrlen);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_request(int sock, char *input, struct sockaddr_in *addr, socklen_t addrlen) {
|
||||||
|
bool compress;
|
||||||
|
const char *output = NULL;
|
||||||
|
size_t output_bytes;
|
||||||
|
|
||||||
struct json_object *result = handle_request(input, &compress);
|
struct json_object *result = handle_request(input, &compress);
|
||||||
if (!result)
|
if (!result)
|
||||||
return;
|
return;
|
||||||
|
@ -361,14 +430,13 @@ static void serve(int sock) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (output) {
|
if (output) {
|
||||||
if (sendto(sock, output, output_bytes, 0, (struct sockaddr *)&addr, addrlen) < 0)
|
if (sendto(sock, output, output_bytes, 0, addr, addrlen) < 0)
|
||||||
perror("sendto failed");
|
perror("sendto failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
json_object_put(result);
|
json_object_put(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
const int one = 1;
|
const int one = 1;
|
||||||
|
|
||||||
|
@ -388,6 +456,14 @@ int main(int argc, char **argv) {
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct timeval timeout;
|
||||||
|
timeout.tv_sec = 2;
|
||||||
|
timeout.tv_usec = 0;
|
||||||
|
|
||||||
|
if (setsockopt (sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
|
||||||
|
sizeof(timeout)) < 0)
|
||||||
|
error("setsockopt failed\n");
|
||||||
|
|
||||||
server_addr.sin6_family = AF_INET6;
|
server_addr.sin6_family = AF_INET6;
|
||||||
server_addr.sin6_addr = in6addr_any;
|
server_addr.sin6_addr = in6addr_any;
|
||||||
|
|
||||||
|
@ -443,8 +519,14 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
load_providers();
|
load_providers();
|
||||||
|
|
||||||
while (true)
|
struct request_queue queue = {};
|
||||||
serve(sock);
|
queue.pop_task = &queue.task_ring[0];
|
||||||
|
queue.push_task = &queue.task_ring[0];
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
while(serve(&queue, sock)) {}
|
||||||
|
queue_process_request(&queue, sock);
|
||||||
|
}
|
||||||
|
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue