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
32const lws_system_ops_t *
33lws_system_get_ops(struct lws_context *context)
34{
35	return context->system_ops;
36}
37
38
39void
40lws_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
47void
48lws_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
54int
55lws_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
67size_t
68lws_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
76int
77lws_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
107int
108lws_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
126void
127lws_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
136lws_system_blob_t *
137lws_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
153int
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
213int
214lws_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