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);
}
|