/** * @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 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; }
/** * @brief Send data to a client * * This function is used to queue arbitrary data to send to a client through its module. It will automatically * generate all http header strings from @p net (if provided) including the content-length (based on @p data). * @param module The client's #Azy_Server_Module object (NOT NULL) * @param net An #Azy_Net object containing http information to use * @param data The data to send * @return EINA_TRUE on success, else EINA_FALSE */ Eina_Bool azy_server_module_send(Azy_Server_Module *module, Azy_Net *net, const Azy_Net_Data *data) { Eina_Strbuf *header; char chunk_size[20]; Eina_Binbuf *chunk_data; Eina_Bool nullify = EINA_FALSE; if (!AZY_MAGIC_CHECK(module, AZY_MAGIC_SERVER_MODULE)) { AZY_MAGIC_FAIL(module, AZY_MAGIC_SERVER_MODULE); return EINA_FALSE; } if (net) { if (!module->client->current) { module->client->current = net; nullify = EINA_TRUE; } if (net->headers_sent) goto post_header; Eina_Bool s; if ((data) && (net->http.transfer_encoding != AZY_NET_TRANSFER_ENCODING_CHUNKED)) azy_net_content_length_set(net, data->size); if (!net->http.res.http_code) azy_net_code_set(net, 200); /* OK */ azy_net_type_set(net, AZY_NET_TYPE_RESPONSE); EINA_SAFETY_ON_TRUE_RETURN_VAL(!(header = azy_net_header_create(net)), EINA_FALSE); EINA_SAFETY_ON_NULL_RETURN_VAL(module->client->current->conn, EINA_FALSE); s = !!ecore_con_client_send(module->client->current->conn, eina_strbuf_string_get(header), eina_strbuf_length_get(header)); eina_strbuf_free(header); if (!s) { ERR("Could not queue header for sending!"); return EINA_FALSE; } net->headers_sent = EINA_TRUE; } post_header: if ((!net) || (net->http.transfer_encoding != AZY_NET_TRANSFER_ENCODING_CHUNKED)) { if (!data || !data->data) return EINA_TRUE; EINA_SAFETY_ON_NULL_RETURN_VAL(module->client->current->conn, EINA_FALSE); EINA_SAFETY_ON_TRUE_RETURN_VAL(!ecore_con_client_send(module->client->current->conn, data->data, data->size), EINA_FALSE); goto post_send; } if (!data || !data->data) { EINA_SAFETY_ON_NULL_RETURN_VAL(module->client->current->conn, EINA_FALSE); EINA_SAFETY_ON_TRUE_RETURN_VAL(!ecore_con_client_send(module->client->current->conn, "0\r\n\r\n", 5), EINA_FALSE); goto post_send; } net->refcount++; sprintf((char *)chunk_size, "%" PRIx64 "\r\n", data->size); chunk_data = eina_binbuf_new(); eina_binbuf_append_length(chunk_data, (unsigned char *)chunk_size, strlen(chunk_size)); eina_binbuf_append_length(chunk_data, data->data, data->size); eina_binbuf_append_length(chunk_data, (unsigned char *)"\r\n", 2); EINA_SAFETY_ON_NULL_RETURN_VAL(module->client->current->conn, EINA_FALSE); EINA_SAFETY_ON_TRUE_RETURN_VAL(!ecore_con_client_send(module->client->current->conn, eina_binbuf_string_get(chunk_data), eina_binbuf_length_get(chunk_data)), EINA_FALSE); eina_binbuf_free(chunk_data); post_send: if (nullify) module->client->current = NULL; return EINA_TRUE; }