2 * The Submit Daemon: High-Level Part of the Protocol
4 * (c) 2007 Martin Mares <mj@ucw.cz>
8 #include "lib/mempool.h"
9 #include "lib/simple-lists.h"
10 #include "lib/stkstring.h"
11 #include "sherlock/object.h"
12 #include "sherlock/objread.h"
18 /*** REQUESTS AND REPLIES ***/
21 read_error_cb(struct obj_read_state *st UNUSED, char *msg)
23 client_error("Request parse error: %s", msg);
27 read_request(struct conn *c)
32 c->pool = mp_new(1024);
33 c->request = obj_new(c->pool);
34 c->reply = obj_new(c->pool);
36 struct obj_read_state st;
37 obj_read_start(&st, c->request);
38 st.error_callback = read_error_cb;
43 int l = bgets_nodie(&c->rx_fb, line, sizeof(line));
45 client_error("Request line too long");
51 client_error("Truncated request");
56 if (size >= max_request_size)
57 client_error("Request too long");
58 obj_read_attr(&st, line[0], line+1);
65 write_reply(struct conn *c)
67 if (!obj_find_attr(c->reply, '-') && !obj_find_attr(c->reply, '+'))
68 obj_set_attr(c->reply, '+', "OK");
72 if (m = obj_find_aval(c->reply, '-'))
73 msg(L_DEBUG, ">> -%s", m);
74 else if (m = obj_find_aval(c->reply, '+'))
75 msg(L_DEBUG, ">> +%s", m);
77 msg(L_DEBUG, ">> ???");
79 obj_write(&c->tx_fb, c->reply, BUCKET_TYPE_PLAIN);
80 bputc(&c->tx_fb, '\n');
85 err(struct conn *c, byte *msg)
87 obj_set_attr(c->reply, '-', msg);
93 copy_attrs(struct odes *dest, struct odes *src)
95 for (struct oattr *a = src->attrs ; a; a=a->next)
96 if (a->attr < OBJ_ATTR_SON)
97 for (struct oattr *aa = a; aa; aa=aa->same)
98 obj_add_attr(dest, aa->attr, aa->val);
102 cmd_status(struct conn *c)
104 uns verbose = obj_find_anum(c->request, 'V', 0);
107 CLIST_FOR_EACH(struct task *, t, task_list)
109 struct odes *to = task_status_find_task(c, t, 1);
110 struct odes *tr = obj_add_son(c->reply, 'T' + OBJ_ATTR_SON);
112 CLIST_FOR_EACH(simp_node *, x, *t->extensions)
113 obj_add_attr(tr, 'A', x->s);
114 CLIST_FOR_EACH(simp_node *, p, t->parts)
116 struct odes *po = task_status_find_part(to, p->s, 1);
117 struct odes *pr = obj_add_son(tr, 'P' + OBJ_ATTR_SON);
119 uns current_ver = obj_find_anum(po, 'V', 0);
120 for (struct oattr *v = obj_find_attr(po, 'V' + OBJ_ATTR_SON); v; v=v->same)
122 struct odes *vo = v->son;
123 uns ver = obj_find_anum(vo, 'V', 0);
124 if (ver == current_ver || verbose)
125 obj_add_son_ref(pr, 'V' + OBJ_ATTR_SON, vo);
133 static struct fastbuf *
134 read_attachment(struct conn *c, uns max_size)
136 uns size = obj_find_anum(c->request, 'S', 0);
139 err(c, "Submission too large");
142 obj_set_attr(c->reply, '+', "Go on");
144 obj_set_attr(c->reply, '+', NULL);
146 // This is less efficient than bbcopy(), but we want our own error handling.
147 struct fastbuf *fb = bopen_tmp(4096);
152 uns cnt = bread(&c->rx_fb, buf, MIN(remains, (uns)sizeof(buf)));
156 client_error("Truncated attachment");
158 bwrite(fb, buf, cnt);
166 cmd_submit(struct conn *c)
168 byte *tname = obj_find_aval(c->request, 'T');
171 err(c, "No task specified");
174 struct task *task = task_find(tname);
177 err(c, "No such task");
181 byte *pname = obj_find_aval(c->request, 'P');
184 simp_node *s = clist_head(&task->parts);
188 else if (!part_exists_p(task, pname))
190 err(c, "No such task part");
194 byte *ext = obj_find_aval(c->request, 'X');
195 if (!ext || !ext_exists_p(task, ext))
197 err(c, "Missing or invalid extension");
201 uns max_size = task->max_size ? : max_attachment_size;
202 struct fastbuf *fb = read_attachment(c, max_size);
207 struct odes *tasko = task_status_find_task(c, task, 1);
208 struct odes *parto = task_status_find_part(tasko, pname, 1);
209 uns current_ver = obj_find_anum(parto, 'V', 0);
210 if (current_ver >= max_versions)
212 err(c, "Maximum number of submits of this task exceeded");
214 task_unlock_status(c, 0);
218 uns replaced_ver = 0;
219 for (struct oattr *a = obj_find_attr(parto, 'V' + OBJ_ATTR_SON); a; a=a->same)
221 uns ver = obj_find_anum(a->son, 'V', 0);
222 byte *ext = obj_find_aval(a->son, 'X');
224 last_ver = MAX(last_ver, ver);
225 if (ver == current_ver)
227 task_delete_part(c->user, tname, pname, ext, ver);
228 obj_set_attr(a->son, 'S', "replaced");
229 replaced_ver = current_ver;
232 struct odes *vero = obj_add_son(parto, 'V' + OBJ_ATTR_SON);
233 obj_set_attr_num(vero, 'V', ++last_ver);
234 obj_set_attr_num(vero, 'T', time(NULL));
235 obj_set_attr_num(vero, 'L', obj_find_anum(c->request, 'S', 0));
236 obj_set_attr(vero, 'S', "submitted");
237 obj_set_attr(vero, 'X', ext);
238 task_submit_part(c->user, tname, pname, ext, last_ver, fb);
239 obj_set_attr_num(parto, 'V', last_ver);
240 task_unlock_status(c, 1);
242 msg(L_INFO, "User %s submitted task %s%s (version %d%s)",
244 (strcmp(tname, pname) ? stk_printf("/%s", pname) : ""),
246 (replaced_ver ? stk_printf(", replaced %d", replaced_ver) : ""));
249 /*** COMMAND MUX ***/
252 execute_command(struct conn *c)
254 byte *cmd = obj_find_aval(c->request, '!');
257 err(c, "Missing command");
261 msg(L_DEBUG, "<< %s", cmd);
262 if (!strcasecmp(cmd, "SUBMIT"))
264 else if (!strcasecmp(cmd, "STATUS"))
267 err(c, "Unknown command");
271 process_command(struct conn *c)
273 if (!read_request(c))
280 /*** INITIAL HANDSHAKE ***/
283 execute_init(struct conn *c)
285 byte *user = obj_find_aval(c->request, 'U');
288 err(c, "Missing user");
292 !strcmp(user, c->cert_name) ||
293 c->rule->allow_admin && !strcmp(c->cert_name, "admin"))
295 if (!user_exists_p(user))
297 err(c, "Unknown user");
300 msg(L_INFO, "Logged in %s", user);
304 err(c, "Permission denied");
305 msg(L_ERROR, "Unauthorized attempt to log in as %s", user);
308 c->user = xstrdup(user);
312 process_init(struct conn *c)
314 if (!read_request(c))
318 return !obj_find_attr(c->reply, '-');