aboutsummaryrefslogtreecommitdiff
path: root/command.c
blob: deaeabe92b4d1c69d0a29b8a50162d774aed2bca (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
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <sys/socket.h>
#include "command.h"
#include "db.h"


static bool send_raw_text(int fd,const char *text,i64 len){
	i64 cursor=0;
	while(cursor<len){
		i64 nwr=send(fd,text+cursor,len-cursor,0);
		if(nwr<0){
			if(errno==EINTR)continue;
			if(errno==ECONNRESET||errno==EPIPE)return true;
			die_perror("send");
		}
		cursor+=nwr;
	}
	return false;
}

static bool send_ok(int fd,const char *tag){
	char *buf=NULL;
	i64 len=asprintf(&buf,"%s ok\n",tag);
	assert(buf);
	bool closed=send_raw_text(fd,buf,len);
	free(buf);
	return closed;
}

static bool send_error(int fd,const char *tag,const char *msg){
	char *buf=NULL;
	i64 len=asprintf(&buf,"%s error %s\n",tag,msg);
	assert(buf);
	bool closed=send_raw_text(fd,buf,len);
	free(buf);
	return closed;
}


static bool cmd_register(int fd,const char *tag,const char **args){
	i64 userid=db_find_user(args[0]);
	if(userid!=-1){
		send_error(fd,tag,"Username already exists");
		return false;
	}
	db_create_user(args[0],args[1]);
	return send_ok(fd,tag);
}

static bool cmd_login(int fd,const char *tag,const char **args){
	(void)fd; (void)tag; (void)args;
	return true;
}


struct cmd_info{
	const char *cmdname;
	int nargs;
	bool longlast;  // whether the last argument should span the rest of the input line
	bool (*handler)(int fd,const char *tag,const char **args);
};

static const struct cmd_info commands[]={
	{"register",2,false,cmd_register},
	{"login",2,false,cmd_login},
};
#define NCOMMANDS (sizeof(commands)/sizeof(commands[0]))


bool handle_input_line(int fd,char *line,size_t linelen){
	char *sepp=memchr(line,' ',linelen);
	if(sepp==NULL){
		debug("No space in input line from connection %d",fd);
		return true;
	}
	char *tag=line;
	size_t taglen=sepp-tag;
	*sepp='\0';
	line+=taglen+1;
	linelen-=taglen+1;

	sepp=memchr(line,' ',linelen);
	if(sepp==NULL)sepp=line+linelen;
	size_t cmdlen=sepp-line;
	size_t cmdi;
	for(cmdi=0;cmdi<NCOMMANDS;cmdi++){
		if(strncmp(line,commands[cmdi].cmdname,cmdlen)==0){
			break;
		}
	}

	int nargs=commands[cmdi].nargs;
	char *args[nargs];
	size_t cursor=cmdlen+1;

	for(int i=0;i<nargs;i++){
		if(cursor>=linelen){
			debug("Connection %d sent too few parameters to command %s",fd,commands[cmdi].cmdname);
			return true;
		}
		if(i==nargs-1&&commands[cmdi].longlast){
			sepp=line+linelen;
		} else {
			sepp=memchr(line+cursor,' ',linelen-cursor);
			if(sepp==NULL)sepp=line+linelen;
		}
		*sepp='\0';
		args[i]=line+cursor;
		cursor=sepp-line+1;
	}
	if(sepp-line<(i64)linelen){
		debug("Connection %d sent too many parameters to command %s",fd,commands[cmdi].cmdname);
		return true;
	}

	return commands[cmdi].handler(fd,tag,(const char**)args);
}