/** * @brief Set the connection info for a client * * This function sets the server address and port for a client to * connect to. The address can be either an ip string (ipv6 supported) * or a web address. * @param client The client object (NOT NULL) * @param addr The server's address (NOT NULL) * @param port The port on the server (-1 < port < 65536) * @return #EINA_TRUE on success, else #EINA_FALSE */ Eina_Bool azy_client_host_set(Azy_Client *client, const char *addr, int port) { DBG("(client=%p)", client); if (!AZY_MAGIC_CHECK(client, AZY_MAGIC_CLIENT)) { AZY_MAGIC_FAIL(client, AZY_MAGIC_CLIENT); return EINA_FALSE; } if ((!addr) || (port < 0) || (port > 65536)) return EINA_FALSE; if (client->addr) eina_stringshare_del(client->addr); if (!strncmp(addr, "http://", 7)) addr += 7; else if (!strncmp(addr, "https://", 8)) addr += 8; client->addr = eina_stringshare_add(addr); client->port = port; return EINA_TRUE; }
/** * @brief Connect the client to its server * * This function begins the connection process for @p client to its * previously set server. This will return EINA_FALSE immediately if an error occurs. * @param client The client object (NOT NULL) * @param secure If #EINA_TRUE, TLS will be used in the connection * @return #EINA_TRUE if successful, or #EINA_FALSE on failure */ Eina_Bool azy_client_connect(Azy_Client *client, Eina_Bool secure) { DBG("(client=%p)", client); Ecore_Con_Server *svr; int flags = ECORE_CON_REMOTE_NODELAY; if (!AZY_MAGIC_CHECK(client, AZY_MAGIC_CLIENT)) { AZY_MAGIC_FAIL(client, AZY_MAGIC_CLIENT); return EINA_FALSE; } if ((client->connected) || (!client->addr) || (!client->port)) return EINA_FALSE; client->secure = !!secure; if (secure) flags |= ECORE_CON_USE_MIXED; if (!(svr = ecore_con_server_connect(flags, client->addr, client->port, NULL))) return EINA_FALSE; ecore_con_server_data_set(svr, client); client->net = azy_net_new(svr); azy_net_header_set(client->net, "host", NULL); azy_net_header_set(client->net, "host", client->addr); return EINA_TRUE; }
/** * @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 Remove a method from a module * * This function removes a callable rpc method from module @p def. After * removal, @p method will no longer be callable. * @note This does not free the method object. * @param def The module definition (NOT NULL) * @param method The method to remove (NOT NULL) * @return EINA_TRUE on success, else EINA_FALSE */ Eina_Bool azy_server_module_def_method_del(Azy_Server_Module_Def *def, Azy_Server_Module_Method *method) { if (!AZY_MAGIC_CHECK(def, AZY_MAGIC_SERVER_MODULE_DEF)) { AZY_MAGIC_FAIL(def, AZY_MAGIC_SERVER_MODULE_DEF); return EINA_FALSE; } if (!AZY_MAGIC_CHECK(method, AZY_MAGIC_SERVER_MODULE_METHOD)) { AZY_MAGIC_FAIL(method, AZY_MAGIC_SERVER_MODULE_METHOD); return EINA_FALSE; } return !!eina_hash_set(def->methods, method->name, NULL); }
int azy_events_type_parse(Azy_Net *net, int type, const unsigned char *header, int len) { const unsigned char *start = NULL; int size; DBG("(net=%p, header=%p, len=%i)", net, header, len); if (!AZY_MAGIC_CHECK(net, AZY_MAGIC_NET)) { AZY_MAGIC_FAIL(net, AZY_MAGIC_NET); return 0; } if (net->size && net->buffer) { unsigned char *buf_start; /* previous buffer */ size = (net->size + len > MAX_HEADER_SIZE) ? MAX_HEADER_SIZE : net->size + len; buf_start = alloca(size); /* grab and combine buffers */ if (header) { memcpy(buf_start, net->buffer, size); if (net->size < size) memcpy(buf_start + net->size, header, size - net->size); len = size; } else { memcpy(buf_start, net->buffer, size); len = size; } start = buf_start; AZY_SKIP_BLANK(start); } else { /* copy pointer */ start = header; /* skip all spaces/newlines/etc and decrement len */ AZY_SKIP_BLANK(start); } if (!start) return 0; /* some clients are dumb and send leading cr/nl/etc */ AZY_SKIP_BLANK(start); if (type == ECORE_CON_EVENT_CLIENT_DATA) return _azy_events_valid_request(net, start, len); return _azy_events_valid_response(net, start, len); }
/** * @brief Return the data received from a client * * This function returns the received data from a server module (client). * This data is set only when clients have called HTTP PUT, and will be handled by * the __upload__ directive in the server. * @param module The server module (NOT NULL) * @return The module's received data */ Azy_Net_Data * azy_server_module_recv_get(Azy_Server_Module *module) { if (!AZY_MAGIC_CHECK(module, AZY_MAGIC_SERVER_MODULE)) { AZY_MAGIC_FAIL(module, AZY_MAGIC_SERVER_MODULE); return NULL; } return &module->recv; }
/** * @brief Returns whether a module has stored params * * This function can be used to determine whether params from previous * method runs are currently stored. It is used by the parser. * @param module The module (NOT NULL) * @return EINA_TRUE if params are stored, else EINA_FALSE */ Eina_Bool azy_server_module_params_exist(Azy_Server_Module *module) { if (!AZY_MAGIC_CHECK(module, AZY_MAGIC_SERVER_MODULE)) { AZY_MAGIC_FAIL(module, AZY_MAGIC_SERVER_MODULE); return EINA_FALSE; } return !!module->params; }
/** * @brief Return the #Azy_Content object of the current module's connection * * This function is used to return the current module's return content object, * allowing manipulation of the return value. * @note This should only be used on a suspended module. * @param module The server module (NOT NULL) * @return The #Azy_Content object */ Azy_Content * azy_server_module_content_get(Azy_Server_Module *module) { if (!AZY_MAGIC_CHECK(module, AZY_MAGIC_SERVER_MODULE)) { AZY_MAGIC_FAIL(module, AZY_MAGIC_SERVER_MODULE); return NULL; } return module->content; }
/** * @brief Return the state of an #Azy_Server_Module object * The return value of this function represents the connection state of the associated client. * @param module The module (NOT NULL) * @return EINA_TRUE if the client is connected, else EINA_FALSE */ Eina_Bool azy_server_module_active_get(Azy_Server_Module *module) { if (!AZY_MAGIC_CHECK(module, AZY_MAGIC_SERVER_MODULE)) { AZY_MAGIC_FAIL(module, AZY_MAGIC_SERVER_MODULE); return EINA_FALSE; } return !module->client->dead; }
/** * @brief Return the private data of a server module * * This function returns the private data of a server module. * This data is set only in the server module definition function, * and has the value specified in the __attrs__ section of the module * in a .azy file. * @param module The server module (NOT NULL) * @return The module's data */ void * azy_server_module_data_get(Azy_Server_Module *module) { if (!AZY_MAGIC_CHECK(module, AZY_MAGIC_SERVER_MODULE)) { AZY_MAGIC_FAIL(module, AZY_MAGIC_SERVER_MODULE); return NULL; } return module->data; }
/** * @brief Get the version of a module * * This function returns the version number of a module as set with * azy_server_module_def_version_set or the __version__() directive in a .azy file. * @param m The module (NOT NULL) * @return The version of the module, or -1.0 on failure */ double azy_server_module_version_get(Azy_Server_Module *m) { if (!AZY_MAGIC_CHECK(m, AZY_MAGIC_SERVER_MODULE)) { AZY_MAGIC_FAIL(m, AZY_MAGIC_SERVER_MODULE); return -1.0; } return m->def->version; }
/** * @brief Return the size of the private data of a module * * This function is equivalent to calling sizeof(Azy_Server_Module). * It returns the total size of the __attrs__ section of a module. * @param def The module def (NOT NULL) * @return The size of the module, or -1 on failure */ int azy_server_module_def_size_get(Azy_Server_Module_Def *def) { if (!AZY_MAGIC_CHECK(def, AZY_MAGIC_SERVER_MODULE_DEF)) { AZY_MAGIC_FAIL(def, AZY_MAGIC_SERVER_MODULE_DEF); return -1; } return def->data_size; }
/** * @brief Get the data previously associated with a client * * This function retrieves the data previously set to @p client * with azy_client_data_set. * @param client The client object (NOT NULL) * @return The data, or NULL on error */ void * azy_client_data_get(Azy_Client *client) { DBG("(client=%p)", client); if (!AZY_MAGIC_CHECK(client, AZY_MAGIC_CLIENT)) { AZY_MAGIC_FAIL(client, AZY_MAGIC_CLIENT); return NULL; } return client->data; }
/** * @brief Check whether a client is connected * * This function returns true only when the client is connected. * @param client The client (NOT NULL) * @return #EINA_TRUE if the client is connected, else #EINA_FALSE */ Eina_Bool azy_client_connected_get(Azy_Client *client) { DBG("(client=%p)", client); if (!AZY_MAGIC_CHECK(client, AZY_MAGIC_CLIENT)) { AZY_MAGIC_FAIL(client, AZY_MAGIC_CLIENT); return EINA_FALSE; } return client->connected; }
/** * @brief Set the __fallback__ callback function for a #Azy_Server_Module_Def * * This function sets the callback that is called any time a user attempts * to call an undefined rpc method. * @param def The module definition (NOT NULL) * @param fallback The callback function to call when an undefined method is requested */ void azy_server_module_def_fallback_set(Azy_Server_Module_Def *def, Azy_Server_Module_Content_Cb fallback) { if (!AZY_MAGIC_CHECK(def, AZY_MAGIC_SERVER_MODULE_DEF)) { AZY_MAGIC_FAIL(def, AZY_MAGIC_SERVER_MODULE_DEF); return; } def->fallback = fallback; }
/** * @brief Add a method to a module * * This function adds a callable rpc method to module @p def. After adding, * @p method should be considered as belonging to @p def until the module is unloaded. * @param def The module definition (NOT NULL) * @param method The method to add (NOT NULL) */ void azy_server_module_def_method_add(Azy_Server_Module_Def *def, Azy_Server_Module_Method *method) { Azy_Server_Module_Method *old; if (!AZY_MAGIC_CHECK(def, AZY_MAGIC_SERVER_MODULE_DEF)) { AZY_MAGIC_FAIL(def, AZY_MAGIC_SERVER_MODULE_DEF); return; } if (!AZY_MAGIC_CHECK(method, AZY_MAGIC_SERVER_MODULE_METHOD)) { AZY_MAGIC_FAIL(method, AZY_MAGIC_SERVER_MODULE_METHOD); return; } if (!def->methods) def->methods = eina_hash_string_superfast_new((Eina_Free_Cb)azy_server_module_method_free); old = eina_hash_set(def->methods, method->name, method); if (old) azy_server_module_method_free(old); }
/** * @brief Set the data previously associated with a client * * This function sets the data associated with @p client to @p data * for retrieval with azy_client_data_get. * @param client The client object (NOT NULL) * @param data The data to associate */ void azy_client_data_set(Azy_Client *client, const void *data) { DBG("(client=%p)", client); if (!AZY_MAGIC_CHECK(client, AZY_MAGIC_CLIENT)) { AZY_MAGIC_FAIL(client, AZY_MAGIC_CLIENT); return; } client->data = (void *)data; }
/** * @brief Set the version of a module * * This function sets the version number of a server module. * @param def The module def (NOT NULL) * @param version The version number of the module */ void azy_server_module_def_version_set(Azy_Server_Module_Def *def, double version) { if (!AZY_MAGIC_CHECK(def, AZY_MAGIC_SERVER_MODULE_DEF)) { AZY_MAGIC_FAIL(def, AZY_MAGIC_SERVER_MODULE_DEF); return; } def->version = version; }
/** * @brief Return the #Azy_Net object of the current or last * module's connection * * This function is used to return the current module's network information, * allowing parsing of headers. * If there is no current network information (Chunked transfer), then it will * return last module's network structure. * @param module The server module (NOT NULL) * @return The #Azy_Net object */ Azy_Net * azy_server_module_net_get(Azy_Server_Module *module) { if (!AZY_MAGIC_CHECK(module, AZY_MAGIC_SERVER_MODULE)) { AZY_MAGIC_FAIL(module, AZY_MAGIC_SERVER_MODULE); return NULL; } EINA_SAFETY_ON_NULL_RETURN_VAL(module->client, NULL); return module->client->current ? module->client->current : module->client->net; }
/** * @brief Get the network object associated with the client * * This function returns the #Azy_Net object associated with @p client * which is used for all outgoing data transmissions. From here, azy_net * namespaced functions can be called as normal upon the returned object. * Note that the returned object belongs to the client, and will only exist * if the client is connected. * @param client The client object (NOT NULL) * @return The #Azy_Net object, or NULL on failure */ Azy_Net * azy_client_net_get(Azy_Client *client) { DBG("(client=%p)", client); if (!AZY_MAGIC_CHECK(client, AZY_MAGIC_CLIENT)) { AZY_MAGIC_FAIL(client, AZY_MAGIC_CLIENT); return NULL; } return client->net; }
/** * @brief Get the port that the client connects to * * This function returns the port number on the server that @p client * connects to. * @param client The client object (NOT NULL) * @return The port number, or -1 on failure */ int azy_client_port_get(Azy_Client *client) { DBG("(client=%p)", client); if (!AZY_MAGIC_CHECK(client, AZY_MAGIC_CLIENT)) { AZY_MAGIC_FAIL(client, AZY_MAGIC_CLIENT); return -1; } return client->port; }
/** * @brief Get the address of the server that the client connects to * * This function returns the address string of the server that @p client * connects to. The returned string is stringshared but still * belongs to the client object. * @param client The client object (NOT NULL) * @return The address string, or NULL on failure */ const char * azy_client_addr_get(Azy_Client *client) { DBG("(client=%p)", client); if (!AZY_MAGIC_CHECK(client, AZY_MAGIC_CLIENT)) { AZY_MAGIC_FAIL(client, AZY_MAGIC_CLIENT); return NULL; } return client->addr; }
/** * @brief Set the size of the private data of a module * * This function should never be called by users. * @param def The module def (NOT NULL) * @param size The size of the module * @return EINA_TRUE on success, else EINA_FALSE */ Eina_Bool azy_server_module_size_set(Azy_Server_Module_Def *def, int size) { if (!AZY_MAGIC_CHECK(def, AZY_MAGIC_SERVER_MODULE_DEF)) { AZY_MAGIC_FAIL(def, AZY_MAGIC_SERVER_MODULE_DEF); return EINA_FALSE; } def->data_size = size; return EINA_TRUE; }
/** * @brief Remove a module from the server object * * This function removes @p module from @p server. Once a module * has been removed, its methods can no longer be called. * Note that this function only removes the module from the server's list * and does not actually free the module. * @param server The server object (NOT NULL) * @param module The module definition (NOT NULL) * @return EINA_TRUE on success, else EINA_FALSE */ Eina_Bool azy_server_module_del(Azy_Server *server, Azy_Server_Module_Def *module) { DBG("server=%p, module=%p", server, module); if (!AZY_MAGIC_CHECK(server, AZY_MAGIC_SERVER)) { AZY_MAGIC_FAIL(server, AZY_MAGIC_SERVER); return EINA_FALSE; } EINA_SAFETY_ON_NULL_RETURN_VAL(module, EINA_FALSE); return eina_hash_del_by_key(server->module_defs, module->name); }
/** * @brief Remove a module from the server object by name * * This function removes the module of name @p from @p server. Once a module * has been removed, its methods can no longer be called. * Note that this function only removes the module from the server's list * and does not actually free the module. * @param server The server object (NOT NULL) * @param name The module's name (NOT NULL) * @return EINA_TRUE on success or module not found, else EINA_FALSE */ Eina_Bool azy_server_module_name_del(Azy_Server *server, const char *name) { DBG("server=%p, name=%s", server, name); if (!AZY_MAGIC_CHECK(server, AZY_MAGIC_SERVER)) { AZY_MAGIC_FAIL(server, AZY_MAGIC_SERVER); return EINA_FALSE; } EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE); return eina_hash_del_by_key(server->module_defs, name); }
/** * @brief Set the __init__ and __shutdown__ callback functions for a #Azy_Server_Module_Def * * This function sets the callbacks called upon module load and module shutdown for @p def. * @param def The module definition (NOT NULL) * @param init The callback function to call upon module init * @param sd The callback function to call upon module shutdown */ void azy_server_module_def_init_shutdown_set(Azy_Server_Module_Def *def, Azy_Server_Module_Cb init, Azy_Server_Module_Shutdown_Cb sd) { if (!AZY_MAGIC_CHECK(def, AZY_MAGIC_SERVER_MODULE_DEF)) { AZY_MAGIC_FAIL(def, AZY_MAGIC_SERVER_MODULE_DEF); return; } def->init = init; def->shutdown = sd; }
/** * @brief Set the __pre__ and __post__ callback functions for a #Azy_Server_Module_Def * * This function sets the callbacks called before and after method calls for @p def. * @param def The module definition (NOT NULL) * @param pre The callback function to call immediately before method calls * @param post The callback function to call immediately after method calls */ void azy_server_module_def_pre_post_set(Azy_Server_Module_Def *def, Azy_Server_Module_Pre_Cb pre, Azy_Server_Module_Content_Cb post) { if (!AZY_MAGIC_CHECK(def, AZY_MAGIC_SERVER_MODULE_DEF)) { AZY_MAGIC_FAIL(def, AZY_MAGIC_SERVER_MODULE_DEF); return; } def->pre = pre; def->post = post; }
/** * @brief Set the __download__ and __upload__ callback functions for a #Azy_Server_Module_Def * * This function sets the callbacks called before and after method calls for @p def. * @param def The module definition (NOT NULL) * @param download The callback function to call for HTTP GET requests * @param upload The callback function to call for HTTP PUT requests */ void azy_server_module_def_download_upload_set(Azy_Server_Module_Def *def, Azy_Server_Module_Cb download, Azy_Server_Module_Cb upload) { if (!AZY_MAGIC_CHECK(def, AZY_MAGIC_SERVER_MODULE_DEF)) { AZY_MAGIC_FAIL(def, AZY_MAGIC_SERVER_MODULE_DEF); return; } def->download = download; def->upload = upload; }
/** * @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); }