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 #include "extension-permessage-deflate.h"
27 #include <stdio.h>
28 #include <string.h>
29 #include <assert.h>
30 
31 #define LWS_ZLIB_MEMLEVEL 8
32 
33 const struct lws_ext_options lws_ext_pm_deflate_options[] = {
34 	/* public RFC7692 settings */
35 	{ "server_no_context_takeover", EXTARG_NONE },
36 	{ "client_no_context_takeover", EXTARG_NONE },
37 	{ "server_max_window_bits",	EXTARG_OPT_DEC },
38 	{ "client_max_window_bits",	EXTARG_OPT_DEC },
39 	/* ones only user code can set */
40 	{ "rx_buf_size",		EXTARG_DEC },
41 	{ "tx_buf_size",		EXTARG_DEC },
42 	{ "compression_level",		EXTARG_DEC },
43 	{ "mem_level",			EXTARG_DEC },
44 	{ NULL, 0 }, /* sentinel */
45 };
46 
47 static void
lws_extension_pmdeflate_restrict_args(struct lws * wsi,struct lws_ext_pm_deflate_priv * priv)48 lws_extension_pmdeflate_restrict_args(struct lws *wsi,
49 				      struct lws_ext_pm_deflate_priv *priv)
50 {
51 	int n, extra;
52 
53 	/* cap the RX buf at the nearest power of 2 to protocol rx buf */
54 
55 	n = (int)wsi->a.context->pt_serv_buf_size;
56 	if (wsi->a.protocol->rx_buffer_size)
57 		n = (int)wsi->a.protocol->rx_buffer_size;
58 
59 	extra = 7;
60 	while (n >= 1 << (extra + 1))
61 		extra++;
62 
63 	if (extra < priv->args[PMD_RX_BUF_PWR2]) {
64 		priv->args[PMD_RX_BUF_PWR2] = (unsigned char)extra;
65 		lwsl_info(" Capping pmd rx to %d\n", 1 << extra);
66 	}
67 }
68 
69 static unsigned char trail[] = { 0, 0, 0xff, 0xff };
70 
71 LWS_VISIBLE int
lws_extension_callback_pm_deflate(struct lws_context * context,const struct lws_extension * ext,struct lws * wsi,enum lws_extension_callback_reasons reason,void * user,void * in,size_t len)72 lws_extension_callback_pm_deflate(struct lws_context *context,
73 				  const struct lws_extension *ext,
74 				  struct lws *wsi,
75 				  enum lws_extension_callback_reasons reason,
76 				  void *user, void *in, size_t len)
77 {
78 	struct lws_ext_pm_deflate_priv *priv =
79 				     (struct lws_ext_pm_deflate_priv *)user;
80 	struct lws_ext_pm_deflate_rx_ebufs *pmdrx =
81 				(struct lws_ext_pm_deflate_rx_ebufs *)in;
82 	struct lws_ext_option_arg *oa;
83 	int n, ret = 0, was_fin = 0, m;
84 	unsigned int pen = 0;
85 	int penbits = 0;
86 
87 	switch (reason) {
88 	case LWS_EXT_CB_NAMED_OPTION_SET:
89 		oa = in;
90 		if (!oa->option_name)
91 			break;
92 		lwsl_ext("%s: named option set: %s\n", __func__,
93 			 oa->option_name);
94 		for (n = 0; n < (int)LWS_ARRAY_SIZE(lws_ext_pm_deflate_options);
95 		     n++)
96 			if (!strcmp(lws_ext_pm_deflate_options[n].name,
97 				    oa->option_name))
98 				break;
99 
100 		if (n == (int)LWS_ARRAY_SIZE(lws_ext_pm_deflate_options))
101 			break;
102 		oa->option_index = n;
103 
104 		/* fallthru */
105 
106 	case LWS_EXT_CB_OPTION_SET:
107 		oa = in;
108 		lwsl_ext("%s: option set: idx %d, %s, len %d\n", __func__,
109 			 oa->option_index, oa->start, oa->len);
110 		if (oa->start)
111 			priv->args[oa->option_index] = (unsigned char)atoi(oa->start);
112 		else
113 			priv->args[oa->option_index] = 1;
114 
115 		if (priv->args[PMD_CLIENT_MAX_WINDOW_BITS] == 8)
116 			priv->args[PMD_CLIENT_MAX_WINDOW_BITS] = 9;
117 
118 		lws_extension_pmdeflate_restrict_args(wsi, priv);
119 		break;
120 
121 	case LWS_EXT_CB_OPTION_CONFIRM:
122 		if (priv->args[PMD_SERVER_MAX_WINDOW_BITS] < 8 ||
123 		    priv->args[PMD_SERVER_MAX_WINDOW_BITS] > 15 ||
124 		    priv->args[PMD_CLIENT_MAX_WINDOW_BITS] < 8 ||
125 		    priv->args[PMD_CLIENT_MAX_WINDOW_BITS] > 15)
126 			return -1;
127 		break;
128 
129 	case LWS_EXT_CB_CLIENT_CONSTRUCT:
130 	case LWS_EXT_CB_CONSTRUCT:
131 
132 		n = (int)context->pt_serv_buf_size;
133 		if (wsi->a.protocol->rx_buffer_size)
134 			n = (int)wsi->a.protocol->rx_buffer_size;
135 
136 		if (n < 128) {
137 			lwsl_info(" permessage-deflate requires the protocol "
138 				  "(%s) to have an RX buffer >= 128\n",
139 				  wsi->a.protocol->name);
140 			return -1;
141 		}
142 
143 		/* fill in **user */
144 		priv = lws_zalloc(sizeof(*priv), "pmd priv");
145 		*((void **)user) = priv;
146 		lwsl_ext("%s: LWS_EXT_CB_*CONSTRUCT\n", __func__);
147 		memset(priv, 0, sizeof(*priv));
148 
149 		/* fill in pointer to options list */
150 		if (in)
151 			*((const struct lws_ext_options **)in) =
152 					lws_ext_pm_deflate_options;
153 
154 		/* fallthru */
155 
156 	case LWS_EXT_CB_OPTION_DEFAULT:
157 
158 		/* set the public, RFC7692 defaults... */
159 
160 		priv->args[PMD_SERVER_NO_CONTEXT_TAKEOVER] = 0,
161 		priv->args[PMD_CLIENT_NO_CONTEXT_TAKEOVER] = 0;
162 		priv->args[PMD_SERVER_MAX_WINDOW_BITS] = 15;
163 		priv->args[PMD_CLIENT_MAX_WINDOW_BITS] = 15;
164 
165 		/* ...and the ones the user code can override */
166 
167 		priv->args[PMD_RX_BUF_PWR2] = 10; /* ie, 1024 */
168 		priv->args[PMD_TX_BUF_PWR2] = 10; /* ie, 1024 */
169 		priv->args[PMD_COMP_LEVEL] = 1;
170 		priv->args[PMD_MEM_LEVEL] = 8;
171 
172 		lws_extension_pmdeflate_restrict_args(wsi, priv);
173 		break;
174 
175 	case LWS_EXT_CB_DESTROY:
176 		lwsl_ext("%s: LWS_EXT_CB_DESTROY\n", __func__);
177 		lws_free(priv->buf_rx_inflated);
178 		lws_free(priv->buf_tx_deflated);
179 		if (priv->rx_init)
180 			(void)inflateEnd(&priv->rx);
181 		if (priv->tx_init)
182 			(void)deflateEnd(&priv->tx);
183 		lws_free(priv);
184 
185 		return ret;
186 
187 
188 	case LWS_EXT_CB_PAYLOAD_RX:
189 		/*
190 		 * ie, we are INFLATING
191 		 */
192 		lwsl_ext(" %s: LWS_EXT_CB_PAYLOAD_RX: in %d, existing in %d\n",
193 			 __func__, pmdrx->eb_in.len, priv->rx.avail_in);
194 
195 		/*
196 		 * If this frame is not marked as compressed,
197 		 * there is nothing we should do with it
198 		 */
199 
200 		if (!(wsi->ws->rsv_first_msg & 0x40) || (wsi->ws->opcode & 8))
201 			/*
202 			 * This is a bit different than DID_NOTHING... we have
203 			 * identified using ext-private bits in the packet, or
204 			 * by it being a control fragment that we SHOULD not do
205 			 * anything to it, parent should continue as if we
206 			 * processed it
207 			 */
208 			return PMDR_NOTHING_WE_SHOULD_DO;
209 
210 		/*
211 		 * we shouldn't come back in here if we already applied the
212 		 * trailer for this compressed packet
213 		 */
214 		if (!wsi->ws->pmd_trailer_application)
215 			return PMDR_DID_NOTHING;
216 
217 		pmdrx->eb_out.len = 0;
218 
219 		lwsl_ext("%s: LWS_EXT_CB_PAYLOAD_RX: in %d, "
220 			 "existing avail in %d, pkt fin: %d\n", __func__,
221 			 pmdrx->eb_in.len, priv->rx.avail_in, wsi->ws->final);
222 
223 		/* if needed, initialize the inflator */
224 
225 		if (!priv->rx_init) {
226 			if (inflateInit2(&priv->rx,
227 			     -priv->args[PMD_SERVER_MAX_WINDOW_BITS]) != Z_OK) {
228 				lwsl_err("%s: iniflateInit failed\n", __func__);
229 				return PMDR_FAILED;
230 			}
231 			priv->rx_init = 1;
232 			if (!priv->buf_rx_inflated)
233 				priv->buf_rx_inflated = lws_malloc(
234 					(unsigned int)(LWS_PRE + 7 + 5 +
235 					    (1 << priv->args[PMD_RX_BUF_PWR2])),
236 					    "pmd rx inflate buf");
237 			if (!priv->buf_rx_inflated) {
238 				lwsl_err("%s: OOM\n", __func__);
239 				return PMDR_FAILED;
240 			}
241 		}
242 
243 #if 0
244 		/*
245 		 * don't give us new input while we still work through
246 		 * the last input
247 		 */
248 
249 		if (priv->rx.avail_in && pmdrx->eb_in.token &&
250 					 pmdrx->eb_in.len) {
251 			lwsl_warn("%s: priv->rx.avail_in %d while getting new in\n",
252 					__func__, priv->rx.avail_in);
253 	//		assert(0);
254 		}
255 #endif
256 		if (!priv->rx.avail_in && pmdrx->eb_in.token && pmdrx->eb_in.len) {
257 			priv->rx.next_in = (unsigned char *)pmdrx->eb_in.token;
258 			priv->rx.avail_in = (uInt)pmdrx->eb_in.len;
259 		}
260 
261 		priv->rx.next_out = priv->buf_rx_inflated + LWS_PRE;
262 		pmdrx->eb_out.token = priv->rx.next_out;
263 		priv->rx.avail_out = (uInt)(1 << priv->args[PMD_RX_BUF_PWR2]);
264 
265 		/* so... if...
266 		 *
267 		 *  - he has no remaining input content for this message, and
268 		 *
269 		 *  - and this is the final fragment, and
270 		 *
271 		 *  - we used everything that could be drained on the input side
272 		 *
273 		 * ...then put back the 00 00 FF FF the sender stripped as our
274 		 * input to zlib
275 		 */
276 		if (!priv->rx.avail_in &&
277 		    wsi->ws->final &&
278 		    !wsi->ws->rx_packet_length &&
279 		    wsi->ws->pmd_trailer_application) {
280 			lwsl_ext("%s: trailer apply 1\n", __func__);
281 			was_fin = 1;
282 			wsi->ws->pmd_trailer_application = 0;
283 			priv->rx.next_in = trail;
284 			priv->rx.avail_in = sizeof(trail);
285 		}
286 
287 		/*
288 		 * if after all that there's nothing pending and nothing to give
289 		 * him right now, bail without having done anything
290 		 */
291 
292 		if (!priv->rx.avail_in)
293 			return PMDR_DID_NOTHING;
294 
295 		n = inflate(&priv->rx, was_fin ? Z_SYNC_FLUSH : Z_NO_FLUSH);
296 		lwsl_ext("inflate ret %d, avi %d, avo %d, wsifinal %d\n", n,
297 			 priv->rx.avail_in, priv->rx.avail_out, wsi->ws->final);
298 		switch (n) {
299 		case Z_NEED_DICT:
300 		case Z_STREAM_ERROR:
301 		case Z_DATA_ERROR:
302 		case Z_MEM_ERROR:
303 			lwsl_err("%s: zlib error inflate %d: \"%s\"\n",
304 				  __func__, n, priv->rx.msg);
305 			return PMDR_FAILED;
306 		}
307 
308 		/*
309 		 * track how much input was used, and advance it
310 		 */
311 
312 		pmdrx->eb_in.token = pmdrx->eb_in.token +
313 				         ((unsigned int)pmdrx->eb_in.len - (unsigned int)priv->rx.avail_in);
314 		pmdrx->eb_in.len = (int)priv->rx.avail_in;
315 
316 		lwsl_debug("%s: %d %d %d %d %d\n", __func__,
317 				priv->rx.avail_in,
318 				wsi->ws->final,
319 				(int)wsi->ws->rx_packet_length,
320 				was_fin,
321 				wsi->ws->pmd_trailer_application);
322 
323 		if (!priv->rx.avail_in &&
324 		    wsi->ws->final &&
325 		    !wsi->ws->rx_packet_length &&
326 		    !was_fin &&
327 		    wsi->ws->pmd_trailer_application) {
328 			lwsl_ext("%s: RX trailer apply 2\n", __func__);
329 
330 			/* we overallocated just for this situation where
331 			 * we might issue something */
332 			priv->rx.avail_out += 5;
333 
334 			was_fin = 1;
335 			wsi->ws->pmd_trailer_application = 0;
336 			priv->rx.next_in = trail;
337 			priv->rx.avail_in = sizeof(trail);
338 			n = inflate(&priv->rx, Z_SYNC_FLUSH);
339 			lwsl_ext("RX trailer infl ret %d, avi %d, avo %d\n",
340 				 n, priv->rx.avail_in, priv->rx.avail_out);
341 			switch (n) {
342 			case Z_NEED_DICT:
343 			case Z_STREAM_ERROR:
344 			case Z_DATA_ERROR:
345 			case Z_MEM_ERROR:
346 				lwsl_info("zlib error inflate %d: %s\n",
347 					  n, priv->rx.msg);
348 				return -1;
349 			}
350 
351 			assert(priv->rx.avail_out);
352 		}
353 
354 		pmdrx->eb_out.len = lws_ptr_diff(priv->rx.next_out,
355 						 pmdrx->eb_out.token);
356 		priv->count_rx_between_fin = priv->count_rx_between_fin + (size_t)pmdrx->eb_out.len;
357 
358 		lwsl_ext("  %s: RX leaving with new effbuff len %d, "
359 			 "rx.avail_in=%d, TOTAL RX since FIN %lu\n",
360 			 __func__, pmdrx->eb_out.len, priv->rx.avail_in,
361 			 (unsigned long)priv->count_rx_between_fin);
362 
363 		if (was_fin) {
364 			lwsl_ext("%s: was_fin\n", __func__);
365 			priv->count_rx_between_fin = 0;
366 			if (priv->args[PMD_SERVER_NO_CONTEXT_TAKEOVER]) {
367 				lwsl_ext("PMD_SERVER_NO_CONTEXT_TAKEOVER\n");
368 				(void)inflateEnd(&priv->rx);
369 				priv->rx_init = 0;
370 			}
371 
372 			return PMDR_EMPTY_FINAL;
373 		}
374 
375 		if (priv->rx.avail_in)
376 			return PMDR_HAS_PENDING;
377 
378 		return PMDR_EMPTY_NONFINAL;
379 
380 	case LWS_EXT_CB_PAYLOAD_TX:
381 
382 		/*
383 		 * ie, we are DEFLATING
384 		 *
385 		 * initialize us if needed
386 		 */
387 
388 		if (!priv->tx_init) {
389 			n = deflateInit2(&priv->tx, priv->args[PMD_COMP_LEVEL],
390 					 Z_DEFLATED,
391 					 -priv->args[PMD_SERVER_MAX_WINDOW_BITS +
392 						(wsi->a.vhost->listen_port <= 0)],
393 					 priv->args[PMD_MEM_LEVEL],
394 					 Z_DEFAULT_STRATEGY);
395 			if (n != Z_OK) {
396 				lwsl_ext("inflateInit2 failed %d\n", n);
397 				return PMDR_FAILED;
398 			}
399 			priv->tx_init = 1;
400 		}
401 
402 		if (!priv->buf_tx_deflated)
403 			priv->buf_tx_deflated = lws_malloc((unsigned int)(LWS_PRE + 7 + 5 +
404 					    (1 << priv->args[PMD_TX_BUF_PWR2])),
405 					    "pmd tx deflate buf");
406 		if (!priv->buf_tx_deflated) {
407 			lwsl_err("%s: OOM\n", __func__);
408 			return PMDR_FAILED;
409 		}
410 
411 		/* hook us up with any deflated input that the caller has */
412 
413 		if (pmdrx->eb_in.token) {
414 
415 			assert(!priv->tx.avail_in);
416 
417 			priv->count_tx_between_fin = priv->count_tx_between_fin + (size_t)pmdrx->eb_in.len;
418 			lwsl_ext("%s: TX: eb_in length %d, "
419 				    "TOTAL TX since FIN: %d\n", __func__,
420 				    pmdrx->eb_in.len,
421 				    (int)priv->count_tx_between_fin);
422 			priv->tx.next_in = (unsigned char *)pmdrx->eb_in.token;
423 			priv->tx.avail_in = (uInt)pmdrx->eb_in.len;
424 		}
425 
426 		priv->tx.next_out = priv->buf_tx_deflated + LWS_PRE + 5;
427 		pmdrx->eb_out.token = priv->tx.next_out;
428 		priv->tx.avail_out = (uInt)(1 << priv->args[PMD_TX_BUF_PWR2]);
429 
430 		pen = 0;
431 		penbits = 0;
432 		deflatePending(&priv->tx, &pen, &penbits);
433 		pen = pen | (unsigned int)penbits;
434 
435 		if (!priv->tx.avail_in && (len & LWS_WRITE_NO_FIN)) {
436 			lwsl_ext("%s: no available in, pen: %u\n", __func__, pen);
437 
438 			if (!pen)
439 				return PMDR_DID_NOTHING;
440 		}
441 
442 		m = Z_NO_FLUSH;
443 		if (!(len & LWS_WRITE_NO_FIN)) {
444 			lwsl_ext("%s: deflate with SYNC_FLUSH, pkt len %d\n",
445 					__func__, (int)wsi->ws->rx_packet_length);
446 			m = Z_SYNC_FLUSH;
447 		}
448 
449 		n = deflate(&priv->tx, m);
450 		if (n == Z_STREAM_ERROR) {
451 			lwsl_notice("%s: Z_STREAM_ERROR\n", __func__);
452 			return PMDR_FAILED;
453 		}
454 
455 		pen = (!priv->tx.avail_out) && n != Z_STREAM_END;
456 
457 		lwsl_ext("%s: deflate ret %d, len 0x%x\n", __func__, n,
458 				(unsigned int)len);
459 
460 		if ((len & 0xf) == LWS_WRITE_TEXT)
461 			priv->tx_first_frame_type = LWSWSOPC_TEXT_FRAME;
462 		if ((len & 0xf) == LWS_WRITE_BINARY)
463 			priv->tx_first_frame_type = LWSWSOPC_BINARY_FRAME;
464 
465 		pmdrx->eb_out.len = lws_ptr_diff(priv->tx.next_out,
466 						 pmdrx->eb_out.token);
467 
468 		if (m == Z_SYNC_FLUSH && !(len & LWS_WRITE_NO_FIN) && !pen &&
469 		    pmdrx->eb_out.len < 4) {
470 			lwsl_err("%s: FAIL want to trim out length %d\n",
471 					__func__, (int)pmdrx->eb_out.len);
472 			assert(0);
473 		}
474 
475 		if (!(len & LWS_WRITE_NO_FIN) &&
476 		    m == Z_SYNC_FLUSH &&
477 		    !pen &&
478 		    pmdrx->eb_out.len >= 4) {
479 			// lwsl_err("%s: Trimming 4 from end of write\n", __func__);
480 			priv->tx.next_out -= 4;
481 			priv->tx.avail_out += 4;
482 			priv->count_tx_between_fin = 0;
483 
484 			assert(priv->tx.next_out[0] == 0x00 &&
485 			       priv->tx.next_out[1] == 0x00 &&
486 			       priv->tx.next_out[2] == 0xff &&
487 			       priv->tx.next_out[3] == 0xff);
488 		}
489 
490 
491 		/*
492 		 * track how much input was used and advance it
493 		 */
494 
495 		pmdrx->eb_in.token = pmdrx->eb_in.token +
496 					((unsigned int)pmdrx->eb_in.len - (unsigned int)priv->tx.avail_in);
497 		pmdrx->eb_in.len = (int)priv->tx.avail_in;
498 
499 		priv->compressed_out = 1;
500 		pmdrx->eb_out.len = lws_ptr_diff(priv->tx.next_out,
501 						 pmdrx->eb_out.token);
502 
503 		lwsl_ext("  TX rewritten with new eb_in len %d, "
504 				"eb_out len %d, deflatePending %d\n",
505 				pmdrx->eb_in.len, pmdrx->eb_out.len, pen);
506 
507 		if (pmdrx->eb_in.len || pen)
508 			return PMDR_HAS_PENDING;
509 
510 		if (!(len & LWS_WRITE_NO_FIN))
511 			return PMDR_EMPTY_FINAL;
512 
513 		return PMDR_EMPTY_NONFINAL;
514 
515 	case LWS_EXT_CB_PACKET_TX_PRESEND:
516 		if (!priv->compressed_out)
517 			break;
518 		priv->compressed_out = 0;
519 
520 		/*
521 		 * we may have not produced any output for the actual "first"
522 		 * write... in that case, we need to fix up the inappropriate
523 		 * use of CONTINUATION when the first real write does come.
524 		 */
525 		if (priv->tx_first_frame_type & 0xf) {
526 			*pmdrx->eb_in.token = (unsigned char)((((unsigned char)*pmdrx->eb_in.token) & (unsigned char)~0xf) |
527 				((unsigned char)priv->tx_first_frame_type & (unsigned char)0xf));
528 			/*
529 			 * We have now written the "first" fragment, only
530 			 * do that once
531 			 */
532 			priv->tx_first_frame_type = 0;
533 		}
534 
535 		n = *(pmdrx->eb_in.token) & 15;
536 
537 		/* set RSV1, but not on CONTINUATION */
538 		if (n == LWSWSOPC_TEXT_FRAME || n == LWSWSOPC_BINARY_FRAME)
539 			*pmdrx->eb_in.token |= 0x40;
540 
541 		lwsl_ext("%s: PRESEND compressed: ws frame 0x%02X, len %d\n",
542 			    __func__, ((*pmdrx->eb_in.token) & 0xff),
543 			    pmdrx->eb_in.len);
544 
545 		if (((*pmdrx->eb_in.token) & 0x80) &&	/* fin */
546 		    priv->args[PMD_CLIENT_NO_CONTEXT_TAKEOVER]) {
547 			lwsl_debug("PMD_CLIENT_NO_CONTEXT_TAKEOVER\n");
548 			(void)deflateEnd(&priv->tx);
549 			priv->tx_init = 0;
550 		}
551 
552 		break;
553 
554 	default:
555 		break;
556 	}
557 
558 	return 0;
559 }
560 
561