NdbCCurve * nodedb_c_curve_create(NodeCurve *node, VLayerID curve_id, const char *name, uint8 dimensions) { NdbCCurve *curve; if(node == NULL || name == NULL || dimensions > 4) return NULL; if(node->curves == NULL) { node->curves = dynarr_new(sizeof (NdbCCurve), 4); dynarr_set_default_func(node->curves, cb_curve_default, NULL); } if(curve_id == (VLayerID) ~0) curve = dynarr_append(node->curves, NULL, NULL); else curve = dynarr_set(node->curves, curve_id, NULL); if(curve != NULL) { curve->id = curve_id; stu_strncpy(curve->name, sizeof curve->name, name); curve->dimensions = dimensions; curve->keys = NULL; printf("Curve curve %u.%u %s created, dim=%u\n", node->node.id, curve_id, name, curve->dimensions); } return curve; }
static int sync_text_buffer(const NodeText *n, const NdbTBuffer *buffer, const NodeText *target, const NdbTBuffer *tbuffer) { int sync = 1, d; DynArr *edit; DiffEdit *ed; const char *text, *ttext; size_t len, tlen; text = textbuf_text(buffer->text); len = textbuf_length(buffer->text); ttext = textbuf_text(tbuffer->text); tlen = textbuf_length(tbuffer->text); if(len == tlen && strcmp(text, ttext) == 0) /* Avoid allocating memory and running diff if equal. */ return sync; edit = dynarr_new(sizeof (*ed), 8); /* printf(" text: '%s' (%u)\n", text, len); printf("target: '%s' (%u)\n", ttext, tlen); */ d = diff_compare_simple(ttext, tlen, text, len, edit); /* printf("Edit distance: %d\n", d);*/ if(d > 0) { unsigned int i, pos = 0; for(i = 0; (ed = dynarr_index(edit, i)) != NULL; i++) { if(ed->op == DIFF_MATCH) { pos = ed->off + ed->len; } else if(ed->op == DIFF_DELETE) { verse_send_t_text_set(target->node.id, tbuffer->id, ed->off, ed->len, NULL); pos = ed->off; } else if(ed->op == DIFF_INSERT) /* Split inserts into something Verse can handle. */ { char temp[1024]; size_t off, chunk; for(off = ed->off, len = ed->len; len > 0; off += chunk, len -= chunk) { chunk = len > sizeof temp - 1 ? sizeof temp - 1 : len; stu_strncpy(temp, chunk + 1, text + off); temp[chunk] = '\0'; verse_send_t_text_set(target->node.id, tbuffer->id, pos, 0, temp); pos += chunk - 1; } } } sync = 0; } dynarr_destroy(edit); return sync; }
Plugin * plugin_new(const char *name) { Plugin *p; if(name == NULL) return NULL; if((p = mem_alloc(sizeof *p)) != NULL) { p->id = 0; stu_strncpy(p->name, sizeof p->name, name); p->library = NULL; p->input = NULL; p->meta = NULL; p->compute = NULL; p->state = NULL; } return p; }
void plugin_set_input(Plugin *p, int index, PValueType type, const char *name, va_list taglist) { if(p == NULL) return; if(index < 0) { LOG_ERR(("Plug-in \"%s\" attempted to set input with negative index--ignored", p->name)); return; } if((p->input == NULL && index != 0) || (p->input != NULL && (size_t) index != dynarr_size(p->input))) { LOG_ERR(("Plug-in \"%s\" attempted to set input \"%s\" with bad index %d--ignored", p->name, name, index)); return; } if(type < P_VALUE_BOOLEAN || type > P_VALUE_MODULE) { LOG_ERR(("Plug-in \"%s\" attempted to set input %d with bad type %d--ignored", p->name, index, type)); return; } if(p->input == NULL) p->input = dynarr_new(sizeof (Input), 2); if(p->input != NULL) { Input i; stu_strncpy(i.name, sizeof i.name, name); i.type = type; i.spec.req = i.spec.def = i.spec.min = i.spec.max = 0; i.spec.enums = NULL; i.desc = NULL; value_init(&i.spec.min_val); value_init(&i.spec.max_val); value_init(&i.spec.def_val); for(;;) { int tag = va_arg(taglist, int); if(tag == P_INPUT_TAG_DONE) break; else if(tag < P_INPUT_TAG_DONE || tag > P_INPUT_TAG_DESC) /* Generous. */ { LOG_WARN(("Aborting on bad tag value for %s.%s: %d", p->name, i.name, tag)); break; } else if(tag == P_INPUT_TAG_REQUIRED) i.spec.req = 1; else if(tag == P_INPUT_TAG_MIN) i.spec.min = value_set_defminmax_va(&i.spec.min_val, i.type, &taglist); else if(tag == P_INPUT_TAG_MAX) i.spec.max = value_set_defminmax_va(&i.spec.max_val, i.type, &taglist); else if(tag == P_INPUT_TAG_DEFAULT) i.spec.def = value_set_defminmax_va(&i.spec.def_val, i.type, &taglist); else if(tag == P_INPUT_TAG_ENUM) { const char *st; if(i.spec.enums == NULL) i.spec.enums = dynstr_new_sized(64); st = dynstr_string(i.spec.enums); if(st != NULL && *st != '\0' && st[strlen(st) - 1] != '|') /* Make sure there are separators. */ dynstr_append_c(i.spec.enums, '|'); dynstr_append(i.spec.enums, va_arg(taglist, char *)); } else if(tag == P_INPUT_TAG_DESC) i.desc = va_arg(taglist, char *); }
static void stu_http_request_handler(stu_event_t *wev) { stu_http_request_t *r; stu_connection_t *c; stu_channel_t *ch; stu_buf_t *buf; stu_table_elt_t *accept; stu_table_elt_t *protocol; stu_int_t n; c = (stu_connection_t *) wev->data; //stu_mutex_lock(&c->lock); if (c->fd == (stu_socket_t) -1) { return; } stu_event_del(&c->write, STU_WRITE_EVENT, 0); buf = &c->buffer; buf->last = buf->start; stu_memzero(buf->start, buf->end - buf->start); r = (stu_http_request_t *) c->data; accept = r->headers_out.sec_websocket_accept; protocol = r->headers_out.sec_websocket_protocol; if (r->headers_out.status == STU_HTTP_SWITCHING_PROTOCOLS) { buf->last = stu_sprintf(buf->last, "HTTP/1.1 101 Switching Protocols" CRLF); buf->last = stu_sprintf(buf->last, "Server: " __NAME "/" __VERSION CRLF); buf->last = stu_sprintf(buf->last, "Upgrade: websocket" CRLF); buf->last = stu_sprintf(buf->last, "Connection: upgrade" CRLF); buf->last = stu_strncpy(buf->last, accept->key.data, accept->key.len); buf->last = stu_sprintf(buf->last, ": "); buf->last = stu_strncpy(buf->last, accept->value.data, accept->value.len); buf->last = stu_sprintf(buf->last, CRLF); if (protocol) { buf->last = stu_strncpy(buf->last, protocol->key.data, protocol->key.len); buf->last = stu_sprintf(buf->last, ": "); buf->last = stu_strncpy(buf->last, protocol->value.data, protocol->value.len); buf->last = stu_sprintf(buf->last, CRLF); } buf->last = stu_sprintf(buf->last, CRLF); } else { buf->last = stu_sprintf(buf->last, "HTTP/1.1 400 Bad Request" CRLF); buf->last = stu_sprintf(buf->last, "Server: " __NAME "/" __VERSION CRLF); buf->last = stu_sprintf(buf->last, "Content-type: text/html" CRLF); buf->last = stu_sprintf(buf->last, "Content-length: %d" CRLF, stu_strlen(__NAME "/" __VERSION "\n")); buf->last = stu_sprintf(buf->last, "Connection: close" CRLF CRLF); buf->last = stu_sprintf(buf->last, __NAME "/" __VERSION "\n"); } n = send(c->fd, buf->start, buf->last - buf->start, 0); if (n == -1) { stu_log_error(stu_errno, "Failed to send data: fd=%d.", c->fd); goto failed; } stu_log_debug(4, "sent: fd=%d, bytes=%d.", c->fd, n); // str=\n%s, buf->start if (r->headers_out.status == STU_HTTP_SWITCHING_PROTOCOLS) { if (stu_http_switch_protocol(r) == STU_ERROR) { stu_log_error(0, "Failed to switch protocol: fd=%d.", c->fd); goto failed; } } return; failed: c->read.active = 0; stu_event_del(&c->read, STU_READ_EVENT, 0); ch = c->user.channel; if (ch) { stu_channel_remove(ch, c); } stu_http_close_connection(c); //done: //stu_mutex_unlock(&c->lock); }
void stu_http_process_request(stu_http_request_t *r) { stu_int_t rc; stu_connection_t *c; stu_table_elt_t *protocol; stu_int_t m, n, size, extened; stu_str_t cid, name, icon, role, state; u_char *d, *s, *p, opcode, temp[STU_HTTP_REQUEST_DEFAULT_SIZE], buf[STU_USER_ID_MAX_LEN]; stu_channel_t *ch; c = r->connection; rc = stu_http_process_request_headers(r); if (rc == STU_AGAIN) { stu_log_debug(4, "Wait to receive."); return; } if (rc != STU_OK) { stu_log_error(0, "Failed to process request headers."); stu_http_finalize_request(r, STU_HTTP_BAD_REQUEST); goto failed; } if (r->headers_in.upgrade == NULL) { stu_log_error(0, "Not an upgrade request."); stu_http_finalize_request(r, STU_HTTP_NOT_IMPLEMENTED); goto failed; } if (stu_cycle->config.edition == PREVIEW) { goto preview; } // enterprise if (stu_upstream_create(c, STU_HTTP_UPSTREAM_IDENT.data, STU_HTTP_UPSTREAM_IDENT.len) == STU_ERROR) { stu_log_error(0, "Failed to create http upstream \"ident\"."); stu_http_finalize_request(r, STU_HTTP_INTERNAL_SERVER_ERROR); goto failed; } c->upstream->read_event_handler = stu_http_upstream_read_handler; c->upstream->write_event_handler = stu_http_upstream_write_handler; c->upstream->create_request_pt = stu_http_upstream_create_request; c->upstream->reinit_request_pt = stu_http_upstream_reinit_request; c->upstream->generate_request_pt = stu_http_upstream_ident_generate_request; c->upstream->process_response_pt = stu_http_upstream_process_response; c->upstream->analyze_response_pt = stu_http_upstream_ident_analyze_response; c->upstream->finalize_handler_pt = stu_http_upstream_finalize_handler; c->upstream->cleanup_pt = stu_http_upstream_cleanup; if (stu_upstream_init(c) == STU_ERROR) { stu_log_error(0, "Failed to init upstream."); stu_http_finalize_request(r, STU_HTTP_INTERNAL_SERVER_ERROR); goto failed; } return; preview: // get channel ID cid.data = stu_calloc(r->target.len + 1); if (cid.data == NULL) { stu_log_error(0, "Failed to pcalloc memory for channel id, fd=%d.", c->fd); stu_http_finalize_request(r, STU_HTTP_INTERNAL_SERVER_ERROR); goto failed; } stu_strncpy(cid.data, r->target.data, r->target.len); cid.len = r->target.len; // reset user ID s = stu_sprintf(buf, "%ld", stu_preview_auto_id++); *s = '\0'; c->user.id.len = s - buf; c->user.id.data = stu_calloc(c->user.id.len + 1); if (c->user.id.data == NULL) { stu_log_error(0, "Failed to pcalloc memory for user id, fd=%d.", c->fd); stu_http_finalize_request(r, STU_HTTP_INTERNAL_SERVER_ERROR); goto failed; } stu_strncpy(c->user.id.data, buf, c->user.id.len); // reset user name if (stu_http_arg(r, STU_PROTOCOL_NAME.data, STU_PROTOCOL_NAME.len, &name) != STU_OK) { stu_log_error(0, "User name not specified, fd=%d.", c->fd); stu_http_finalize_request(r, STU_HTTP_INTERNAL_SERVER_ERROR); goto failed; } d = s = name.data; stu_unescape_uri(&d, &s, name.len, 0); name.len = d - name.data; c->user.name.data = stu_calloc(name.len + 1); if (c->user.name.data == NULL) { stu_log_error(0, "Failed to pcalloc memory for user name, fd=%d.", c->fd); stu_http_finalize_request(r, STU_HTTP_INTERNAL_SERVER_ERROR); goto failed; } stu_strncpy(c->user.name.data, name.data, name.len); c->user.name.len = name.len; // reset user icon if (stu_http_arg(r, STU_PROTOCOL_ICON.data, STU_PROTOCOL_ICON.len, &icon) == STU_OK) { c->user.icon.data = stu_calloc(icon.len + 1); if (c->user.icon.data == NULL) { stu_log_error(0, "Failed to pcalloc memory for user icon, fd=%d.", c->fd); stu_http_finalize_request(r, STU_HTTP_INTERNAL_SERVER_ERROR); goto failed; } stu_strncpy(c->user.icon.data, icon.data, icon.len); c->user.icon.len = icon.len; } // reset user role c->user.role = STU_USER_ROLE_NORMAL; if (stu_http_arg(r, STU_PROTOCOL_ROLE.data, STU_PROTOCOL_ROLE.len, &role) == STU_OK) { m = atoi((const char *) role.data); stu_user_set_role(&c->user, m & 0xFF); } // insert user into channel if (stu_channel_insert(&cid, c) == STU_ERROR) { stu_log_error(0, "Failed to insert connection: fd=%d.", c->fd); stu_http_finalize_request(r, STU_HTTP_INTERNAL_SERVER_ERROR); goto failed; } ch = c->user.channel; if (stu_http_arg(r, STU_PROTOCOL_STATE.data, STU_PROTOCOL_STATE.len, &state) == STU_OK) { if (c->user.role & 0xF0) { m = atoi((const char *) state.data); ch->state = m & 0xFF; } } // finalize request protocol = r->headers_out.sec_websocket_protocol; if (protocol && stu_strncmp("binary", protocol->value.data, protocol->value.len) == 0) { opcode = STU_WEBSOCKET_OPCODE_BINARY; } else { opcode = STU_WEBSOCKET_OPCODE_TEXT; } stu_http_finalize_request(r, STU_HTTP_SWITCHING_PROTOCOLS); p = stu_sprintf( (u_char *) temp + 10, (const char *) STU_HTTP_UPSTREAM_IDENT_RESPONSE.data, c->user.id.data, c->user.name.data, c->user.icon.data, c->user.role, ch->id.data, ch->state, ch->userlist.length ); *p = '\0'; size = p - temp - 10; p = stu_websocket_encode_frame(opcode, temp, size, &extened); n = send(c->fd, p, size + 2 + extened, 0); if (n == -1) { stu_log_debug(4, "Failed to send \"ident\" frame: fd=%d.", c->fd); goto failed; } stu_log_debug(4, "sent: fd=%d, bytes=%d.", c->fd, n); return; failed: c->read.active = 0; stu_event_del(&c->read, STU_READ_EVENT, 0); stu_http_close_connection(c); }