2 * @file sip-transport.c
6 * Copyright (C) 2010 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 void sip_transport_response(struct sipe_core_private
*sipe_private
,
422 GString
*outstr
= g_string_new("");
425 const gchar
*keepers
[] = { "To", "From", "Call-ID", "CSeq", "Via", "Record-Route", NULL
};
427 /* Can return NULL! */
428 contact
= get_contact(sipe_private
);
430 sipmsg_add_header(msg
, "Contact", contact
);
435 gchar
*len
= g_strdup_printf("%" G_GSIZE_FORMAT
, (gsize
) strlen(body
));
436 sipmsg_add_header(msg
, "Content-Length", len
);
439 sipmsg_add_header(msg
, "Content-Length", "0");
442 msg
->response
= code
;
444 sipmsg_strip_headers(msg
, keepers
);
445 sipmsg_merge_new_headers(msg
);
446 sign_outgoing_message(msg
, sipe_private
, msg
->method
);
448 g_string_append_printf(outstr
, "SIP/2.0 %d %s\r\n", code
, text
);
451 name
= ((struct sipnameval
*) (tmp
->data
))->name
;
452 value
= ((struct sipnameval
*) (tmp
->data
))->value
;
454 g_string_append_printf(outstr
, "%s: %s\r\n", name
, value
);
455 tmp
= g_slist_next(tmp
);
457 g_string_append_printf(outstr
, "\r\n%s", body
? body
: "");
458 sipe_utils_message_debug("SIP", outstr
->str
, NULL
, TRUE
);
459 sipe_backend_transport_message(sipe_private
->transport
->connection
, outstr
->str
);
460 g_string_free(outstr
, TRUE
);
463 static void transactions_remove(struct sipe_core_private
*sipe_private
,
464 struct transaction
*trans
)
466 struct sip_transport
*transport
= sipe_private
->transport
;
467 if (transport
->transactions
) {
468 transport
->transactions
= g_slist_remove(transport
->transactions
,
470 SIPE_DEBUG_INFO("SIP transactions count:%d after removal", g_slist_length(transport
->transactions
));
472 if (trans
->msg
) sipmsg_free(trans
->msg
);
473 if (trans
->payload
) {
474 (*trans
->payload
->destroy
)(trans
->payload
->data
);
475 g_free(trans
->payload
);
478 if (trans
->timeout_key
) {
479 sipe_schedule_cancel(sipe_private
, trans
->timeout_key
);
480 g_free(trans
->timeout_key
);
486 static struct transaction
*transactions_find(struct sip_transport
*transport
,
489 GSList
*transactions
= transport
->transactions
;
490 const gchar
*call_id
= sipmsg_find_header(msg
, "Call-ID");
491 const gchar
*cseq
= sipmsg_find_header(msg
, "CSeq");
494 if (!call_id
|| !cseq
) {
495 SIPE_DEBUG_ERROR_NOFORMAT("transaction_find: no Call-ID or CSeq!");
499 key
= g_strdup_printf("<%s><%s>", call_id
, cseq
);
500 while (transactions
) {
501 struct transaction
*trans
= transactions
->data
;
502 if (!g_strcasecmp(trans
->key
, key
)) {
506 transactions
= transactions
->next
;
513 static void transaction_timeout_cb(struct sipe_core_private
*sipe_private
,
516 struct transaction
*trans
= data
;
517 (trans
->timeout_callback
)(sipe_private
, trans
->msg
, trans
);
518 transactions_remove(sipe_private
, trans
);
521 const gchar
*sip_transport_user_agent(struct sipe_core_private
*sipe_private
)
523 struct sip_transport
*transport
= sipe_private
->transport
;
525 if (!transport
->user_agent
) {
526 const gchar
*useragent
= sipe_backend_setting(SIPE_CORE_PUBLIC
,
527 SIPE_SETTING_USER_AGENT
);
528 if (is_empty(useragent
)) {
529 /*@TODO: better approach to define _user_ OS, it's version and host architecture */
531 #if defined(__linux__) || defined(__linux) || defined(__LINUX__)
532 #define SIPE_TARGET_PLATFORM "linux"
533 #elif defined(__NetBSD__) ||defined( __OpenBSD__) || defined(__FreeBSD__)
534 #define SIPE_TARGET_PLATFORM "bsd"
535 #elif defined(__APPLE__) || defined(__MACOS__)
536 #define SIPE_TARGET_PLATFORM "macosx"
537 #elif defined(_AIX) || defined(__AIX__) || defined(__aix__)
538 #define SIPE_TARGET_PLATFORM "aix"
539 #elif defined(__solaris__) || defined(__sun)
540 #define SIPE_TARGET_PLATFORM "sun"
541 #elif defined(_WIN32)
542 #define SIPE_TARGET_PLATFORM "win"
543 #elif defined(__CYGWIN__)
544 #define SIPE_TARGET_PLATFORM "cygwin"
545 #elif defined(__hpux__)
546 #define SIPE_TARGET_PLATFORM "hpux"
547 #elif defined(__sgi__)
548 #define SIPE_TARGET_PLATFORM "irix"
550 #define SIPE_TARGET_PLATFORM "unknown"
553 #if defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64)
554 #define SIPE_TARGET_ARCH "x86_64"
555 #elif defined(__386__) || defined(__i386__) || defined(__i386) || defined(_M_IX86) || defined(_M_I386)
556 #define SIPE_TARGET_ARCH "i386"
557 #elif defined(__ppc64__)
558 #define SIPE_TARGET_ARCH "ppc64"
559 #elif defined(__powerpc__) || defined(__powerpc) || defined(__ppc__) || defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PWR)
560 #define SIPE_TARGET_ARCH "ppc"
561 #elif defined(__hppa__) || defined(__hppa)
562 #define SIPE_TARGET_ARCH "hppa"
563 #elif defined(__mips__) || defined(__mips) || defined(_MIPS_ARCH) || defined(_M_MRX000)
564 #define SIPE_TARGET_ARCH "mips"
565 #elif defined(__s390__) || defined(__s390) || defined(__s390x__) || defined(__s390x)
566 #define SIPE_TARGET_ARCH "s390"
567 #elif defined(__sparc__) || defined(__sparc) || defined(__sparcv8)
568 #define SIPE_TARGET_ARCH "sparc"
569 #elif defined(__arm__)
570 #define SIPE_TARGET_ARCH "arm"
572 #define SIPE_TARGET_ARCH "other"
574 gchar
*backend
= sipe_backend_version();
575 transport
->user_agent
= g_strdup_printf("%s Sipe/" PACKAGE_VERSION
" (" SIPE_TARGET_PLATFORM
"-" SIPE_TARGET_ARCH
"; %s)",
577 transport
->server_version
? transport
->server_version
: "");
580 transport
->user_agent
= g_strdup(useragent
);
583 return(transport
->user_agent
);
586 struct transaction
*sip_transport_request_timeout(struct sipe_core_private
*sipe_private
,
590 const gchar
*addheaders
,
592 struct sip_dialog
*dialog
,
593 TransCallback callback
,
595 TransCallback timeout_callback
)
597 struct sip_transport
*transport
= sipe_private
->transport
;
598 struct sipe_account_data
*sip
= SIPE_ACCOUNT_DATA_PRIVATE
;
601 gchar
*ourtag
= dialog
&& dialog
->ourtag
? g_strdup(dialog
->ourtag
) : NULL
;
602 gchar
*theirtag
= dialog
&& dialog
->theirtag
? g_strdup(dialog
->theirtag
) : NULL
;
603 gchar
*theirepid
= dialog
&& dialog
->theirepid
? g_strdup(dialog
->theirepid
) : NULL
;
604 gchar
*callid
= dialog
&& dialog
->callid
? g_strdup(dialog
->callid
) : gencallid();
605 gchar
*branch
= dialog
&& dialog
->callid
? NULL
: genbranch();
606 gchar
*route
= g_strdup("");
607 gchar
*epid
= get_epid(sipe_private
);
608 int cseq
= dialog
? ++dialog
->cseq
: 1 /* as Call-Id is new in this case */;
609 struct transaction
*trans
= NULL
;
611 if (dialog
&& dialog
->routes
)
613 GSList
*iter
= dialog
->routes
;
618 route
= g_strdup_printf("%sRoute: <%s>\r\n", route
, (char *)iter
->data
);
620 iter
= g_slist_next(iter
);
624 if (!ourtag
&& !dialog
) {
628 if (sipe_strequal(method
, "REGISTER")) {
629 if (sip
->regcallid
) {
631 callid
= g_strdup(sip
->regcallid
);
633 sip
->regcallid
= g_strdup(callid
);
635 cseq
= ++transport
->cseq
;
638 buf
= g_strdup_printf("%s %s SIP/2.0\r\n"
639 "Via: SIP/2.0/%s %s:%d%s%s\r\n"
640 "From: <sip:%s>%s%s;epid=%s\r\n"
641 "To: <%s>%s%s%s%s\r\n"
642 "Max-Forwards: 70\r\n"
647 "Content-Length: %" G_GSIZE_FORMAT
"\r\n\r\n%s",
649 dialog
&& dialog
->request
? dialog
->request
: url
,
650 TRANSPORT_DESCRIPTOR
,
651 sipe_backend_network_ip_address(),
652 transport
->connection
->client_port
,
653 branch
? ";branch=" : "",
654 branch
? branch
: "",
655 sipe_private
->username
,
656 ourtag
? ";tag=" : "",
657 ourtag
? ourtag
: "",
660 theirtag
? ";tag=" : "",
661 theirtag
? theirtag
: "",
662 theirepid
? ";epid=" : "",
663 theirepid
? theirepid
: "",
666 sip_transport_user_agent(sipe_private
),
669 addheaders
? addheaders
: "",
670 body
? (gsize
) strlen(body
) : 0,
674 //printf ("parsing msg buf:\n%s\n\n", buf);
675 msg
= sipmsg_parse_msg(buf
);
685 sign_outgoing_message(msg
, sipe_private
, method
);
687 buf
= sipmsg_to_string(msg
);
689 /* add to ongoing transactions */
690 /* ACK isn't supposed to be answered ever. So we do not keep transaction for it. */
691 if (!sipe_strequal(method
, "ACK")) {
692 trans
= g_new0(struct transaction
, 1);
693 trans
->callback
= callback
;
695 trans
->key
= g_strdup_printf("<%s><%d %s>", callid
, cseq
, method
);
696 if (timeout_callback
) {
697 trans
->timeout_callback
= timeout_callback
;
698 trans
->timeout_key
= g_strdup_printf("<transaction timeout>%s", trans
->key
);
699 sipe_schedule_seconds(sipe_private
,
703 transaction_timeout_cb
,
706 transport
->transactions
= g_slist_append(transport
->transactions
,
708 SIPE_DEBUG_INFO("SIP transactions count:%d after addition", g_slist_length(transport
->transactions
));
714 sipe_utils_message_debug("SIP", buf
, NULL
, TRUE
);
715 sipe_backend_transport_message(transport
->connection
, buf
);
721 struct transaction
*sip_transport_request(struct sipe_core_private
*sipe_private
,
725 const gchar
*addheaders
,
727 struct sip_dialog
*dialog
,
728 TransCallback callback
)
730 return sip_transport_request_timeout(sipe_private
,
742 static void sip_transport_simple_request(struct sipe_core_private
*sipe_private
,
744 struct sip_dialog
*dialog
)
746 sip_transport_request(sipe_private
,
756 void sip_transport_ack(struct sipe_core_private
*sipe_private
,
757 struct sip_dialog
*dialog
)
759 sip_transport_simple_request(sipe_private
, "ACK", dialog
);
762 void sip_transport_bye(struct sipe_core_private
*sipe_private
,
763 struct sip_dialog
*dialog
)
765 sip_transport_simple_request(sipe_private
, "BYE", dialog
);
768 struct transaction
*sip_transport_info(struct sipe_core_private
*sipe_private
,
769 const gchar
*addheaders
,
771 struct sip_dialog
*dialog
,
772 TransCallback callback
)
774 return sip_transport_request(sipe_private
,
784 struct transaction
*sip_transport_invite(struct sipe_core_private
*sipe_private
,
785 const gchar
*addheaders
,
787 struct sip_dialog
*dialog
,
788 TransCallback callback
)
790 return sip_transport_request(sipe_private
,
800 struct transaction
*sip_transport_service(struct sipe_core_private
*sipe_private
,
802 const gchar
*addheaders
,
804 TransCallback callback
)
806 return sip_transport_request(sipe_private
,
816 void sip_transport_subscribe(struct sipe_core_private
*sipe_private
,
818 const gchar
*addheaders
,
820 struct sip_dialog
*dialog
,
821 TransCallback callback
)
823 sip_transport_request(sipe_private
,
834 sipe_get_auth_scheme_name(struct sipe_core_private
*sipe_private
)
836 const char *res
= "NTLM";
838 if (SIPE_CORE_PUBLIC_FLAG_IS(KRB5
)) {
842 (void) sipe_private
; /* make compiler happy */
847 static void do_register(struct sipe_core_private
*sipe_private
,
848 gboolean deregister
);
850 static void do_reauthenticate_cb(struct sipe_core_private
*sipe_private
,
851 SIPE_UNUSED_PARAMETER gpointer unused
)
853 struct sip_transport
*transport
= sipe_private
->transport
;
855 /* register again when security token expires */
856 /* we have to start a new authentication as the security token
857 * is almost expired by sending a not signed REGISTER message */
858 SIPE_DEBUG_INFO_NOFORMAT("do a full reauthentication");
859 sipe_auth_free(&transport
->registrar
);
860 sipe_auth_free(&transport
->proxy
);
861 sipe_schedule_cancel(sipe_private
, "<registration>");
862 transport
->reregister_set
= FALSE
;
863 transport
->register_attempt
= 0;
864 do_register(sipe_private
, FALSE
);
865 transport
->reauthenticate_set
= FALSE
;
868 static void sip_transport_default_contact(struct sipe_core_private
*sipe_private
)
870 struct sip_transport
*transport
= sipe_private
->transport
;
871 sipe_private
->contact
= g_strdup_printf("<sip:%s:%d;maddr=%s;transport=%s>;proxy=replace",
872 sipe_private
->username
,
873 transport
->connection
->client_port
,
874 sipe_backend_network_ip_address(),
875 TRANSPORT_DESCRIPTOR
);
878 static void do_register_cb(struct sipe_core_private
*sipe_private
,
879 SIPE_UNUSED_PARAMETER
void *unused
)
881 do_register(sipe_private
, FALSE
);
884 static void sip_transport_set_reregister(struct sipe_core_private
*sipe_private
,
887 sipe_schedule_seconds(sipe_private
,
895 static void sipe_server_register(struct sipe_core_private
*sipe_private
,
900 static gboolean
process_register_response(struct sipe_core_private
*sipe_private
,
902 SIPE_UNUSED_PARAMETER
struct transaction
*trans
)
904 struct sip_transport
*transport
= sipe_private
->transport
;
905 struct sipe_account_data
*sip
= SIPE_ACCOUNT_DATA_PRIVATE
;
907 const gchar
*expires_header
;
909 GSList
*hdr
= msg
->headers
;
910 struct sipnameval
*elem
;
912 expires_header
= sipmsg_find_header(msg
, "Expires");
913 expires
= expires_header
!= NULL
? strtol(expires_header
, NULL
, 10) : 0;
914 SIPE_DEBUG_INFO("process_register_response: got response to REGISTER; expires = %d", expires
);
916 switch (msg
->response
) {
919 const gchar
*contact_hdr
;
924 const gchar
*server_hdr
= sipmsg_find_header(msg
, "Server");
925 const char *auth_scheme
;
927 if (!transport
->reregister_set
) {
928 sip_transport_set_reregister(sipe_private
,
930 transport
->reregister_set
= TRUE
;
933 if (server_hdr
&& !transport
->server_version
) {
934 transport
->server_version
= g_strdup(server_hdr
);
935 g_free(transport
->user_agent
);
936 transport
->user_agent
= NULL
;
939 auth_scheme
= sipe_get_auth_scheme_name(sipe_private
);
940 tmp
= sipmsg_find_auth_header(msg
, auth_scheme
);
943 SIPE_DEBUG_INFO("process_register_response: Auth header: %s", tmp
);
944 fill_auth(tmp
, &transport
->registrar
);
947 if (!transport
->reauthenticate_set
) {
948 gchar
*action_name
= g_strdup_printf("<%s>", "+reauthentication");
949 guint reauth_timeout
;
950 if (transport
->registrar
.type
== AUTH_TYPE_KERBEROS
&& transport
->registrar
.expires
> 0) {
951 /* assuming normal Kerberos ticket expiration of about 8-10 hours */
952 reauth_timeout
= transport
->registrar
.expires
- 300;
954 /* NTLM: we have to reauthenticate as our security token expires
955 after eight hours (be five minutes early) */
956 reauth_timeout
= (8 * 3600) - 300;
958 sipe_schedule_seconds(sipe_private
,
962 do_reauthenticate_cb
,
965 transport
->reauthenticate_set
= TRUE
;
968 sipe_backend_connection_completed(SIPE_CORE_PUBLIC
);
970 epid
= get_epid(sipe_private
);
971 uuid
= generateUUIDfromEPID(epid
);
974 // There can be multiple Contact headers (one per location where the user is logged in) so
975 // make sure to only get the one for this uuid
976 for (i
= 0; (contact_hdr
= sipmsg_find_header_instance (msg
, "Contact", i
)); i
++) {
977 gchar
* valid_contact
= sipmsg_find_part_of_header (contact_hdr
, uuid
, NULL
, NULL
);
979 gruu
= sipmsg_find_part_of_header(contact_hdr
, "gruu=\"", "\"", NULL
);
980 //SIPE_DEBUG_INFO("process_register_response: got gruu %s from contact hdr w/ right uuid: %s", gruu, contact_hdr);
981 g_free(valid_contact
);
984 //SIPE_DEBUG_INFO("process_register_response: ignoring contact hdr b/c not right uuid: %s", contact_hdr);
989 g_free(sipe_private
->contact
);
991 sipe_private
->contact
= g_strdup_printf("<%s>", gruu
);
994 //SIPE_DEBUG_INFO_NOFORMAT("process_register_response: didn't find gruu in a Contact hdr");
995 sip_transport_default_contact(sipe_private
);
997 SIPE_CORE_PRIVATE_FLAG_UNSET(OCS2007
);
998 SIPE_CORE_PRIVATE_FLAG_UNSET(REMOTE_USER
);
999 sip
->batched_support
= FALSE
;
1004 if (sipe_strcase_equal(elem
->name
, "Supported")) {
1005 if (sipe_strcase_equal(elem
->value
, "msrtc-event-categories")) {
1006 /* We interpret this as OCS2007+ indicator */
1007 SIPE_CORE_PRIVATE_FLAG_SET(OCS2007
);
1008 SIPE_DEBUG_INFO("Supported: %s (indicates OCS2007+)", elem
->value
);
1010 if (sipe_strcase_equal(elem
->value
, "adhoclist")) {
1011 sip
->batched_support
= TRUE
;
1012 SIPE_DEBUG_INFO("Supported: %s", elem
->value
);
1015 if (sipe_strcase_equal(elem
->name
, "Allow-Events")){
1016 gchar
**caps
= g_strsplit(elem
->value
,",",0);
1019 sip
->allow_events
= g_slist_append(sip
->allow_events
, g_strdup(caps
[i
]));
1020 SIPE_DEBUG_INFO("Allow-Events: %s", caps
[i
]);
1025 if (sipe_strcase_equal(elem
->name
, "ms-user-logon-data")) {
1026 if (sipe_strcase_equal(elem
->value
, "RemoteUser")) {
1027 SIPE_CORE_PRIVATE_FLAG_SET(REMOTE_USER
);
1028 SIPE_DEBUG_INFO_NOFORMAT("ms-user-logon-data: RemoteUser (connected "
1029 "via Edge Server)");
1032 hdr
= g_slist_next(hdr
);
1035 /* rejoin open chats to be able to use them by continue to send messages */
1036 sipe_backend_chat_rejoin_all(SIPE_CORE_PUBLIC
);
1039 if (!transport
->subscribed
) { //do it just once, not every re-register
1041 if (g_slist_find_custom(sip
->allow_events
, "vnd-microsoft-roaming-contacts",
1042 (GCompareFunc
)g_ascii_strcasecmp
)) {
1043 sipe_subscribe_roaming_contacts(sipe_private
);
1046 /* For 2007+ it does not make sence to subscribe to:
1047 * vnd-microsoft-roaming-ACL
1048 * vnd-microsoft-provisioning (not v2)
1050 * These are for backward compatibility.
1052 if (SIPE_CORE_PRIVATE_FLAG_IS(OCS2007
))
1054 if (g_slist_find_custom(sip
->allow_events
, "vnd-microsoft-roaming-self",
1055 (GCompareFunc
)g_ascii_strcasecmp
)) {
1056 sipe_subscribe_roaming_self(sipe_private
);
1058 if (g_slist_find_custom(sip
->allow_events
, "vnd-microsoft-provisioning-v2",
1059 (GCompareFunc
)g_ascii_strcasecmp
)) {
1060 sipe_subscribe_roaming_provisioning_v2(sipe_private
);
1063 /* For 2005- servers */
1066 //sipe_options_request(sip, sipe_private->public.sip_domain);
1068 if (g_slist_find_custom(sip
->allow_events
, "vnd-microsoft-roaming-ACL",
1069 (GCompareFunc
)g_ascii_strcasecmp
)) {
1070 sipe_subscribe_roaming_acl(sipe_private
);
1072 if (g_slist_find_custom(sip
->allow_events
, "vnd-microsoft-provisioning",
1073 (GCompareFunc
)g_ascii_strcasecmp
)) {
1074 sipe_subscribe_roaming_provisioning(sipe_private
);
1076 if (g_slist_find_custom(sip
->allow_events
, "presence.wpending",
1077 (GCompareFunc
)g_ascii_strcasecmp
)) {
1078 sipe_subscribe_presence_wpending(sipe_private
,
1082 /* For 2007+ we publish our initial statuses and calendar data only after
1083 * received our existing publications in sipe_process_roaming_self()
1084 * Only in this case we know versions of current publications made
1087 /* For 2005- we publish our initial statuses only after
1088 * received our existing UserInfo data in response to
1089 * self subscription.
1090 * Only in this case we won't override existing UserInfo data
1091 * set earlier or by other client on our behalf.
1095 transport
->subscribed
= TRUE
;
1098 timeout
= sipmsg_find_part_of_header(sipmsg_find_header(msg
, "ms-keep-alive"),
1099 "timeout=", ";", NULL
);
1100 if (timeout
!= NULL
) {
1101 sscanf(timeout
, "%u", &sipe_private
->public.keepalive_timeout
);
1102 SIPE_DEBUG_INFO("process_register_response: server determined keep alive timeout is %u seconds",
1103 sipe_private
->public.keepalive_timeout
);
1107 SIPE_DEBUG_INFO("process_register_response: got 200, removing CSeq: %d", transport
->cseq
);
1112 gchar
*redirect
= parse_from(sipmsg_find_header(msg
, "Contact"));
1114 if (redirect
&& (g_strncasecmp("sip:", redirect
, 4) == 0)) {
1115 gchar
**parts
= g_strsplit(redirect
+ 4, ";", 0);
1119 guint transport
= SIPE_TRANSPORT_TLS
;
1122 tmp
= g_strsplit(parts
[0], ":", 0);
1123 hostname
= g_strdup(tmp
[0]);
1124 if (tmp
[1]) port
= strtoul(tmp
[1], NULL
, 10);
1128 tmp
= g_strsplit(parts
[i
], "=", 0);
1130 if (g_strcasecmp("transport", tmp
[0]) == 0) {
1131 if (g_strcasecmp("tcp", tmp
[1]) == 0) {
1132 transport
= SIPE_TRANSPORT_TCP
;
1141 /* Close old connection */
1142 sipe_connection_cleanup(sipe_private
);
1144 /* Create new connection */
1145 sipe_server_register(sipe_private
, transport
, hostname
, port
);
1146 SIPE_DEBUG_INFO("process_register_response: redirected to host %s port %d transport %d",
1147 hostname
, port
, transport
);
1154 const char *auth_scheme
;
1155 SIPE_DEBUG_INFO("process_register_response: REGISTER retries %d", transport
->registrar
.retries
);
1156 if (transport
->registrar
.retries
> 2) {
1157 SIPE_DEBUG_INFO_NOFORMAT("process_register_response: still not authenticated after 3 tries - giving up.");
1158 sipe_backend_connection_error(SIPE_CORE_PUBLIC
,
1159 SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED
,
1160 _("Authentication failed"));
1164 if (transport
->reauthenticate_set
) {
1165 SIPE_DEBUG_ERROR_NOFORMAT("process_register_response: RE-REGISTER rejected, triggering re-authentication");
1166 do_reauthenticate_cb(sipe_private
, NULL
);
1170 auth_scheme
= sipe_get_auth_scheme_name(sipe_private
);
1171 tmp
= sipmsg_find_auth_header(msg
, auth_scheme
);
1173 SIPE_DEBUG_INFO("process_register_response: Auth header: %s", tmp
? tmp
: "");
1175 char *tmp2
= g_strconcat(_("Incompatible authentication scheme chosen"), ": ", auth_scheme
, NULL
);
1176 sipe_backend_connection_error(SIPE_CORE_PUBLIC
,
1177 SIPE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE
,
1182 fill_auth(tmp
, &transport
->registrar
);
1183 transport
->reregister_set
= FALSE
;
1184 transport
->register_attempt
= 0;
1185 do_register(sipe_private
,
1186 sipe_backend_connection_is_disconnecting(SIPE_CORE_PUBLIC
));
1191 const gchar
*diagnostics
= sipmsg_find_header(msg
, "Warning");
1192 gchar
**reason
= NULL
;
1194 if (diagnostics
!= NULL
) {
1196 Warning: 310 lcs.microsoft.com "You are currently not using the recommended version of the client"
1198 reason
= g_strsplit(diagnostics
, "\"", 0);
1200 warning
= g_strdup_printf(_("You have been rejected by the server: %s"),
1201 (reason
&& reason
[1]) ? reason
[1] : _("no reason given"));
1204 sipe_backend_connection_error(SIPE_CORE_PUBLIC
,
1205 SIPE_CONNECTION_ERROR_INVALID_SETTINGS
,
1213 const gchar
*diagnostics
= sipmsg_find_header(msg
, "ms-diagnostics");
1214 gchar
*reason
= NULL
;
1216 if (diagnostics
!= NULL
) {
1217 reason
= sipmsg_find_part_of_header(diagnostics
, "reason=\"", "\"", NULL
);
1219 warning
= g_strdup_printf(_("Not found: %s. Please contact your Administrator"),
1220 diagnostics
? (reason
? reason
: _("no reason given")) :
1221 _("SIP is either not enabled for the destination URI or it does not exist"));
1224 sipe_backend_connection_error(SIPE_CORE_PUBLIC
,
1225 SIPE_CONNECTION_ERROR_INVALID_USERNAME
,
1231 case 504: /* Server time-out */
1232 /* first attempt + 5 retries */
1233 if (transport
->register_attempt
< 6) {
1234 SIPE_DEBUG_INFO("process_register_response: RE-REGISTER timeout on attempt %d, retrying later",
1235 transport
->register_attempt
);
1236 sip_transport_set_reregister(sipe_private
, 60);
1242 const gchar
*diagnostics
= sipmsg_find_header(msg
, "ms-diagnostics");
1243 gchar
*reason
= NULL
;
1245 if (diagnostics
!= NULL
) {
1246 reason
= sipmsg_find_part_of_header(diagnostics
, "reason=\"", "\"", NULL
);
1248 warning
= g_strdup_printf(_("Service unavailable: %s"), reason
? reason
: _("no reason given"));
1251 sipe_backend_connection_error(SIPE_CORE_PUBLIC
,
1252 SIPE_CONNECTION_ERROR_NETWORK
,
1262 static gboolean
register_response_timeout(struct sipe_core_private
*sipe_private
,
1263 SIPE_UNUSED_PARAMETER
struct sipmsg
*msg
,
1264 SIPE_UNUSED_PARAMETER
struct transaction
*trans
)
1266 struct sip_transport
*transport
= sipe_private
->transport
;
1267 if (transport
->register_attempt
< 6) {
1268 SIPE_DEBUG_INFO("register_response_timeout: no answer to attempt %d, retrying",
1269 transport
->register_attempt
);
1270 do_register(sipe_private
, FALSE
);
1272 gchar
*warning
= g_strdup_printf(_("Service unavailable: %s"), _("no reason given"));
1273 sipe_backend_connection_error(SIPE_CORE_PUBLIC
,
1274 SIPE_CONNECTION_ERROR_NETWORK
,
1281 static void do_register(struct sipe_core_private
*sipe_private
,
1282 gboolean deregister
)
1284 struct sip_transport
*transport
= sipe_private
->transport
;
1291 if (!sipe_private
->public.sip_domain
) return;
1294 if (transport
->reregister_set
) {
1295 transport
->reregister_set
= FALSE
;
1296 transport
->register_attempt
= 1;
1298 transport
->register_attempt
++;
1302 epid
= get_epid(sipe_private
);
1303 uuid
= generateUUIDfromEPID(epid
);
1304 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"
1305 "Supported: gruu-10, adhoclist, msrtc-event-categories, com.microsoft.msrtc.presence\r\n"
1306 "Event: registration\r\n"
1307 "Allow-Events: presence\r\n"
1308 "ms-keep-alive: UAC;hop-hop=yes\r\n"
1310 sipe_backend_network_ip_address(),
1311 transport
->connection
->client_port
,
1312 TRANSPORT_DESCRIPTOR
,
1314 deregister
? "Expires: 0\r\n" : "");
1318 uri
= sip_uri_from_name(sipe_private
->public.sip_domain
);
1319 to
= sip_uri_self(sipe_private
);
1320 sip_transport_request_timeout(sipe_private
,
1327 process_register_response
,
1329 deregister
? NULL
: register_response_timeout
);
1335 /* Make sure that all messages are pushed to the server
1336 before the connection gets shut down */
1337 SIPE_DEBUG_INFO_NOFORMAT("De-register from server. Flushing outstanding messages.");
1338 sipe_backend_transport_flush(transport
->connection
);
1342 void sip_transport_deregister(struct sipe_core_private
*sipe_private
)
1344 do_register(sipe_private
, TRUE
);
1347 void sip_transport_disconnect(struct sipe_core_private
*sipe_private
)
1349 struct sip_transport
*transport
= sipe_private
->transport
;
1351 sipe_backend_transport_disconnect(transport
->connection
);
1353 sipe_auth_free(&transport
->registrar
);
1354 sipe_auth_free(&transport
->proxy
);
1356 g_free(transport
->server_name
);
1357 g_free(transport
->server_version
);
1358 g_free(transport
->user_agent
);
1360 while (transport
->transactions
)
1361 transactions_remove(sipe_private
,
1362 transport
->transactions
->data
);
1366 sipe_private
->transport
= NULL
;
1367 sipe_private
->service_data
= NULL
;
1369 if (sipe_private
->dns_query
)
1370 sipe_backend_dns_query_cancel(sipe_private
->dns_query
);
1374 guint
sip_transport_port(struct sipe_core_private
*sipe_private
)
1376 return sipe_private
->transport
->server_port
;
1379 static void process_input_message(struct sipe_core_private
*sipe_private
,
1382 struct sip_transport
*transport
= sipe_private
->transport
;
1383 gboolean notfound
= FALSE
;
1384 const char *method
= msg
->method
? msg
->method
: "NOT FOUND";
1386 SIPE_DEBUG_INFO("process_input_message: msg->response(%d),msg->method(%s)",
1387 msg
->response
, method
);
1389 if (msg
->response
== 0) { /* request */
1390 if (sipe_strequal(method
, "MESSAGE")) {
1391 process_incoming_message(sipe_private
, msg
);
1392 } else if (sipe_strequal(method
, "NOTIFY")) {
1393 SIPE_DEBUG_INFO_NOFORMAT("send->process_incoming_notify");
1394 process_incoming_notify(sipe_private
, msg
, TRUE
, FALSE
);
1395 } else if (sipe_strequal(method
, "BENOTIFY")) {
1396 SIPE_DEBUG_INFO_NOFORMAT("send->process_incoming_benotify");
1397 process_incoming_notify(sipe_private
, msg
, TRUE
, TRUE
);
1398 } else if (sipe_strequal(method
, "INVITE")) {
1399 process_incoming_invite(sipe_private
, msg
);
1400 } else if (sipe_strequal(method
, "REFER")) {
1401 process_incoming_refer(sipe_private
, msg
);
1402 } else if (sipe_strequal(method
, "OPTIONS")) {
1403 process_incoming_options(sipe_private
, msg
);
1404 } else if (sipe_strequal(method
, "INFO")) {
1405 process_incoming_info(sipe_private
, msg
);
1406 } else if (sipe_strequal(method
, "ACK")) {
1407 /* ACK's don't need any response */
1408 } else if (sipe_strequal(method
, "PRACK")) {
1409 sip_transport_response(sipe_private
, msg
, 200, "OK", NULL
);
1410 } else if (sipe_strequal(method
, "SUBSCRIBE")) {
1411 /* LCS 2005 sends us these - just respond 200 OK */
1412 sip_transport_response(sipe_private
, msg
, 200, "OK", NULL
);
1413 } else if (sipe_strequal(method
, "CANCEL")) {
1414 process_incoming_cancel(sipe_private
, msg
);
1415 } else if (sipe_strequal(method
, "BYE")) {
1416 process_incoming_bye(sipe_private
, msg
);
1418 sip_transport_response(sipe_private
, msg
, 501, "Not implemented", NULL
);
1422 } else { /* response */
1423 struct transaction
*trans
= transactions_find(transport
, msg
);
1425 if (msg
->response
< 200) {
1426 if (msg
->bodylen
!= 0) {
1427 SIPE_DEBUG_INFO("got provisional (%d) response with body", msg
->response
);
1428 if (trans
->callback
) {
1429 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: we have a transaction callback");
1430 (trans
->callback
)(sipe_private
, msg
, trans
);
1433 /* ignore provisional response */
1434 SIPE_DEBUG_INFO("process_input_message: got provisional (%d) response, ignoring", msg
->response
);
1437 /* Transaction not yet completed */
1440 } else if (msg
->response
== 401) { /* Unauthorized */
1442 if (sipe_strequal(trans
->msg
->method
, "REGISTER")) {
1443 /* Expected response during authentication handshake */
1444 transport
->registrar
.retries
++;
1445 SIPE_DEBUG_INFO("process_input_message: RE-REGISTER CSeq: %d", transport
->cseq
);
1449 /* Are we registered? */
1450 if (transport
->reregister_set
) {
1451 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: 401 response to non-REGISTER message. Retrying with new authentication.");
1452 sign_outgoing_message(trans
->msg
,
1454 trans
->msg
->method
);
1457 * We don't have a valid authentication at the moment.
1458 * Resend message unchanged. It will be rejected again
1459 * and hopefully by then we have a valid authentication.
1461 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: 401 response to non-REGISTER message. Bouncing...");
1464 /* Resend request */
1465 resend
= sipmsg_to_string(trans
->msg
);
1466 sipe_utils_message_debug("SIP", resend
, NULL
, TRUE
);
1467 sipe_backend_transport_message(sipe_private
->transport
->connection
, resend
);
1470 /* Transaction not yet completed */
1474 } else if (msg
->response
== 407) { /* Proxy Authentication Required */
1476 if (transport
->proxy
.retries
> 30) {
1477 SIPE_DEBUG_ERROR_NOFORMAT("process_input_message: too many proxy authentication retries. Giving up.");
1479 gchar
*resend
, *auth
;
1482 transport
->proxy
.retries
++;
1484 /* do proxy authentication */
1485 ptmp
= sipmsg_find_header(msg
, "Proxy-Authenticate");
1486 fill_auth(ptmp
, &transport
->proxy
);
1487 auth
= auth_header(sipe_private
, &transport
->proxy
, trans
->msg
);
1488 sipmsg_remove_header_now(trans
->msg
, "Proxy-Authorization");
1489 sipmsg_add_header_now_pos(trans
->msg
, "Proxy-Authorization", auth
, 5);
1492 /* resend request */
1493 resend
= sipmsg_to_string(trans
->msg
);
1494 sipe_utils_message_debug("SIP", resend
, NULL
, TRUE
);
1495 sipe_backend_transport_message(sipe_private
->transport
->connection
, resend
);
1498 /* Transaction not yet completed */
1503 transport
->registrar
.retries
= 0;
1504 transport
->proxy
.retries
= 0;
1507 /* Is transaction completed? */
1509 if (trans
->callback
) {
1510 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: we have a transaction callback");
1511 /* call the callback to process response */
1512 (trans
->callback
)(sipe_private
, msg
, trans
);
1515 SIPE_DEBUG_INFO("process_input_message: removing CSeq %d", transport
->cseq
);
1516 transactions_remove(sipe_private
, trans
);
1519 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: received response to unknown transaction");
1525 SIPE_DEBUG_INFO("received a unknown sip message with method %s and response %d", method
, msg
->response
);
1529 static void sip_transport_input(struct sipe_transport_connection
*conn
)
1531 struct sipe_core_private
*sipe_private
= conn
->user_data
;
1532 struct sip_transport
*transport
= sipe_private
->transport
;
1533 gchar
*cur
= conn
->buffer
;
1535 /* according to the RFC remove CRLF at the beginning */
1536 while (*cur
== '\r' || *cur
== '\n') {
1539 if (cur
!= conn
->buffer
)
1540 sipe_utils_shrink_buffer(conn
, cur
);
1542 /* Received a full Header? */
1543 transport
->processing_input
= TRUE
;
1544 while (transport
->processing_input
&&
1545 ((cur
= strstr(conn
->buffer
, "\r\n\r\n")) != NULL
)) {
1551 msg
= sipmsg_parse_header(conn
->buffer
);
1554 remainder
= conn
->buffer_used
- (cur
- conn
->buffer
);
1555 if (msg
&& remainder
>= (guint
) msg
->bodylen
) {
1556 char *dummy
= g_malloc(msg
->bodylen
+ 1);
1557 memcpy(dummy
, cur
, msg
->bodylen
);
1558 dummy
[msg
->bodylen
] = '\0';
1560 cur
+= msg
->bodylen
;
1561 sipe_utils_message_debug("SIP",
1565 sipe_utils_shrink_buffer(conn
, cur
);
1568 SIPE_DEBUG_INFO("sipe_transport_input: body too short (%d < %d, strlen %d) - ignoring message", remainder
, msg
->bodylen
, (int)strlen(conn
->buffer
));
1572 /* restore header for next try */
1577 // Verify the signature before processing it
1578 if (transport
->registrar
.gssapi_context
) {
1579 struct sipmsg_breakdown msgbd
;
1580 gchar
*signature_input_str
;
1583 sipmsg_breakdown_parse(&msgbd
, transport
->registrar
.realm
, transport
->registrar
.target
);
1584 signature_input_str
= sipmsg_breakdown_get_string(transport
->registrar
.version
, &msgbd
);
1586 rspauth
= sipmsg_find_part_of_header(sipmsg_find_header(msg
, "Authentication-Info"), "rspauth=\"", "\"", NULL
);
1588 if (rspauth
!= NULL
) {
1589 if (!sip_sec_verify_signature(transport
->registrar
.gssapi_context
, signature_input_str
, rspauth
)) {
1590 SIPE_DEBUG_INFO_NOFORMAT("sip_transport_input: signature of incoming message validated");
1591 process_input_message(sipe_private
, msg
);
1593 SIPE_DEBUG_INFO_NOFORMAT("sip_transport_input: signature of incoming message is invalid.");
1594 sipe_backend_connection_error(SIPE_CORE_PUBLIC
,
1595 SIPE_CONNECTION_ERROR_NETWORK
,
1596 _("Invalid message signature received"));
1598 } else if ((msg
->response
== 401) ||
1599 sipe_strequal(msg
->method
, "REGISTER")) {
1600 /* a) Retry non-REGISTER requests with updated authentication */
1601 /* b) We must always process REGISTER responses */
1602 process_input_message(sipe_private
, msg
);
1604 /* OCS sends provisional messages that are *not* signed */
1605 if (msg
->response
>= 200) {
1606 /* We are not calling process_input_message(),
1607 so we need to drop the transaction here. */
1608 struct transaction
*trans
= transactions_find(transport
, msg
);
1609 if (trans
) transactions_remove(sipe_private
, trans
);
1611 SIPE_DEBUG_INFO_NOFORMAT("sip_transport_input: message without authentication data - ignoring");
1613 g_free(signature_input_str
);
1616 sipmsg_breakdown_free(&msgbd
);
1618 process_input_message(sipe_private
, msg
);
1623 /* Redirect: old content of "transport" is no longer valid */
1624 transport
= sipe_private
->transport
;
1628 static void sip_transport_connected(struct sipe_transport_connection
*conn
)
1630 struct sipe_core_private
*sipe_private
= conn
->user_data
;
1631 sipe_private
->service_data
= NULL
;
1632 do_register(sipe_private
, FALSE
);
1635 static void resolve_next_service(struct sipe_core_private
*sipe_private
,
1636 const struct sip_service_data
*start
);
1637 static void sip_transport_error(struct sipe_transport_connection
*conn
,
1640 struct sipe_core_private
*sipe_private
= conn
->user_data
;
1642 /* This failed attempt was based on a DNS SRV record */
1643 if (sipe_private
->service_data
) {
1644 resolve_next_service(sipe_private
, NULL
);
1646 sipe_backend_connection_error(SIPE_CORE_PUBLIC
,
1647 SIPE_CONNECTION_ERROR_NETWORK
,
1652 /* server_name must be g_alloc()'ed */
1653 static void sipe_server_register(struct sipe_core_private
*sipe_private
,
1658 sipe_connect_setup setup
= {
1661 (server_port
!= 0) ? server_port
:
1662 (type
== SIPE_TRANSPORT_TLS
) ? 5061 : 5060,
1664 sip_transport_connected
,
1665 sip_transport_input
,
1668 struct sip_transport
*transport
= g_new0(struct sip_transport
, 1);
1670 transport
->server_name
= server_name
;
1671 transport
->server_port
= setup
.server_port
;
1672 transport
->connection
= sipe_backend_transport_connect(SIPE_CORE_PUBLIC
,
1674 sipe_private
->transport
= transport
;
1677 struct sip_service_data
{
1678 const char *protocol
;
1679 const char *transport
;
1683 /* Service list for autodection */
1684 static const struct sip_service_data service_autodetect
[] = {
1685 { "sipinternaltls", "tcp", SIPE_TRANSPORT_TLS
}, /* for internal TLS connections */
1686 { "sipinternal", "tcp", SIPE_TRANSPORT_TCP
}, /* for internal TCP connections */
1687 { "sip", "tls", SIPE_TRANSPORT_TLS
}, /* for external TLS connections */
1688 { "sip", "tcp", SIPE_TRANSPORT_TCP
}, /*.for external TCP connections */
1692 /* Service list for SSL/TLS */
1693 static const struct sip_service_data service_tls
[] = {
1694 { "sipinternaltls", "tcp", SIPE_TRANSPORT_TLS
}, /* for internal TLS connections */
1695 { "sip", "tls", SIPE_TRANSPORT_TLS
}, /* for external TLS connections */
1699 /* Service list for TCP */
1700 static const struct sip_service_data service_tcp
[] = {
1701 { "sipinternal", "tcp", SIPE_TRANSPORT_TCP
}, /* for internal TCP connections */
1702 { "sip", "tcp", SIPE_TRANSPORT_TCP
}, /*.for external TCP connections */
1706 static const struct sip_service_data
*services
[] = {
1707 service_autodetect
, /* SIPE_TRANSPORT_AUTO */
1708 service_tls
, /* SIPE_TRANSPORT_TLS */
1709 service_tcp
/* SIPE_TRANSPORT_TCP */
1712 static void sipe_core_dns_resolved(struct sipe_core_public
*sipe_public
,
1713 const gchar
*hostname
, guint port
)
1715 struct sipe_core_private
*sipe_private
= SIPE_CORE_PRIVATE
;
1717 sipe_private
->dns_query
= NULL
;
1720 SIPE_DEBUG_INFO("sipe_core_dns_resolved - SRV hostname: %s port: %d",
1722 sipe_server_register(sipe_private
,
1723 sipe_private
->service_data
->type
,
1724 g_strdup(hostname
), port
);
1726 resolve_next_service(SIPE_CORE_PRIVATE
, NULL
);
1730 static void resolve_next_service(struct sipe_core_private
*sipe_private
,
1731 const struct sip_service_data
*start
)
1734 sipe_private
->service_data
= start
;
1736 sipe_private
->service_data
++;
1737 if (sipe_private
->service_data
->protocol
== NULL
) {
1738 guint type
= sipe_private
->transport_type
;
1740 /* We tried all services */
1741 sipe_private
->service_data
= NULL
;
1743 /* Try connecting to the SIP hostname directly */
1744 SIPE_DEBUG_INFO_NOFORMAT("no SRV records found; using SIP domain as fallback");
1745 if (type
== SIPE_TRANSPORT_AUTO
)
1746 type
= SIPE_TRANSPORT_TLS
;
1748 sipe_server_register(sipe_private
, type
,
1749 g_strdup(sipe_private
->public.sip_domain
),
1755 /* Try to resolve next service */
1756 sipe_private
->dns_query
= sipe_backend_dns_query_srv(
1757 sipe_private
->service_data
->protocol
,
1758 sipe_private
->service_data
->transport
,
1759 sipe_private
->public.sip_domain
,
1760 (sipe_dns_resolved_cb
) sipe_core_dns_resolved
,
1764 void sipe_core_transport_sip_connect(struct sipe_core_public
*sipe_public
,
1766 const gchar
*server
,
1769 struct sipe_core_private
*sipe_private
= SIPE_CORE_PRIVATE
;
1772 /* Use user specified server[:port] */
1773 int port_number
= 0;
1776 port_number
= atoi(port
);
1778 SIPE_DEBUG_INFO("sipe_core_connect: user specified SIP server %s:%d",
1779 server
, port_number
);
1781 sipe_server_register(sipe_private
, transport
,
1782 g_strdup(server
), port_number
);
1784 /* Server auto-discovery */
1786 /* Remember user specified transport type */
1787 sipe_private
->transport_type
= transport
;
1788 resolve_next_service(sipe_private
, services
[transport
]);
1792 void sipe_core_transport_sip_keepalive(struct sipe_core_public
*sipe_public
)
1794 SIPE_DEBUG_INFO("sending keep alive %d",
1795 sipe_public
->keepalive_timeout
);
1796 sipe_utils_message_debug("SIP", "", NULL
, TRUE
);
1797 sipe_backend_transport_message(SIPE_CORE_PRIVATE
->transport
->connection
,