2 * @file sip-transport.c
6 * Copyright (C) 2010-11 SIPE Project <http://sipe.sourceforge.net/>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 * This module incapsulates SIP (RFC3261) protocol and provides
25 * higher level API (a layer) to XML-based SIPE (SIP with Extensions).
26 * Underlying leyer for this is TCP/SSL layer.
28 * A diagram in pseudographics:
30 * === SIPE (XML-based) layer ======================
31 * === SIP RFC3261 transport layer (This module) ===
32 * === TCP/SSL layer ===============================
34 * Authentication (Kerberos and NTLM) is applicable to this layer only.
35 * The same with message integtity (signing). No sip-sec* code should
36 * be used ourside of this module.
38 * SIP errors as codes(both as a return codes and network conditions) should be
39 * escalated to higher leyer (SIPE). Network conditions include no response
40 * within timeout interval.
42 * This module should support redirect internally. No escalations to higher
45 * NO SIP-messages (headers) composing and processing should be outside of
46 * this module (!) Like headers: Via, Route, Contact, Authorization, etc.
47 * It's all irrelevant to higher layer responsibilities.
61 #include "sipe-common.h"
64 #include "sip-transport.h"
65 #include "sipe-backend.h"
66 #include "sipe-core.h"
67 #include "sipe-core-private.h"
68 #include "sipe-dialog.h"
69 #include "sipe-digest.h"
70 #include "sipe-incoming.h"
72 #include "sipe-schedule.h"
73 #include "sipe-sign.h"
74 #include "sipe-subscriptions.h"
75 #include "sipe-utils.h"
81 struct sip_sec_context
*gssapi_context
;
93 /* sip-transport.c private data */
94 struct sip_transport
{
95 struct sipe_transport_connection
*connection
;
99 gchar
*server_version
;
103 GSList
*transactions
;
105 struct sip_auth registrar
;
106 struct sip_auth proxy
;
109 guint register_attempt
;
111 gboolean processing_input
; /* whether full header received */
112 gboolean reregister_set
; /* whether reregister timer set */
113 gboolean reauthenticate_set
; /* whether reauthenticate timer set */
114 gboolean subscribed
; /* whether subscribed to events, except buddies presence */
117 /* Keep in sync with sipe_transport_type! */
118 static const char *transport_descriptor
[] = { "", "tls", "tcp"};
119 #define TRANSPORT_DESCRIPTOR (transport_descriptor[transport->connection->type])
121 static char *genbranch()
123 return g_strdup_printf("z9hG4bK%04X%04X%04X%04X%04X",
124 rand() & 0xFFFF, rand() & 0xFFFF, rand() & 0xFFFF,
125 rand() & 0xFFFF, rand() & 0xFFFF);
128 static void sipe_auth_free(struct sip_auth
*auth
)
130 g_free(auth
->opaque
);
134 g_free(auth
->target
);
137 auth
->type
= AUTH_TYPE_UNSET
;
140 g_free(auth
->gssapi_data
);
141 auth
->gssapi_data
= NULL
;
142 sip_sec_destroy_context(auth
->gssapi_context
);
143 auth
->gssapi_context
= NULL
;
146 static void sipe_make_signature(struct sipe_core_private
*sipe_private
,
149 struct sip_transport
*transport
= sipe_private
->transport
;
150 if (transport
->registrar
.gssapi_context
) {
151 struct sipmsg_breakdown msgbd
;
152 gchar
*signature_input_str
;
154 sipmsg_breakdown_parse(&msgbd
, transport
->registrar
.realm
, transport
->registrar
.target
);
155 msgbd
.rand
= g_strdup_printf("%08x", g_random_int());
156 transport
->registrar
.ntlm_num
++;
157 msgbd
.num
= g_strdup_printf("%d", transport
->registrar
.ntlm_num
);
158 signature_input_str
= sipmsg_breakdown_get_string(transport
->registrar
.version
, &msgbd
);
159 if (signature_input_str
!= NULL
) {
160 char *signature_hex
= sip_sec_make_signature(transport
->registrar
.gssapi_context
, signature_input_str
);
161 msg
->signature
= signature_hex
;
162 msg
->rand
= g_strdup(msgbd
.rand
);
163 msg
->num
= g_strdup(msgbd
.num
);
164 g_free(signature_input_str
);
166 sipmsg_breakdown_free(&msgbd
);
170 static gchar
*auth_header(struct sipe_core_private
*sipe_private
,
171 struct sip_auth
*auth
,
174 struct sipe_account_data
*sip
= SIPE_ACCOUNT_DATA_PRIVATE
;
175 const char *authuser
= sip
->authuser
;
178 if (!authuser
|| strlen(authuser
) < 1) {
179 authuser
= sipe_private
->username
;
182 if (auth
->type
== AUTH_TYPE_NTLM
|| auth
->type
== AUTH_TYPE_KERBEROS
) { /* NTLM or Kerberos */
183 gchar
*auth_protocol
= (auth
->type
== AUTH_TYPE_NTLM
? "NTLM" : "Kerberos");
186 // If we have a signature for the message, include that
187 if (msg
->signature
) {
188 return g_strdup_printf("%s qop=\"auth\", opaque=\"%s\", realm=\"%s\", targetname=\"%s\", crand=\"%s\", cnum=\"%s\", response=\"%s\"", auth_protocol
, auth
->opaque
, auth
->realm
, auth
->target
, msg
->rand
, msg
->num
, msg
->signature
);
191 if ((auth
->type
== AUTH_TYPE_NTLM
&& auth
->nc
== 3 && auth
->gssapi_data
&& auth
->gssapi_context
== NULL
)
192 || (auth
->type
== AUTH_TYPE_KERBEROS
&& auth
->nc
== 3)) {
195 gchar
*sign_str
= NULL
;
197 gssapi_data
= sip_sec_init_context(&(auth
->gssapi_context
),
200 SIPE_CORE_PUBLIC_FLAG_IS(SSO
),
201 sip
->authdomain
? sip
->authdomain
: "",
206 if (!gssapi_data
|| !auth
->gssapi_context
) {
207 sipe_backend_connection_error(SIPE_CORE_PUBLIC
,
208 SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED
,
209 _("Failed to authenticate to server"));
213 if (auth
->version
> 3) {
214 sipe_make_signature(sipe_private
, msg
);
215 sign_str
= g_strdup_printf(", crand=\"%s\", cnum=\"%s\", response=\"%s\"",
216 msg
->rand
, msg
->num
, msg
->signature
);
218 sign_str
= g_strdup("");
221 opaque
= (auth
->type
== AUTH_TYPE_NTLM
? g_strdup_printf(", opaque=\"%s\"", auth
->opaque
) : g_strdup(""));
222 version_str
= auth
->version
> 2 ? g_strdup_printf(", version=%d", auth
->version
) : g_strdup("");
223 ret
= g_strdup_printf("%s qop=\"auth\"%s, realm=\"%s\", targetname=\"%s\", gssapi-data=\"%s\"%s%s", auth_protocol
, opaque
, auth
->realm
, auth
->target
, gssapi_data
, version_str
, sign_str
);
231 version_str
= auth
->version
> 2 ? g_strdup_printf(", version=%d", auth
->version
) : g_strdup("");
232 ret
= g_strdup_printf("%s qop=\"auth\", realm=\"%s\", targetname=\"%s\", gssapi-data=\"\"%s", auth_protocol
, auth
->realm
, auth
->target
, version_str
);
236 } else { /* Digest */
239 guchar digest
[SIPE_DIGEST_MD5_LENGTH
];
241 /* Calculate new session key */
243 SIPE_DEBUG_INFO("Digest nonce: %s realm: %s", auth
->gssapi_data
, auth
->realm
);
246 * Calculate a session key for HTTP MD5 Digest authentation
248 * See RFC 2617 for more information.
250 string
= g_strdup_printf("%s:%s:%s",
254 sipe_digest_md5((guchar
*)string
, strlen(string
), digest
);
256 auth
->opaque
= buff_to_hex_str(digest
, sizeof(digest
));
261 * Calculate a response for HTTP MD5 Digest authentication
263 * See RFC 2617 for more information.
265 string
= g_strdup_printf("%s:%s", msg
->method
, msg
->target
);
266 sipe_digest_md5((guchar
*)string
, strlen(string
), digest
);
269 hex_digest
= buff_to_hex_str(digest
, sizeof(digest
));
270 string
= g_strdup_printf("%s:%s:%s", auth
->opaque
, auth
->gssapi_data
, hex_digest
);
272 sipe_digest_md5((guchar
*)string
, strlen(string
), digest
);
275 hex_digest
= buff_to_hex_str(digest
, sizeof(digest
));
276 SIPE_DEBUG_INFO("Digest response %s", hex_digest
);
277 ret
= g_strdup_printf("Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", nc=\"%08d\", response=\"%s\"", authuser
, auth
->realm
, auth
->gssapi_data
, msg
->target
, auth
->nc
++, hex_digest
);
283 static char *parse_attribute(const char *attrname
, const char *source
)
285 const char *tmp
, *tmp2
;
287 int len
= strlen(attrname
);
289 if (g_str_has_prefix(source
, attrname
)) {
291 tmp2
= g_strstr_len(tmp
, strlen(tmp
), "\"");
293 retval
= g_strndup(tmp
, tmp2
- tmp
);
295 retval
= g_strdup(tmp
);
301 static void fill_auth(const gchar
*hdr
, struct sip_auth
*auth
)
307 SIPE_DEBUG_ERROR_NOFORMAT("fill_auth: hdr==NULL");
311 if (!g_strncasecmp(hdr
, "NTLM", 4)) {
312 SIPE_DEBUG_INFO_NOFORMAT("fill_auth: type NTLM");
313 auth
->type
= AUTH_TYPE_NTLM
;
316 } else if (!g_strncasecmp(hdr
, "Kerberos", 8)) {
317 SIPE_DEBUG_INFO_NOFORMAT("fill_auth: type Kerberos");
318 auth
->type
= AUTH_TYPE_KERBEROS
;
322 SIPE_DEBUG_INFO_NOFORMAT("fill_auth: type Digest");
323 auth
->type
= AUTH_TYPE_DIGEST
;
327 parts
= g_strsplit(hdr
, "\", ", 0);
328 for (i
= 0; parts
[i
]; i
++) {
331 //SIPE_DEBUG_INFO("parts[i] %s", parts[i]);
333 if ((tmp
= parse_attribute("gssapi-data=\"", parts
[i
]))) {
334 g_free(auth
->gssapi_data
);
335 auth
->gssapi_data
= tmp
;
337 if (auth
->type
== AUTH_TYPE_NTLM
) {
338 /* NTLM module extracts nonce from gssapi-data */
342 } else if ((tmp
= parse_attribute("nonce=\"", parts
[i
]))) {
343 /* Only used with AUTH_TYPE_DIGEST */
344 g_free(auth
->gssapi_data
);
345 auth
->gssapi_data
= tmp
;
346 } else if ((tmp
= parse_attribute("opaque=\"", parts
[i
]))) {
347 g_free(auth
->opaque
);
349 } else if ((tmp
= parse_attribute("realm=\"", parts
[i
]))) {
353 if (auth
->type
== AUTH_TYPE_DIGEST
) {
354 /* Throw away old session key */
355 g_free(auth
->opaque
);
359 } else if ((tmp
= parse_attribute("targetname=\"", parts
[i
]))) {
360 g_free(auth
->target
);
362 } else if ((tmp
= parse_attribute("version=", parts
[i
]))) {
363 auth
->version
= atoi(tmp
);
366 // uncomment to revert to previous functionality if version 3+ does not work.
367 // auth->version = 2;
374 static void sign_outgoing_message (struct sipmsg
* msg
,
375 struct sipe_core_private
*sipe_private
,
378 struct sip_transport
*transport
= sipe_private
->transport
;
381 if (transport
->registrar
.type
== AUTH_TYPE_UNSET
) {
385 sipe_make_signature(sipe_private
, msg
);
387 if (transport
->registrar
.type
&& sipe_strequal(method
, "REGISTER")) {
388 buf
= auth_header(sipe_private
, &transport
->registrar
, msg
);
390 sipmsg_add_header_now_pos(msg
, "Authorization", buf
, 5);
393 } else if (sipe_strequal(method
,"SUBSCRIBE") || sipe_strequal(method
,"SERVICE") || sipe_strequal(method
,"MESSAGE") || sipe_strequal(method
,"INVITE") || sipe_strequal(method
, "ACK") || sipe_strequal(method
, "NOTIFY") || sipe_strequal(method
, "BYE") || sipe_strequal(method
, "INFO") || sipe_strequal(method
, "OPTIONS") || sipe_strequal(method
, "REFER") || sipe_strequal(method
, "PRACK")) {
394 transport
->registrar
.nc
= 3;
395 transport
->registrar
.type
= AUTH_TYPE_NTLM
;
397 if (SIPE_CORE_PUBLIC_FLAG_IS(KRB5
)) {
398 transport
->registrar
.type
= AUTH_TYPE_KERBEROS
;
401 /* that's why I don't like macros. It's unobvious what's hidden there */
406 buf
= auth_header(sipe_private
, &transport
->registrar
, msg
);
407 sipmsg_add_header_now_pos(msg
, "Authorization", buf
, 5);
410 SIPE_DEBUG_INFO("not adding auth header to msg w/ method %s", method
);
414 static const gchar
*sip_transport_user_agent(struct sipe_core_private
*sipe_private
)
416 struct sip_transport
*transport
= sipe_private
->transport
;
418 if (!transport
->user_agent
) {
419 const gchar
*useragent
= sipe_backend_setting(SIPE_CORE_PUBLIC
,
420 SIPE_SETTING_USER_AGENT
);
421 if (is_empty(useragent
)) {
422 /*@TODO: better approach to define _user_ OS, it's version and host architecture */
424 #if defined(__linux__) || defined(__linux) || defined(__LINUX__)
425 #define SIPE_TARGET_PLATFORM "linux"
426 #elif defined(__NetBSD__) ||defined( __OpenBSD__) || defined(__FreeBSD__)
427 #define SIPE_TARGET_PLATFORM "bsd"
428 #elif defined(__APPLE__) || defined(__MACOS__)
429 #define SIPE_TARGET_PLATFORM "macosx"
430 #elif defined(_AIX) || defined(__AIX__) || defined(__aix__)
431 #define SIPE_TARGET_PLATFORM "aix"
432 #elif defined(__solaris__) || defined(__sun)
433 #define SIPE_TARGET_PLATFORM "sun"
434 #elif defined(_WIN32)
435 #define SIPE_TARGET_PLATFORM "win"
436 #elif defined(__CYGWIN__)
437 #define SIPE_TARGET_PLATFORM "cygwin"
438 #elif defined(__hpux__)
439 #define SIPE_TARGET_PLATFORM "hpux"
440 #elif defined(__sgi__)
441 #define SIPE_TARGET_PLATFORM "irix"
443 #define SIPE_TARGET_PLATFORM "unknown"
446 #if defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64)
447 #define SIPE_TARGET_ARCH "x86_64"
448 #elif defined(__386__) || defined(__i386__) || defined(__i386) || defined(_M_IX86) || defined(_M_I386)
449 #define SIPE_TARGET_ARCH "i386"
450 #elif defined(__ppc64__)
451 #define SIPE_TARGET_ARCH "ppc64"
452 #elif defined(__powerpc__) || defined(__powerpc) || defined(__ppc__) || defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PWR)
453 #define SIPE_TARGET_ARCH "ppc"
454 #elif defined(__hppa__) || defined(__hppa)
455 #define SIPE_TARGET_ARCH "hppa"
456 #elif defined(__mips__) || defined(__mips) || defined(_MIPS_ARCH) || defined(_M_MRX000)
457 #define SIPE_TARGET_ARCH "mips"
458 #elif defined(__s390__) || defined(__s390) || defined(__s390x__) || defined(__s390x)
459 #define SIPE_TARGET_ARCH "s390"
460 #elif defined(__sparc__) || defined(__sparc) || defined(__sparcv8)
461 #define SIPE_TARGET_ARCH "sparc"
462 #elif defined(__arm__)
463 #define SIPE_TARGET_ARCH "arm"
465 #define SIPE_TARGET_ARCH "other"
467 gchar
*backend
= sipe_backend_version();
468 transport
->user_agent
= g_strdup_printf("%s Sipe/" PACKAGE_VERSION
" (" SIPE_TARGET_PLATFORM
"-" SIPE_TARGET_ARCH
"; %s)",
470 transport
->server_version
? transport
->server_version
: "");
473 transport
->user_agent
= g_strdup(useragent
);
476 return(transport
->user_agent
);
479 void sip_transport_response(struct sipe_core_private
*sipe_private
,
487 GString
*outstr
= g_string_new("");
490 const gchar
*keepers
[] = { "To", "From", "Call-ID", "CSeq", "Via", "Record-Route", NULL
};
492 /* Can return NULL! */
493 contact
= get_contact(sipe_private
);
495 sipmsg_add_header(msg
, "Contact", contact
);
500 gchar
*len
= g_strdup_printf("%" G_GSIZE_FORMAT
, (gsize
) strlen(body
));
501 sipmsg_add_header(msg
, "Content-Length", len
);
504 sipmsg_add_header(msg
, "Content-Length", "0");
507 sipmsg_add_header(msg
, "User-Agent", sip_transport_user_agent(sipe_private
));
509 msg
->response
= code
;
511 sipmsg_strip_headers(msg
, keepers
);
512 sipmsg_merge_new_headers(msg
);
513 sign_outgoing_message(msg
, sipe_private
, msg
->method
);
515 g_string_append_printf(outstr
, "SIP/2.0 %d %s\r\n", code
, text
);
518 name
= ((struct sipnameval
*) (tmp
->data
))->name
;
519 value
= ((struct sipnameval
*) (tmp
->data
))->value
;
521 g_string_append_printf(outstr
, "%s: %s\r\n", name
, value
);
522 tmp
= g_slist_next(tmp
);
524 g_string_append_printf(outstr
, "\r\n%s", body
? body
: "");
525 sipe_utils_message_debug("SIP", outstr
->str
, NULL
, TRUE
);
526 sipe_backend_transport_message(sipe_private
->transport
->connection
, outstr
->str
);
527 g_string_free(outstr
, TRUE
);
530 static void transactions_remove(struct sipe_core_private
*sipe_private
,
531 struct transaction
*trans
)
533 struct sip_transport
*transport
= sipe_private
->transport
;
534 if (transport
->transactions
) {
535 transport
->transactions
= g_slist_remove(transport
->transactions
,
537 SIPE_DEBUG_INFO("SIP transactions count:%d after removal", g_slist_length(transport
->transactions
));
539 if (trans
->msg
) sipmsg_free(trans
->msg
);
540 if (trans
->payload
) {
541 (*trans
->payload
->destroy
)(trans
->payload
->data
);
542 g_free(trans
->payload
);
545 if (trans
->timeout_key
) {
546 sipe_schedule_cancel(sipe_private
, trans
->timeout_key
);
547 g_free(trans
->timeout_key
);
553 static struct transaction
*transactions_find(struct sip_transport
*transport
,
556 GSList
*transactions
= transport
->transactions
;
557 const gchar
*call_id
= sipmsg_find_header(msg
, "Call-ID");
558 const gchar
*cseq
= sipmsg_find_header(msg
, "CSeq");
561 if (!call_id
|| !cseq
) {
562 SIPE_DEBUG_ERROR_NOFORMAT("transaction_find: no Call-ID or CSeq!");
566 key
= g_strdup_printf("<%s><%s>", call_id
, cseq
);
567 while (transactions
) {
568 struct transaction
*trans
= transactions
->data
;
569 if (!g_strcasecmp(trans
->key
, key
)) {
573 transactions
= transactions
->next
;
580 static void transaction_timeout_cb(struct sipe_core_private
*sipe_private
,
583 struct transaction
*trans
= data
;
584 (trans
->timeout_callback
)(sipe_private
, trans
->msg
, trans
);
585 transactions_remove(sipe_private
, trans
);
588 struct transaction
*sip_transport_request_timeout(struct sipe_core_private
*sipe_private
,
592 const gchar
*addheaders
,
594 struct sip_dialog
*dialog
,
595 TransCallback callback
,
597 TransCallback timeout_callback
)
599 struct sip_transport
*transport
= sipe_private
->transport
;
600 struct sipe_account_data
*sip
= SIPE_ACCOUNT_DATA_PRIVATE
;
603 gchar
*ourtag
= dialog
&& dialog
->ourtag
? g_strdup(dialog
->ourtag
) : NULL
;
604 gchar
*theirtag
= dialog
&& dialog
->theirtag
? g_strdup(dialog
->theirtag
) : NULL
;
605 gchar
*theirepid
= dialog
&& dialog
->theirepid
? g_strdup(dialog
->theirepid
) : NULL
;
606 gchar
*callid
= dialog
&& dialog
->callid
? g_strdup(dialog
->callid
) : gencallid();
607 gchar
*branch
= dialog
&& dialog
->callid
? NULL
: genbranch();
608 gchar
*route
= g_strdup("");
609 gchar
*epid
= get_epid(sipe_private
);
610 int cseq
= dialog
? ++dialog
->cseq
: 1 /* as Call-Id is new in this case */;
611 struct transaction
*trans
= NULL
;
613 if (dialog
&& dialog
->routes
)
615 GSList
*iter
= dialog
->routes
;
620 route
= g_strdup_printf("%sRoute: %s\r\n", route
, (char *)iter
->data
);
622 iter
= g_slist_next(iter
);
626 if (!ourtag
&& !dialog
) {
630 if (sipe_strequal(method
, "REGISTER")) {
631 if (sip
->regcallid
) {
633 callid
= g_strdup(sip
->regcallid
);
635 sip
->regcallid
= g_strdup(callid
);
637 cseq
= ++transport
->cseq
;
640 buf
= g_strdup_printf("%s %s SIP/2.0\r\n"
641 "Via: SIP/2.0/%s %s:%d%s%s\r\n"
642 "From: <sip:%s>%s%s;epid=%s\r\n"
643 "To: <%s>%s%s%s%s\r\n"
644 "Max-Forwards: 70\r\n"
649 "Content-Length: %" G_GSIZE_FORMAT
"\r\n\r\n%s",
651 dialog
&& dialog
->request
? dialog
->request
: url
,
652 TRANSPORT_DESCRIPTOR
,
653 sipe_backend_network_ip_address(),
654 transport
->connection
->client_port
,
655 branch
? ";branch=" : "",
656 branch
? branch
: "",
657 sipe_private
->username
,
658 ourtag
? ";tag=" : "",
659 ourtag
? ourtag
: "",
662 theirtag
? ";tag=" : "",
663 theirtag
? theirtag
: "",
664 theirepid
? ";epid=" : "",
665 theirepid
? theirepid
: "",
668 sip_transport_user_agent(sipe_private
),
671 addheaders
? addheaders
: "",
672 body
? (gsize
) strlen(body
) : 0,
676 //printf ("parsing msg buf:\n%s\n\n", buf);
677 msg
= sipmsg_parse_msg(buf
);
687 sign_outgoing_message(msg
, sipe_private
, method
);
689 buf
= sipmsg_to_string(msg
);
691 /* add to ongoing transactions */
692 /* ACK isn't supposed to be answered ever. So we do not keep transaction for it. */
693 if (!sipe_strequal(method
, "ACK")) {
694 trans
= g_new0(struct transaction
, 1);
695 trans
->callback
= callback
;
697 trans
->key
= g_strdup_printf("<%s><%d %s>", callid
, cseq
, method
);
698 if (timeout_callback
) {
699 trans
->timeout_callback
= timeout_callback
;
700 trans
->timeout_key
= g_strdup_printf("<transaction timeout>%s", trans
->key
);
701 sipe_schedule_seconds(sipe_private
,
705 transaction_timeout_cb
,
708 transport
->transactions
= g_slist_append(transport
->transactions
,
710 SIPE_DEBUG_INFO("SIP transactions count:%d after addition", g_slist_length(transport
->transactions
));
716 sipe_utils_message_debug("SIP", buf
, NULL
, TRUE
);
717 sipe_backend_transport_message(transport
->connection
, buf
);
723 struct transaction
*sip_transport_request(struct sipe_core_private
*sipe_private
,
727 const gchar
*addheaders
,
729 struct sip_dialog
*dialog
,
730 TransCallback callback
)
732 return sip_transport_request_timeout(sipe_private
,
744 static void sip_transport_simple_request(struct sipe_core_private
*sipe_private
,
746 struct sip_dialog
*dialog
)
748 sip_transport_request(sipe_private
,
758 void sip_transport_ack(struct sipe_core_private
*sipe_private
,
759 struct sip_dialog
*dialog
)
761 sip_transport_simple_request(sipe_private
, "ACK", dialog
);
764 void sip_transport_bye(struct sipe_core_private
*sipe_private
,
765 struct sip_dialog
*dialog
)
767 sip_transport_simple_request(sipe_private
, "BYE", dialog
);
770 struct transaction
*sip_transport_info(struct sipe_core_private
*sipe_private
,
771 const gchar
*addheaders
,
773 struct sip_dialog
*dialog
,
774 TransCallback callback
)
776 return sip_transport_request(sipe_private
,
786 struct transaction
*sip_transport_invite(struct sipe_core_private
*sipe_private
,
787 const gchar
*addheaders
,
789 struct sip_dialog
*dialog
,
790 TransCallback callback
)
792 return sip_transport_request(sipe_private
,
802 struct transaction
*sip_transport_service(struct sipe_core_private
*sipe_private
,
804 const gchar
*addheaders
,
806 TransCallback callback
)
808 return sip_transport_request(sipe_private
,
818 void sip_transport_subscribe(struct sipe_core_private
*sipe_private
,
820 const gchar
*addheaders
,
822 struct sip_dialog
*dialog
,
823 TransCallback callback
)
825 sip_transport_request(sipe_private
,
836 sipe_get_auth_scheme_name(struct sipe_core_private
*sipe_private
)
838 const char *res
= "NTLM";
840 if (SIPE_CORE_PUBLIC_FLAG_IS(KRB5
)) {
844 (void) sipe_private
; /* make compiler happy */
849 static void do_register(struct sipe_core_private
*sipe_private
,
850 gboolean deregister
);
852 static void do_reauthenticate_cb(struct sipe_core_private
*sipe_private
,
853 SIPE_UNUSED_PARAMETER gpointer unused
)
855 struct sip_transport
*transport
= sipe_private
->transport
;
857 /* register again when security token expires */
858 /* we have to start a new authentication as the security token
859 * is almost expired by sending a not signed REGISTER message */
860 SIPE_DEBUG_INFO_NOFORMAT("do a full reauthentication");
861 sipe_auth_free(&transport
->registrar
);
862 sipe_auth_free(&transport
->proxy
);
863 sipe_schedule_cancel(sipe_private
, "<registration>");
864 transport
->reregister_set
= FALSE
;
865 transport
->register_attempt
= 0;
866 do_register(sipe_private
, FALSE
);
867 transport
->reauthenticate_set
= FALSE
;
870 static void sip_transport_default_contact(struct sipe_core_private
*sipe_private
)
872 struct sip_transport
*transport
= sipe_private
->transport
;
873 sipe_private
->contact
= g_strdup_printf("<sip:%s:%d;maddr=%s;transport=%s>;proxy=replace",
874 sipe_private
->username
,
875 transport
->connection
->client_port
,
876 sipe_backend_network_ip_address(),
877 TRANSPORT_DESCRIPTOR
);
880 static void do_register_cb(struct sipe_core_private
*sipe_private
,
881 SIPE_UNUSED_PARAMETER
void *unused
)
883 do_register(sipe_private
, FALSE
);
886 static void sip_transport_set_reregister(struct sipe_core_private
*sipe_private
,
889 sipe_schedule_seconds(sipe_private
,
897 static void sipe_server_register(struct sipe_core_private
*sipe_private
,
902 static gboolean
process_register_response(struct sipe_core_private
*sipe_private
,
904 SIPE_UNUSED_PARAMETER
struct transaction
*trans
)
906 struct sip_transport
*transport
= sipe_private
->transport
;
907 struct sipe_account_data
*sip
= SIPE_ACCOUNT_DATA_PRIVATE
;
909 const gchar
*expires_header
;
911 GSList
*hdr
= msg
->headers
;
912 struct sipnameval
*elem
;
914 expires_header
= sipmsg_find_header(msg
, "Expires");
915 expires
= expires_header
!= NULL
? strtol(expires_header
, NULL
, 10) : 0;
916 SIPE_DEBUG_INFO("process_register_response: got response to REGISTER; expires = %d", expires
);
918 switch (msg
->response
) {
921 const gchar
*contact_hdr
;
926 const gchar
*server_hdr
= sipmsg_find_header(msg
, "Server");
927 const char *auth_scheme
;
929 if (!transport
->reregister_set
) {
930 sip_transport_set_reregister(sipe_private
,
932 transport
->reregister_set
= TRUE
;
935 if (server_hdr
&& !transport
->server_version
) {
936 transport
->server_version
= g_strdup(server_hdr
);
937 g_free(transport
->user_agent
);
938 transport
->user_agent
= NULL
;
941 auth_scheme
= sipe_get_auth_scheme_name(sipe_private
);
942 tmp
= sipmsg_find_auth_header(msg
, auth_scheme
);
945 SIPE_DEBUG_INFO("process_register_response: Auth header: %s", tmp
);
946 fill_auth(tmp
, &transport
->registrar
);
949 if (!transport
->reauthenticate_set
) {
950 gchar
*action_name
= g_strdup_printf("<%s>", "+reauthentication");
951 guint reauth_timeout
;
952 if (transport
->registrar
.type
== AUTH_TYPE_KERBEROS
&& transport
->registrar
.expires
> 0) {
953 /* assuming normal Kerberos ticket expiration of about 8-10 hours */
954 reauth_timeout
= transport
->registrar
.expires
- 300;
956 /* NTLM: we have to reauthenticate as our security token expires
957 after eight hours (be five minutes early) */
958 reauth_timeout
= (8 * 3600) - 300;
960 sipe_schedule_seconds(sipe_private
,
964 do_reauthenticate_cb
,
967 transport
->reauthenticate_set
= TRUE
;
970 sipe_backend_connection_completed(SIPE_CORE_PUBLIC
);
972 epid
= get_epid(sipe_private
);
973 uuid
= generateUUIDfromEPID(epid
);
976 // There can be multiple Contact headers (one per location where the user is logged in) so
977 // make sure to only get the one for this uuid
978 for (i
= 0; (contact_hdr
= sipmsg_find_header_instance (msg
, "Contact", i
)); i
++) {
979 gchar
* valid_contact
= sipmsg_find_part_of_header (contact_hdr
, uuid
, NULL
, NULL
);
981 gruu
= sipmsg_find_part_of_header(contact_hdr
, "gruu=\"", "\"", NULL
);
982 //SIPE_DEBUG_INFO("process_register_response: got gruu %s from contact hdr w/ right uuid: %s", gruu, contact_hdr);
983 g_free(valid_contact
);
986 //SIPE_DEBUG_INFO("process_register_response: ignoring contact hdr b/c not right uuid: %s", contact_hdr);
991 g_free(sipe_private
->contact
);
993 sipe_private
->contact
= g_strdup_printf("<%s>", gruu
);
996 //SIPE_DEBUG_INFO_NOFORMAT("process_register_response: didn't find gruu in a Contact hdr");
997 sip_transport_default_contact(sipe_private
);
999 SIPE_CORE_PRIVATE_FLAG_UNSET(OCS2007
);
1000 SIPE_CORE_PRIVATE_FLAG_UNSET(REMOTE_USER
);
1001 sip
->batched_support
= FALSE
;
1006 if (sipe_strcase_equal(elem
->name
, "Supported")) {
1007 if (sipe_strcase_equal(elem
->value
, "msrtc-event-categories")) {
1008 /* We interpret this as OCS2007+ indicator */
1009 SIPE_CORE_PRIVATE_FLAG_SET(OCS2007
);
1010 SIPE_DEBUG_INFO("Supported: %s (indicates OCS2007+)", elem
->value
);
1012 if (sipe_strcase_equal(elem
->value
, "adhoclist")) {
1013 sip
->batched_support
= TRUE
;
1014 SIPE_DEBUG_INFO("Supported: %s", elem
->value
);
1017 if (sipe_strcase_equal(elem
->name
, "Allow-Events")){
1018 gchar
**caps
= g_strsplit(elem
->value
,",",0);
1021 sip
->allow_events
= g_slist_append(sip
->allow_events
, g_strdup(caps
[i
]));
1022 SIPE_DEBUG_INFO("Allow-Events: %s", caps
[i
]);
1027 if (sipe_strcase_equal(elem
->name
, "ms-user-logon-data")) {
1028 if (sipe_strcase_equal(elem
->value
, "RemoteUser")) {
1029 SIPE_CORE_PRIVATE_FLAG_SET(REMOTE_USER
);
1030 SIPE_DEBUG_INFO_NOFORMAT("ms-user-logon-data: RemoteUser (connected "
1031 "via Edge Server)");
1034 hdr
= g_slist_next(hdr
);
1037 /* rejoin open chats to be able to use them by continue to send messages */
1038 sipe_backend_chat_rejoin_all(SIPE_CORE_PUBLIC
);
1041 if (!transport
->subscribed
) { //do it just once, not every re-register
1043 if (g_slist_find_custom(sip
->allow_events
, "vnd-microsoft-roaming-contacts",
1044 (GCompareFunc
)g_ascii_strcasecmp
)) {
1045 sipe_subscribe_roaming_contacts(sipe_private
);
1048 /* For 2007+ it does not make sence to subscribe to:
1049 * vnd-microsoft-roaming-ACL
1050 * vnd-microsoft-provisioning (not v2)
1052 * These are for backward compatibility.
1054 if (SIPE_CORE_PRIVATE_FLAG_IS(OCS2007
))
1056 if (g_slist_find_custom(sip
->allow_events
, "vnd-microsoft-roaming-self",
1057 (GCompareFunc
)g_ascii_strcasecmp
)) {
1058 sipe_subscribe_roaming_self(sipe_private
);
1060 if (g_slist_find_custom(sip
->allow_events
, "vnd-microsoft-provisioning-v2",
1061 (GCompareFunc
)g_ascii_strcasecmp
)) {
1062 sipe_subscribe_roaming_provisioning_v2(sipe_private
);
1065 /* For 2005- servers */
1068 //sipe_options_request(sip, sipe_private->public.sip_domain);
1070 if (g_slist_find_custom(sip
->allow_events
, "vnd-microsoft-roaming-ACL",
1071 (GCompareFunc
)g_ascii_strcasecmp
)) {
1072 sipe_subscribe_roaming_acl(sipe_private
);
1074 if (g_slist_find_custom(sip
->allow_events
, "vnd-microsoft-provisioning",
1075 (GCompareFunc
)g_ascii_strcasecmp
)) {
1076 sipe_subscribe_roaming_provisioning(sipe_private
);
1078 if (g_slist_find_custom(sip
->allow_events
, "presence.wpending",
1079 (GCompareFunc
)g_ascii_strcasecmp
)) {
1080 sipe_subscribe_presence_wpending(sipe_private
,
1084 /* For 2007+ we publish our initial statuses and calendar data only after
1085 * received our existing publications in sipe_process_roaming_self()
1086 * Only in this case we know versions of current publications made
1089 /* For 2005- we publish our initial statuses only after
1090 * received our existing UserInfo data in response to
1091 * self subscription.
1092 * Only in this case we won't override existing UserInfo data
1093 * set earlier or by other client on our behalf.
1097 transport
->subscribed
= TRUE
;
1100 timeout
= sipmsg_find_part_of_header(sipmsg_find_header(msg
, "ms-keep-alive"),
1101 "timeout=", ";", NULL
);
1102 if (timeout
!= NULL
) {
1103 sscanf(timeout
, "%u", &sipe_private
->public.keepalive_timeout
);
1104 SIPE_DEBUG_INFO("process_register_response: server determined keep alive timeout is %u seconds",
1105 sipe_private
->public.keepalive_timeout
);
1109 SIPE_DEBUG_INFO("process_register_response: got 200, removing CSeq: %d", transport
->cseq
);
1114 gchar
*redirect
= parse_from(sipmsg_find_header(msg
, "Contact"));
1116 if (redirect
&& (g_strncasecmp("sip:", redirect
, 4) == 0)) {
1117 gchar
**parts
= g_strsplit(redirect
+ 4, ";", 0);
1121 guint transport
= SIPE_TRANSPORT_TLS
;
1124 tmp
= g_strsplit(parts
[0], ":", 0);
1125 hostname
= g_strdup(tmp
[0]);
1126 if (tmp
[1]) port
= strtoul(tmp
[1], NULL
, 10);
1130 tmp
= g_strsplit(parts
[i
], "=", 0);
1132 if (g_strcasecmp("transport", tmp
[0]) == 0) {
1133 if (g_strcasecmp("tcp", tmp
[1]) == 0) {
1134 transport
= SIPE_TRANSPORT_TCP
;
1143 /* Close old connection */
1144 sipe_connection_cleanup(sipe_private
);
1146 /* Create new connection */
1147 sipe_server_register(sipe_private
, transport
, hostname
, port
);
1148 SIPE_DEBUG_INFO("process_register_response: redirected to host %s port %d transport %d",
1149 hostname
, port
, transport
);
1156 const char *auth_scheme
;
1157 SIPE_DEBUG_INFO("process_register_response: REGISTER retries %d", transport
->registrar
.retries
);
1158 if (transport
->registrar
.retries
> 2) {
1159 SIPE_DEBUG_INFO_NOFORMAT("process_register_response: still not authenticated after 3 tries - giving up.");
1160 sipe_backend_connection_error(SIPE_CORE_PUBLIC
,
1161 SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED
,
1162 _("Authentication failed"));
1166 if (transport
->reauthenticate_set
) {
1167 SIPE_DEBUG_ERROR_NOFORMAT("process_register_response: RE-REGISTER rejected, triggering re-authentication");
1168 do_reauthenticate_cb(sipe_private
, NULL
);
1172 auth_scheme
= sipe_get_auth_scheme_name(sipe_private
);
1173 tmp
= sipmsg_find_auth_header(msg
, auth_scheme
);
1175 SIPE_DEBUG_INFO("process_register_response: Auth header: %s", tmp
? tmp
: "");
1177 char *tmp2
= g_strconcat(_("Incompatible authentication scheme chosen"), ": ", auth_scheme
, NULL
);
1178 sipe_backend_connection_error(SIPE_CORE_PUBLIC
,
1179 SIPE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE
,
1184 fill_auth(tmp
, &transport
->registrar
);
1185 transport
->reregister_set
= FALSE
;
1186 transport
->register_attempt
= 0;
1187 do_register(sipe_private
,
1188 sipe_backend_connection_is_disconnecting(SIPE_CORE_PUBLIC
));
1195 sipmsg_parse_warning(msg
, &reason
);
1196 reason
= reason
? reason
: sipmsg_get_ms_diagnostics_public_reason(msg
);
1197 warning
= g_strdup_printf(_("You have been rejected by the server: %s"),
1198 reason
? reason
: _("no reason given"));
1201 sipe_backend_connection_error(SIPE_CORE_PUBLIC
,
1202 SIPE_CONNECTION_ERROR_INVALID_SETTINGS
,
1210 const gchar
*diagnostics
= sipmsg_find_header(msg
, "ms-diagnostics");
1211 gchar
*reason
= sipmsg_get_ms_diagnostics_reason(msg
);
1213 warning
= g_strdup_printf(_("Not found: %s. Please contact your Administrator"),
1214 diagnostics
? (reason
? reason
: _("no reason given")) :
1215 _("SIP is either not enabled for the destination URI or it does not exist"));
1218 sipe_backend_connection_error(SIPE_CORE_PUBLIC
,
1219 SIPE_CONNECTION_ERROR_INVALID_USERNAME
,
1225 case 504: /* Server time-out */
1226 /* first attempt + 5 retries */
1227 if (transport
->register_attempt
< 6) {
1228 SIPE_DEBUG_INFO("process_register_response: RE-REGISTER timeout on attempt %d, retrying later",
1229 transport
->register_attempt
);
1230 sip_transport_set_reregister(sipe_private
, 60);
1236 gchar
*reason
= sipmsg_get_ms_diagnostics_reason(msg
);
1238 warning
= g_strdup_printf(_("Service unavailable: %s"), reason
? reason
: _("no reason given"));
1241 sipe_backend_connection_error(SIPE_CORE_PUBLIC
,
1242 SIPE_CONNECTION_ERROR_NETWORK
,
1252 static gboolean
register_response_timeout(struct sipe_core_private
*sipe_private
,
1253 SIPE_UNUSED_PARAMETER
struct sipmsg
*msg
,
1254 SIPE_UNUSED_PARAMETER
struct transaction
*trans
)
1256 struct sip_transport
*transport
= sipe_private
->transport
;
1257 if (transport
->register_attempt
< 6) {
1258 SIPE_DEBUG_INFO("register_response_timeout: no answer to attempt %d, retrying",
1259 transport
->register_attempt
);
1260 do_register(sipe_private
, FALSE
);
1262 gchar
*warning
= g_strdup_printf(_("Service unavailable: %s"), _("no reason given"));
1263 sipe_backend_connection_error(SIPE_CORE_PUBLIC
,
1264 SIPE_CONNECTION_ERROR_NETWORK
,
1271 static void do_register(struct sipe_core_private
*sipe_private
,
1272 gboolean deregister
)
1274 struct sip_transport
*transport
= sipe_private
->transport
;
1281 if (!sipe_private
->public.sip_domain
) return;
1284 if (transport
->reregister_set
) {
1285 transport
->reregister_set
= FALSE
;
1286 transport
->register_attempt
= 1;
1288 transport
->register_attempt
++;
1292 epid
= get_epid(sipe_private
);
1293 uuid
= generateUUIDfromEPID(epid
);
1294 hdr
= g_strdup_printf("Contact: <sip:%s:%d;transport=%s;ms-opaque=d3470f2e1d>;methods=\"INVITE, MESSAGE, INFO, SUBSCRIBE, OPTIONS, BYE, CANCEL, NOTIFY, ACK, REFER, BENOTIFY\";proxy=replace;+sip.instance=\"<urn:uuid:%s>\"\r\n"
1295 "Supported: gruu-10, adhoclist, msrtc-event-categories, com.microsoft.msrtc.presence\r\n"
1296 "Event: registration\r\n"
1297 "Allow-Events: presence\r\n"
1298 "ms-keep-alive: UAC;hop-hop=yes\r\n"
1300 sipe_backend_network_ip_address(),
1301 transport
->connection
->client_port
,
1302 TRANSPORT_DESCRIPTOR
,
1304 deregister
? "Expires: 0\r\n" : "");
1308 uri
= sip_uri_from_name(sipe_private
->public.sip_domain
);
1309 to
= sip_uri_self(sipe_private
);
1310 sip_transport_request_timeout(sipe_private
,
1317 process_register_response
,
1319 deregister
? NULL
: register_response_timeout
);
1325 /* Make sure that all messages are pushed to the server
1326 before the connection gets shut down */
1327 SIPE_DEBUG_INFO_NOFORMAT("De-register from server. Flushing outstanding messages.");
1328 sipe_backend_transport_flush(transport
->connection
);
1332 void sip_transport_deregister(struct sipe_core_private
*sipe_private
)
1334 do_register(sipe_private
, TRUE
);
1337 void sip_transport_disconnect(struct sipe_core_private
*sipe_private
)
1339 struct sip_transport
*transport
= sipe_private
->transport
;
1341 sipe_backend_transport_disconnect(transport
->connection
);
1343 sipe_auth_free(&transport
->registrar
);
1344 sipe_auth_free(&transport
->proxy
);
1346 g_free(transport
->server_name
);
1347 g_free(transport
->server_version
);
1348 g_free(transport
->user_agent
);
1350 while (transport
->transactions
)
1351 transactions_remove(sipe_private
,
1352 transport
->transactions
->data
);
1356 sipe_private
->transport
= NULL
;
1357 sipe_private
->service_data
= NULL
;
1359 if (sipe_private
->dns_query
)
1360 sipe_backend_dns_query_cancel(sipe_private
->dns_query
);
1364 guint
sip_transport_port(struct sipe_core_private
*sipe_private
)
1366 return sipe_private
->transport
->server_port
;
1369 static void process_input_message(struct sipe_core_private
*sipe_private
,
1372 struct sip_transport
*transport
= sipe_private
->transport
;
1373 gboolean notfound
= FALSE
;
1374 const char *method
= msg
->method
? msg
->method
: "NOT FOUND";
1376 SIPE_DEBUG_INFO("process_input_message: msg->response(%d),msg->method(%s)",
1377 msg
->response
, method
);
1379 if (msg
->response
== 0) { /* request */
1380 if (sipe_strequal(method
, "MESSAGE")) {
1381 process_incoming_message(sipe_private
, msg
);
1382 } else if (sipe_strequal(method
, "NOTIFY")) {
1383 SIPE_DEBUG_INFO_NOFORMAT("send->process_incoming_notify");
1384 process_incoming_notify(sipe_private
, msg
, TRUE
, FALSE
);
1385 } else if (sipe_strequal(method
, "BENOTIFY")) {
1386 SIPE_DEBUG_INFO_NOFORMAT("send->process_incoming_benotify");
1387 process_incoming_notify(sipe_private
, msg
, TRUE
, TRUE
);
1388 } else if (sipe_strequal(method
, "INVITE")) {
1389 process_incoming_invite(sipe_private
, msg
);
1390 } else if (sipe_strequal(method
, "REFER")) {
1391 process_incoming_refer(sipe_private
, msg
);
1392 } else if (sipe_strequal(method
, "OPTIONS")) {
1393 process_incoming_options(sipe_private
, msg
);
1394 } else if (sipe_strequal(method
, "INFO")) {
1395 process_incoming_info(sipe_private
, msg
);
1396 } else if (sipe_strequal(method
, "ACK")) {
1397 /* ACK's don't need any response */
1398 } else if (sipe_strequal(method
, "PRACK")) {
1399 sip_transport_response(sipe_private
, msg
, 200, "OK", NULL
);
1400 } else if (sipe_strequal(method
, "SUBSCRIBE")) {
1401 /* LCS 2005 sends us these - just respond 200 OK */
1402 sip_transport_response(sipe_private
, msg
, 200, "OK", NULL
);
1403 } else if (sipe_strequal(method
, "CANCEL")) {
1404 process_incoming_cancel(sipe_private
, msg
);
1405 } else if (sipe_strequal(method
, "BYE")) {
1406 process_incoming_bye(sipe_private
, msg
);
1408 sip_transport_response(sipe_private
, msg
, 501, "Not implemented", NULL
);
1412 } else { /* response */
1413 struct transaction
*trans
= transactions_find(transport
, msg
);
1415 if (msg
->response
< 200) {
1416 if (msg
->bodylen
!= 0) {
1417 SIPE_DEBUG_INFO("got provisional (%d) response with body", msg
->response
);
1418 if (trans
->callback
) {
1419 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: we have a transaction callback");
1420 (trans
->callback
)(sipe_private
, msg
, trans
);
1423 /* ignore provisional response */
1424 SIPE_DEBUG_INFO("process_input_message: got provisional (%d) response, ignoring", msg
->response
);
1427 /* Transaction not yet completed */
1430 } else if (msg
->response
== 401) { /* Unauthorized */
1432 if (sipe_strequal(trans
->msg
->method
, "REGISTER")) {
1433 /* Expected response during authentication handshake */
1434 transport
->registrar
.retries
++;
1435 SIPE_DEBUG_INFO("process_input_message: RE-REGISTER CSeq: %d", transport
->cseq
);
1439 /* Are we registered? */
1440 if (transport
->reregister_set
) {
1441 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: 401 response to non-REGISTER message. Retrying with new authentication.");
1442 sign_outgoing_message(trans
->msg
,
1444 trans
->msg
->method
);
1447 * We don't have a valid authentication at the moment.
1448 * Resend message unchanged. It will be rejected again
1449 * and hopefully by then we have a valid authentication.
1451 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: 401 response to non-REGISTER message. Bouncing...");
1454 /* Resend request */
1455 resend
= sipmsg_to_string(trans
->msg
);
1456 sipe_utils_message_debug("SIP", resend
, NULL
, TRUE
);
1457 sipe_backend_transport_message(sipe_private
->transport
->connection
, resend
);
1460 /* Transaction not yet completed */
1464 } else if (msg
->response
== 407) { /* Proxy Authentication Required */
1466 if (transport
->proxy
.retries
> 30) {
1467 SIPE_DEBUG_ERROR_NOFORMAT("process_input_message: too many proxy authentication retries. Giving up.");
1469 gchar
*resend
, *auth
;
1472 transport
->proxy
.retries
++;
1474 /* do proxy authentication */
1475 ptmp
= sipmsg_find_header(msg
, "Proxy-Authenticate");
1476 fill_auth(ptmp
, &transport
->proxy
);
1477 auth
= auth_header(sipe_private
, &transport
->proxy
, trans
->msg
);
1478 sipmsg_remove_header_now(trans
->msg
, "Proxy-Authorization");
1479 sipmsg_add_header_now_pos(trans
->msg
, "Proxy-Authorization", auth
, 5);
1482 /* resend request */
1483 resend
= sipmsg_to_string(trans
->msg
);
1484 sipe_utils_message_debug("SIP", resend
, NULL
, TRUE
);
1485 sipe_backend_transport_message(sipe_private
->transport
->connection
, resend
);
1488 /* Transaction not yet completed */
1493 transport
->registrar
.retries
= 0;
1494 transport
->proxy
.retries
= 0;
1497 /* Is transaction completed? */
1499 if (trans
->callback
) {
1500 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: we have a transaction callback");
1501 /* call the callback to process response */
1502 (trans
->callback
)(sipe_private
, msg
, trans
);
1505 SIPE_DEBUG_INFO("process_input_message: removing CSeq %d", transport
->cseq
);
1506 transactions_remove(sipe_private
, trans
);
1509 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: received response to unknown transaction");
1515 SIPE_DEBUG_INFO("received a unknown sip message with method %s and response %d", method
, msg
->response
);
1519 static void sip_transport_input(struct sipe_transport_connection
*conn
)
1521 struct sipe_core_private
*sipe_private
= conn
->user_data
;
1522 struct sip_transport
*transport
= sipe_private
->transport
;
1523 gchar
*cur
= conn
->buffer
;
1525 /* according to the RFC remove CRLF at the beginning */
1526 while (*cur
== '\r' || *cur
== '\n') {
1529 if (cur
!= conn
->buffer
)
1530 sipe_utils_shrink_buffer(conn
, cur
);
1532 /* Received a full Header? */
1533 transport
->processing_input
= TRUE
;
1534 while (transport
->processing_input
&&
1535 ((cur
= strstr(conn
->buffer
, "\r\n\r\n")) != NULL
)) {
1541 msg
= sipmsg_parse_header(conn
->buffer
);
1544 remainder
= conn
->buffer_used
- (cur
- conn
->buffer
);
1545 if (msg
&& remainder
>= (guint
) msg
->bodylen
) {
1546 char *dummy
= g_malloc(msg
->bodylen
+ 1);
1547 memcpy(dummy
, cur
, msg
->bodylen
);
1548 dummy
[msg
->bodylen
] = '\0';
1550 cur
+= msg
->bodylen
;
1551 sipe_utils_message_debug("SIP",
1555 sipe_utils_shrink_buffer(conn
, cur
);
1558 SIPE_DEBUG_INFO("sipe_transport_input: body too short (%d < %d, strlen %d) - ignoring message", remainder
, msg
->bodylen
, (int)strlen(conn
->buffer
));
1562 /* restore header for next try */
1567 // Verify the signature before processing it
1568 if (transport
->registrar
.gssapi_context
) {
1569 struct sipmsg_breakdown msgbd
;
1570 gchar
*signature_input_str
;
1573 sipmsg_breakdown_parse(&msgbd
, transport
->registrar
.realm
, transport
->registrar
.target
);
1574 signature_input_str
= sipmsg_breakdown_get_string(transport
->registrar
.version
, &msgbd
);
1576 rspauth
= sipmsg_find_part_of_header(sipmsg_find_header(msg
, "Authentication-Info"), "rspauth=\"", "\"", NULL
);
1578 if (rspauth
!= NULL
) {
1579 if (!sip_sec_verify_signature(transport
->registrar
.gssapi_context
, signature_input_str
, rspauth
)) {
1580 SIPE_DEBUG_INFO_NOFORMAT("sip_transport_input: signature of incoming message validated");
1581 process_input_message(sipe_private
, msg
);
1583 SIPE_DEBUG_INFO_NOFORMAT("sip_transport_input: signature of incoming message is invalid.");
1584 sipe_backend_connection_error(SIPE_CORE_PUBLIC
,
1585 SIPE_CONNECTION_ERROR_NETWORK
,
1586 _("Invalid message signature received"));
1588 } else if ((msg
->response
== 401) ||
1589 sipe_strequal(msg
->method
, "REGISTER")) {
1590 /* a) Retry non-REGISTER requests with updated authentication */
1591 /* b) We must always process REGISTER responses */
1592 process_input_message(sipe_private
, msg
);
1594 /* OCS sends provisional messages that are *not* signed */
1595 if (msg
->response
>= 200) {
1596 /* We are not calling process_input_message(),
1597 so we need to drop the transaction here. */
1598 struct transaction
*trans
= transactions_find(transport
, msg
);
1599 if (trans
) transactions_remove(sipe_private
, trans
);
1601 SIPE_DEBUG_INFO_NOFORMAT("sip_transport_input: message without authentication data - ignoring");
1603 g_free(signature_input_str
);
1606 sipmsg_breakdown_free(&msgbd
);
1608 process_input_message(sipe_private
, msg
);
1613 /* Redirect: old content of "transport" is no longer valid */
1614 transport
= sipe_private
->transport
;
1618 static void sip_transport_connected(struct sipe_transport_connection
*conn
)
1620 struct sipe_core_private
*sipe_private
= conn
->user_data
;
1621 sipe_private
->service_data
= NULL
;
1622 do_register(sipe_private
, FALSE
);
1625 static void resolve_next_service(struct sipe_core_private
*sipe_private
,
1626 const struct sip_service_data
*start
);
1627 static void sip_transport_error(struct sipe_transport_connection
*conn
,
1630 struct sipe_core_private
*sipe_private
= conn
->user_data
;
1632 /* This failed attempt was based on a DNS SRV record */
1633 if (sipe_private
->service_data
) {
1634 resolve_next_service(sipe_private
, NULL
);
1636 sipe_backend_connection_error(SIPE_CORE_PUBLIC
,
1637 SIPE_CONNECTION_ERROR_NETWORK
,
1642 /* server_name must be g_alloc()'ed */
1643 static void sipe_server_register(struct sipe_core_private
*sipe_private
,
1648 sipe_connect_setup setup
= {
1651 (server_port
!= 0) ? server_port
:
1652 (type
== SIPE_TRANSPORT_TLS
) ? 5061 : 5060,
1654 sip_transport_connected
,
1655 sip_transport_input
,
1658 struct sip_transport
*transport
= g_new0(struct sip_transport
, 1);
1660 transport
->server_name
= server_name
;
1661 transport
->server_port
= setup
.server_port
;
1662 transport
->connection
= sipe_backend_transport_connect(SIPE_CORE_PUBLIC
,
1664 sipe_private
->transport
= transport
;
1667 struct sip_service_data
{
1668 const char *protocol
;
1669 const char *transport
;
1673 /* Service list for autodection */
1674 static const struct sip_service_data service_autodetect
[] = {
1675 { "sipinternaltls", "tcp", SIPE_TRANSPORT_TLS
}, /* for internal TLS connections */
1676 { "sipinternal", "tcp", SIPE_TRANSPORT_TCP
}, /* for internal TCP connections */
1677 { "sip", "tls", SIPE_TRANSPORT_TLS
}, /* for external TLS connections */
1678 { "sip", "tcp", SIPE_TRANSPORT_TCP
}, /*.for external TCP connections */
1682 /* Service list for SSL/TLS */
1683 static const struct sip_service_data service_tls
[] = {
1684 { "sipinternaltls", "tcp", SIPE_TRANSPORT_TLS
}, /* for internal TLS connections */
1685 { "sip", "tls", SIPE_TRANSPORT_TLS
}, /* for external TLS connections */
1689 /* Service list for TCP */
1690 static const struct sip_service_data service_tcp
[] = {
1691 { "sipinternal", "tcp", SIPE_TRANSPORT_TCP
}, /* for internal TCP connections */
1692 { "sip", "tcp", SIPE_TRANSPORT_TCP
}, /*.for external TCP connections */
1696 static const struct sip_service_data
*services
[] = {
1697 service_autodetect
, /* SIPE_TRANSPORT_AUTO */
1698 service_tls
, /* SIPE_TRANSPORT_TLS */
1699 service_tcp
/* SIPE_TRANSPORT_TCP */
1702 static void sipe_core_dns_resolved(struct sipe_core_public
*sipe_public
,
1703 const gchar
*hostname
, guint port
)
1705 struct sipe_core_private
*sipe_private
= SIPE_CORE_PRIVATE
;
1707 sipe_private
->dns_query
= NULL
;
1710 SIPE_DEBUG_INFO("sipe_core_dns_resolved - SRV hostname: %s port: %d",
1712 sipe_server_register(sipe_private
,
1713 sipe_private
->service_data
->type
,
1714 g_strdup(hostname
), port
);
1716 resolve_next_service(SIPE_CORE_PRIVATE
, NULL
);
1720 static void resolve_next_service(struct sipe_core_private
*sipe_private
,
1721 const struct sip_service_data
*start
)
1724 sipe_private
->service_data
= start
;
1726 sipe_private
->service_data
++;
1727 if (sipe_private
->service_data
->protocol
== NULL
) {
1728 guint type
= sipe_private
->transport_type
;
1730 /* We tried all services */
1731 sipe_private
->service_data
= NULL
;
1733 /* Try connecting to the SIP hostname directly */
1734 SIPE_DEBUG_INFO_NOFORMAT("no SRV records found; using SIP domain as fallback");
1735 if (type
== SIPE_TRANSPORT_AUTO
)
1736 type
= SIPE_TRANSPORT_TLS
;
1738 sipe_server_register(sipe_private
, type
,
1739 g_strdup(sipe_private
->public.sip_domain
),
1745 /* Try to resolve next service */
1746 sipe_private
->dns_query
= sipe_backend_dns_query_srv(
1747 sipe_private
->service_data
->protocol
,
1748 sipe_private
->service_data
->transport
,
1749 sipe_private
->public.sip_domain
,
1750 (sipe_dns_resolved_cb
) sipe_core_dns_resolved
,
1754 void sipe_core_transport_sip_connect(struct sipe_core_public
*sipe_public
,
1756 const gchar
*server
,
1759 struct sipe_core_private
*sipe_private
= SIPE_CORE_PRIVATE
;
1762 /* Use user specified server[:port] */
1763 int port_number
= 0;
1766 port_number
= atoi(port
);
1768 SIPE_DEBUG_INFO("sipe_core_connect: user specified SIP server %s:%d",
1769 server
, port_number
);
1771 sipe_server_register(sipe_private
, transport
,
1772 g_strdup(server
), port_number
);
1774 /* Server auto-discovery */
1776 /* Remember user specified transport type */
1777 sipe_private
->transport_type
= transport
;
1778 resolve_next_service(sipe_private
, services
[transport
]);
1782 void sipe_core_transport_sip_keepalive(struct sipe_core_public
*sipe_public
)
1784 SIPE_DEBUG_INFO("sending keep alive %d",
1785 sipe_public
->keepalive_timeout
);
1786 sipe_utils_message_debug("SIP", "", NULL
, TRUE
);
1787 sipe_backend_transport_message(SIPE_CORE_PRIVATE
->transport
->connection
,
1791 int sip_transaction_cseq(struct transaction
*trans
)
1795 g_return_val_if_fail(trans
&& trans
->key
, 0);
1797 sscanf(trans
->key
, "<%*[a-zA-Z0-9]><%d INVITE>", &cseq
);