1 /*
2 * This file is part of the Sofia-SIP package
3 *
4 * Copyright (C) 2006 Nokia Corporation.
5 *
6 * Contact: Pekka Pessi <pekka.pessi@nokia.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 2.1 of
11 * the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 * 02110-1301 USA
22 *
23 */
24
25 /**@CFILE tport_sigcomp.c Transport using SigComp.
26 *
27 * Incomplete.
28 *
29 * See tport.docs for more detailed description of tport interface.
30 *
31 * @author Pekka Pessi <Pekka.Pessi@nokia.com>
32 * @author Martti Mela <Martti.Mela@nokia.com>
33 *
34 * @date Created: Fri Mar 24 08:45:49 EET 2006 ppessi
35 */
36
37 #include "config.h"
38
39 #include "tport.h"
40
41 #include <sofia-sip/su_string.h>
42 #include <stdlib.h>
43 #include <time.h>
44 #include <assert.h>
45 #include <errno.h>
46 #include <limits.h>
47
48 #include <sigcomp.h>
49
50 /* ---------------------------------------------------------------------- */
51 /* SigComp */
52
53 typedef struct tport_sigcomp_handler tport_sigcomp_handler_t;
54
55 /** @internal Per end-point SigComp data */
56 struct tport_compressor {
57 struct sigcomp_state_handler *msc_state_handler;
58 struct sigcomp_compartment *msc_compartment;
59 };
60
61 /** @internal Per-socket SigComp data */
62 struct tport_comp {
63 struct sigcomp_udvm *sc_udvm;
64 struct sigcomp_compartment *sc_cc;
65 struct sigcomp_compressor *sc_compressor;
66 struct sigcomp_buffer *sc_output;
67 unsigned sc_compressed;
68
69 struct sigcomp_buffer *sc_input;
70 unsigned sc_copied;
71
72 enum {
73 format_is_unknown,
74 format_is_sigcomp,
75 format_is_noncomp
76 } sc_infmt, sc_outfmt;
77 };
78
79
vsc_master_init_sigcomp(tport_t * mr,char const * algorithm)80 tport_compressor_t *vsc_master_init_sigcomp(tport_t *mr,
81 char const *algorithm)
82 {
83 tport_compressor_t *retval = NLL;
84 stuct sigcomp_state_handler *sh = NULL;
85 struct sigcomp_algorithm *a = NULL;
86 struct sigcomp_compartment *cc = NULL;
87
88 if (algorithm == NULL)
89 algorithm = getenv("SIGCOMP_ALGORITHM");
90
91 retval = su_zalloc((su_home_t *)mr, sizeof *retval);
92 if (retval == NULL)
93 return retval;
94
95 sh = sigcomp_state_handler_create();
96
97 if (sh == NULL) {
98 SU_DEBUG_1(("tport: initializing SigComp state handler: %s\n",
99 strerror(errno)));
100 vsc_master_deinit_sigcomp(mr, retval), retval = NULL;
101 return retval;
102 }
103 retval->msc_state_handler = sh;
104
105 a = sigcomp_algorithm_by_name(algorithm);
106 cc = sigcomp_compartment_create(a, sh, 0, "", 0, NULL, 0);
107
108 if (cc == NULL) {
109 SU_DEBUG_1(("tport: initializing SigComp master compartment: %s\n",
110 strerror(errno)));
111 vsc_master_deinit_sigcomp(mr, retval), retval = NULL;
112 return retval;
113 }
114
115 self->msc_compartment = cc;
116
117 return retval;
118 }
119
120 if (self->sa_compartment) {
121 agent_sigcomp_options(self, self->sa_compartment);
122 sigcomp_compartment_option(self->sa_compartment, "stateless");
123 }
124 else
125
126 if (mr->mr_compartment)
127 sigcomp_compartment_unref(mt->mr_compartment);
128 mr->mr_compartment = sigcomp_compartment_ref(cc);
129
130 return cc;
131 }
132
133
134 void vsc_master_deinit_sigcomp(tport_master_t *mr)
135 {
136 tport_sigcomp_vtable_t const *vsc = tport_sigcomp_vtable;
137
138 if (mr->mr_compartment)
139 sigcomp_compartment_unref(mr->mr_compartment), mr->mr_compartment = NULL;
140
141 }
142
143 char const *vsc_comp_name(tport_sigcomp_t const *master_sc,
144 char const *proposed_name,
145 tagi_t const *tags)
146 {
147 if (master_sc == NULL ||
148 master_sc->sc_cc == NULL ||
149 !su_casematch(compression, tport_sigcomp_name))
150 return NULL;
151
152 return tport_sigcomp_name;
153 }
154
155 /** Check if transport can receive compressed messages */
156 int vsc_can_recv_sigcomp(tport_sigcomp_t const *sc)
157 {
158 return sc && sc->sc_infmt != format_is_noncomp;
159 }
160
161 /** Check if transport can send compressed messages */
162 int vsc_can_send_sigcomp(tport_sigcomp_t const *sc)
163 {
164 return sc && sc->sc_outfmt != format_is_noncomp;
165 }
166
167 /** Set/reset compression */
168 int vsc_set_compression(tport_t *self,
169 tport_sigcomp_t *sc,
170 char const *comp)
171 {
172 if (self == NULL)
173 ;
174 else if (comp == NULL) {
175 if (sc == NULL || sc->sc_outfmt != format_is_sigcomp) {
176 self->tp_name->tpn_comp = NULL;
177 return 0;
178 }
179 }
180 else {
181 comp = tport_canonize_comp(comp);
182
183 if (comp && sc && sc->sc_outfmt != format_is_noncomp) {
184 self->tp_name->tpn_comp = comp;
185 return 0;
186 }
187 }
188
189 return -1;
190 }
191
192
193 /** Assign a SigComp compartment (to a possibly connected tport). */
194 int tport_sigcomp_assign(tport_t *self, struct sigcomp_compartment *cc)
195 {
196 if (tport_is_connection_oriented(self) &&
197 tport_is_secondary(self) &&
198 self->tp_socket != INVALID_SOCKET) {
199
200 if (self->tp_sigcomp->sc_cc) {
201 if (cc == self->tp_sigcomp->sc_cc)
202 return 0;
203
204 /* Remove old assignment */
205 sigcomp_compartment_unref(self->tp_sigcomp->sc_cc);
206 }
207
208 self->tp_sigcomp->sc_cc = sigcomp_compartment_ref(cc);
209
210 return 0;
211 }
212
213 return su_seterrno(EINVAL);
214 }
215
216
217 void vsc_sigcomp_shutdown(tport_t *self, int how)
218 {
219 if (self->tp_socket != -1)
220 shutdown(self->tp_socket, how - 1);
221
222 if (how >= 2 && self->tp_sigcomp->sc_cc) {
223 sigcomp_compartment_unref(self->tp_sigcomp->sc_cc);
224 self->tp_sigcomp->sc_cc = NULL;
225 }
226 }
227
228 static int vsc_recv_sigcomp_r(tport_t*, msg_t**, struct sigcomp_udvm*, int);
229 static struct sigcomp_compartment *vsc_primary_compartment(tport_master_t *);
230
231
232 static int tport_sigcomp_init_secondary()
233 {
234 if (accept) {
235 if (!pri->pri_primary->tp_name->tpn_comp)
236 self->tp_sigcomp->sc_infmt = format_is_noncomp;
237 }
238 else {
239 /* XXX - no tpn here */
240 if (tpn->tpn_comp == pri->pri_primary->tp_name->tpn_comp)
241 self->tp_name->tpn_comp = pri->pri_primary->tp_name->tpn_comp;
242 if (!pri->pri_primary->tp_name->tpn_comp)
243 self->tp_sigcomp->sc_infmt = format_is_noncomp;
244 }
245 }
246
247 static int tport_sigcomp_deinit_secondary(tport_t *self)
248 {
249 if (self->tp_sigcomp) {
250 tport_sigcomp_t *sc = self->tp_sigcomp;
251
252 if (sc->sc_udvm)
253 sigcomp_udvm_free(sc->sc_udvm), sc->sc_udvm = NULL;
254 if (sc->sc_compressor)
255 sigcomp_compressor_free(sc->sc_compressor), sc->sc_compressor = NULL;
256 }
257 }
258
259 #if 0
260 #if HAVE_SIGCOMP
261 if (tport_can_recv_sigcomp(self))
262 return tport_recv_sigcomp_stream(self);
263 #endif
264 #endif
265
266 /** Try to receive stream data using SigComp. */
267 static int tport_recv_sigcomp_stream(tport_t *self)
268 {
269 struct sigcomp_udvm *udvm;
270 int retval;
271
272 SU_DEBUG_7(("%s(%p)\n", __func__, self));
273
274 /* Peek for first byte in stream,
275 determine if this is a compressed stream or not */
276 if (self->tp_sigcomp->sc_infmt == format_is_unknown) {
277 unsigned char sample;
278 int n;
279
280 n = recv(self->tp_socket, &sample, 1, MSG_PEEK);
281 if (n < 0)
282 return n;
283
284 if (n == 0) {
285 recv(self->tp_socket, &sample, 1, 0);
286 return 0; /* E-o-S from first message */
287 }
288
289 if ((sample & 0xf8) != 0xf8) {
290 /* Not SigComp, receive as usual */
291 if (tport_is_primary(self)) {
292 SU_DEBUG_1(("%s(%p): receive semantics not implemented\n",
293 __func__, self));
294 su_seterrno(EINVAL); /* Internal error */
295 return -1;
296 }
297
298 /* Do not try to receive with sigcomp from this socket */
299 self->tp_sigcomp->sc_infmt = format_is_noncomp;
300
301 return tport_recv_stream(self);
302 }
303
304 /* SigComp, receive using UDVM */
305 self->tp_sigcomp->sc_infmt = format_is_sigcomp;
306
307 /* Initialize UDVM */
308 self->tp_sigcomp->sc_udvm = tport_init_udvm(self);
309 if (!self->tp_sigcomp->sc_udvm) {
310 int save = su_errno();
311 recv(self->tp_socket, &sample, 1, 0); /* remove msg from socket */
312 return su_seterrno(save);
313 }
314 }
315
316 udvm = self->tp_sigcomp->sc_udvm; assert(udvm);
317
318 retval = tport_recv_sigcomp_r(self, &self->tp_msg, udvm, N);
319
320 if (retval < 0)
321 sigcomp_udvm_reject(udvm);
322
323 return retval;
324 }
325
326 /** Receive data available on the socket.
327 *
328 * @retval -1 error
329 * @retval 0 end-of-stream
330 * @retval 1 normal receive
331 * @retval 2 incomplete recv, recv again
332 */
333 static int tport_recv_sigcomp_r(tport_t *self,
334 msg_t **mmsg,
335 struct sigcomp_udvm *udvm,
336 int N)
337 {
338 msg_t *msg;
339 size_t n, m, i;
340 int eos, complete;
341 ssize_t veclen;
342 msg_iovec_t iovec[msg_n_fragments] = {{ 0 }};
343 su_sockaddr_t su[1];
344 socklen_t su_size = sizeof(su);
345 struct sigcomp_buffer *input, *output;
346 void *data;
347 size_t dlen;
348
349 SU_DEBUG_7(("%s(%p)\n", __func__, self));
350
351 assert(udvm);
352
353 if (sigcomp_udvm_has_input(udvm)) {
354 input = sigcomp_udvm_input_buffer(udvm, n = N = 0); assert(input);
355 }
356 else {
357 if (N == 0) {
358 assert(self->tp_addrinfo->ai_socktype != SOCK_DGRAM);
359 if (self->tp_addrinfo->ai_socktype == SOCK_DGRAM) {
360 recv(self->tp_socket, (void *)su, 1, 0);
361 return 1;
362 }
363 }
364
365 input = sigcomp_udvm_input_buffer(udvm, N); assert(input);
366 if (input == NULL)
367 return su_seterrno(EIO);
368
369 data = input->b_data + input->b_avail;
370 dlen = input->b_size - input->b_avail;
371
372 if (tport_is_stream(self)) {
373 n = recv(self->tp_socket, data, dlen, 0);
374 }
375 else if (dlen >= N) {
376 n = recvfrom(self->tp_socket, data, dlen, 0, &su->su_sa, &su_size);
377 SU_CANONIZE_SOCKADDR(su);
378 }
379 else {
380 recvfrom(self->tp_socket, data, dlen, 0, &su->su_sa, &su_size);
381 SU_CANONIZE_SOCKADDR(su);
382 su_seterrno(EMSGSIZE); /* Protocol error */
383 return -1;
384 }
385
386 if (n == (unsigned)-1) {
387 char const *pn = self->tp_protoname;
388 int err = su_errno();
389
390 if (su_is_blocking(err)) {
391 SU_DEBUG_7(("%s(%p): recv from %s: EAGAIN\n", __func__, self, pn));
392 return 1;
393 }
394
395 SU_DEBUG_1(("%s(%p): recv from %s: %s (%d)\n", __func__, self, pn,
396 su_strerror(err), err));
397 return -1;
398 }
399
400 /* XXX - in case of stream, use message buffers for output? */
401
402 input->b_avail += n;
403 input->b_complete = (n == 0) || !tport_is_stream(self);
404 }
405
406 for (complete = eos = 0; !complete;) {
407 output = sigcomp_udvm_output_buffer(udvm, 16384);
408
409 if (sigcomp_udvm_decompress(udvm, output, input) < 0) {
410 int error = sigcomp_udvm_errno(udvm);
411
412 SU_DEBUG_3(("%s: UDVM error %d: %s\n", __func__,
413 error, sigcomp_udvm_strerror(udvm)));
414
415 su_seterrno(EREMOTEIO);
416
417 return -1;
418 }
419
420 data = output->b_data + output->b_used;
421 dlen = output->b_avail - output->b_used;
422 complete = output->b_complete;
423 eos = complete && input->b_complete;
424
425 veclen = tport_recv_iovec(self, mmsg, iovec, dlen, eos);
426
427 if (dlen ? veclen <= 0 : veclen < 0) {
428 return -1;
429 }
430
431 for (i = 0, n = 0; i < veclen; i++) {
432 m = iovec[i].mv_len; assert(dlen >= n + m);
433 memcpy(iovec[i].mv_base, data + n, m);
434 n += m;
435 }
436 assert(dlen == n);
437
438 msg = *mmsg;
439
440 if (msg) {
441 /* Message address */
442 if (self->tp_addrinfo->ai_socktype == SOCK_STREAM)
443 msg_set_address(msg, self->tp_addr, self->tp_addrlen);
444 else
445 msg_set_address(msg, su, su_size);
446
447 SU_DEBUG_5(("%s(%p): sigcomp recv = %u => %u %s\n", __func__, self,
448 N, dlen, eos ? " (complete)" : ""));
449
450 msg_mark_as_compressed(msg);
451
452 /* Write the received data to the message dump file */
453 if (self->tp_master->mr_dump_file && !self->tp_pri->pri_threadpool)
454 tport_dump_iovec(self, msg, n, iovec, veclen, "recv", "from");
455
456 /* Send the received data to the capture server */
457 if (self->tp_master->mr_capt_sock && !self->tp_pri->pri_threadpool)
458 tport_dump_iovec(self, msg, 0);
459
460 msg_recv_commit(msg, dlen, eos); /* Mark buffer as used */
461 }
462 else {
463 SU_DEBUG_5(("%s(%p): sigcomp recv = %u => %u %s\n", __func__, self,
464 N, dlen, eos ? " (complete)" : ""));
465 if (complete || !tport_is_stream(self)) {
466 sigcomp_udvm_reject(udvm); /* Reject empty message */
467 }
468 }
469
470 if (self->tp_addrinfo->ai_socktype == SOCK_STREAM) {
471 if (eos)
472 return 0;
473
474 if (output->b_complete)
475 return n < N || sigcomp_udvm_has_pending_data(udvm) ? 2 : 1;
476
477 if (!sigcomp_udvm_has_input(udvm))
478 return 1;
479 }
480 }
481
482 return eos ? 0 : 2;
483 }
484
485 static
486 int vsc_send_sigcomp(tport_t const *self,
487 msg_t *msg,
488 msg_iovec_t iov[],
489 int iovused,
490 struct sigcomp_compartment *cc,
491 tport_sigcomp_t *sc)
492 {
493 struct sigcomp_compressor *c = sc->sc_compressor;
494 struct sigcomp_buffer *input = sc->sc_input;
495 struct sigcomp_buffer *output = sc->sc_output;
496 msg_iovec_t ciov[1];
497
498 int i, n, m, k, stream = tport_is_stream(self);
499 char const *ccname;
500 int ccnamelen;
501
502 su_addrinfo_t *ai = msg_addrinfo(msg);
503
504 int compress = (cc || (cc = sc->sc_cc)) && ai->ai_flags & TP_AI_COMPRESSED;
505
506 if (!compress) {
507 if (stream)
508 sc->sc_outfmt = format_is_noncomp;
509 ai->ai_flags &= ~TP_AI_COMPRESSED;
510 return self->tp_pri->pri_vtable->vtp_send(self, msg, iov, iovused, NULL);
511 }
512
513 if (stream)
514 sc->sc_outfmt = format_is_sigcomp;
515
516 assert(cc);
517
518 if (c == NULL) {
519 assert(input == NULL);
520 if (stream)
521 c = sigcomp_compressor_create_for_stream(cc);
522 else
523 c = sigcomp_compressor_create(cc);
524 sc->sc_compressor = c;
525 }
526
527 ccname = sigcomp_compartment_name(cc, &ccnamelen);
528
529 if (sc->sc_compressed != 0) {
530 input = NONE;
531 }
532 else if (input == NULL) {
533 int input_size = -1;
534
535 if (tport_is_udp(self)) {
536 input_size = 0;
537
538 for (i = 0; i < iovused; i++)
539 input_size += iov[i].siv_len;
540 }
541
542 sc->sc_input = input = sigcomp_compressor_input_buffer(c, input_size);
543
544 assert(input->b_avail == 0 && input->b_used == 0);
545 }
546 else if (!input->b_complete) {
547 int input_size = 0;
548
549 for (i = 0; i < iovused; i++)
550 input_size += iov[i].siv_len;
551
552 if (input_size > input->b_size - input->b_avail)
553 sigcomp_buffer_align_available(input, 0);
554 }
555
556 if (output == NULL)
557 sc->sc_output = output = sigcomp_compressor_output_buffer(c, NULL);
558
559 if (!c || !input || !output) {
560 SU_DEBUG_3(("%s(%p): %s (%u)%s%s%s\n",
561 __func__, self, strerror(errno), errno,
562 c ? "" : " (comp)",
563 input ? "" : " (input)",
564 output ? "" : " (output)"));
565 sigcomp_compressor_free(c);
566 sc->sc_compressor = NULL;
567 sc->sc_output = NULL; sc->sc_input = NULL;
568 sc->sc_compressed = 0; sc->sc_copied = 0;
569 return -1;
570 }
571
572 if (sc->sc_compressed == 0) {
573 k = sc->sc_copied;
574
575 if (!input->b_complete) {
576 int m = sc->sc_copied;
577
578 for (i = 0, n = 0; i < iovused; i++) {
579 char *b = iov[i].siv_base;
580 int l = iov[i].siv_len;
581
582 if (m >= l) {
583 m -= l;
584 continue;
585 }
586
587 b += m; l -= m;
588
589 if (input->b_size == input->b_avail)
590 break;
591
592 if (l > input->b_size - input->b_avail)
593 l = input->b_size - input->b_avail;
594
595 memcpy(input->b_data + input->b_avail, b, l);
596 input->b_avail += l; n += l; sc->sc_copied += l;
597
598 if (l != iov[i].siv_len)
599 break;
600 }
601 input->b_complete = i == iovused;
602 assert(stream || input->b_complete); (void)stream;
603 }
604
605 m = output->b_avail - output->b_used;
606
607 n = sigcomp_compressor_compress(c, output, input);
608
609 if (n < 0) {
610 SU_DEBUG_3(("%s(%p): %s (%u)\n", __func__, self,
611 sigcomp_compressor_strerror(c),
612 sigcomp_compressor_errno(c)));
613 sigcomp_compressor_free(c);
614 sc->sc_compressor = NULL;
615 sc->sc_output = NULL; sc->sc_input = NULL;
616 sc->sc_compressed = 0;
617 return -1;
618 }
619
620 assert(input->b_complete || sc->sc_copied - k > 0);
621
622 SU_DEBUG_5(("%s: input %u (%u new) compressed %u to %u with '%.*s'\n",
623 __func__, sc->sc_copied, k, n,
624 (output->b_avail - output->b_used) - m,
625 ccnamelen, ccname));
626
627 sc->sc_compressed = n;
628
629 assert(stream || output->b_complete);
630 }
631 else {
632 assert(tport_is_connection_oriented(self));
633 n = sc->sc_compressed;
634 }
635
636 assert(input && cc && c && output);
637
638 ciov->siv_base = output->b_data + output->b_used;
639 ciov->siv_len = output->b_avail - output->b_used;
640
641 m = self->tp_pri->pri_vtable->vtp_send(self, msg, ciov, 1);
642
643 if (m == -1) {
644 int error = su_errno();
645
646 if (su_is_blocking(error)) {
647 sigcomp_compressor_free(c);
648 sc->sc_compressor = NULL;
649 sc->sc_output = NULL; sc->sc_input = NULL;
650 sc->sc_compressed = 0; sc->sc_copied = 0;
651 su_seterrno(error);
652 }
653
654 return -1;
655 }
656
657 output->b_used += m;
658
659 if (output->b_used < output->b_avail)
660 return 0;
661
662 if (output->b_complete) {
663 sigcomp_compressor_accept(c, cc), sc->sc_output = output = NULL;
664 }
665
666 if (input != NONE && input->b_avail == input->b_used && input->b_complete)
667 sigcomp_buffer_reset(input, -1), sc->sc_input = input = NULL;
668
669 if (!input && !output) {
670 sigcomp_compressor_free(c);
671 sc->sc_compressor = NULL;
672 }
673
674 assert(sc->sc_compressed >= n); assert(sc->sc_copied >= n);
675
676 sc->sc_compressed -= n;
677 sc->sc_copied -= n;
678
679 return n;
680 }
681
682 /** Initialize UDVM */
683 static
684 struct sigcomp_udvm *tport_init_udvm(tport_t *self)
685 {
686 struct sigcomp_compartment *cc;
687 struct sigcomp_udvm *udvm;
688
689 if (self->tp_sigcomp->sc_udvm)
690 return self->tp_sigcomp->sc_udvm;
691
692 cc = tport_primary_compartment(self->tp_master);
693
694 if (!cc)
695 return NULL;
696
697 if (self->tp_addrinfo->ai_socktype == SOCK_STREAM)
698 udvm = sigcomp_udvm_create_for_stream(cc);
699 else
700 udvm = sigcomp_udvm_create_for_compartment(cc);
701
702 return udvm;
703 }
704
705
706 /** Get primary compartment */
707 static
708 struct sigcomp_compartment *
709 tport_primary_compartment(tport_master_t *mr)
710 {
711 return mr->mr_compartment;
712 }
713
714 /** Test if tport has a SigComp compartment is assigned to it. */
715 int vsc_has_sigcomp_assigned(tport_sigcomp_t const *sc)
716 {
717 return sc && sc->sc_udvm != NULL;
718 }
719
720 static
721 void vsc_try_accept_sigcomp(tport_t *self, msg_t *msg)
722 {
723 struct sigcomp_udvm *udvm;
724
725 udvm = self->tp_sigcomp->sc_udvm;
726 if (udvm && sigcomp_udvm_is_complete(udvm)) {
727 if (self->tp_master->mr_tpac->tpac_sigcomp_accept &&
728 self->tp_sigcomp->sc_cc == NULL) {
729 tport_t *ref;
730 struct tport_delivery *d;
731
732 d = self->tp_master->mr_delivery;
733
734 d->d_tport = self;
735 d->d_msg = msg;
736 d->d_udvm = &self->tp_sigcomp->sc_udvm;
737 *d->d_from = *self->tp_name;
738
739 ref = tport_incref(self);
740 STACK_SIGCOMP_ACCEPT(self, msg);
741 /* Reject by default */
742 if (self->tp_sigcomp->sc_udvm)
743 sigcomp_udvm_accept(self->tp_sigcomp->sc_udvm, NULL);
744 tport_decref(&ref);
745
746 d->d_msg = NULL;
747 }
748 else {
749 if (tport_log->log_level >= 5) {
750 char const *name;
751 int namelen;
752
753 name = sigcomp_compartment_name(self->tp_sigcomp->sc_cc, &namelen);
754 SU_DEBUG_5(("tport(%p): msg %p SigComp implicit accept '%.*s'\n",
755 self, msg, namelen, name));
756 }
757 sigcomp_udvm_accept(udvm, self->tp_sigcomp->sc_cc);
758 }
759 }
760 }
761
762
763 /** Accept a SigComp message */
764 int
765 tport_sigcomp_accept(tport_t *self,
766 struct sigcomp_compartment *cc,
767 msg_t *msg)
768 {
769 struct sigcomp_udvm *udvm;
770
771 if (self == NULL || msg != self->tp_master->mr_delivery->d_msg)
772 return su_seterrno(EINVAL);
773
774 if (!self->tp_master->mr_delivery->d_udvm || cc == NONE)
775 return 0;
776
777 udvm = *self->tp_master->mr_delivery->d_udvm;
778
779 if (udvm) {
780 if (tport_log->log_level >= 5) {
781 char const *name;
782 int namelen;
783
784 if (cc) {
785 name = sigcomp_compartment_name(cc, &namelen);
786 SU_DEBUG_5(("tport(%p): msg %p SigComp accept '%.*s'\n",
787 self, msg, namelen, name));
788 }
789 else {
790 SU_DEBUG_5(("tport(%p): msg %p SigComp reject\n", self, msg));
791 }
792 }
793 sigcomp_udvm_accept(udvm, cc);
794 }
795
796 self->tp_master->mr_delivery->d_udvm = NULL;
797
798 return 0;
799 }
800
801
802 /** Pass message to the protocol stack */
803 void
804 tport_sigcomp_deliver(tport_t *self, msg_t *msg, su_time_t now)
805 {
806 /* XXX - no d */
807
808 STACK_RECV(self, msg, now);
809
810 if (d->d_udvm && *d->d_udvm)
811 sigcomp_udvm_accept(*d->d_udvm, NULL); /* reject */
812 }
813
814
815 #if HAVE_SIGCOMP && 0
816
817 su_inline
818 int msg_is_compressed(msg_t *msg)
819 {
820 return msg &&
821 (msg_addrinfo(msg)->ai_flags & TP_AI_COMPRESSED) == TP_AI_COMPRESSED;
822 }
823
824 su_inline
825 void msg_mark_as_compressed(msg_t *msg)
826 {
827 if (msg)
828 msg_addrinfo(msg)->ai_flags |= TP_AI_COMPRESSED;
829 }
830
831
832 struct sigcomp_udvm **tport_get_udvm_slot(tport_t *self)
833 {
834 tport_sigcomp_vtable_t const *vsc = tport_sigcomp_vtable;
835
836 if (vsc)
837
838 #if HAVE_SIGCOMP
839 return &self->tp_sigcomp->sc_udvm;
840 #else
841 return NULL;
842 #endif
843 }
844
845 struct sigcomp_compartment *
846 tport_sigcomp_assign_if_needed(tport_t *self,
847 struct sigcomp_compartment *cc)
848 {
849 if (self->tp_name->tpn_comp) {
850 if (cc)
851 tport_sigcomp_assign(self, cc);
852 else if (self->tp_sigcomp->sc_cc)
853 cc = self->tp_sigcomp->sc_cc;
854 else
855 /* Use default compartment */
856 cc = self->tp_master->mr_compartment;
857 }
858 else
859 cc = NULL;
860
861 return cc;
862 }
863
864 /** Receive data from datagram using SigComp. */
865 int tport_recv_sigcomp_dgram(tport_t *self, int N)
866 {
867 char dummy[1];
868 int error = EBADMSG;
869 #if HAVE_SIGCOMP
870 struct sigcomp_udvm *udvm;
871
872 if (self->tp_sigcomp->sc_udvm == 0)
873 self->tp_sigcomp->sc_udvm = tport_init_udvm(self);
874
875 udvm = self->tp_sigcomp->sc_udvm;
876
877 if (udvm) {
878 retval = tport_recv_sigcomp_r(self, &self->tp_msg, udvm, N);
879 if (retval < 0)
880 sigcomp_udvm_reject(udvm);
881 return retval;
882 }
883 error = su_errno();
884 #endif
885 recv(self->tp_socket, dummy, 1, 0); /* remove msg from socket */
886 /* XXX - send NACK ? */
887 return su_seterrno(error);
888 }
889