Imported Upstream version 3.2.0
[platform/upstream/libwebsockets.git] / lib / plat / unix / unix-plugins.c
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Lesser General Public
8  *  License as published by the Free Software Foundation:
9  *  version 2.1 of the License.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public
17  *  License along with this library; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  *  MA  02110-1301  USA
20  */
21
22 #define _GNU_SOURCE
23 #include "core/private.h"
24
25 #include <pwd.h>
26 #include <grp.h>
27
28 #ifdef LWS_WITH_PLUGINS
29 #include <dlfcn.h>
30 #endif
31 #include <dirent.h>
32
33 static int filter(const struct dirent *ent)
34 {
35         if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
36                 return 0;
37
38         return 1;
39 }
40
41 int
42 lws_plat_plugins_init(struct lws_context * context, const char * const *d)
43 {
44         struct lws_plugin_capability lcaps;
45         struct lws_plugin *plugin;
46         lws_plugin_init_func initfunc;
47         struct dirent **namelist;
48         int n, i, m, ret = 0;
49         char path[256];
50         void *l;
51
52 #if defined(LWS_WITH_PLUGINS) && (UV_VERSION_MAJOR > 0)
53         if (lws_check_opt(context->options, LWS_SERVER_OPTION_LIBUV))
54                 return lws_uv_plugins_init(context, d);
55 #endif
56
57         lwsl_notice("  Plugins:\n");
58
59         while (d && *d) {
60                 n = scandir(*d, &namelist, filter, alphasort);
61                 if (n < 0) {
62                         lwsl_err("Scandir on %s failed\n", *d);
63                         return 1;
64                 }
65
66                 for (i = 0; i < n; i++) {
67                         if (strlen(namelist[i]->d_name) < 7)
68                                 goto inval;
69
70                         lwsl_notice("   %s\n", namelist[i]->d_name);
71
72                         lws_snprintf(path, sizeof(path) - 1, "%s/%s", *d,
73                                  namelist[i]->d_name);
74                         l = dlopen(path, RTLD_NOW);
75                         if (!l) {
76                                 lwsl_err("Error loading DSO: %s\n", dlerror());
77                                 while (i++ < n)
78                                         free(namelist[i]);
79                                 goto bail;
80                         }
81                         /* we could open it, can we get his init function? */
82                         m = lws_snprintf(path, sizeof(path) - 1, "init_%s",
83                                      namelist[i]->d_name + 3 /* snip lib... */);
84                         path[m - 3] = '\0'; /* snip the .so */
85                         initfunc = dlsym(l, path);
86                         if (!initfunc) {
87                                 lwsl_err("Failed to get init on %s: %s",
88                                                 namelist[i]->d_name, dlerror());
89                                 dlclose(l);
90                         }
91                         lcaps.api_magic = LWS_PLUGIN_API_MAGIC;
92                         m = initfunc(context, &lcaps);
93                         if (m) {
94                                 lwsl_err("Initializing %s failed %d\n",
95                                         namelist[i]->d_name, m);
96                                 dlclose(l);
97                                 goto skip;
98                         }
99
100                         plugin = lws_malloc(sizeof(*plugin), "plugin");
101                         if (!plugin) {
102                                 lwsl_err("OOM\n");
103                                 goto bail;
104                         }
105                         plugin->list = context->plugin_list;
106                         context->plugin_list = plugin;
107                         lws_strncpy(plugin->name, namelist[i]->d_name,
108                                     sizeof(plugin->name));
109                         plugin->l = l;
110                         plugin->caps = lcaps;
111                         context->plugin_protocol_count += lcaps.count_protocols;
112                         context->plugin_extension_count += lcaps.count_extensions;
113
114                         free(namelist[i]);
115                         continue;
116
117         skip:
118                         dlclose(l);
119         inval:
120                         free(namelist[i]);
121                 }
122                 free(namelist);
123                 d++;
124         }
125
126         return 0;
127
128 bail:
129         free(namelist);
130
131         return ret;
132 }
133
134 int
135 lws_plat_plugins_destroy(struct lws_context * context)
136 {
137         struct lws_plugin *plugin = context->plugin_list, *p;
138         lws_plugin_destroy_func func;
139         char path[256];
140         int m;
141
142 #if defined(LWS_WITH_PLUGINS) && (UV_VERSION_MAJOR > 0)
143         if (lws_check_opt(context->options, LWS_SERVER_OPTION_LIBUV))
144                 return lws_uv_plugins_destroy(context);
145 #endif
146
147         if (!plugin)
148                 return 0;
149
150         lwsl_notice("%s\n", __func__);
151
152         while (plugin) {
153                 p = plugin;
154                 m = lws_snprintf(path, sizeof(path) - 1, "destroy_%s",
155                                  plugin->name + 3);
156                 path[m - 3] = '\0';
157                 func = dlsym(plugin->l, path);
158                 if (!func) {
159                         lwsl_err("Failed to get destroy on %s: %s",
160                                         plugin->name, dlerror());
161                         goto next;
162                 }
163                 m = func(context);
164                 if (m)
165                         lwsl_err("Initializing %s failed %d\n",
166                                 plugin->name, m);
167 next:
168                 dlclose(p->l);
169                 plugin = p->list;
170                 p->list = NULL;
171                 free(p);
172         }
173
174         context->plugin_list = NULL;
175
176         return 0;
177 }