aboutsummaryrefslogtreecommitdiff
path: root/main.c
blob: f05977867041988ae257485ae1c713faa152c80f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <assert.h>
#include "command.h"
#include "conn_data.h"
#include "db.h"
#include "runloop.h"

#define PORT (29536)  // python: int("msg",36)


static int create_server_socket(void){
	int sock=socket(AF_INET,SOCK_STREAM,0);
	if(sock<0)die_perror("socket");
	int one=1;
	setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&one,sizeof one);

	struct sockaddr_in name;
	name.sin_family=AF_INET;
	name.sin_addr.s_addr=htonl(INADDR_ANY);
	name.sin_port=htons(PORT);
	if(bind(sock,(struct sockaddr*)&name,sizeof name)<0)die_perror("bind");

	if(listen(sock,16)<0)die_perror("listen");
	return sock;
}

struct hash_item{
	struct conn_data cd;
	struct hash_item *next;
};

#define CONN_HASH_SIZE (16)
static struct hash_item *conn_hash[CONN_HASH_SIZE];

static struct conn_data* find_conn_data(int fd){
	struct hash_item *item=conn_hash[fd%CONN_HASH_SIZE];
	while(item&&item->cd.fd!=fd)item=item->next;
	assert(item);
	return &item->cd;
}

static void delete_conn_data(int fd){
	struct hash_item *item=conn_hash[fd%CONN_HASH_SIZE];
	assert(item);
	if(item->cd.fd==fd){
		conn_hash[fd%CONN_HASH_SIZE]=item->next;
		conn_data_nullify(&item->cd);
		free(item);
		return;
	}
	struct hash_item *parent=NULL;
	while(item&&item->cd.fd!=fd){
		parent=item;
		item=item->next;
	}
	assert(parent);
	assert(item);
	conn_data_nullify(&item->cd);
	parent->next=item->next;
	free(item);
}

static bool client_socket_callback(int fd){
	struct conn_data *data=find_conn_data(fd);
	if(data->bufsz-data->buflen<256){
		data->bufsz*=2;
		data->buffer=realloc(data->buffer,data->bufsz,char);
	}

	ssize_t ret;
	do ret=read(fd,data->buffer+data->buflen,data->bufsz-data->buflen);
	while(ret<0&&errno==EINTR);
	if(ret<0)die_perror("read");
	if(ret==0){
		delete_conn_data(fd);
		close(fd);
		return true;
	}
	data->buflen+=ret;

	char *lfp=memchr(data->buffer,'\n',data->buflen);
	if(lfp==NULL)return false;
	size_t length=lfp-data->buffer;
	bool should_close=handle_input_line(data,data->buffer,length);
	memmove(data->buffer,lfp+1,data->buflen-length-1);
	data->buflen-=length+1;

	if(should_close){
		delete_conn_data(fd);
		close(fd);
		return true;
	}
	return false;
}

static bool server_socket_callback(int fd){
	int sock;
	do sock=accept(fd,NULL,NULL);
	while(sock<0&&errno==EINTR);
	if(sock<0)die_perror("accept");
	runloop_add_fd(sock,client_socket_callback);

	struct hash_item *item=malloc(1,struct hash_item);
	conn_data_init(&item->cd,sock);
	item->next=conn_hash[sock%CONN_HASH_SIZE];
	conn_hash[sock%CONN_HASH_SIZE]=item;
	debug("Added conn_data for fd=%d",sock);
	return false;
}

int main(void){
	srandomdev();

	db_init();
	int sock=create_server_socket();
	printf("Listening on port %d\n",PORT);
	runloop_add_fd(sock,server_socket_callback);
	runloop_run();
	db_close();
}