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