1 /*
2 * libwebsockets - small server side websockets and web server implementation
3 *
4 * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 * IN THE SOFTWARE.
23 */
24
25 #include <private-lib-core.h>
26
27 /*
28 * It's either a buflist (.is_direct = 0) or
29 * a direct pointer + len (.is_direct = 1)
30 */
31
32 const lws_system_ops_t *
lws_system_get_ops(struct lws_context * context)33 lws_system_get_ops(struct lws_context *context)
34 {
35 return context->system_ops;
36 }
37
38
39 void
lws_system_blob_direct_set(lws_system_blob_t * b,const uint8_t * ptr,size_t len)40 lws_system_blob_direct_set(lws_system_blob_t *b, const uint8_t *ptr, size_t len)
41 {
42 b->is_direct = 1;
43 b->u.direct.ptr = ptr;
44 b->u.direct.len = len;
45 }
46
47 void
lws_system_blob_heap_empty(lws_system_blob_t * b)48 lws_system_blob_heap_empty(lws_system_blob_t *b)
49 {
50 b->is_direct = 0;
51 lws_buflist_destroy_all_segments(&b->u.bl);
52 }
53
54 int
lws_system_blob_heap_append(lws_system_blob_t * b,const uint8_t * buf,size_t len)55 lws_system_blob_heap_append(lws_system_blob_t *b, const uint8_t *buf, size_t len)
56 {
57 assert(!b->is_direct);
58
59 lwsl_debug("%s: blob %p\n", __func__, b);
60
61 if (lws_buflist_append_segment(&b->u.bl, buf, len) < 0)
62 return -1;
63
64 return 0;
65 }
66
67 size_t
lws_system_blob_get_size(lws_system_blob_t * b)68 lws_system_blob_get_size(lws_system_blob_t *b)
69 {
70 if (b->is_direct)
71 return b->u.direct.len;
72
73 return lws_buflist_total_len(&b->u.bl);
74 }
75
76 int
lws_system_blob_get(lws_system_blob_t * b,uint8_t * buf,size_t * len,size_t ofs)77 lws_system_blob_get(lws_system_blob_t *b, uint8_t *buf, size_t *len, size_t ofs)
78 {
79 int n;
80
81 if (b->is_direct) {
82
83 assert(b->u.direct.ptr);
84
85 if (ofs >= b->u.direct.len) {
86 *len = 0;
87 return 1;
88 }
89
90 if (*len > b->u.direct.len - ofs)
91 *len = b->u.direct.len - ofs;
92
93 memcpy(buf, b->u.direct.ptr + ofs, *len);
94
95 return 0;
96 }
97
98 n = lws_buflist_linear_copy(&b->u.bl, ofs, buf, *len);
99 if (n < 0)
100 return -2;
101
102 *len = (unsigned int)n;
103
104 return 0;
105 }
106
107 int
lws_system_blob_get_single_ptr(lws_system_blob_t * b,const uint8_t ** ptr)108 lws_system_blob_get_single_ptr(lws_system_blob_t *b, const uint8_t **ptr)
109 {
110 if (b->is_direct) {
111 *ptr = b->u.direct.ptr;
112 return 0;
113 }
114
115 if (!b->u.bl)
116 return -1;
117
118 if (b->u.bl->next)
119 return -1; /* multipart buflist, no single pointer to it all */
120
121 *ptr = (const uint8_t *)&b->u.bl[1] + LWS_PRE;
122
123 return 0;
124 }
125
126 void
lws_system_blob_destroy(lws_system_blob_t * b)127 lws_system_blob_destroy(lws_system_blob_t *b)
128 {
129 if (!b)
130 return;
131 // lwsl_info("%s: blob %p\n", __func__, b);
132 if (!b->is_direct)
133 lws_buflist_destroy_all_segments(&b->u.bl);
134 }
135
136 lws_system_blob_t *
lws_system_get_blob(struct lws_context * context,lws_system_blob_item_t type,int idx)137 lws_system_get_blob(struct lws_context *context, lws_system_blob_item_t type,
138 int idx)
139 {
140 if (idx < 0 ||
141 idx >= (int)LWS_ARRAY_SIZE(context->system_blobs))
142 return NULL;
143
144 return &context->system_blobs[type + (unsigned int)idx];
145 }
146
147 #if defined(LWS_WITH_NETWORK)
148
149 /*
150 * Caller must protect the whole call with system-specific locking
151 */
152
153 int
__lws_system_attach(struct lws_context * context,int tsi,lws_attach_cb_t cb,lws_system_states_t state,void * opaque,struct lws_attach_item ** get)154 __lws_system_attach(struct lws_context *context, int tsi, lws_attach_cb_t cb,
155 lws_system_states_t state, void *opaque,
156 struct lws_attach_item **get)
157 {
158 struct lws_context_per_thread *pt = &context->pt[tsi];
159 struct lws_attach_item *item;
160
161 if (!get) {
162 /*
163 * allocate and add to the head of the pt's attach list
164 */
165
166 item = lws_zalloc(sizeof(*item), __func__);
167 if (!item)
168 return 1;
169
170 item->cb = cb;
171 item->opaque = opaque;
172 item->state = state;
173
174 lws_dll2_add_head(&item->list, &pt->attach_owner);
175
176 lws_cancel_service(context);
177
178 return 0;
179 }
180
181 *get = NULL;
182 #if defined(LWS_WITH_SYS_STATE)
183 if (!pt->attach_owner.count)
184 return 0;
185
186 /*
187 * If any, return the first guy whose state requirement matches
188 */
189
190 lws_start_foreach_dll(struct lws_dll2 *, d,
191 lws_dll2_get_head(&pt->attach_owner)) {
192 item = lws_container_of(d, lws_attach_item_t, list);
193
194 if (pt->context->mgr_system.state >= (int)item->state) {
195 *get = item;
196 lws_dll2_remove(d);
197
198 /*
199 * We detached it, but the caller now has the
200 * responsibility to lws_free() *get.
201 */
202
203 return 0;
204 }
205 } lws_end_foreach_dll(d);
206 #endif
207
208 /* nobody ready to go... leave *get as NULL and return cleanly */
209
210 return 0;
211 }
212
213 int
lws_system_do_attach(struct lws_context_per_thread * pt)214 lws_system_do_attach(struct lws_context_per_thread *pt)
215 {
216 /*
217 * If nothing to do, we just return immediately
218 */
219
220 while (pt->attach_owner.count) {
221
222 struct lws_attach_item *item;
223
224 /*
225 * If anybody used the attach apis, there must be an
226 * implementation of the (*attach) lws_system op function
227 */
228
229 assert(pt->context->system_ops->attach);
230 if (!pt->context->system_ops->attach) {
231 lwsl_err("%s: define (*attach)\n", __func__);
232 return 1;
233 }
234
235 /*
236 * System locking is applied only around this next call, while
237 * we detach and get a pointer to the tail attach item. We
238 * become responsible to free what we have detached.
239 */
240
241 if (pt->context->system_ops->attach(pt->context, pt->tid, NULL,
242 0, NULL, &item)) {
243 lwsl_err("%s: attach problem\n", __func__);
244 return 1;
245 }
246
247 if (!item)
248 /* there's nothing more to do at the moment */
249 return 0;
250
251 /*
252 * Do the callback from the lws event loop thread
253 */
254
255 item->cb(pt->context, pt->tid, item->opaque);
256
257 /* it's done, destroy the item */
258
259 lws_free(item);
260 }
261
262 return 0;
263 }
264
265 #endif
266