enum http_rc_e action_forward_stats (struct req_args_s *args) { const char *id = OPT("id"); if (!id) return _reply_format_error (args, BADREQ("Missing SRVID")); args->rp->no_access(); MESSAGE req = metautils_message_create_named("REQ_STATS"); GByteArray *encoded = message_marshall_gba_and_clean (req); gchar *packed = NULL; GError *err = gridd_client_exec_and_concat_string (id, 1.0, encoded, &packed); if (err) { g_free0 (packed); if (CODE_IS_NETWORK_ERROR(err->code)) { if (err->code == ERRCODE_CONN_TIMEOUT || err->code == ERRCODE_READ_TIMEOUT) return _reply_gateway_timeout (args, err); return _reply_srv_unavailable (args, err); } return _reply_common_error (args, err); } for (gchar *s=packed; *s ;++s) { if (*s == '=') *s = ' '; } /* TODO(jfs): quite duplicated from _reply_json() but the original was not suitable. */ args->rp->set_status (200, "OK"); args->rp->set_body_bytes (g_bytes_new_take((guint8*)packed, strlen(packed))); args->rp->finalize (); return HTTPRC_DONE; }
enum http_rc_e action_dir_srv_renew (struct req_args_s *args, struct json_object *jargs) { (void) jargs; const gchar *type = TYPE(); if (!type) return _reply_format_error (args, NEWERROR(CODE_BAD_REQUEST, "No service type provided")); gboolean autocreate = _request_has_flag (args, PROXYD_HEADER_MODE, "autocreate"); gboolean dryrun = _request_has_flag (args, PROXYD_HEADER_MODE, "dryrun"); gchar **urlv = NULL; GError *hook (const gchar * m1) { struct addr_info_s m1a; if (!grid_string_to_addrinfo (m1, NULL, &m1a)) return NEWERROR (CODE_NETWORK_ERROR, "Invalid M1 address"); GError *err = NULL; urlv = meta1v2_remote_poll_reference_service (&m1a, &err, args->url, type, dryrun, autocreate); return err; } GError *err = _m1_locate_and_action (args, hook); if (!err || CODE_IS_NETWORK_ERROR(err->code)) { /* Also decache on timeout, a majority of request succeed, * and it will probably silently succeed */ hc_decache_reference_service (resolver, args->url, type); } if (err) return _reply_common_error (args, err); EXTRA_ASSERT (urlv != NULL); return _reply_success_json (args, _pack_and_freev_m1url_list (NULL, urlv)); }
enum http_rc_e action_dir_srv_unlink (struct req_args_s *args) { const gchar *type = TYPE(); if (!type) return _reply_format_error (args, NEWERROR( CODE_BAD_REQUEST, "No service type provided")); GError *hook (const gchar * m1) { struct addr_info_s m1a; if (!grid_string_to_addrinfo (m1, NULL, &m1a)) return NEWERROR (CODE_NETWORK_ERROR, "Invalid M1 address"); GError *err = NULL; meta1v2_remote_unlink_service (&m1a, &err, args->url, type); return err; } GError *err = _m1_locate_and_action (args, hook); if (!err || CODE_IS_NETWORK_ERROR(err->code)) { /* Also decache on timeout, a majority of request succeed, * and it will probably silently succeed */ hc_decache_reference_service (resolver, args->url, type); } if (!err) return _reply_success_json (args, NULL); return _reply_common_error (args, err); }
enum http_rc_e _reply_common_error (struct req_args_s *args, GError *err) { if (CODE_IS_NOTFOUND(err->code)) return _reply_notfound_error (args, err); if (err->code == CODE_BAD_REQUEST) return _reply_format_error (args, err); return _reply_system_error (args, err); }
enum http_rc_e action_dir_srv_relink (struct req_args_s *args, struct json_object *jargs) { GError *err = NULL; struct meta1_service_url_s *m1u_kept = NULL, *m1u_repl = NULL; gchar **newset = NULL; const gchar *type = TYPE(); if (!type) return _reply_format_error (args, NEWERROR(CODE_BAD_REQUEST, "No service type provided")); gboolean dryrun = _request_has_flag (args, PROXYD_HEADER_MODE, "dryrun"); struct json_object *jkept, *jrepl; struct metautils_json_mapping_s mapping[] = { {"kept", &jkept, json_type_object, 0}, {"replaced", &jrepl, json_type_object, 0}, {NULL, NULL, 0, 0} }; err = metautils_extract_json (jargs, mapping); if (!err && jkept && json_object_is_type(jkept, json_type_object)) { if (NULL != (err = meta1_service_url_load_json_object (jkept, &m1u_kept))) g_prefix_error (&err, "invalid service in [%s]: ", "kept"); } if (!err && jrepl && json_object_is_type(jrepl, json_type_object)) { if (NULL != (err = meta1_service_url_load_json_object (jrepl, &m1u_repl))) g_prefix_error (&err, "invalid service in [%s]: ", "replaced"); } if (!err) { gchar *kept = NULL, *repl = NULL; GError *hook (const gchar * m1) { struct addr_info_s m1a; if (!grid_string_to_addrinfo (m1, NULL, &m1a)) return NEWERROR (CODE_NETWORK_ERROR, "Invalid M1 address"); if (newset) g_strfreev (newset); return meta1v2_remote_relink_service (&m1a, args->url, kept, repl, dryrun, &newset); } kept = meta1_pack_url (m1u_kept); repl = m1u_repl ? meta1_pack_url (m1u_repl) : NULL; err = _m1_locate_and_action (args, hook); g_free (kept); g_free (repl); }
enum http_rc_e action_cs_put (struct req_args_s *args) { struct json_tokener *parser; struct json_object *jbody; enum http_rc_e rc; parser = json_tokener_new (); jbody = json_tokener_parse_ex (parser, (char *) args->rq->body->data, args->rq->body->len); if (!json_object_is_type (jbody, json_type_object)) rc = _reply_format_error (args, BADREQ ("Invalid srv")); else rc = _registration (args, REGOP_PUSH, jbody); json_object_put (jbody); json_tokener_free (parser); return rc; }
static enum http_rc_e _registration (struct req_args_s *args, enum reg_op_e op, struct json_object *jsrv) { GError *err; if (!push_queue) return _reply_bad_gateway(args, NEWERROR(CODE_INTERNAL_ERROR, "Service upstream disabled")); if (NULL != (err = _cs_check_tokens(args))) return _reply_notfound_error (args, err); struct service_info_s *si = NULL; err = service_info_load_json_object (jsrv, &si); if (err) { if (err->code == CODE_BAD_REQUEST) return _reply_format_error (args, err); else return _reply_system_error (args, err); } if (!validate_namespace (si->ns_name)) { service_info_clean (si); return _reply_system_error (args, NEWERROR (CODE_NAMESPACE_NOTMANAGED, "Unexpected NS")); } si->score.timestamp = network_server_bogonow(args->rq->client->server); if (op == REGOP_PUSH) si->score.value = SCORE_UNSET; else if (op == REGOP_UNLOCK) si->score.value = SCORE_UNLOCK; else /* if (op == REGOP_LOCK) */ si->score.value = CLAMP(si->score.value, SCORE_DOWN, SCORE_MAX); gchar *key = service_info_key(si); PUSH_DO(lru_tree_insert(push_queue, key, si)); GString *gstr = g_string_new (""); service_info_encode_json (gstr, si); return _reply_success_json (args, gstr); }
enum http_rc_e action_dir_srv_force (struct req_args_s *args, struct json_object *jargs) { struct meta1_service_url_s *m1u = NULL; const gchar *type = TYPE(); if (!type) return _reply_format_error (args, NEWERROR(CODE_BAD_REQUEST, "No service type provided")); gboolean force = _request_has_flag (args, PROXYD_HEADER_MODE, "replace"); gboolean autocreate = _request_has_flag (args, PROXYD_HEADER_MODE, "autocreate"); GError *hook (const gchar * m1) { struct addr_info_s m1a; if (!grid_string_to_addrinfo (m1, NULL, &m1a)) return NEWERROR (CODE_NETWORK_ERROR, "Invalid M1 address"); GError *e = NULL; gchar *packed = meta1_pack_url (m1u); meta1v2_remote_force_reference_service (&m1a, &e, args->url, packed, autocreate, force); g_free (packed); return e; } GError *err = meta1_service_url_load_json_object (jargs, &m1u); if (!err) err = _m1_locate_and_action (args, hook); if (m1u) { meta1_service_url_clean (m1u); m1u = NULL; } if (!err || CODE_IS_NETWORK_ERROR(err->code)) { /* Also decache on timeout, a majority of request succeed, * and it will probably silently succeed */ hc_decache_reference_service (resolver, args->url, type); } if (err) return _reply_common_error (args, err); return _reply_success_json (args, NULL); }
enum http_rc_e action_dir_srv_list (struct req_args_s *args) { const gchar *type = TYPE(); if (!type) return _reply_format_error (args, NEWERROR( CODE_BAD_REQUEST, "No service type provided")); gchar **urlv = NULL; GError *err = hc_resolve_reference_service (resolver, args->url, type, &urlv); EXTRA_ASSERT ((err != NULL) ^ (urlv != NULL)); if (!err) { if ((args->flags & FLAG_NOEMPTY) && !*urlv) { g_strfreev (urlv); urlv = NULL; return _reply_notfound_error (args, NEWERROR (CODE_NOT_FOUND, "No service linked")); } return _reply_success_json (args, _pack_and_freev_m1url_list (NULL, urlv)); } return _reply_common_error (args, err); }
static enum http_rc_e _registration (struct req_args_s *args, enum reg_op_e op, struct json_object *jsrv) { GError *err; if (!jsrv || !json_object_is_type (jsrv, json_type_object)) return _reply_common_error (args, BADREQ("Expected: json object")); if (!push_queue) return _reply_bad_gateway(args, NEWERROR(CODE_INTERNAL_ERROR, "Service upstream disabled")); if (NULL != (err = _cs_check_tokens(args))) return _reply_notfound_error (args, err); struct service_info_s *si = NULL; err = service_info_load_json_object (jsrv, &si, TRUE); if (err) { if (err->code == CODE_BAD_REQUEST) return _reply_format_error (args, err); else return _reply_system_error (args, err); } if (!si->type[0]) { service_info_clean (si); return _reply_format_error (args, BADREQ("Service type not specified")); } if (!si->ns_name[0]) { g_strlcpy (si->ns_name, nsname, sizeof(si->ns_name)); } else if (!validate_namespace (si->ns_name)) { service_info_clean (si); return _reply_format_error (args, NEWERROR (CODE_NAMESPACE_NOTMANAGED, "Unexpected NS")); } si->score.timestamp = oio_ext_real_time () / G_TIME_SPAN_SECOND; if (op == REGOP_PUSH) si->score.value = SCORE_UNSET; else if (op == REGOP_UNLOCK) si->score.value = SCORE_UNLOCK; else /* if (op == REGOP_LOCK) */ si->score.value = CLAMP(si->score.value, SCORE_DOWN, SCORE_MAX); // TODO follow the DRY principle and factorize this! if (flag_cache_enabled) { GString *gstr = g_string_new (""); service_info_encode_json (gstr, si, TRUE); PUSH_DO(lru_tree_insert(push_queue, service_info_key(si), si)); return _reply_success_json (args, gstr); } else { CSURL(cs); GSList l = {.data = si, .next = NULL}; if (NULL != (err = conscience_remote_push_services (cs, &l))) { service_info_clean (si); return _reply_common_error (args, err); } else { GString *gstr = g_string_new (""); service_info_encode_json (gstr, si, TRUE); service_info_clean (si); return _reply_success_json (args, gstr); } } }
enum http_rc_e action_forward (struct req_args_s *args) { const char *id = OPT("id"); const char *action = TOK("ACTION"); if (!id) return _reply_format_error (args, BADREQ("Missing SRVID")); if (!action) return _reply_format_error (args, BADREQ("Missing action")); GError *err = NULL; if (!g_ascii_strcasecmp (action, "flush")) { err = sqlx_remote_execute_FLUSH (id); if (!err) return _reply_success_json (args, NULL); return _reply_common_error (args, err); } if (!g_ascii_strcasecmp (action, "reload")) { err = sqlx_remote_execute_RELOAD (id); if (!err) return _reply_success_json (args, NULL); return _reply_common_error (args, err); } if (!g_ascii_strcasecmp (action, "kill")) { GByteArray *encoded = message_marshall_gba_and_clean ( metautils_message_create_named("REQ_KILL")); err = gridd_client_exec (id, 1.0, encoded); if (err) return _reply_common_error (args, err); return _reply_success_json (args, NULL); } if (!g_ascii_strcasecmp (action, "ping")) { args->rp->no_access(); GByteArray *encoded = message_marshall_gba_and_clean ( metautils_message_create_named("REQ_PING")); err = gridd_client_exec (id, 1.0, encoded); if (err) return _reply_common_error (args, err); return _reply_success_json (args, NULL); } if (!g_ascii_strcasecmp (action, "lean-glib")) { MESSAGE req = metautils_message_create_named("REQ_LEAN"); metautils_message_add_field_str(req, "LIBC", "1"); metautils_message_add_field_str(req, "THREADS", "1"); GByteArray *encoded = message_marshall_gba_and_clean (req); err = gridd_client_exec (id, 1.0, encoded); if (err) return _reply_common_error (args, err); return _reply_success_json (args, NULL); } if (!g_ascii_strcasecmp (action, "lean-sqlx")) { GByteArray *encoded = message_marshall_gba_and_clean ( metautils_message_create_named(NAME_MSGNAME_SQLX_LEANIFY)); err = gridd_client_exec (id, 1.0, encoded); if (err) return _reply_common_error (args, err); return _reply_success_json (args, NULL); } if (!g_ascii_strcasecmp (action, "version")) { args->rp->no_access(); MESSAGE req = metautils_message_create_named("REQ_VERSION"); GByteArray *encoded = message_marshall_gba_and_clean (req); gchar *packed = NULL; err = gridd_client_exec_and_concat_string (id, 1.0, encoded, &packed); if (err) { g_free0 (packed); return _reply_common_error (args, err); } /* TODO(jfs): quite duplicated from _reply_json() but the original was not suitable. */ args->rp->set_status (200, "OK"); args->rp->set_body_bytes (g_bytes_new_take((guint8*)packed, strlen(packed))); args->rp->finalize (); return HTTPRC_DONE; } if (!g_ascii_strcasecmp (action, "handlers")) { args->rp->no_access(); MESSAGE req = metautils_message_create_named("REQ_HANDLERS"); GByteArray *encoded = message_marshall_gba_and_clean (req); gchar *packed = NULL; err = gridd_client_exec_and_concat_string (id, 1.0, encoded, &packed); if (err) { g_free0 (packed); return _reply_common_error (args, err); } /* TODO(jfs): quite duplicated from _reply_json() but the original was not suitable. */ args->rp->set_status (200, "OK"); args->rp->set_body_bytes (g_bytes_new_take((guint8*)packed, strlen(packed))); args->rp->finalize (); return HTTPRC_DONE; } return _reply_common_error (args, BADREQ("unexpected action")); }
static enum http_rc_e _registration (struct req_args_s *args, enum reg_op_e op, struct json_object *jsrv) { GError *err; if (!jsrv || !json_object_is_type (jsrv, json_type_object)) return _reply_common_error (args, BADREQ("Expected: json object")); if (!push_queue) return _reply_bad_gateway(args, SYSERR("Service upstream disabled")); if (NULL != (err = _cs_check_tokens(args))) return _reply_notfound_error (args, err); struct service_info_s *si = NULL; err = service_info_load_json_object (jsrv, &si, TRUE); if (err) { g_prefix_error (&err, "JSON error: "); if (err->code == CODE_BAD_REQUEST) return _reply_format_error (args, err); else return _reply_system_error (args, err); } if (!si->type[0]) { service_info_clean (si); return _reply_format_error (args, BADREQ("Service type not specified")); } if (!si->ns_name[0]) { GRID_TRACE2("%s NS forced to %s", __FUNCTION__, si->ns_name); g_strlcpy (si->ns_name, nsname, sizeof(si->ns_name)); } else if (!validate_namespace (si->ns_name)) { service_info_clean (si); return _reply_format_error (args, BADNS()); } gchar *k = service_info_key (si); STRING_STACKIFY(k); GRID_TRACE2("%s op=%s score=%d key=[%s]", __FUNCTION__, _regop_2str(op), si->score.value, k); switch (op) { case REGOP_PUSH: si->score.value = SCORE_UNSET; if (!service_is_known (k)) { service_learn (k); service_tag_set_value_boolean (service_info_ensure_tag ( si->tags, NAME_TAGNAME_RAWX_FIRST), TRUE); } break; case REGOP_LOCK: si->score.value = CLAMP(si->score.value, SCORE_DOWN, SCORE_MAX); break; case REGOP_UNLOCK: si->score.value = SCORE_UNLOCK; break; default: g_assert_not_reached(); } if (cs_expire_local_services > 0) { struct service_info_s *v = service_info_dup (si); v->score.timestamp = oio_ext_monotonic_seconds (); PUSH_DO( const struct service_info_s *si0 = lru_tree_get(srv_registered, k); if (si0) v->score.value = si0->score.value; lru_tree_insert (srv_registered, g_strdup(k), v); ); }