Coverage Report

Created: 2025-09-04 07:51

/src/fluent-bit/lib/monkey/mk_server/mk_plugin.c
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3
/*  Monkey HTTP Server
4
 *  ==================
5
 *  Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
6
 *
7
 *  Licensed under the Apache License, Version 2.0 (the "License");
8
 *  you may not use this file except in compliance with the License.
9
 *  You may obtain a copy of the License at
10
 *
11
 *      http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 *  Unless required by applicable law or agreed to in writing, software
14
 *  distributed under the License is distributed on an "AS IS" BASIS,
15
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 *  See the License for the specific language governing permissions and
17
 *  limitations under the License.
18
 */
19
20
#include <monkey/monkey.h>
21
#include <monkey/mk_utils.h>
22
#include <monkey/mk_http.h>
23
#include <monkey/mk_clock.h>
24
#include <monkey/mk_plugin.h>
25
#include <monkey/mk_mimetype.h>
26
#include <monkey/mk_vhost.h>
27
#include <monkey/mk_static_plugins.h>
28
#include <monkey/mk_plugin_stage.h>
29
#include <monkey/mk_core.h>
30
#include <monkey/mk_net.h>
31
32
#ifndef _WIN32
33
#include <dlfcn.h>
34
#include <err.h>
35
#endif
36
37
enum {
38
    bufsize = 256
39
};
40
41
static struct plugin_stagemap *plg_stagemap;
42
struct plugin_network_io *plg_netiomap;
43
44
struct mk_plugin *mk_plugin_lookup(char *shortname, struct mk_server *server)
45
0
{
46
0
    struct mk_list *head;
47
0
    struct mk_plugin *p = NULL;
48
49
0
    mk_list_foreach(head, &server->plugins) {
50
0
        p = mk_list_entry(head, struct mk_plugin, _head);
51
0
        if (strcmp(p->shortname, shortname) == 0){
52
0
            return p;
53
0
        }
54
0
    }
55
56
0
    return NULL;
57
0
}
58
59
void *mk_plugin_load_dynamic(const char *path)
60
0
{
61
0
    void *handle;
62
63
#ifdef _WIN32
64
    handle = (void *) LoadLibraryA(path);
65
#else
66
0
    handle = dlopen(path, RTLD_LAZY);
67
68
0
    if (!handle) {
69
0
        mk_warn("dlopen() %s", dlerror());
70
0
    }
71
0
#endif
72
73
0
    return handle;
74
0
}
75
76
void *mk_plugin_load_symbol(void *handler, const char *symbol)
77
0
{
78
0
    void *s;
79
80
#ifdef _WIN32
81
    s = GetProcAddress((HMODULE)handler, symbol);
82
#else
83
0
    dlerror();
84
0
    s = dlsym(handler, symbol);
85
0
    if (dlerror() != NULL) {
86
0
        return NULL;
87
0
    }
88
0
#endif
89
90
0
    return s;
91
0
}
92
93
/* Initialize a plugin, trigger the init_plugin callback */
94
static int mk_plugin_init(struct plugin_api *api,
95
                          struct mk_plugin *plugin,
96
                          struct mk_server *server)
97
0
{
98
0
    int ret;
99
0
    unsigned long len;
100
0
    char path[1024];
101
0
    char *conf_dir = NULL;
102
0
    struct file_info f_info;
103
104
0
    MK_TRACE("Load Plugin: '%s'", plugin->shortname);
105
106
0
    snprintf(path, 1024, "%s/%s",
107
0
             server->path_conf_root, server->conf_plugins);
108
0
    ret = mk_file_get_info(path, &f_info, MK_FILE_READ);
109
0
    if (ret == -1 || f_info.is_directory == MK_FALSE) {
110
0
        snprintf(path, 1024, "%s", server->conf_plugins);
111
0
    }
112
113
    /* Build plugin configuration path */
114
0
    mk_string_build(&conf_dir,
115
0
                    &len,
116
0
                    "%s/%s/",
117
0
                    path, plugin->shortname);
118
119
    /* Init plugin */
120
0
    plugin->api = api;
121
0
    plugin->server_ctx = server;
122
123
0
    if (plugin->network != NULL) {
124
0
        plugin->network->plugin = plugin;
125
0
    }
126
127
0
    ret = plugin->init_plugin(plugin, conf_dir);
128
0
    mk_mem_free(conf_dir);
129
130
0
    return ret;
131
0
}
132
133
134
/*
135
 * Load a plugin into Monkey core, 'type' defines if it's a MK_PLUGIN_STATIC or
136
 * a MK_PLUGIN_DYNAMIC. 'shortname' is mandatory and 'path' is only used when
137
 * MK_PLUGIN_DYNAMIC is set and represents the absolute path of the shared
138
 * library.
139
 */
140
struct mk_plugin *mk_plugin_load(int type, const char *shortname,
141
                                 void *data, struct mk_server *server)
142
0
{
143
0
    char *path;
144
0
    char symbol[64];
145
0
    void *handler;
146
0
    struct mk_list *head;
147
0
    struct mk_plugin *tmp;
148
0
    struct mk_plugin *plugin = NULL;
149
0
    struct mk_plugin_stage *stage;
150
151
    /* Set main struct name to reference */
152
0
    if (type == MK_PLUGIN_DYNAMIC) {
153
0
        path = (char *) data;
154
0
        handler = mk_plugin_load_dynamic(path);
155
0
        if (!handler) {
156
0
            return NULL;
157
0
        }
158
159
0
        snprintf(symbol, sizeof(symbol) - 1, "mk_plugin_%s", shortname);
160
0
        plugin  = mk_plugin_load_symbol(handler, symbol);
161
0
        if (!plugin) {
162
0
            mk_warn("Plugin '%s' is not registering properly", path);
163
#ifdef _WIN32
164
            FreeLibrary((HMODULE)handler);
165
#else
166
0
            dlclose(handler);
167
0
#endif
168
0
            return NULL;
169
0
        }
170
171
        /* Make sure this is not loaded twice (ref #218) */
172
0
        mk_list_foreach(head, &server->plugins) {
173
0
            tmp = mk_list_entry(head, struct mk_plugin, _head);
174
0
            if (tmp->load_type == MK_PLUGIN_STATIC &&
175
0
                strcmp(tmp->name, plugin->name) == 0){
176
0
                mk_warn("Plugin '%s' have been built-in.",
177
0
                        tmp->shortname);
178
#ifdef _WIN32
179
                FreeLibrary((HMODULE)handler);
180
#else
181
0
                dlclose(handler);
182
0
#endif
183
0
                return NULL;
184
0
            }
185
0
        }
186
187
0
        plugin->load_type = MK_PLUGIN_DYNAMIC;
188
0
        plugin->handler   = handler;
189
0
        plugin->path      = mk_string_dup(path);
190
0
    }
191
0
    else if (type == MK_PLUGIN_STATIC) {
192
0
        plugin = (struct mk_plugin *) data;
193
0
        plugin->load_type = MK_PLUGIN_STATIC;
194
0
    }
195
196
0
    if (!plugin) {
197
0
        return NULL;
198
0
    }
199
200
    /* Validate all callbacks are set */
201
0
    if (!plugin->shortname || !plugin->name || !plugin->version ||
202
0
        !plugin->init_plugin || !plugin->exit_plugin) {
203
0
        mk_warn("Plugin '%s' is not registering all fields properly",
204
0
                shortname);
205
0
        return NULL;
206
0
    }
207
208
0
    if (plugin->hooks & MK_PLUGIN_NETWORK_LAYER) {
209
0
        mk_bug(!plugin->network);
210
0
    }
211
212
0
    mk_list_init(&plugin->stage_list);
213
0
    if (plugin->hooks & MK_PLUGIN_STAGE) {
214
0
        struct mk_plugin_stage *st;
215
216
0
        stage = plugin->stage;
217
0
        if (stage->stage10) {
218
0
            st = mk_mem_alloc(sizeof(struct mk_plugin_stage));
219
0
            st->stage10 = stage->stage10;
220
0
            st->plugin  = plugin;
221
0
            mk_list_add(&st->_head, &server->stage10_handler);
222
0
            mk_list_add(&st->_parent_head, &plugin->stage_list);
223
0
        }
224
0
        if (stage->stage20) {
225
0
            st = mk_mem_alloc(sizeof(struct mk_plugin_stage));
226
0
            st->stage20 = stage->stage20;
227
0
            st->plugin  = plugin;
228
0
            mk_list_add(&st->_head, &server->stage20_handler);
229
0
            mk_list_add(&st->_parent_head, &plugin->stage_list);
230
0
        }
231
0
        if (stage->stage30) {
232
0
            st = mk_mem_alloc(sizeof(struct mk_plugin_stage));
233
0
            st->stage30 = stage->stage30;
234
0
            st->plugin  = plugin;
235
0
            mk_list_add(&st->_head, &server->stage30_handler);
236
0
            mk_list_add(&st->_parent_head, &plugin->stage_list);
237
0
        }
238
0
        if (stage->stage40) {
239
0
            st = mk_mem_alloc(sizeof(struct mk_plugin_stage));
240
0
            st->stage40 = stage->stage40;
241
0
            st->plugin  = plugin;
242
0
            mk_list_add(&st->_head, &server->stage40_handler);
243
0
            mk_list_add(&st->_parent_head, &plugin->stage_list);
244
0
        }
245
0
        if (stage->stage50) {
246
0
            st = mk_mem_alloc(sizeof(struct mk_plugin_stage));
247
0
            st->stage50 = stage->stage50;
248
0
            st->plugin  = plugin;
249
0
            mk_list_add(&st->_head, &server->stage50_handler);
250
0
            mk_list_add(&st->_parent_head, &plugin->stage_list);
251
0
        }
252
0
    }
253
254
0
    if (type == MK_PLUGIN_DYNAMIC) {
255
        /* Add Plugin to the end of the list */
256
0
        mk_list_add(&plugin->_head, &server->plugins);
257
0
    }
258
259
0
    return plugin;
260
0
}
261
262
void mk_plugin_unregister(struct mk_plugin *p)
263
0
{
264
0
    mk_mem_free(p->path);
265
0
    mk_list_del(&p->_head);
266
0
    if (p->load_type == MK_PLUGIN_DYNAMIC) {
267
#ifdef _WIN32
268
        FreeLibrary((HMODULE)p->handler);
269
#else
270
0
        dlclose(p->handler);
271
0
#endif
272
0
    }
273
274
0
}
275
276
void mk_plugin_api_init(struct mk_server *server)
277
0
{
278
0
    struct plugin_api *api;
279
280
    /* Create an instance of the API */
281
0
    api = mk_mem_alloc_z(sizeof(struct plugin_api));
282
283
0
#ifndef _WIN32
284
0
    __builtin_prefetch(api);
285
0
#endif
286
287
    /* Setup and connections list */
288
    /* FIXME: api->config = server; */
289
290
    /* API plugins funcions */
291
292
    /* Error helper */
293
0
    api->_error = mk_print;
294
295
    /* HTTP callbacks */
296
0
    api->http_request_end = mk_plugin_http_request_end;
297
0
    api->http_request_error = mk_plugin_http_error;
298
299
    /* Memory callbacks */
300
0
    api->pointer_set = mk_ptr_set;
301
0
    api->pointer_print = mk_ptr_print;
302
0
    api->pointer_to_buf = mk_ptr_to_buf;
303
0
    api->plugin_load_symbol = mk_plugin_load_symbol;
304
0
    api->mem_alloc = mk_mem_alloc;
305
0
    api->mem_alloc_z = mk_mem_alloc_z;
306
0
    api->mem_realloc = mk_mem_realloc;
307
0
    api->mem_free = mk_mem_free;
308
309
    /* String Callbacks */
310
0
    api->str_build = mk_string_build;
311
0
    api->str_dup = mk_string_dup;
312
0
    api->str_search = mk_string_search;
313
0
    api->str_search_n = mk_string_search_n;
314
0
    api->str_char_search = mk_string_char_search;
315
0
    api->str_copy_substr = mk_string_copy_substr;
316
0
    api->str_itop = mk_string_itop;
317
0
    api->str_split_line = mk_string_split_line;
318
0
    api->str_split_free = mk_string_split_free;
319
320
    /* File Callbacks */
321
0
    api->file_to_buffer = mk_file_to_buffer;
322
0
    api->file_get_info = mk_file_get_info;
323
324
    /* HTTP Callbacks */
325
0
    api->header_prepare = mk_plugin_header_prepare;
326
0
    api->header_add = mk_plugin_header_add;
327
0
    api->header_get = mk_http_header_get;
328
0
    api->header_set_http_status = mk_header_set_http_status;
329
330
    /* Channels / Streams */
331
0
    api->channel_new   = mk_channel_new;
332
0
    api->channel_flush = mk_channel_flush;
333
0
    api->channel_write = mk_channel_write;
334
0
    api->channel_append_stream = mk_channel_append_stream;
335
336
    /* IOV callbacks */
337
0
    api->iov_create  = mk_iov_create;
338
0
    api->iov_realloc = mk_iov_realloc;
339
0
    api->iov_free = mk_iov_free;
340
0
    api->iov_free_marked = mk_iov_free_marked;
341
0
    api->iov_add =  mk_iov_add;
342
0
    api->iov_set_entry =  mk_iov_set_entry;
343
0
    api->iov_send =  mk_iov_send;
344
0
    api->iov_print =  mk_iov_print;
345
346
    /* events mechanism */
347
0
    api->ev_loop_create = mk_event_loop_create;
348
0
    api->ev_add = mk_event_add;
349
0
    api->ev_del = mk_event_del;
350
0
    api->ev_timeout_create = mk_event_timeout_create;
351
0
    api->ev_channel_create = mk_event_channel_create;
352
0
    api->ev_wait = mk_event_wait;
353
0
    api->ev_backend = mk_event_backend;
354
355
    /* Mimetype */
356
0
    api->mimetype_lookup = mk_mimetype_lookup;
357
358
    /* Socket callbacks */
359
0
    api->socket_cork_flag = mk_socket_set_cork_flag;
360
0
    api->socket_connect = mk_socket_connect;
361
0
    api->socket_open = mk_socket_open;
362
0
    api->socket_reset = mk_socket_reset;
363
0
    api->socket_set_tcp_fastopen = mk_socket_set_tcp_fastopen;
364
0
    api->socket_set_tcp_reuseport = mk_socket_set_tcp_reuseport;
365
0
    api->socket_set_tcp_nodelay = mk_socket_set_tcp_nodelay;
366
0
    api->socket_set_nonblocking = mk_socket_set_nonblocking;
367
0
    api->socket_create = mk_socket_create;
368
0
    api->socket_ip_str = mk_socket_ip_str;
369
370
    /* Async network */
371
0
    api->net_conn_create = mk_net_conn_create;
372
373
    /* Config Callbacks */
374
0
    api->config_create = mk_rconf_create;
375
0
    api->config_open = mk_rconf_open;
376
0
    api->config_free = mk_rconf_free;
377
0
    api->config_section_get = mk_rconf_section_get;
378
0
    api->config_section_get_key = mk_rconf_section_get_key;
379
380
    /* Scheduler and Event callbacks */
381
0
    api->sched_loop           = mk_sched_loop;
382
0
    api->sched_get_connection = mk_sched_get_connection;
383
0
    api->sched_event_free     = mk_sched_event_free;
384
0
    api->sched_remove_client  = mk_plugin_sched_remove_client;
385
0
    api->sched_worker_info    = mk_plugin_sched_get_thread_conf;
386
387
    /* Worker functions */
388
0
    api->worker_spawn = mk_utils_worker_spawn;
389
0
    api->worker_rename = mk_utils_worker_rename;
390
391
    /* Time functions */
392
0
    api->time_unix   = mk_plugin_time_now_unix;
393
0
    api->time_to_gmt = mk_utils_utime2gmt;
394
0
    api->time_human  = mk_plugin_time_now_human;
395
396
0
    api->stacktrace = (void *) mk_utils_stacktrace;
397
0
    api->kernel_version = mk_kernel_version;
398
0
    api->kernel_features_print = mk_kernel_features_print;
399
0
    api->plugins = &server->plugins;
400
401
    /* handler */
402
0
    api->handler_param_get = mk_handler_param_get;
403
404
0
    server->api = api;
405
0
}
406
407
void mk_plugin_load_static(struct mk_server *server)
408
0
{
409
    /* Load static plugins */
410
0
    mk_list_init(&server->plugins);
411
0
    mk_static_plugins(&server->plugins);
412
0
}
413
414
void mk_plugin_load_all(struct mk_server *server)
415
0
{
416
0
    int ret;
417
0
    char *tmp;
418
0
    char *path;
419
0
    char shortname[64];
420
0
    struct mk_plugin *p;
421
0
    struct mk_rconf *cnf;
422
0
    struct mk_rconf_section *section;
423
0
    struct mk_rconf_entry *entry;
424
0
    struct mk_list *head;
425
0
    struct mk_list *htmp;
426
0
    struct file_info f_info;
427
428
0
    mk_plugin_load_static(server);
429
0
    mk_list_foreach_safe(head, htmp, &server->plugins) {
430
0
        p = mk_list_entry(head, struct mk_plugin, _head);
431
432
        /* Load the static plugin */
433
0
        p = mk_plugin_load(MK_PLUGIN_STATIC,
434
0
                           p->shortname,
435
0
                           (void *) p,
436
0
                           server);
437
0
        if (!p) {
438
0
            continue;
439
0
        }
440
0
        ret = mk_plugin_init(server->api, p, server);
441
0
        if (ret == -1) {
442
            /* Free plugin, do not register, error initializing */
443
0
            mk_warn("Plugin initialization failed: %s", p->shortname);
444
0
            mk_plugin_unregister(p);
445
0
            continue;
446
0
        }
447
0
        else if (ret == -2) {
448
            /* Do not register, just skip it */
449
0
            mk_plugin_unregister(p);
450
0
            continue;
451
0
        }
452
0
    }
453
454
    /* In case there are not dynamic plugins */
455
0
    if (!server->conf_plugin_load) {
456
0
        return;
457
0
    }
458
459
    /* Read configuration file */
460
0
    path = mk_mem_alloc_z(1024);
461
0
    snprintf(path, 1024, "%s/%s", server->path_conf_root,
462
0
             server->conf_plugin_load);
463
0
    ret = mk_file_get_info(path, &f_info, MK_FILE_READ);
464
0
    if (ret == -1 || f_info.is_file == MK_FALSE) {
465
0
        snprintf(path, 1024, "%s", server->conf_plugin_load);
466
0
    }
467
468
0
    cnf = mk_rconf_open(path);
469
0
    if (!cnf) {
470
0
        mk_warn("No dynamic plugins loaded.");
471
0
        mk_mem_free(path);
472
0
        return;
473
0
    }
474
475
    /* Read section 'PLUGINS' */
476
0
    section = mk_rconf_section_get(cnf, "PLUGINS");
477
0
    if (!section) {
478
0
        exit(EXIT_FAILURE);
479
0
    }
480
481
    /* Read key entries */
482
0
    mk_list_foreach_safe(head, htmp, &section->entries) {
483
0
        entry = mk_list_entry(head, struct mk_rconf_entry, _head);
484
0
        if (strcasecmp(entry->key, "Load") == 0) {
485
486
            /* Get plugin 'shortname' */
487
0
            tmp = memrchr(entry->val, '-', strlen(entry->val));
488
0
            ++tmp;
489
0
            memset(shortname, '\0', sizeof(shortname) - 1);
490
0
            strncpy(shortname, tmp, strlen(tmp) - 3);
491
492
            /* Load the dynamic plugin */
493
0
            p = mk_plugin_load(MK_PLUGIN_DYNAMIC,
494
0
                               shortname,
495
0
                               entry->val,
496
0
                               server);
497
0
            if (!p) {
498
0
                mk_warn("Invalid plugin '%s'", entry->val);
499
0
                continue;
500
0
            }
501
502
0
            ret = mk_plugin_init(server->api, p, server);
503
0
            if (ret < 0) {
504
                /* Free plugin, do not register */
505
0
                MK_TRACE("Unregister plugin '%s'", p->shortname);
506
0
                mk_plugin_unregister(p);
507
0
                continue;
508
0
            }
509
0
        }
510
0
    }
511
512
    /* Look for plugins thread key data */
513
0
    mk_plugin_preworker_calls(server);
514
0
    mk_vhost_map_handlers(server);
515
0
    mk_mem_free(path);
516
0
    mk_rconf_free(cnf);
517
0
}
518
519
static void mk_plugin_exit_stages(struct mk_plugin *p)
520
0
{
521
0
    struct mk_list *tmp;
522
0
    struct mk_list *head;
523
0
    struct mk_plugin_stage *st;
524
525
0
    mk_list_foreach_safe(head, tmp, &p->stage_list) {
526
0
        st = mk_list_entry(head, struct mk_plugin_stage, _parent_head);
527
528
        /* remove from direct config->stageN head list */
529
0
        mk_list_del(&st->_head);
530
531
        /* remove from plugin->stage_lists */
532
0
        mk_list_del(&st->_parent_head);
533
0
        mk_mem_free(st);
534
0
    }
535
0
}
536
537
/* Invoke all plugins 'exit' hook and free resources by the plugin interface */
538
void mk_plugin_exit_all(struct mk_server *server)
539
0
{
540
0
    struct mk_plugin *plugin;
541
0
    struct mk_list *head, *tmp;
542
543
    /* Plugins */
544
0
    mk_list_foreach(head, &server->plugins) {
545
0
        plugin = mk_list_entry(head, struct mk_plugin, _head);
546
0
        plugin->exit_plugin(plugin);
547
0
    }
548
549
    /* Plugin interface it self */
550
0
    mk_list_foreach_safe(head, tmp, &server->plugins) {
551
0
        plugin = mk_list_entry(head, struct mk_plugin, _head);
552
0
        mk_list_del(&plugin->_head);
553
0
        mk_plugin_exit_stages(plugin);
554
555
0
        if (plugin->load_type == MK_PLUGIN_DYNAMIC) {
556
0
            mk_mem_free(plugin->path);
557
#ifdef _WIN32
558
            FreeLibrary((HMODULE)plugin->handler);
559
#else
560
0
            dlclose(plugin ->handler);
561
0
#endif
562
0
        }
563
0
        else if (plugin->load_type == MK_PLUGIN_STATIC) {
564
0
            if (plugin->network != NULL) {
565
0
                mk_mem_free(plugin->network);
566
0
            }
567
568
0
            mk_mem_free(plugin);
569
0
        }
570
0
    }
571
572
0
    mk_mem_free(server->api);
573
0
    mk_mem_free(plg_stagemap);
574
0
}
575
576
/*
577
 * When a worker is exiting, it invokes this function to release any plugin
578
 * associated data.
579
 */
580
void mk_plugin_exit_worker()
581
0
{
582
0
}
583
584
/* This function is called by every created worker
585
 * for plugins which need to set some data under a thread
586
 * context
587
 */
588
void mk_plugin_core_process(struct mk_server *server)
589
0
{
590
0
    struct mk_plugin *node;
591
0
    struct mk_list *head;
592
593
0
    mk_list_foreach(head, &server->plugins) {
594
0
        node = mk_list_entry(head, struct mk_plugin, _head);
595
596
        /* Init plugin */
597
0
        if (node->master_init) {
598
0
            node->master_init(server);
599
0
        }
600
0
    }
601
0
}
602
603
/* This function is called by every created worker
604
 * for plugins which need to set some data under a thread
605
 * context
606
 */
607
void mk_plugin_core_thread(struct mk_server *server)
608
0
{
609
610
0
    struct mk_plugin *node;
611
0
    struct mk_list *head;
612
613
0
    mk_list_foreach(head, &server->plugins) {
614
0
        node = mk_list_entry(head, struct mk_plugin, _head);
615
616
        /* Init plugin thread context */
617
0
        if (node->worker_init) {
618
0
            node->worker_init(server);
619
0
        }
620
0
    }
621
0
}
622
623
/* This function is called by Monkey *outside* of the
624
 * thread context for plugins, so here's the right
625
 * place to set pthread keys or similar
626
 */
627
void mk_plugin_preworker_calls(struct mk_server *server)
628
0
{
629
0
    int ret;
630
0
    struct mk_plugin *node;
631
0
    struct mk_list *head;
632
633
0
    mk_list_foreach(head, &server->plugins) {
634
0
        node = mk_list_entry(head, struct mk_plugin, _head);
635
636
        /* Init pthread keys */
637
0
        if (node->thread_key) {
638
0
            MK_TRACE("[%s] Set thread key", node->shortname);
639
640
0
            ret = pthread_key_create(node->thread_key, NULL);
641
0
            if (ret != 0) {
642
0
                mk_err("Plugin Error: could not create key for %s",
643
0
                       node->shortname);
644
0
            }
645
0
        }
646
0
    }
647
0
}
648
649
int mk_plugin_http_error(int http_status, struct mk_http_session *cs,
650
                         struct mk_http_request *sr,
651
                         struct mk_plugin *plugin)
652
0
{
653
0
    return mk_http_error(http_status, cs, sr, plugin->server_ctx);
654
0
}
655
656
657
int mk_plugin_http_request_end(struct mk_plugin *plugin,
658
                               struct mk_http_session *cs, int close)
659
0
{
660
0
    int ret;
661
0
    int con;
662
0
    struct mk_http_request *sr;
663
0
    struct mk_server *server = plugin->server_ctx;
664
665
0
    MK_TRACE("[FD %i] PLUGIN HTTP REQUEST END", cs->socket);
666
667
0
    cs->status = MK_REQUEST_STATUS_INCOMPLETE;
668
0
    if (mk_list_is_empty(&cs->request_list) == 0) {
669
0
        MK_TRACE("[FD %i] Tried to end non-existing request.", cs->socket);
670
0
        return -1;
671
0
    }
672
673
0
    sr = mk_list_entry_last(&cs->request_list, struct mk_http_request, _head);
674
0
    mk_plugin_stage_run_40(cs, sr, server);
675
676
0
    if (close == MK_TRUE) {
677
0
        cs->close_now = MK_TRUE;
678
0
    }
679
680
    /* Let's check if we should ask to finalize the connection or not */
681
0
    ret = mk_http_request_end(cs, server);
682
0
    MK_TRACE("[FD %i] HTTP session end = %i", cs->socket, ret);
683
0
    if (ret < 0) {
684
0
        con = mk_sched_event_close(cs->conn, mk_sched_get_thread_conf(),
685
0
                                   MK_EP_SOCKET_DONE, server);
686
0
        if (con != 0) {
687
0
            return con;
688
0
        }
689
0
        else {
690
0
            return -1;
691
0
        }
692
0
    }
693
694
0
    return ret;
695
0
}
696
697
/* Plugin epoll event handlers
698
 * ---------------------------
699
 * this functions are called by connection.c functions as mk_conn_read(),
700
 * mk_conn_write(),mk_conn_error(), mk_conn_close() and mk_conn_timeout().
701
 *
702
 * Return Values:
703
 * -------------
704
 *    MK_PLUGIN_RET_EVENT_NOT_ME: There's no plugin hook associated
705
 */
706
707
void mk_plugin_event_bad_return(const char *hook, int ret)
708
0
{
709
0
    mk_err("[%s] Not allowed return value %i", hook, ret);
710
0
}
711
712
int mk_plugin_time_now_unix(struct mk_server *server)
713
0
{
714
0
    return server->clock_context->log_current_utime;
715
0
}
716
717
mk_ptr_t *mk_plugin_time_now_human(struct mk_server *server)
718
0
{
719
0
    return &server->clock_context->log_current_time;
720
0
}
721
722
int mk_plugin_sched_remove_client(int socket, struct mk_server *server)
723
0
{
724
0
    struct mk_sched_conn *conn;
725
0
    struct mk_sched_worker *sched;
726
727
0
    MK_TRACE("[FD %i] remove client", socket);
728
729
0
    sched = mk_sched_get_thread_conf();
730
0
    conn  = mk_sched_get_connection(sched, socket);
731
0
    if (!conn) {
732
0
        return -1;
733
0
    }
734
735
0
    return mk_sched_remove_client(conn, sched, server);
736
0
}
737
738
int mk_plugin_header_prepare(struct mk_plugin *plugin,
739
                             struct mk_http_session *cs,
740
                             struct mk_http_request *sr)
741
0
{
742
0
    return mk_header_prepare(cs, sr, plugin->server_ctx);
743
0
}
744
745
746
int mk_plugin_header_add(struct mk_http_request *sr, char *row, int len)
747
0
{
748
0
    mk_bug(!sr);
749
750
0
    if (!sr->headers._extra_rows) {
751
        /*
752
         * We allocate space for a fixed number of IOV entries:
753
         *
754
         *   MK_PLUGIN_HEADER_EXTRA_ROWS = X
755
         *
756
         *  we use (MK_PLUGIN_HEADER_EXTRA_ROWS * 2) thinking in an ending CRLF
757
         */
758
0
        sr->headers._extra_rows = mk_iov_create(MK_PLUGIN_HEADER_EXTRA_ROWS * 2, 0);
759
0
        mk_bug(!sr->headers._extra_rows);
760
0
    }
761
762
0
    mk_iov_add(sr->headers._extra_rows, row, len,
763
0
               MK_FALSE);
764
0
    mk_iov_add(sr->headers._extra_rows,
765
0
               mk_iov_crlf.data, mk_iov_crlf.len,
766
0
               MK_FALSE);
767
0
    return 0;
768
0
}
769
770
struct mk_sched_worker *mk_plugin_sched_get_thread_conf()
771
0
{
772
0
    return MK_TLS_GET(mk_tls_sched_worker_node);
773
0
}
774
775
struct mk_plugin *mk_plugin_cap(char cap, struct mk_server *server)
776
0
{
777
0
    struct mk_list *head;
778
0
    struct mk_plugin *plugin;
779
780
0
    mk_list_foreach(head, &server->plugins) {
781
0
        plugin = mk_list_entry(head, struct mk_plugin, _head);
782
0
        if (plugin->capabilities & cap) {
783
0
            return plugin;
784
0
        }
785
0
    }
786
787
0
    return NULL;
788
0
}
789
790
struct mk_vhost_handler_param *mk_handler_param_get(int id,
791
                                                    struct mk_list *params)
792
0
{
793
0
    int i = 0;
794
0
    struct mk_list *head;
795
796
0
    mk_list_foreach(head, params) {
797
0
        if (i == id) {
798
0
            return mk_list_entry(head, struct mk_vhost_handler_param, _head);
799
0
        }
800
0
        i++;
801
0
    }
802
803
0
    return NULL;
804
0
}