unrealircd

- supernets unrealircd source & configuration
git clone git://git.acid.vegas/unrealircd.git
Log | Files | Refs | Archive | README | LICENSE

api-rpc.c (3653B)

      1 /************************************************************************
      2  * UnrealIRCd - Unreal Internet Relay Chat Daemon - src/api-rpc.c
      3  * (c) 2022- Bram Matthys and The UnrealIRCd Team
      4  * License: GPLv2 or later
      5  */
      6 
      7 /** @file
      8  * @brief RPC API
      9  */
     10 #include "unrealircd.h"
     11 
     12 /** This is the RPC API used for web requests.
     13  * For an overview of available RPC's (not the API)
     14  * see https://www.unrealircd.org/docs/RPC
     15  * @defgroup RPCAPI RPC API
     16  * @{
     17  */
     18 
     19 /** List of RPC handlers */
     20 MODVAR RPCHandler *rpchandlers = NULL;
     21 
     22 /* Forward declarations */
     23 static void unload_rpc_handler_commit(RPCHandler *m);
     24 
     25 /** Adds a new RPC handler.
     26  * @param module The module which owns this RPC handler.
     27  * @param mreq   The details of the request such as the method name, callback, etc.
     28  * @return Returns the handle to the RPC handler if successful, otherwise NULL.
     29  *         The module's error code contains specific information about the
     30  *         error.
     31  */
     32 RPCHandler *RPCHandlerAdd(Module *module, RPCHandlerInfo *mreq)
     33 {
     34 	RPCHandler *m;
     35 	ModuleObject *mobj;
     36 
     37 	/* Some consistency checks to avoid a headache for module devs later on: */
     38 	if (!mreq->method || !mreq->call)
     39 	{
     40 		unreal_log(ULOG_ERROR, "module", "RPCHANDLERADD_API_ERROR", NULL,
     41 			   "RPCHandlerAdd() from module $module_name: "
     42 			   "Missing required fields.",
     43 			   log_data_string("module_name", module->header->name));
     44 		abort();
     45 	}
     46 
     47 	m = RPCHandlerFind(mreq->method);
     48 	if (m)
     49 	{
     50 		if (m->unloaded)
     51 		{
     52 			m->unloaded = 0;
     53 		} else {
     54 			if (module)
     55 				module->errorcode = MODERR_EXISTS;
     56 			return NULL;
     57 		}
     58 	} else {
     59 		/* New RPC handler */
     60 		m = safe_alloc(sizeof(RPCHandler));
     61 		safe_strdup(m->method, mreq->method);
     62 		AddListItem(m, rpchandlers);
     63 	}
     64 	/* Add or update the following fields: */
     65 	m->owner = module;
     66 	m->flags = mreq->flags;
     67 	m->loglevel = mreq->loglevel;
     68 	if (!valid_loglevel(m->loglevel))
     69 		m->loglevel = ULOG_INFO;
     70 	m->call = mreq->call;
     71 
     72 	/* Add module object */
     73 	mobj = safe_alloc(sizeof(ModuleObject));
     74 	mobj->type = MOBJ_RPC;
     75 	mobj->object.rpc = m;
     76 	AddListItem(mobj, module->objects);
     77 	module->errorcode = MODERR_NOERROR;
     78 
     79 	return m;
     80 }
     81 
     82 /** Returns the RPC handler for the given method name.
     83  * @param method The method to search for.
     84  * @return Returns the handle to the RPC handler,
     85  *         or NULL if not found.
     86  */
     87 RPCHandler *RPCHandlerFind(const char *method)
     88 {
     89 	RPCHandler *m;
     90 
     91 	for (m = rpchandlers; m; m = m->next)
     92 	{
     93 		if (!strcasecmp(method, m->method))
     94 			return m;
     95 	}
     96 	return NULL;
     97 }
     98 
     99 /** Remove the specified RPC handler - modules should not call this.
    100  * This is done automatically for modules on unload, so is only called internally.
    101  * @param m The PRC handler to remove.
    102  */
    103 void RPCHandlerDel(RPCHandler *m)
    104 {
    105 	if (m->owner)
    106 	{
    107 		ModuleObject *mobj;
    108 		for (mobj = m->owner->objects; mobj; mobj = mobj->next) {
    109 			if (mobj->type == MOBJ_RPC && mobj->object.rpc == m)
    110 			{
    111 				DelListItem(mobj, m->owner->objects);
    112 				safe_free(mobj);
    113 				break;
    114 			}
    115 		}
    116 		m->owner = NULL;
    117 	}
    118 
    119 	if (loop.rehashing)
    120 		m->unloaded = 1;
    121 	else
    122 		unload_rpc_handler_commit(m);
    123 }
    124 
    125 /** @} */
    126 
    127 static void unload_rpc_handler_commit(RPCHandler *m)
    128 {
    129 	/* This is an unusual operation, I think we should log it. */
    130 	unreal_log(ULOG_INFO, "module", "UNLOAD_RPC_HANDLER", NULL,
    131 	           "Unloading RPC handler for '$method'",
    132 	           log_data_string("method", m->method));
    133 
    134 	/* Destroy the object */
    135 	DelListItem(m, rpchandlers);
    136 	safe_free(m->method);
    137 	safe_free(m);
    138 }
    139 
    140 void unload_all_unused_rpc_handlers(void)
    141 {
    142 	RPCHandler *m, *m_next;
    143 
    144 	for (m = rpchandlers; m; m = m_next)
    145 	{
    146 		m_next = m->next;
    147 		if (m->unloaded)
    148 			unload_rpc_handler_commit(m);
    149 	}
    150 }