/** * @brief Free an #Azy_Client * * This function frees a client and ALL associated data. If called * on a connected client, azy_client_close will be called and then the client * will be freed. * @param client The client (NOT NULL) */ void azy_client_free(Azy_Client *client) { DBG("(client=%p)", client); if (!AZY_MAGIC_CHECK(client, AZY_MAGIC_CLIENT)) { AZY_MAGIC_FAIL(client, AZY_MAGIC_CLIENT); return; } if (client->connected) azy_client_close(client); AZY_MAGIC_SET(client, AZY_MAGIC_NONE); if (client->addr) eina_stringshare_del(client->addr); if (client->session_id) eina_stringshare_del(client->session_id); if (client->add) ecore_event_handler_del(client->add); if (client->del) ecore_event_handler_del(client->del); if (client->upgrade) ecore_event_handler_del(client->upgrade); if (client->callbacks) eina_hash_free(client->callbacks); if (client->free_callbacks) eina_hash_free(client->free_callbacks); if (client->conns) client->conns = eina_list_free(client->conns); free(client); }
/** * @brief Send arbitrary data to a connected server * * This function is used to send arbitrary data to a connected server using @p client through HTTP PUT. * It relies on the user to set required headers by operating on the client's #Azy_Net object. * @param client The client (NOT NULL) * @param send_data The data+length to send (NOT NULL) * @param data Optional data to pass to associated callbacks * @return The #Azy_Client_Call_Id of the transmission, to be used with azy_client_callback_set, * or 0 on failure * @see azy_net_header_set */ Azy_Client_Call_Id azy_client_put(Azy_Client *client, const Azy_Net_Data *send_data, void *data) { Eina_Strbuf *msg; Azy_Client_Handler_Data *hd; if (!AZY_MAGIC_CHECK(client, AZY_MAGIC_CLIENT)) { AZY_MAGIC_FAIL(client, AZY_MAGIC_CLIENT); return 0; } EINA_SAFETY_ON_NULL_RETURN_VAL(send_data, 0); EINA_SAFETY_ON_NULL_RETURN_VAL(send_data->data, 0); azy_net_message_length_set(client->net, send_data->size); azy_net_type_set(client->net, AZY_NET_TYPE_PUT); msg = azy_net_header_create(client->net); EINA_SAFETY_ON_NULL_GOTO(msg, error); #ifdef ISCOMFITOR DBG("\nSENDING >>>>>>>>>>>>>>>>>>>>>>>>\n%.*s%.*s\n>>>>>>>>>>>>>>>>>>>>>>>>", eina_strbuf_length_get(msg), eina_strbuf_string_get(msg), (int)send_data->size, send_data->data); #endif EINA_SAFETY_ON_TRUE_GOTO(!ecore_con_server_send(client->net->conn, eina_strbuf_string_get(msg), eina_strbuf_length_get(msg)), error); INFO("Send [1/2] complete! %zi bytes queued for sending.", eina_strbuf_length_get(msg)); eina_strbuf_free(msg); msg = NULL; EINA_SAFETY_ON_TRUE_GOTO(!ecore_con_server_send(client->net->conn, send_data->data, send_data->size), error); INFO("Send [2/2] complete! %" PRIi64 " bytes queued for sending.", send_data->size); ecore_con_server_flush(client->net->conn); EINA_SAFETY_ON_TRUE_RETURN_VAL(!(hd = calloc(1, sizeof(Azy_Client_Handler_Data))), 0); if (!client->conns) { client->recv = ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DATA, (Ecore_Event_Handler_Cb)_azy_client_handler_data, hd); ecore_con_server_data_set(client->net->conn, client); } hd->client = client; hd->content_data = data; hd->type = AZY_NET_TYPE_PUT; AZY_MAGIC_SET(hd, AZY_MAGIC_CLIENT_DATA_HANDLER); while (++azy_client_send_id__ < 1) ; hd->id = azy_client_send_id__; client->conns = eina_list_append(client->conns, hd); return azy_client_send_id__; error: if (msg) eina_strbuf_free(msg); return 0; }
/** * @brief Free a method object * * This function frees a method object. After calling, the method will no * longer be callable. This function must only be called AFTER * azy_server_module_def_method_del to avoid undefined methods remaining * in the module's method list after they've been freed. * @param method The method to free (NOT NULL) */ void azy_server_module_method_free(Azy_Server_Module_Method *method) { if (!AZY_MAGIC_CHECK(method, AZY_MAGIC_SERVER_MODULE_METHOD)) { AZY_MAGIC_FAIL(method, AZY_MAGIC_SERVER_MODULE_METHOD); return; } AZY_MAGIC_SET(method, AZY_MAGIC_NONE); eina_stringshare_del(method->name); free(method); }
/** * @brief Create a new module definition with the given name * * This function creates a blank #Azy_Server_Module_Def with @p name. * @param name The name of the module (NOT NULL) * @return The new #Azy_Server_Module_Def, or NULL on failure */ Azy_Server_Module_Def * azy_server_module_def_new(const char *name) { Azy_Server_Module_Def *def; EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL); def = calloc(1, sizeof(Azy_Server_Module_Def)); EINA_SAFETY_ON_NULL_RETURN_VAL(def, NULL); def->name = eina_stringshare_add(name); AZY_MAGIC_SET(def, AZY_MAGIC_SERVER_MODULE_DEF); return def; }
/** * @brief Allocate a new client object * * This function creates a new client object for use in connecting to a * server. * @return The new client, or NULL on failure */ Azy_Client * azy_client_new(void) { Azy_Client *client; if (!(client = calloc(1, sizeof(Azy_Client)))) return NULL; client->add = ecore_event_handler_add(ECORE_CON_EVENT_SERVER_ADD, (Ecore_Event_Handler_Cb)_azy_client_handler_add, client); client->del = ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DEL, (Ecore_Event_Handler_Cb)_azy_client_handler_del, client); client->upgrade = ecore_event_handler_add(ECORE_CON_EVENT_SERVER_UPGRADE, (Ecore_Event_Handler_Cb)_azy_client_handler_upgrade, client); AZY_MAGIC_SET(client, AZY_MAGIC_CLIENT); return client; }
/** * @brief Free the given #Azy_Server_Module_Def * * This function frees the given #Azy_Server_Module_Def, and should only * be called after the module will no longer be used. * @param def The #Azy_Server_Module_Def to free */ void azy_server_module_def_free(Azy_Server_Module_Def *def) { if (!def) return; if (!AZY_MAGIC_CHECK(def, AZY_MAGIC_SERVER_MODULE_DEF)) { AZY_MAGIC_FAIL(def, AZY_MAGIC_SERVER_MODULE_DEF); return; } eina_stringshare_del(def->name); eina_hash_free(def->methods); if (def->module) eina_module_free(def->module); AZY_MAGIC_SET(def, AZY_MAGIC_NONE); free(def); }
/** * @brief Create a new method object with specified name and callback * * This function creates a new method object with stringshared @p name and * callback @p cb. * @param name The name of the method * @param cb The callback of the method * @return The new #Azy_Server_Module_Method object, or NULL on failure */ Azy_Server_Module_Method * azy_server_module_method_new(const char *name, Azy_Server_Module_Content_Cb cb) { Azy_Server_Module_Method *method; EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL); EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL); method = calloc(1, sizeof(Azy_Server_Module_Method)); EINA_SAFETY_ON_NULL_RETURN_VAL(method, NULL); method->name = eina_stringshare_add(name); method->method = cb; AZY_MAGIC_SET(method, AZY_MAGIC_SERVER_MODULE_METHOD); return method; }
/** * @brief Make an HTTP GET or POST request using a connected client with no HTTP BODY * * This function is used to make a GET or POST request using @p client to the uri of the client's * #Azy_Net object (azy_net_get(client)) using HTTP method @p type, content-type * defined by @p transport, and the optional deserialization function specified by @p cb. * @param client The client (NOT NULL) * @param type The HTTP method to use (NOT NULL) * @param netdata The HTTP BODY to send with a POST * @param cb The deserialization callback to use for the response * @param data The user data to be passed to resulting callbacks * @return The #Azy_Client_Call_Id of the transmission, to be used with azy_client_callback_set, * or 0 on failure */ Azy_Client_Call_Id azy_client_blank(Azy_Client *client, Azy_Net_Type type, Azy_Net_Data *netdata, Azy_Content_Cb cb, void *data) { Eina_Strbuf *msg; Azy_Client_Handler_Data *hd; DBG("(client=%p, net=%p)", client, client->net); if (!AZY_MAGIC_CHECK(client, AZY_MAGIC_CLIENT)) { AZY_MAGIC_FAIL(client, AZY_MAGIC_CLIENT); return 0; } EINA_SAFETY_ON_NULL_RETURN_VAL(client->net, 0); EINA_SAFETY_ON_TRUE_RETURN_VAL((type != AZY_NET_TYPE_GET) && (type != AZY_NET_TYPE_POST), 0); while (++azy_client_send_id__ < 1) ; client->net->type = type; if (!client->net->http.req.http_path) { WARN("NULL URI passed, defaulting to \"/\""); azy_net_uri_set(client->net, "/"); } if (netdata && netdata->size && (type == AZY_NET_TYPE_POST)) azy_net_message_length_set(client->net, netdata->size); msg = azy_net_header_create(client->net); EINA_SAFETY_ON_NULL_GOTO(msg, error); #ifdef ISCOMFITOR char buf[64]; snprintf(buf, sizeof(buf), "\nSENDING >>>>>>>>>>>>>>>>>>>>>>>>\n%%.%zus\n>>>>>>>>>>>>>>>>>>>>>>>>", eina_strbuf_length_get(msg)); DBG(buf, eina_strbuf_string_get(msg)); #endif EINA_SAFETY_ON_TRUE_GOTO(!ecore_con_server_send(client->net->conn, eina_strbuf_string_get(msg), eina_strbuf_length_get(msg)), error); if (netdata && netdata->size && (type == AZY_NET_TYPE_POST)) { INFO("Send [1/2] complete! %zu bytes queued for sending.", eina_strbuf_length_get(msg)); EINA_SAFETY_ON_TRUE_GOTO(!ecore_con_server_send(client->net->conn, netdata->data, netdata->size), error); INFO("Send [2/2] complete! %" PRIi64 " bytes queued for sending.", netdata->size); } else INFO("Send [1/1] complete! %zu bytes queued for sending.", eina_strbuf_length_get(msg)); eina_strbuf_free(msg); msg = NULL; ecore_con_server_flush(client->net->conn); hd = calloc(1, sizeof(Azy_Client_Handler_Data)); EINA_SAFETY_ON_NULL_RETURN_VAL(hd, 0); hd->client = client; hd->callback = cb; hd->type = type; hd->content_data = data; if (netdata && netdata->size && (type == AZY_NET_TYPE_POST)) { hd->send = eina_strbuf_new(); eina_strbuf_append_length(hd->send, (char *)netdata->data, netdata->size); } hd->id = azy_client_send_id__; AZY_MAGIC_SET(hd, AZY_MAGIC_CLIENT_DATA_HANDLER); if (!client->conns) { client->recv = ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DATA, (Ecore_Event_Handler_Cb)_azy_client_handler_data, hd); ecore_con_server_data_set(client->net->conn, client); } client->conns = eina_list_append(client->conns, hd); DBG("(client=%p, net=%p, hd=%p)", client, client->net, hd); return azy_client_send_id__; error: if (msg) eina_strbuf_free(msg); return 0; }
/** * @brief Make a method call using a connected client * * This function is used to make a method call on @p client as defined in * @p content, using content-type defined by @p transport and the deserialization * function specified by @p cb. This should generally not be used by users, as azy_parser * will automatically generate the correct calls from a .azy file. * @param client The client (NOT NULL) * @param content The content containing the method name and parameters (NOT NULL) * @param transport The content-type (xml/json/etc) to use * @param cb The deserialization callback to use for the response * @return The #Azy_Client_Call_Id of the transmission, to be used with azy_client_callback_set, * or 0 on failure */ Azy_Client_Call_Id azy_client_call(Azy_Client *client, Azy_Content *content, Azy_Net_Transport transport, Azy_Content_Cb cb) { Eina_Strbuf *msg; Azy_Client_Handler_Data *hd; DBG("(client=%p, net=%p, content=%p)", client, client->net, content); if (!AZY_MAGIC_CHECK(client, AZY_MAGIC_CLIENT)) { AZY_MAGIC_FAIL(client, AZY_MAGIC_CLIENT); return 0; } EINA_SAFETY_ON_NULL_RETURN_VAL(client->net, 0); EINA_SAFETY_ON_NULL_RETURN_VAL(content, 0); EINA_SAFETY_ON_NULL_RETURN_VAL(content->method, 0); INFO("New method call: '%s'", content->method); while (++azy_client_send_id__ < 1) ; content->id = azy_client_send_id__; azy_net_transport_set(client->net, transport); if (!azy_content_serialize_request(content, transport)) return 0; azy_net_type_set(client->net, AZY_NET_TYPE_POST); if (!client->net->http.req.http_path) { WARN("URI currently set to NULL, defaulting to \"/\""); azy_net_uri_set(client->net, "/"); } azy_net_message_length_set(client->net, content->length); msg = azy_net_header_create(client->net); EINA_SAFETY_ON_NULL_GOTO(msg, error); if (azy_rpc_log_dom >= 0) { char buf[64]; snprintf(buf, sizeof(buf), "\nSENDING >>>>>>>>>>>>>>>>>>>>>>>>\n%%.%is%%.%llis\n>>>>>>>>>>>>>>>>>>>>>>>>", eina_strbuf_length_get(msg), content->length); RPC_DBG(buf, eina_strbuf_string_get(msg), content->buffer); } EINA_SAFETY_ON_TRUE_GOTO(!ecore_con_server_send(client->net->conn, eina_strbuf_string_get(msg), eina_strbuf_length_get(msg)), error); INFO("Send [1/2] complete! %zu bytes queued for sending.", eina_strbuf_length_get(msg)); eina_strbuf_free(msg); msg = NULL; EINA_SAFETY_ON_TRUE_GOTO(!ecore_con_server_send(client->net->conn, content->buffer, content->length), error); INFO("Send [2/2] complete! %lli bytes queued for sending.", content->length); ecore_con_server_flush(client->net->conn); hd = calloc(1, sizeof(Azy_Client_Handler_Data)); EINA_SAFETY_ON_NULL_RETURN_VAL(hd, 0); hd->client = client; hd->method = eina_stringshare_ref(content->method); hd->callback = cb; hd->type = AZY_NET_TYPE_POST; hd->content_data = content->data; hd->send = eina_strbuf_new(); eina_strbuf_append_length(hd->send, (char *)content->buffer, content->length); hd->id = azy_client_send_id__; AZY_MAGIC_SET(hd, AZY_MAGIC_CLIENT_DATA_HANDLER); if (!client->conns) { client->recv = ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DATA, (Ecore_Event_Handler_Cb)_azy_client_handler_data, hd); ecore_con_server_data_set(client->net->conn, client); } client->conns = eina_list_append(client->conns, hd); DBG("(client=%p, net=%p, content=%p, hd=%p)", client, client->net, content, hd); return azy_client_send_id__; error: if (msg) eina_strbuf_free(msg); return 0; }