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 = 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];
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 + 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 (!pt->attach_owner.count)
183 		return 0;
184 
185 	/*
186 	 * If any, return the first guy whose state requirement matches
187 	 */
188 
189 	lws_start_foreach_dll(struct lws_dll2 *, d,
190 			      lws_dll2_get_head(&pt->attach_owner)) {
191 		item = lws_container_of(d, lws_attach_item_t, list);
192 
193 		if (pt->context->mgr_system.state >= (int)item->state) {
194 			*get = item;
195 			lws_dll2_remove(d);
196 
197 			/*
198 			 * We detached it, but the caller now has the
199 			 * responsibility to lws_free() *get.
200 			 */
201 
202 			return 0;
203 		}
204 	} lws_end_foreach_dll(d);
205 
206 	/* nobody ready to go... leave *get as NULL and return cleanly */
207 
208 	return 0;
209 }
210 
211 int
lws_system_do_attach(struct lws_context_per_thread * pt)212 lws_system_do_attach(struct lws_context_per_thread *pt)
213 {
214 	/*
215 	 * If nothing to do, we just return immediately
216 	 */
217 
218 	while (pt->attach_owner.count) {
219 
220 		struct lws_attach_item *item;
221 
222 		/*
223 		 * If anybody used the attach apis, there must be an
224 		 * implementation of the (*attach) lws_system op function
225 		 */
226 
227 		assert(pt->context->system_ops->attach);
228 		if (!pt->context->system_ops->attach) {
229 			lwsl_err("%s: define (*attach)\n", __func__);
230 			return 1;
231 		}
232 
233 		/*
234 		 * System locking is applied only around this next call, while
235 		 * we detach and get a pointer to the tail attach item.  We
236 		 * become responsible to free what we have detached.
237 		 */
238 
239 		if (pt->context->system_ops->attach(pt->context, pt->tid, NULL,
240 						    0, NULL, &item)) {
241 			lwsl_err("%s: attach problem\n", __func__);
242 			return 1;
243 		}
244 
245 		if (!item)
246 			/* there's nothing more to do at the moment */
247 			return 0;
248 
249 		/*
250 		 * Do the callback from the lws event loop thread
251 		 */
252 
253 		item->cb(pt->context, pt->tid, item->opaque);
254 
255 		/* it's done, destroy the item */
256 
257 		lws_free(item);
258 	}
259 
260 	return 0;
261 }
262 
263 #endif
264