tls: add Server Key Exchange message
[siplcs.git] / src / core / sip-transport.c
blob992b72eca7a6a92a2f675b9dffdfbb0132f39af3
1 /**
2 * @file sip-transport.c
4 * pidgin-sipe
6 * Copyright (C) 2010-2015 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
23 /**
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
43 * layers needed.
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.
49 * Specification references:
51 * - [MS-SIPAE]: http://msdn.microsoft.com/en-us/library/cc431510.aspx
54 #ifdef HAVE_CONFIG_H
55 #include "config.h"
56 #endif
58 #include <stdlib.h>
59 #include <string.h>
60 #include <stdio.h>
62 #include <glib.h>
64 #include "sipe-common.h"
65 #include "sipmsg.h"
66 #include "sip-sec.h"
67 #include "sip-sec-digest.h"
68 #include "sip-transport.h"
69 #include "sipe-backend.h"
70 #include "sipe-core.h"
71 #include "sipe-core-private.h"
72 #include "sipe-certificate.h"
73 #include "sipe-dialog.h"
74 #include "sipe-incoming.h"
75 #include "sipe-nls.h"
76 #include "sipe-notify.h"
77 #include "sipe-schedule.h"
78 #include "sipe-sign.h"
79 #include "sipe-subscriptions.h"
80 #include "sipe-utils.h"
82 struct sip_auth {
83 guint type;
84 struct sip_sec_context *gssapi_context;
85 gchar *gssapi_data;
86 gchar *opaque;
87 const gchar *protocol;
88 gchar *realm;
89 gchar *sts_uri;
90 gchar *target;
91 guint version;
92 guint retries;
93 guint ntlm_num;
94 guint expires;
95 gboolean can_retry;
98 /* sip-transport.c private data */
99 struct sip_transport {
100 struct sipe_transport_connection *connection;
102 gchar *server_name;
103 guint server_port;
104 gchar *server_version;
106 gchar *user_agent;
108 GSList *transactions;
110 struct sip_auth registrar;
111 struct sip_auth proxy;
113 guint cseq;
114 guint register_attempt;
116 guint keepalive_timeout;
117 time_t last_message;
119 gboolean processing_input; /* whether full header received */
120 gboolean auth_incomplete; /* whether authentication not completed */
121 gboolean auth_retry; /* whether next authentication should be tried */
122 gboolean reregister_set; /* whether reregister timer set */
123 gboolean reauthenticate_set; /* whether reauthenticate timer set */
124 gboolean subscribed; /* whether subscribed to events, except buddies presence */
125 gboolean deregister; /* whether in deregistration */
128 /* Keep in sync with sipe_transport_type! */
129 static const char *transport_descriptor[] = { "", "tls", "tcp"};
130 #define TRANSPORT_DESCRIPTOR (transport_descriptor[transport->connection->type])
132 static char *genbranch()
134 return g_strdup_printf("z9hG4bK%04X%04X%04X%04X%04X",
135 rand() & 0xFFFF, rand() & 0xFFFF, rand() & 0xFFFF,
136 rand() & 0xFFFF, rand() & 0xFFFF);
139 static void sipe_auth_free(struct sip_auth *auth)
141 g_free(auth->opaque);
142 auth->opaque = NULL;
143 auth->protocol = NULL;
144 g_free(auth->realm);
145 auth->realm = NULL;
146 g_free(auth->sts_uri);
147 auth->sts_uri = NULL;
148 g_free(auth->target);
149 auth->target = NULL;
150 auth->version = 0;
151 auth->type = SIPE_AUTHENTICATION_TYPE_UNSET;
152 auth->retries = 0;
153 auth->expires = 0;
154 auth->can_retry = FALSE;
155 g_free(auth->gssapi_data);
156 auth->gssapi_data = NULL;
157 sip_sec_destroy_context(auth->gssapi_context);
158 auth->gssapi_context = NULL;
161 static void sipe_make_signature(struct sipe_core_private *sipe_private,
162 struct sipmsg *msg)
164 struct sip_transport *transport = sipe_private->transport;
165 if (sip_sec_context_is_ready(transport->registrar.gssapi_context)) {
166 struct sipmsg_breakdown msgbd;
167 gchar *signature_input_str;
168 msgbd.msg = msg;
169 sipmsg_breakdown_parse(&msgbd, transport->registrar.realm, transport->registrar.target,
170 transport->registrar.protocol);
171 msgbd.rand = g_strdup_printf("%08x", g_random_int());
172 transport->registrar.ntlm_num++;
173 msgbd.num = g_strdup_printf("%d", transport->registrar.ntlm_num);
174 signature_input_str = sipmsg_breakdown_get_string(transport->registrar.version, &msgbd);
175 if (signature_input_str != NULL) {
176 char *signature_hex = sip_sec_make_signature(transport->registrar.gssapi_context, signature_input_str);
177 g_free(msg->signature);
178 msg->signature = signature_hex;
179 g_free(msg->rand);
180 msg->rand = g_strdup(msgbd.rand);
181 g_free(msg->num);
182 msg->num = g_strdup(msgbd.num);
183 g_free(signature_input_str);
185 sipmsg_breakdown_free(&msgbd);
189 static const gchar *const auth_type_to_protocol[] = {
190 NULL, /* SIPE_AUTHENTICATION_TYPE_UNSET */
191 NULL, /* SIPE_AUTHENTICATION_TYPE_BASIC */
192 "NTLM", /* SIPE_AUTHENTICATION_TYPE_NTLM */
193 "Kerberos", /* SIPE_AUTHENTICATION_TYPE_KERBEROS */
194 NULL, /* SIPE_AUTHENTICATION_TYPE_NEGOTIATE */
195 "TLS-DSK", /* SIPE_AUTHENTICATION_TYPE_TLS_DSK */
196 NULL, /* SIPE_AUTHENTICATION_TYPE_AUTOMATIC */
198 #define AUTH_PROTOCOLS (sizeof(auth_type_to_protocol)/sizeof(gchar *))
200 static gchar *msg_signature_to_auth(struct sip_auth *auth,
201 struct sipmsg *msg)
203 return(g_strdup_printf("%s qop=\"auth\", opaque=\"%s\", realm=\"%s\", targetname=\"%s\", crand=\"%s\", cnum=\"%s\", response=\"%s\"",
204 auth->protocol,
205 auth->opaque, auth->realm, auth->target,
206 msg->rand, msg->num, msg->signature));
209 static gboolean auth_can_retry(struct sip_transport *transport,
210 const struct sip_auth *auth)
212 /* NTLM is the scheme with lowest priority - don't retry */
213 gboolean retry =
214 auth->can_retry &&
215 (auth->type != SIPE_AUTHENTICATION_TYPE_NTLM);
216 if (retry)
217 transport->auth_retry = TRUE;
218 return(retry);
221 static void initialize_auth_retry(struct sipe_core_private *sipe_private,
222 struct sip_auth *auth)
224 struct sip_transport *transport = sipe_private->transport;
226 if (auth_can_retry(transport, auth)) {
227 if (auth->gssapi_context) {
228 /* need to drop context for retry */
229 sip_sec_destroy_context(auth->gssapi_context);
230 auth->gssapi_context = NULL;
232 } else {
233 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
234 SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
235 _("Failed to authenticate to server"));
239 static gchar *initialize_auth_context(struct sipe_core_private *sipe_private,
240 struct sip_auth *auth,
241 struct sipmsg *msg)
243 struct sip_transport *transport = sipe_private->transport;
244 gchar *ret;
245 gchar *gssapi_data = NULL;
246 gchar *sign_str;
247 gchar *gssapi_str;
248 gchar *opaque_str;
249 gchar *version_str;
252 * If transport is de-registering when we reach this point then we
253 * are in the middle of the previous authentication context setup
254 * attempt. So we shouldn't try another attempt.
256 if (transport->deregister)
257 return NULL;
259 /* Create security context or handshake continuation? */
260 if (auth->gssapi_context) {
261 /* Perform next step in authentication handshake */
262 gboolean status = sip_sec_init_context_step(auth->gssapi_context,
263 auth->target,
264 auth->gssapi_data,
265 &gssapi_data,
266 &auth->expires);
268 /* If authentication is completed gssapi_data can be NULL */
269 if (!(status &&
270 (sip_sec_context_is_ready(auth->gssapi_context) || gssapi_data))) {
271 SIPE_DEBUG_ERROR_NOFORMAT("initialize_auth_context: security context continuation failed");
272 g_free(gssapi_data);
273 initialize_auth_retry(sipe_private, auth);
274 return NULL;
277 } else {
278 /* Create security context */
279 gpointer password = sipe_private->password;
281 /* For TLS-DSK the "password" is a certificate */
282 if (auth->type == SIPE_AUTHENTICATION_TYPE_TLS_DSK) {
283 password = sipe_certificate_tls_dsk_find(sipe_private,
284 auth->target);
286 if (!password) {
287 if (auth->sts_uri) {
288 SIPE_DEBUG_INFO("initialize_auth_context: TLS-DSK Certificate Provisioning URI %s",
289 auth->sts_uri);
290 if (!sipe_certificate_tls_dsk_generate(sipe_private,
291 auth->target,
292 auth->sts_uri)) {
293 gchar *tmp = g_strdup_printf(_("Can't request certificate from %s"),
294 auth->sts_uri);
295 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
296 SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
297 tmp);
298 g_free(tmp);
300 } else {
301 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
302 SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
303 _("No URI for certificate provisioning service provided"));
306 /* we can't authenticate the message yet */
307 transport->auth_incomplete = TRUE;
309 return(NULL);
310 } else {
311 SIPE_DEBUG_INFO("initialize_auth_context: TLS-DSK certificate for target '%s' found.",
312 auth->target);
316 auth->gssapi_context = sip_sec_create_context(auth->type,
317 SIPE_CORE_PRIVATE_FLAG_IS(SSO),
318 FALSE, /* connection-less for SIP */
319 sipe_private->authuser,
320 password);
322 if (auth->gssapi_context) {
323 sip_sec_init_context_step(auth->gssapi_context,
324 auth->target,
325 NULL,
326 &gssapi_data,
327 &(auth->expires));
330 /* if auth->gssapi_context is NULL then gssapi_data is still NULL */
331 if (!gssapi_data) {
332 SIPE_DEBUG_ERROR_NOFORMAT("initialize_auth_context: security context initialization failed");
333 initialize_auth_retry(sipe_private, auth);
334 return NULL;
338 if ((auth->version > 3) &&
339 sip_sec_context_is_ready(auth->gssapi_context)) {
340 sipe_make_signature(sipe_private, msg);
341 sign_str = g_strdup_printf(", crand=\"%s\", cnum=\"%s\", response=\"%s\"",
342 msg->rand, msg->num, msg->signature);
343 } else {
344 sign_str = g_strdup("");
347 if (gssapi_data) {
348 gssapi_str = g_strdup_printf(", gssapi-data=\"%s\"",
349 gssapi_data);
350 g_free(gssapi_data);
351 } else {
352 gssapi_str = g_strdup("");
355 opaque_str = auth->opaque ? g_strdup_printf(", opaque=\"%s\"", auth->opaque) : g_strdup("");
357 if (auth->version > 2) {
358 version_str = g_strdup_printf(", version=%d", auth->version);
359 } else {
360 version_str = g_strdup("");
363 ret = g_strdup_printf("%s qop=\"auth\"%s, realm=\"%s\", targetname=\"%s\"%s%s%s",
364 auth->protocol, opaque_str,
365 auth->realm, auth->target,
366 gssapi_str, version_str, sign_str);
367 g_free(version_str);
368 g_free(opaque_str);
369 g_free(gssapi_str);
370 g_free(sign_str);
372 return(ret);
375 static gchar *auth_header(struct sipe_core_private *sipe_private,
376 struct sip_auth *auth,
377 struct sipmsg *msg)
379 gchar *ret = NULL;
382 * If the message is already signed then we have an authentication
383 * context, i.e. the authentication handshake is complete. Generate
384 * authentication header from message signature.
386 if (msg->signature) {
387 ret = msg_signature_to_auth(auth, msg);
390 * We should reach this point only when the authentication context
391 * needs to be initialized.
393 } else {
394 ret = initialize_auth_context(sipe_private, auth, msg);
397 return(ret);
400 static void fill_auth(const gchar *hdr, struct sip_auth *auth)
402 const gchar *param;
404 /* skip authentication identifier */
405 hdr = strchr(hdr, ' ');
406 if (!hdr) {
407 SIPE_DEBUG_ERROR_NOFORMAT("fill_auth: corrupted authentication header");
408 return;
410 while (*hdr == ' ')
411 hdr++;
413 /* start of next parameter value */
414 while ((param = strchr(hdr, '=')) != NULL) {
415 const gchar *end;
417 /* parameter value type */
418 param++;
419 if (*param == '"') {
420 /* string: xyz="..."(,) */
421 end = strchr(++param, '"');
422 if (!end) {
423 SIPE_DEBUG_ERROR("fill_auth: corrupted string parameter near '%s'", hdr);
424 break;
426 } else {
427 /* number: xyz=12345(,) */
428 end = strchr(param, ',');
429 if (!end) {
430 /* last parameter */
431 end = param + strlen(param);
435 #if 0
436 SIPE_DEBUG_INFO("fill_auth: hdr '%s'", hdr);
437 SIPE_DEBUG_INFO("fill_auth: param '%s'", param);
438 SIPE_DEBUG_INFO("fill_auth: end '%s'", end);
439 #endif
441 /* parameter type */
442 if (g_str_has_prefix(hdr, "gssapi-data=\"")) {
443 g_free(auth->gssapi_data);
444 auth->gssapi_data = g_strndup(param, end - param);
445 } else if (g_str_has_prefix(hdr, "opaque=\"")) {
446 g_free(auth->opaque);
447 auth->opaque = g_strndup(param, end - param);
448 } else if (g_str_has_prefix(hdr, "realm=\"")) {
449 g_free(auth->realm);
450 auth->realm = g_strndup(param, end - param);
451 } else if (g_str_has_prefix(hdr, "sts-uri=\"")) {
452 /* Only used with SIPE_AUTHENTICATION_TYPE_TLS_DSK */
453 g_free(auth->sts_uri);
454 auth->sts_uri = g_strndup(param, end - param);
455 } else if (g_str_has_prefix(hdr, "targetname=\"")) {
456 g_free(auth->target);
457 auth->target = g_strndup(param, end - param);
458 } else if (g_str_has_prefix(hdr, "version=")) {
459 auth->version = atoi(param);
462 /* skip to next parameter */
463 while ((*end == '"') || (*end == ',') || (*end == ' '))
464 end++;
465 hdr = end;
468 return;
471 static void sign_outgoing_message(struct sipe_core_private *sipe_private,
472 struct sipmsg *msg)
474 struct sip_transport *transport = sipe_private->transport;
475 gchar *buf;
477 if (transport->registrar.type == SIPE_AUTHENTICATION_TYPE_UNSET) {
478 return;
481 sipe_make_signature(sipe_private, msg);
483 buf = auth_header(sipe_private, &transport->registrar, msg);
484 if (buf) {
485 sipmsg_add_header_now(msg, "Authorization", buf);
486 g_free(buf);
490 static const gchar *sip_transport_user_agent(struct sipe_core_private *sipe_private)
492 struct sip_transport *transport = sipe_private->transport;
494 if (!transport->user_agent) {
495 const gchar *useragent = sipe_backend_setting(SIPE_CORE_PUBLIC,
496 SIPE_SETTING_USER_AGENT);
497 if (is_empty(useragent)) {
498 /*@TODO: better approach to define _user_ OS, it's version and host architecture */
499 /* ref: lzodefs.h */
500 #if defined(__linux__) || defined(__linux) || defined(__LINUX__)
501 #define SIPE_TARGET_PLATFORM "linux"
502 #elif defined(__NetBSD__) ||defined( __OpenBSD__) || defined(__FreeBSD__)
503 #define SIPE_TARGET_PLATFORM "bsd"
504 #elif defined(__APPLE__) || defined(__MACOS__)
505 #define SIPE_TARGET_PLATFORM "macosx"
506 #elif defined(_AIX) || defined(__AIX__) || defined(__aix__)
507 #define SIPE_TARGET_PLATFORM "aix"
508 #elif defined(__solaris__) || defined(__sun)
509 #define SIPE_TARGET_PLATFORM "sun"
510 #elif defined(_WIN32)
511 #define SIPE_TARGET_PLATFORM "win"
512 #elif defined(__CYGWIN__)
513 #define SIPE_TARGET_PLATFORM "cygwin"
514 #elif defined(__hpux__)
515 #define SIPE_TARGET_PLATFORM "hpux"
516 #elif defined(__sgi__)
517 #define SIPE_TARGET_PLATFORM "irix"
518 #else
519 #define SIPE_TARGET_PLATFORM "unknown"
520 #endif
522 #if defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64)
523 #define SIPE_TARGET_ARCH "x86_64"
524 #elif defined(__386__) || defined(__i386__) || defined(__i386) || defined(_M_IX86) || defined(_M_I386)
525 #define SIPE_TARGET_ARCH "i386"
526 #elif defined(__ppc64__)
527 #define SIPE_TARGET_ARCH "ppc64"
528 #elif defined(__powerpc__) || defined(__powerpc) || defined(__ppc__) || defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PWR)
529 #define SIPE_TARGET_ARCH "ppc"
530 #elif defined(__hppa__) || defined(__hppa)
531 #define SIPE_TARGET_ARCH "hppa"
532 #elif defined(__mips__) || defined(__mips) || defined(_MIPS_ARCH) || defined(_M_MRX000)
533 #define SIPE_TARGET_ARCH "mips"
534 #elif defined(__s390__) || defined(__s390) || defined(__s390x__) || defined(__s390x)
535 #define SIPE_TARGET_ARCH "s390"
536 #elif defined(__sparc__) || defined(__sparc) || defined(__sparcv8)
537 #define SIPE_TARGET_ARCH "sparc"
538 #elif defined(__arm__)
539 #define SIPE_TARGET_ARCH "arm"
540 #else
541 #define SIPE_TARGET_ARCH "other"
542 #endif
543 gchar *backend = sipe_backend_version();
544 transport->user_agent = g_strdup_printf("%s Sipe/" PACKAGE_VERSION " (" SIPE_TARGET_PLATFORM "-" SIPE_TARGET_ARCH "; %s)",
545 backend,
546 transport->server_version ? transport->server_version : "");
547 g_free(backend);
548 } else {
549 transport->user_agent = g_strdup(useragent);
552 return(transport->user_agent);
556 * NOTE: Do *NOT* call sipe_backend_transport_message(...) directly!
558 * All SIP messages must pass through this function in order to update
559 * the timestamp for keepalive tracking.
561 static void send_sip_message(struct sip_transport *transport,
562 const gchar *string)
564 sipe_utils_message_debug("SIP", string, NULL, TRUE);
565 transport->last_message = time(NULL);
566 sipe_backend_transport_message(transport->connection, string);
569 static void start_keepalive_timer(struct sipe_core_private *sipe_private,
570 guint seconds);
571 static void keepalive_timeout(struct sipe_core_private *sipe_private,
572 SIPE_UNUSED_PARAMETER gpointer data)
574 struct sip_transport *transport = sipe_private->transport;
575 if (transport) {
576 guint since_last = time(NULL) - transport->last_message;
577 guint restart = transport->keepalive_timeout;
578 if (since_last >= restart) {
579 SIPE_DEBUG_INFO("keepalive_timeout: expired %d", restart);
580 send_sip_message(transport, "\r\n\r\n");
581 } else {
582 /* timeout not reached since last message -> reschedule */
583 restart -= since_last;
585 start_keepalive_timer(sipe_private, restart);
589 static void start_keepalive_timer(struct sipe_core_private *sipe_private,
590 guint seconds)
592 sipe_schedule_seconds(sipe_private,
593 "<+keepalive-timeout>",
594 NULL,
595 seconds,
596 keepalive_timeout,
597 NULL);
600 void sip_transport_response(struct sipe_core_private *sipe_private,
601 struct sipmsg *msg,
602 guint code,
603 const char *text,
604 const char *body)
606 gchar *name;
607 gchar *value;
608 GString *outstr = g_string_new("");
609 gchar *contact;
610 GSList *tmp;
611 static const gchar *keepers[] = { "To", "From", "Call-ID", "CSeq", "Via", "Record-Route", NULL };
613 /* Can return NULL! */
614 contact = get_contact(sipe_private);
615 if (contact) {
616 sipmsg_add_header(msg, "Contact", contact);
617 g_free(contact);
620 if (body) {
621 gchar *len = g_strdup_printf("%" G_GSIZE_FORMAT , (gsize) strlen(body));
622 sipmsg_add_header(msg, "Content-Length", len);
623 g_free(len);
624 } else {
625 sipmsg_add_header(msg, "Content-Length", "0");
628 sipmsg_add_header(msg, "User-Agent", sip_transport_user_agent(sipe_private));
630 msg->response = code;
632 sipmsg_strip_headers(msg, keepers);
633 sipmsg_merge_new_headers(msg);
634 sign_outgoing_message(sipe_private, msg);
636 g_string_append_printf(outstr, "SIP/2.0 %d %s\r\n", code, text);
637 tmp = msg->headers;
638 while (tmp) {
639 name = ((struct sipnameval*) (tmp->data))->name;
640 value = ((struct sipnameval*) (tmp->data))->value;
642 g_string_append_printf(outstr, "%s: %s\r\n", name, value);
643 tmp = g_slist_next(tmp);
645 g_string_append_printf(outstr, "\r\n%s", body ? body : "");
646 send_sip_message(sipe_private->transport, outstr->str);
647 g_string_free(outstr, TRUE);
650 static void transactions_remove(struct sipe_core_private *sipe_private,
651 struct transaction *trans)
653 struct sip_transport *transport = sipe_private->transport;
654 if (transport->transactions) {
655 transport->transactions = g_slist_remove(transport->transactions,
656 trans);
657 SIPE_DEBUG_INFO("SIP transactions count:%d after removal", g_slist_length(transport->transactions));
659 if (trans->msg) sipmsg_free(trans->msg);
660 if (trans->payload) {
661 if (trans->payload->destroy)
662 (*trans->payload->destroy)(trans->payload->data);
663 g_free(trans->payload);
665 g_free(trans->key);
666 if (trans->timeout_key) {
667 sipe_schedule_cancel(sipe_private, trans->timeout_key);
668 g_free(trans->timeout_key);
670 g_free(trans);
674 static struct transaction *transactions_find(struct sip_transport *transport,
675 struct sipmsg *msg)
677 GSList *transactions = transport->transactions;
678 const gchar *call_id = sipmsg_find_header(msg, "Call-ID");
679 const gchar *cseq = sipmsg_find_header(msg, "CSeq");
680 gchar *key;
682 if (!call_id || !cseq) {
683 SIPE_DEBUG_ERROR_NOFORMAT("transaction_find: no Call-ID or CSeq!");
684 return NULL;
687 key = g_strdup_printf("<%s><%s>", call_id, cseq);
688 while (transactions) {
689 struct transaction *trans = transactions->data;
690 if (!g_ascii_strcasecmp(trans->key, key)) {
691 g_free(key);
692 return trans;
694 transactions = transactions->next;
696 g_free(key);
698 return NULL;
701 static void transaction_timeout_cb(struct sipe_core_private *sipe_private,
702 gpointer data)
704 struct transaction *trans = data;
705 (trans->timeout_callback)(sipe_private, trans->msg, trans);
706 transactions_remove(sipe_private, trans);
709 struct transaction *sip_transport_request_timeout(struct sipe_core_private *sipe_private,
710 const gchar *method,
711 const gchar *url,
712 const gchar *to,
713 const gchar *addheaders,
714 const gchar *body,
715 struct sip_dialog *dialog,
716 TransCallback callback,
717 guint timeout,
718 TransCallback timeout_callback)
720 struct sip_transport *transport = sipe_private->transport;
721 char *buf;
722 struct sipmsg *msg;
723 gchar *ourtag = dialog && dialog->ourtag ? g_strdup(dialog->ourtag) : NULL;
724 gchar *theirtag = dialog && dialog->theirtag ? g_strdup(dialog->theirtag) : NULL;
725 gchar *theirepid = dialog && dialog->theirepid ? g_strdup(dialog->theirepid) : NULL;
726 gchar *callid = dialog && dialog->callid ? g_strdup(dialog->callid) : gencallid();
727 gchar *branch = dialog && dialog->callid ? NULL : genbranch();
728 gchar *route = g_strdup("");
729 gchar *epid = get_epid(sipe_private);
730 int cseq = dialog ? ++dialog->cseq : 1 /* as Call-Id is new in this case */;
731 struct transaction *trans = NULL;
733 if (dialog && dialog->routes)
735 GSList *iter = dialog->routes;
737 while(iter)
739 char *tmp = route;
740 route = g_strdup_printf("%sRoute: %s\r\n", route, (char *)iter->data);
741 g_free(tmp);
742 iter = g_slist_next(iter);
746 if (!ourtag && !dialog) {
747 ourtag = gentag();
750 if (sipe_strequal(method, "REGISTER")) {
751 if (sipe_private->register_callid) {
752 g_free(callid);
753 callid = g_strdup(sipe_private->register_callid);
754 } else {
755 sipe_private->register_callid = g_strdup(callid);
757 cseq = ++transport->cseq;
760 buf = g_strdup_printf("%s %s SIP/2.0\r\n"
761 "Via: SIP/2.0/%s %s:%d%s%s\r\n"
762 "From: <sip:%s>%s%s;epid=%s\r\n"
763 "To: <%s>%s%s%s%s\r\n"
764 "Max-Forwards: 70\r\n"
765 "CSeq: %d %s\r\n"
766 "User-Agent: %s\r\n"
767 "Call-ID: %s\r\n"
768 "%s%s"
769 "Content-Length: %" G_GSIZE_FORMAT "\r\n\r\n%s",
770 method,
771 dialog && dialog->request ? dialog->request : url,
772 TRANSPORT_DESCRIPTOR,
773 sipe_backend_network_ip_address(SIPE_CORE_PUBLIC),
774 transport->connection->client_port,
775 branch ? ";branch=" : "",
776 branch ? branch : "",
777 sipe_private->username,
778 ourtag ? ";tag=" : "",
779 ourtag ? ourtag : "",
780 epid,
782 theirtag ? ";tag=" : "",
783 theirtag ? theirtag : "",
784 theirepid ? ";epid=" : "",
785 theirepid ? theirepid : "",
786 cseq,
787 method,
788 sip_transport_user_agent(sipe_private),
789 callid,
790 route,
791 addheaders ? addheaders : "",
792 body ? (gsize) strlen(body) : 0,
793 body ? body : "");
796 //printf ("parsing msg buf:\n%s\n\n", buf);
797 msg = sipmsg_parse_msg(buf);
799 g_free(buf);
800 g_free(ourtag);
801 g_free(theirtag);
802 g_free(theirepid);
803 g_free(branch);
804 g_free(route);
805 g_free(epid);
807 sign_outgoing_message(sipe_private, msg);
809 /* The authentication scheme is not ready so we can't send the message.
810 This should only happen for REGISTER messages. */
811 if (!transport->auth_incomplete) {
812 buf = sipmsg_to_string(msg);
814 /* add to ongoing transactions */
815 /* ACK isn't supposed to be answered ever. So we do not keep transaction for it. */
816 if (!sipe_strequal(method, "ACK")) {
817 trans = g_new0(struct transaction, 1);
818 trans->callback = callback;
819 trans->msg = msg;
820 trans->key = g_strdup_printf("<%s><%d %s>", callid, cseq, method);
821 if (timeout_callback) {
822 trans->timeout_callback = timeout_callback;
823 trans->timeout_key = g_strdup_printf("<transaction timeout>%s", trans->key);
824 sipe_schedule_seconds(sipe_private,
825 trans->timeout_key,
826 trans,
827 timeout,
828 transaction_timeout_cb,
829 NULL);
831 transport->transactions = g_slist_append(transport->transactions,
832 trans);
833 SIPE_DEBUG_INFO("SIP transactions count:%d after addition", g_slist_length(transport->transactions));
836 send_sip_message(transport, buf);
837 g_free(buf);
840 if (!trans) sipmsg_free(msg);
841 g_free(callid);
842 return trans;
845 struct transaction *sip_transport_request(struct sipe_core_private *sipe_private,
846 const gchar *method,
847 const gchar *url,
848 const gchar *to,
849 const gchar *addheaders,
850 const gchar *body,
851 struct sip_dialog *dialog,
852 TransCallback callback)
854 return sip_transport_request_timeout(sipe_private,
855 method,
856 url,
858 addheaders,
859 body,
860 dialog,
861 callback,
863 NULL);
866 static void sip_transport_simple_request(struct sipe_core_private *sipe_private,
867 const gchar *method,
868 struct sip_dialog *dialog)
870 sip_transport_request(sipe_private,
871 method,
872 dialog->with,
873 dialog->with,
874 NULL,
875 NULL,
876 dialog,
877 NULL);
880 void sip_transport_ack(struct sipe_core_private *sipe_private,
881 struct sip_dialog *dialog)
883 sip_transport_simple_request(sipe_private, "ACK", dialog);
886 void sip_transport_bye(struct sipe_core_private *sipe_private,
887 struct sip_dialog *dialog)
889 sip_transport_simple_request(sipe_private, "BYE", dialog);
892 struct transaction *sip_transport_info(struct sipe_core_private *sipe_private,
893 const gchar *addheaders,
894 const gchar *body,
895 struct sip_dialog *dialog,
896 TransCallback callback)
898 return sip_transport_request(sipe_private,
899 "INFO",
900 dialog->with,
901 dialog->with,
902 addheaders,
903 body,
904 dialog,
905 callback);
908 struct transaction *sip_transport_invite(struct sipe_core_private *sipe_private,
909 const gchar *addheaders,
910 const gchar *body,
911 struct sip_dialog *dialog,
912 TransCallback callback)
914 return sip_transport_request(sipe_private,
915 "INVITE",
916 dialog->with,
917 dialog->with,
918 addheaders,
919 body,
920 dialog,
921 callback);
924 struct transaction *sip_transport_service(struct sipe_core_private *sipe_private,
925 const gchar *uri,
926 const gchar *addheaders,
927 const gchar *body,
928 TransCallback callback)
930 return sip_transport_request(sipe_private,
931 "SERVICE",
932 uri,
933 uri,
934 addheaders,
935 body,
936 NULL,
937 callback);
940 void sip_transport_subscribe(struct sipe_core_private *sipe_private,
941 const gchar *uri,
942 const gchar *addheaders,
943 const gchar *body,
944 struct sip_dialog *dialog,
945 TransCallback callback)
947 sip_transport_request(sipe_private,
948 "SUBSCRIBE",
949 uri,
950 uri,
951 addheaders,
952 body,
953 dialog,
954 callback);
957 void sip_transport_update(struct sipe_core_private *sipe_private,
958 struct sip_dialog *dialog,
959 TransCallback callback)
961 sip_transport_request(sipe_private,
962 "UPDATE",
963 dialog->with,
964 dialog->with,
965 NULL,
966 NULL,
967 dialog,
968 callback);
971 static const gchar *get_auth_header(struct sipe_core_private *sipe_private,
972 guint type,
973 struct sipmsg *msg)
975 struct sip_auth *auth = &sipe_private->transport->registrar;
977 auth->type = type;
978 auth->protocol = auth_type_to_protocol[auth->type];
980 return(sipmsg_find_auth_header(msg, auth->protocol));
983 static void do_register(struct sipe_core_private *sipe_private,
984 gboolean deregister);
986 static void do_reauthenticate_cb(struct sipe_core_private *sipe_private,
987 SIPE_UNUSED_PARAMETER gpointer unused)
989 struct sip_transport *transport = sipe_private->transport;
991 /* register again when security token expires */
992 /* we have to start a new authentication as the security token
993 * is almost expired by sending a not signed REGISTER message */
994 SIPE_DEBUG_INFO_NOFORMAT("do a full reauthentication");
995 sipe_auth_free(&transport->registrar);
996 sipe_auth_free(&transport->proxy);
997 sipe_schedule_cancel(sipe_private, "<registration>");
998 transport->auth_retry = TRUE;
999 transport->reregister_set = FALSE;
1000 transport->register_attempt = 0;
1001 do_register(sipe_private, FALSE);
1002 transport->reauthenticate_set = FALSE;
1005 static void sip_transport_default_contact(struct sipe_core_private *sipe_private)
1007 struct sip_transport *transport = sipe_private->transport;
1008 sipe_private->contact = g_strdup_printf("<sip:%s:%d;maddr=%s;transport=%s>;proxy=replace",
1009 sipe_private->username,
1010 transport->connection->client_port,
1011 sipe_backend_network_ip_address(SIPE_CORE_PUBLIC),
1012 TRANSPORT_DESCRIPTOR);
1015 static void do_register_cb(struct sipe_core_private *sipe_private,
1016 SIPE_UNUSED_PARAMETER void *unused)
1018 do_register(sipe_private, FALSE);
1021 static void sip_transport_set_reregister(struct sipe_core_private *sipe_private,
1022 int expires)
1024 sipe_schedule_seconds(sipe_private,
1025 "<registration>",
1026 NULL,
1027 expires,
1028 do_register_cb,
1029 NULL);
1032 static void sipe_server_register(struct sipe_core_private *sipe_private,
1033 guint type,
1034 gchar *server_name,
1035 guint server_port);
1037 static gboolean process_register_response(struct sipe_core_private *sipe_private,
1038 struct sipmsg *msg,
1039 SIPE_UNUSED_PARAMETER struct transaction *trans)
1041 struct sip_transport *transport = sipe_private->transport;
1042 const gchar *expires_header;
1043 int expires, i;
1044 GSList *hdr = msg->headers;
1045 struct sipnameval *elem;
1047 expires_header = sipmsg_find_header(msg, "Expires");
1048 expires = expires_header != NULL ? strtol(expires_header, NULL, 10) : 0;
1049 SIPE_DEBUG_INFO("process_register_response: got response to REGISTER; expires = %d", expires);
1051 switch (msg->response) {
1052 case 200:
1053 if (expires) {
1054 const gchar *contact_hdr;
1055 const gchar *auth_hdr;
1056 gchar *gruu = NULL;
1057 gchar *uuid;
1058 gchar *timeout;
1059 const gchar *server_hdr = sipmsg_find_header(msg, "Server");
1061 if (!transport->reregister_set) {
1062 /* Schedule re-register 30 seconds before expiration */
1063 if (expires > 30)
1064 expires -= 30;
1065 sip_transport_set_reregister(sipe_private,
1066 expires);
1067 transport->reregister_set = TRUE;
1070 if (server_hdr && !transport->server_version) {
1071 transport->server_version = g_strdup(server_hdr);
1072 g_free(transport->user_agent);
1073 transport->user_agent = NULL;
1076 auth_hdr = sipmsg_find_auth_header(msg,
1077 transport->registrar.protocol);
1078 if (auth_hdr) {
1079 SIPE_DEBUG_INFO("process_register_response: Auth header: %s", auth_hdr);
1080 fill_auth(auth_hdr, &transport->registrar);
1083 if (!transport->reauthenticate_set) {
1084 /* [MS-SIPAE] Section 3.2.2 Timers
1086 * When the ... authentication handshake completes
1087 * and the SA enters the "established" state, the
1088 * SIP protocol client MUST start an SA expiration
1089 * timer.
1090 * ...
1091 * The expiration timer value is the lesser of
1093 * - Kerberos: the service ticket expiry time
1094 * - TLS-DSK: the certificate expiration time
1096 * and eight hours, further reduced by some buffer
1097 * time.
1098 * ...
1099 * The protocol client MUST choose a sufficient
1100 * buffer time to allow for the ... authentication
1101 * handshake that reestablishes the SA to complete
1102 * ... This value SHOULD be five (5) minutes or
1103 * longer.
1105 guint reauth_timeout = transport->registrar.expires;
1107 SIPE_DEBUG_INFO_NOFORMAT("process_register_response: authentication handshake completed successfully");
1109 if ((reauth_timeout == 0) ||
1110 (reauth_timeout > 8 * 60 * 60))
1111 reauth_timeout = 8 * 60 * 60;
1112 if (reauth_timeout > 5 * 60)
1113 reauth_timeout -= 5 * 60;
1115 sipe_schedule_seconds(sipe_private,
1116 "<+reauthentication>",
1117 NULL,
1118 reauth_timeout,
1119 do_reauthenticate_cb,
1120 NULL);
1121 transport->reauthenticate_set = TRUE;
1124 uuid = get_uuid(sipe_private);
1126 // There can be multiple Contact headers (one per location where the user is logged in) so
1127 // make sure to only get the one for this uuid
1128 for (i = 0; (contact_hdr = sipmsg_find_header_instance (msg, "Contact", i)); i++) {
1129 gchar * valid_contact = sipmsg_find_part_of_header (contact_hdr, uuid, NULL, NULL);
1130 if (valid_contact) {
1131 gruu = sipmsg_find_part_of_header(contact_hdr, "gruu=\"", "\"", NULL);
1132 //SIPE_DEBUG_INFO("process_register_response: got gruu %s from contact hdr w/ right uuid: %s", gruu, contact_hdr);
1133 g_free(valid_contact);
1134 break;
1135 } else {
1136 //SIPE_DEBUG_INFO("process_register_response: ignoring contact hdr b/c not right uuid: %s", contact_hdr);
1139 g_free(uuid);
1141 g_free(sipe_private->contact);
1142 if(gruu) {
1143 sipe_private->contact = g_strdup_printf("<%s>", gruu);
1144 g_free(gruu);
1145 } else {
1146 //SIPE_DEBUG_INFO_NOFORMAT("process_register_response: didn't find gruu in a Contact hdr");
1147 sip_transport_default_contact(sipe_private);
1149 SIPE_CORE_PRIVATE_FLAG_UNSET(OCS2007);
1150 SIPE_CORE_PRIVATE_FLAG_UNSET(REMOTE_USER);
1151 SIPE_CORE_PRIVATE_FLAG_UNSET(BATCHED_SUPPORT);
1153 while(hdr)
1155 elem = hdr->data;
1156 if (sipe_strcase_equal(elem->name, "Supported")) {
1157 if (sipe_strcase_equal(elem->value, "msrtc-event-categories")) {
1158 /* We interpret this as OCS2007+ indicator */
1159 SIPE_CORE_PRIVATE_FLAG_SET(OCS2007);
1160 SIPE_DEBUG_INFO("Supported: %s (indicates OCS2007+)", elem->value);
1162 if (sipe_strcase_equal(elem->value, "adhoclist")) {
1163 SIPE_CORE_PRIVATE_FLAG_SET(BATCHED_SUPPORT);
1164 SIPE_DEBUG_INFO("Supported: %s", elem->value);
1167 if (sipe_strcase_equal(elem->name, "Allow-Events")){
1168 gchar **caps = g_strsplit(elem->value,",",0);
1169 i = 0;
1170 while (caps[i]) {
1171 sipe_private->allowed_events = g_slist_append(sipe_private->allowed_events, g_strdup(caps[i]));
1172 SIPE_DEBUG_INFO("Allow-Events: %s", caps[i]);
1173 i++;
1175 g_strfreev(caps);
1177 if (sipe_strcase_equal(elem->name, "ms-user-logon-data")) {
1178 if (sipe_strcase_equal(elem->value, "RemoteUser")) {
1179 SIPE_CORE_PRIVATE_FLAG_SET(REMOTE_USER);
1180 SIPE_DEBUG_INFO_NOFORMAT("ms-user-logon-data: RemoteUser (connected "
1181 "via Edge Server)");
1184 hdr = g_slist_next(hdr);
1187 sipe_backend_connection_completed(SIPE_CORE_PUBLIC);
1189 /* rejoin open chats to be able to use them by continue to send messages */
1190 sipe_backend_chat_rejoin_all(SIPE_CORE_PUBLIC);
1192 /* subscriptions, done only once */
1193 if (!transport->subscribed) {
1194 sipe_subscription_self_events(sipe_private);
1195 transport->subscribed = TRUE;
1198 timeout = sipmsg_find_part_of_header(sipmsg_find_header(msg, "ms-keep-alive"),
1199 "timeout=", ";", NULL);
1200 if (timeout != NULL) {
1201 sscanf(timeout, "%u", &transport->keepalive_timeout);
1202 SIPE_DEBUG_INFO("process_register_response: server determined keep alive timeout is %u seconds",
1203 transport->keepalive_timeout);
1204 g_free(timeout);
1207 SIPE_DEBUG_INFO("process_register_response: got 200, removing CSeq: %d", transport->cseq);
1209 break;
1210 case 301:
1212 gchar *redirect = parse_from(sipmsg_find_header(msg, "Contact"));
1214 SIPE_DEBUG_INFO_NOFORMAT("process_register_response: authentication handshake completed successfully (with redirect)");
1216 if (redirect && (g_ascii_strncasecmp("sip:", redirect, 4) == 0)) {
1217 gchar **parts = g_strsplit(redirect + 4, ";", 0);
1218 gchar **tmp;
1219 gchar *hostname;
1220 int port = 0;
1221 guint transport_type = SIPE_TRANSPORT_TLS;
1222 int i = 1;
1224 tmp = g_strsplit(parts[0], ":", 0);
1225 hostname = g_strdup(tmp[0]);
1226 if (tmp[1]) port = strtoul(tmp[1], NULL, 10);
1227 g_strfreev(tmp);
1229 while (parts[i]) {
1230 tmp = g_strsplit(parts[i], "=", 0);
1231 if (tmp[1]) {
1232 if (g_ascii_strcasecmp("transport", tmp[0]) == 0) {
1233 if (g_ascii_strcasecmp("tcp", tmp[1]) == 0) {
1234 transport_type = SIPE_TRANSPORT_TCP;
1238 g_strfreev(tmp);
1239 i++;
1241 g_strfreev(parts);
1243 /* Close old connection */
1244 sipe_core_connection_cleanup(sipe_private);
1245 /* transport and sipe_private->transport are invalid after this */
1247 /* Create new connection */
1248 sipe_server_register(sipe_private, transport_type, hostname, port);
1249 /* sipe_private->transport has a new value */
1250 SIPE_DEBUG_INFO("process_register_response: redirected to host %s port %d transport %d",
1251 hostname, port, transport_type);
1253 g_free(redirect);
1255 break;
1256 case 401:
1258 const char *auth_hdr = NULL;
1260 SIPE_DEBUG_INFO("process_register_response: REGISTER retries %d", transport->registrar.retries);
1262 if (transport->reauthenticate_set) {
1263 SIPE_DEBUG_ERROR_NOFORMAT("process_register_response: RE-REGISTER rejected, triggering re-authentication");
1264 do_reauthenticate_cb(sipe_private, NULL);
1265 return TRUE;
1268 if (sip_sec_context_is_ready(transport->registrar.gssapi_context)) {
1269 struct sip_auth *auth = &transport->registrar;
1271 /* NTLM is the scheme with lowest priority - don't retry */
1272 if (auth_can_retry(transport, auth)) {
1273 guint failed = auth->type;
1274 SIPE_DEBUG_INFO_NOFORMAT("process_register_response: authentication handshake failed - trying next authentication scheme.");
1275 sipe_auth_free(auth);
1276 auth->type = failed;
1277 } else {
1278 SIPE_DEBUG_INFO_NOFORMAT("process_register_response: authentication handshake failed - giving up.");
1279 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1280 SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
1281 _("Authentication failed"));
1282 return TRUE;
1286 if (sipe_private->authentication_type == SIPE_AUTHENTICATION_TYPE_AUTOMATIC) {
1287 struct sip_auth *auth = &transport->registrar;
1288 guint try = auth->type;
1290 while (!auth_hdr) {
1292 * Determine next authentication
1293 * scheme in priority order
1295 if (transport->auth_retry)
1296 switch (try) {
1297 case SIPE_AUTHENTICATION_TYPE_UNSET:
1298 try = SIPE_AUTHENTICATION_TYPE_TLS_DSK;
1299 break;
1301 case SIPE_AUTHENTICATION_TYPE_TLS_DSK:
1302 #if defined(HAVE_GSSAPI_GSSAPI_H) || defined(HAVE_SSPI)
1303 try = SIPE_AUTHENTICATION_TYPE_KERBEROS;
1304 break;
1306 case SIPE_AUTHENTICATION_TYPE_KERBEROS:
1307 #endif
1308 try = SIPE_AUTHENTICATION_TYPE_NTLM;
1309 break;
1311 default:
1312 try = SIPE_AUTHENTICATION_TYPE_UNSET;
1313 break;
1316 auth->can_retry = (try != SIPE_AUTHENTICATION_TYPE_UNSET);
1318 if (!auth->can_retry) {
1319 SIPE_DEBUG_INFO_NOFORMAT("process_register_response: no more authentication schemes to try");
1320 break;
1323 auth_hdr = get_auth_header(sipe_private,
1324 try,
1325 msg);
1328 transport->auth_retry = FALSE;
1330 } else
1331 auth_hdr = get_auth_header(sipe_private,
1332 sipe_private->authentication_type,
1333 msg);
1335 if (!auth_hdr) {
1336 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1337 SIPE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE,
1338 _("Incompatible authentication scheme chosen"));
1339 return TRUE;
1341 SIPE_DEBUG_INFO("process_register_response: Auth header: %s", auth_hdr);
1342 fill_auth(auth_hdr, &transport->registrar);
1343 transport->reregister_set = FALSE;
1344 transport->register_attempt = 0;
1345 do_register(sipe_private,
1346 sipe_backend_connection_is_disconnecting(SIPE_CORE_PUBLIC));
1348 break;
1349 case 403:
1351 gchar *reason;
1352 gchar *warning;
1353 sipmsg_parse_warning(msg, &reason);
1354 reason = reason ? reason : sipmsg_get_ms_diagnostics_public_reason(msg);
1355 warning = g_strdup_printf(_("You have been rejected by the server: %s"),
1356 reason ? reason : _("no reason given"));
1357 g_free(reason);
1359 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1360 SIPE_CONNECTION_ERROR_INVALID_SETTINGS,
1361 warning);
1362 g_free(warning);
1363 return TRUE;
1365 break;
1366 case 404:
1368 const gchar *diagnostics = sipmsg_find_header(msg, "ms-diagnostics");
1369 gchar *reason = sipmsg_get_ms_diagnostics_reason(msg);
1370 gchar *warning;
1371 warning = g_strdup_printf(_("Not found: %s. Please contact your Administrator"),
1372 diagnostics ? (reason ? reason : _("no reason given")) :
1373 _("SIP is either not enabled for the destination URI or it does not exist"));
1374 g_free(reason);
1376 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1377 SIPE_CONNECTION_ERROR_INVALID_USERNAME,
1378 warning);
1379 g_free(warning);
1380 return TRUE;
1382 break;
1383 case 504: /* Server time-out */
1384 /* first attempt + 5 retries */
1385 if (transport->register_attempt < 6) {
1386 SIPE_DEBUG_INFO("process_register_response: RE-REGISTER timeout on attempt %d, retrying later",
1387 transport->register_attempt);
1388 sip_transport_set_reregister(sipe_private, 60);
1389 return TRUE;
1391 /* FALLTHROUGH */
1392 case 503:
1394 gchar *reason = sipmsg_get_ms_diagnostics_reason(msg);
1395 gchar *warning;
1396 warning = g_strdup_printf(_("Service unavailable: %s"), reason ? reason : _("no reason given"));
1397 g_free(reason);
1399 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1400 SIPE_CONNECTION_ERROR_NETWORK,
1401 warning);
1402 g_free(warning);
1403 return TRUE;
1405 break;
1407 return TRUE;
1410 static gboolean register_response_timeout(struct sipe_core_private *sipe_private,
1411 SIPE_UNUSED_PARAMETER struct sipmsg *msg,
1412 SIPE_UNUSED_PARAMETER struct transaction *trans)
1414 struct sip_transport *transport = sipe_private->transport;
1415 if (transport->register_attempt < 6) {
1416 SIPE_DEBUG_INFO("register_response_timeout: no answer to attempt %d, retrying",
1417 transport->register_attempt);
1418 do_register(sipe_private, FALSE);
1419 } else {
1420 gchar *warning = g_strdup_printf(_("Service unavailable: %s"), _("no reason given"));
1421 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1422 SIPE_CONNECTION_ERROR_NETWORK,
1423 warning);
1424 g_free(warning);
1426 return TRUE;
1429 static void do_register(struct sipe_core_private *sipe_private,
1430 gboolean deregister)
1432 struct sip_transport *transport = sipe_private->transport;
1433 char *uri;
1434 char *to;
1435 char *hdr;
1436 char *uuid;
1438 if (!sipe_private->public.sip_domain) return;
1440 if (!deregister) {
1441 if (transport->reregister_set) {
1442 transport->reregister_set = FALSE;
1443 transport->register_attempt = 1;
1444 } else {
1445 transport->register_attempt++;
1449 transport->deregister = deregister;
1450 transport->auth_incomplete = FALSE;
1452 uuid = get_uuid(sipe_private);
1453 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"
1454 "Supported: gruu-10, adhoclist, msrtc-event-categories, com.microsoft.msrtc.presence\r\n"
1455 "Event: registration\r\n"
1456 "Allow-Events: presence\r\n"
1457 "ms-keep-alive: UAC;hop-hop=yes\r\n"
1458 "%s",
1459 sipe_backend_network_ip_address(SIPE_CORE_PUBLIC),
1460 transport->connection->client_port,
1461 TRANSPORT_DESCRIPTOR,
1462 uuid,
1463 deregister ? "Expires: 0\r\n" : "");
1464 g_free(uuid);
1466 uri = sip_uri_from_name(sipe_private->public.sip_domain);
1467 to = sip_uri_self(sipe_private);
1468 sip_transport_request_timeout(sipe_private,
1469 "REGISTER",
1470 uri,
1472 hdr,
1474 NULL,
1475 process_register_response,
1477 deregister ? NULL : register_response_timeout);
1478 g_free(to);
1479 g_free(uri);
1480 g_free(hdr);
1482 if (deregister) {
1483 /* Make sure that all messages are pushed to the server
1484 before the connection gets shut down */
1485 SIPE_DEBUG_INFO_NOFORMAT("De-register from server. Flushing outstanding messages.");
1486 sipe_backend_transport_flush(transport->connection);
1490 void sip_transport_deregister(struct sipe_core_private *sipe_private)
1492 do_register(sipe_private, TRUE);
1495 void sip_transport_disconnect(struct sipe_core_private *sipe_private)
1497 struct sip_transport *transport = sipe_private->transport;
1499 /* transport can be NULL during connection setup */
1500 if (transport) {
1501 sipe_backend_transport_disconnect(transport->connection);
1503 sipe_auth_free(&transport->registrar);
1504 sipe_auth_free(&transport->proxy);
1506 g_free(transport->server_name);
1507 g_free(transport->server_version);
1508 g_free(transport->user_agent);
1510 while (transport->transactions)
1511 transactions_remove(sipe_private,
1512 transport->transactions->data);
1514 g_free(transport);
1517 sipe_private->transport = NULL;
1518 sipe_private->service_data = NULL;
1519 sipe_private->address_data = NULL;
1521 sipe_schedule_cancel(sipe_private, "<+keepalive-timeout>");
1523 if (sipe_private->dns_query)
1524 sipe_backend_dns_query_cancel(sipe_private->dns_query);
1528 void sip_transport_authentication_completed(struct sipe_core_private *sipe_private)
1530 do_reauthenticate_cb(sipe_private, NULL);
1533 guint sip_transport_port(struct sipe_core_private *sipe_private)
1535 return sipe_private->transport->server_port;
1538 static void process_input_message(struct sipe_core_private *sipe_private,
1539 struct sipmsg *msg)
1541 struct sip_transport *transport = sipe_private->transport;
1542 gboolean notfound = FALSE;
1543 const char *method = msg->method ? msg->method : "NOT FOUND";
1545 SIPE_DEBUG_INFO("process_input_message: msg->response(%d),msg->method(%s)",
1546 msg->response, method);
1548 if (msg->response == 0) { /* request */
1549 if (sipe_strequal(method, "MESSAGE")) {
1550 process_incoming_message(sipe_private, msg);
1551 } else if (sipe_strequal(method, "NOTIFY")) {
1552 SIPE_DEBUG_INFO_NOFORMAT("send->process_incoming_notify");
1553 process_incoming_notify(sipe_private, msg);
1554 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
1555 } else if (sipe_strequal(method, "BENOTIFY")) {
1556 SIPE_DEBUG_INFO_NOFORMAT("send->process_incoming_benotify");
1557 process_incoming_notify(sipe_private, msg);
1558 } else if (sipe_strequal(method, "INVITE")) {
1559 process_incoming_invite(sipe_private, msg);
1560 } else if (sipe_strequal(method, "REFER")) {
1561 process_incoming_refer(sipe_private, msg);
1562 } else if (sipe_strequal(method, "OPTIONS")) {
1563 process_incoming_options(sipe_private, msg);
1564 } else if (sipe_strequal(method, "INFO")) {
1565 process_incoming_info(sipe_private, msg);
1566 } else if (sipe_strequal(method, "ACK")) {
1567 /* ACK's don't need any response */
1568 } else if (sipe_strequal(method, "PRACK")) {
1569 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
1570 } else if (sipe_strequal(method, "SUBSCRIBE")) {
1571 /* LCS 2005 sends us these - just respond 200 OK */
1572 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
1573 } else if (sipe_strequal(method, "CANCEL")) {
1574 process_incoming_cancel(sipe_private, msg);
1575 } else if (sipe_strequal(method, "BYE")) {
1576 process_incoming_bye(sipe_private, msg);
1577 } else {
1578 sip_transport_response(sipe_private, msg, 501, "Not implemented", NULL);
1579 notfound = TRUE;
1582 } else { /* response */
1583 struct transaction *trans = transactions_find(transport, msg);
1584 if (trans) {
1585 if (msg->response < 200) {
1586 /* ignore provisional response */
1587 SIPE_DEBUG_INFO("process_input_message: got provisional (%d) response, ignoring", msg->response);
1589 /* Transaction not yet completed */
1590 trans = NULL;
1592 } else if (msg->response == 401) { /* Unauthorized */
1594 if (sipe_strequal(trans->msg->method, "REGISTER")) {
1595 /* Expected response during authentication handshake */
1596 transport->registrar.retries++;
1597 SIPE_DEBUG_INFO("process_input_message: RE-REGISTER CSeq: %d", transport->cseq);
1598 } else {
1599 gchar *resend;
1601 /* Are we registered? */
1602 if (transport->reregister_set) {
1603 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: 401 response to non-REGISTER message. Retrying with new authentication.");
1604 sipmsg_remove_header_now(trans->msg, "Authorization");
1605 sign_outgoing_message(sipe_private,
1606 trans->msg);
1607 } else {
1609 * We don't have a valid authentication at the moment.
1610 * Resend message unchanged. It will be rejected again
1611 * and hopefully by then we have a valid authentication.
1613 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: 401 response to non-REGISTER message. Bouncing...");
1616 /* Resend request */
1617 resend = sipmsg_to_string(trans->msg);
1618 send_sip_message(sipe_private->transport, resend);
1619 g_free(resend);
1621 /* Transaction not yet completed */
1622 trans = NULL;
1625 } else if (msg->response == 407) { /* Proxy Authentication Required */
1627 if (transport->proxy.retries++ <= 30) {
1628 const gchar *proxy_hdr = sipmsg_find_header(msg, "Proxy-Authenticate");
1630 if (proxy_hdr) {
1631 gchar *auth = NULL;
1633 if (!g_ascii_strncasecmp(proxy_hdr, "Digest", 6)) {
1634 auth = sip_sec_digest_authorization(sipe_private,
1635 proxy_hdr + 7,
1636 msg->method,
1637 msg->target);
1638 } else {
1639 guint i;
1641 transport->proxy.type = SIPE_AUTHENTICATION_TYPE_UNSET;
1642 for (i = 0; i < AUTH_PROTOCOLS; i++) {
1643 const gchar *protocol = auth_type_to_protocol[i];
1644 if (protocol &&
1645 !g_ascii_strncasecmp(proxy_hdr, protocol, strlen(protocol))) {
1646 SIPE_DEBUG_INFO("process_input_message: proxy authentication scheme '%s'", protocol);
1647 transport->proxy.type = i;
1648 transport->proxy.protocol = protocol;
1649 fill_auth(proxy_hdr, &transport->proxy);
1650 auth = auth_header(sipe_private, &transport->proxy, trans->msg);
1651 break;
1656 if (auth) {
1657 gchar *resend;
1659 /* replace old proxy authentication with new one */
1660 sipmsg_remove_header_now(trans->msg, "Proxy-Authorization");
1661 sipmsg_add_header_now(trans->msg, "Proxy-Authorization", auth);
1662 g_free(auth);
1664 /* resend request with proxy authentication */
1665 resend = sipmsg_to_string(trans->msg);
1666 send_sip_message(sipe_private->transport, resend);
1667 g_free(resend);
1669 /* Transaction not yet completed */
1670 trans = NULL;
1672 } else
1673 SIPE_DEBUG_ERROR_NOFORMAT("process_input_message: can't generate proxy authentication. Giving up.");
1674 } else
1675 SIPE_DEBUG_ERROR_NOFORMAT("process_input_message: 407 response without 'Proxy-Authenticate' header. Giving up.");
1676 } else
1677 SIPE_DEBUG_ERROR_NOFORMAT("process_input_message: too many proxy authentication retries. Giving up.");
1679 } else {
1680 transport->registrar.retries = 0;
1681 transport->proxy.retries = 0;
1684 /* Is transaction completed? */
1685 if (trans) {
1686 if (trans->callback) {
1687 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: we have a transaction callback");
1688 /* call the callback to process response */
1689 (trans->callback)(sipe_private, msg, trans);
1690 /* transport && trans no longer valid after redirect */
1694 * Redirect case: sipe_private->transport is
1695 * the new transport with empty queue
1697 if (sipe_private->transport->transactions) {
1698 SIPE_DEBUG_INFO("process_input_message: removing CSeq %d", transport->cseq);
1699 transactions_remove(sipe_private, trans);
1702 } else {
1703 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: received response to unknown transaction");
1704 notfound = TRUE;
1708 if (notfound) {
1709 SIPE_DEBUG_INFO("received a unknown sip message with method %s and response %d", method, msg->response);
1713 static void sip_transport_input(struct sipe_transport_connection *conn)
1715 struct sipe_core_private *sipe_private = conn->user_data;
1716 struct sip_transport *transport = sipe_private->transport;
1717 gchar *cur = conn->buffer;
1719 /* according to the RFC remove CRLF at the beginning */
1720 while (*cur == '\r' || *cur == '\n') {
1721 cur++;
1723 if (cur != conn->buffer)
1724 sipe_utils_shrink_buffer(conn, cur);
1726 /* Received a full Header? */
1727 transport->processing_input = TRUE;
1728 while (transport->processing_input &&
1729 ((cur = strstr(conn->buffer, "\r\n\r\n")) != NULL)) {
1730 struct sipmsg *msg;
1731 guint remainder;
1733 cur += 2;
1734 cur[0] = '\0';
1735 msg = sipmsg_parse_header(conn->buffer);
1737 cur += 2;
1738 remainder = conn->buffer_used - (cur - conn->buffer);
1739 if (msg && remainder >= (guint) msg->bodylen) {
1740 char *dummy = g_malloc(msg->bodylen + 1);
1741 memcpy(dummy, cur, msg->bodylen);
1742 dummy[msg->bodylen] = '\0';
1743 msg->body = dummy;
1744 cur += msg->bodylen;
1745 sipe_utils_message_debug("SIP",
1746 conn->buffer,
1747 msg->body,
1748 FALSE);
1749 sipe_utils_shrink_buffer(conn, cur);
1750 } else {
1751 if (msg) {
1752 SIPE_DEBUG_INFO("sipe_transport_input: body too short (%d < %d, strlen %d) - ignoring message", remainder, msg->bodylen, (int)strlen(conn->buffer));
1753 sipmsg_free(msg);
1756 /* restore header for next try */
1757 cur[-2] = '\r';
1758 return;
1761 /* Fatal header parse error? */
1762 if (msg->response == SIPMSG_RESPONSE_FATAL_ERROR) {
1763 /* can't proceed -> drop connection */
1764 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1765 SIPE_CONNECTION_ERROR_NETWORK,
1766 _("Corrupted message received"));
1767 transport->processing_input = FALSE;
1769 /* Verify the signature before processing it */
1770 } else if (sip_sec_context_is_ready(transport->registrar.gssapi_context)) {
1771 struct sipmsg_breakdown msgbd;
1772 gchar *signature_input_str;
1773 gchar *rspauth;
1774 msgbd.msg = msg;
1775 sipmsg_breakdown_parse(&msgbd, transport->registrar.realm, transport->registrar.target,
1776 transport->registrar.protocol);
1777 signature_input_str = sipmsg_breakdown_get_string(transport->registrar.version, &msgbd);
1779 rspauth = sipmsg_find_part_of_header(sipmsg_find_header(msg, "Authentication-Info"), "rspauth=\"", "\"", NULL);
1781 if (rspauth != NULL) {
1782 if (sip_sec_verify_signature(transport->registrar.gssapi_context, signature_input_str, rspauth)) {
1783 SIPE_DEBUG_INFO_NOFORMAT("sip_transport_input: signature of incoming message validated");
1784 process_input_message(sipe_private, msg);
1785 /* transport is invalid after redirect */
1786 } else {
1787 SIPE_DEBUG_INFO_NOFORMAT("sip_transport_input: signature of incoming message is invalid.");
1788 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1789 SIPE_CONNECTION_ERROR_NETWORK,
1790 _("Invalid message signature received"));
1791 transport->processing_input = FALSE;
1793 } else if ((msg->response == 401) ||
1794 sipe_strequal(msg->method, "REGISTER")) {
1795 /* a) Retry non-REGISTER requests with updated authentication */
1796 /* b) We must always process REGISTER responses */
1797 process_input_message(sipe_private, msg);
1798 } else {
1799 /* OCS sends provisional messages that are *not* signed */
1800 if (msg->response >= 200) {
1801 /* We are not calling process_input_message(),
1802 so we need to drop the transaction here. */
1803 struct transaction *trans = transactions_find(transport, msg);
1804 if (trans) transactions_remove(sipe_private, trans);
1806 SIPE_DEBUG_INFO_NOFORMAT("sip_transport_input: message without authentication data - ignoring");
1808 g_free(signature_input_str);
1810 g_free(rspauth);
1811 sipmsg_breakdown_free(&msgbd);
1812 } else {
1813 process_input_message(sipe_private, msg);
1816 sipmsg_free(msg);
1818 /* Redirect: old content of "transport" & "conn" is no longer valid */
1819 transport = sipe_private->transport;
1820 conn = transport->connection;
1824 static void sip_transport_connected(struct sipe_transport_connection *conn)
1826 struct sipe_core_private *sipe_private = conn->user_data;
1827 struct sip_transport *transport = sipe_private->transport;
1829 sipe_private->service_data = NULL;
1830 sipe_private->address_data = NULL;
1833 * Initial keepalive timeout during REGISTER phase
1835 * NOTE: 60 seconds is a guess. Needs more testing!
1837 transport->keepalive_timeout = 60;
1838 start_keepalive_timer(sipe_private, transport->keepalive_timeout);
1840 do_register(sipe_private, FALSE);
1843 static void resolve_next_service(struct sipe_core_private *sipe_private,
1844 const struct sip_service_data *start);
1845 static void resolve_next_address(struct sipe_core_private *sipe_private,
1846 gboolean initial);
1847 static void sip_transport_error(struct sipe_transport_connection *conn,
1848 const gchar *msg)
1850 struct sipe_core_private *sipe_private = conn->user_data;
1852 /* This failed attempt was based on a DNS SRV record */
1853 if (sipe_private->service_data) {
1854 resolve_next_service(sipe_private, NULL);
1855 /* This failed attempt was based on a DNS A record */
1856 } else if (sipe_private->address_data) {
1857 resolve_next_address(sipe_private, FALSE);
1858 } else {
1859 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1860 SIPE_CONNECTION_ERROR_NETWORK,
1861 msg);
1865 /* server_name must be g_alloc()'ed */
1866 static void sipe_server_register(struct sipe_core_private *sipe_private,
1867 guint type,
1868 gchar *server_name,
1869 guint server_port)
1871 sipe_connect_setup setup = {
1872 type,
1873 server_name,
1874 (server_port != 0) ? server_port :
1875 (type == SIPE_TRANSPORT_TLS) ? 5061 : 5060,
1876 sipe_private,
1877 sip_transport_connected,
1878 sip_transport_input,
1879 sip_transport_error
1881 struct sip_transport *transport = g_new0(struct sip_transport, 1);
1883 transport->auth_retry = TRUE;
1884 transport->server_name = server_name;
1885 transport->server_port = setup.server_port;
1886 transport->connection = sipe_backend_transport_connect(SIPE_CORE_PUBLIC,
1887 &setup);
1888 sipe_private->transport = transport;
1891 struct sip_service_data {
1892 const char *protocol;
1893 const char *transport;
1894 guint type;
1898 * Autodiscover using DNS SRV records. See RFC2782/3263
1900 * Service list for AUTO
1902 static const struct sip_service_data service_autodetect[] = {
1903 { "sipinternaltls", "tcp", SIPE_TRANSPORT_TLS }, /* for internal TLS connections */
1904 { "sipinternal", "tcp", SIPE_TRANSPORT_TCP }, /* for internal TCP connections */
1905 { "sip", "tls", SIPE_TRANSPORT_TLS }, /* for external TLS connections */
1906 { "sip", "tcp", SIPE_TRANSPORT_TCP }, /*.for external TCP connections */
1907 { NULL, NULL, 0 }
1910 /* Service list for SSL/TLS */
1911 static const struct sip_service_data service_tls[] = {
1912 { "sipinternaltls", "tcp", SIPE_TRANSPORT_TLS }, /* for internal TLS connections */
1913 { "sip", "tls", SIPE_TRANSPORT_TLS }, /* for external TLS connections */
1914 { NULL, NULL, 0 }
1917 /* Service list for TCP */
1918 static const struct sip_service_data service_tcp[] = {
1919 { "sipinternal", "tcp", SIPE_TRANSPORT_TCP }, /* for internal TCP connections */
1920 { "sip", "tcp", SIPE_TRANSPORT_TCP }, /*.for external TCP connections */
1921 { NULL, NULL, 0 }
1924 static const struct sip_service_data *services[] = {
1925 service_autodetect, /* SIPE_TRANSPORT_AUTO */
1926 service_tls, /* SIPE_TRANSPORT_TLS */
1927 service_tcp /* SIPE_TRANSPORT_TCP */
1930 struct sip_address_data {
1931 const char *prefix;
1932 guint port;
1936 * Autodiscover using DNS A records. This is an extension addded
1937 * by Microsoft. See http://support.microsoft.com/kb/2619522
1939 static const struct sip_address_data addresses[] = {
1940 { "sipinternal", 5061 },
1941 { "sipexternal", 443 },
1943 * Our implementation supports only one port per host name. If the host name
1944 * resolves OK, we abort the search and try to connect. If we would know if we
1945 * are trying to connect from "Intranet" or "Internet" then we could choose
1946 * between those two ports.
1948 * We drop port 5061 in order to cover the "Internet" case.
1950 * { "sip", 5061 },
1952 { "sip", 443 },
1953 { NULL, 0 }
1956 static void sipe_core_dns_resolved(struct sipe_core_public *sipe_public,
1957 const gchar *hostname, guint port)
1959 struct sipe_core_private *sipe_private = SIPE_CORE_PRIVATE;
1960 gboolean service = sipe_private->service_data != NULL;
1962 sipe_private->dns_query = NULL;
1964 if (hostname) {
1965 gchar *host;
1966 guint type;
1968 if (service) {
1969 host = g_strdup(hostname);
1970 type = sipe_private->service_data->type;
1971 } else {
1972 /* DNS A resolver returns an IP address */
1973 host = g_strdup_printf("%s.%s",
1974 sipe_private->address_data->prefix,
1975 sipe_private->public.sip_domain);
1976 port = sipe_private->address_data->port;
1977 type = sipe_private->transport_type;
1978 if (type == SIPE_TRANSPORT_AUTO)
1979 type = SIPE_TRANSPORT_TLS;
1982 SIPE_DEBUG_INFO("sipe_core_dns_resolved - %s hostname: %s port: %d",
1983 service ? "SRV" : "A", hostname, port);
1984 sipe_server_register(sipe_private, type, host, port);
1985 } else {
1986 if (service)
1987 resolve_next_service(SIPE_CORE_PRIVATE, NULL);
1988 else
1989 resolve_next_address(SIPE_CORE_PRIVATE, FALSE);
1993 static void resolve_next_service(struct sipe_core_private *sipe_private,
1994 const struct sip_service_data *start)
1996 if (start) {
1997 sipe_private->service_data = start;
1998 } else {
1999 sipe_private->service_data++;
2000 if (sipe_private->service_data->protocol == NULL) {
2002 /* We tried all services */
2003 sipe_private->service_data = NULL;
2005 /* Try A records list next */
2006 SIPE_DEBUG_INFO_NOFORMAT("no SRV records found; trying A records next");
2007 resolve_next_address(sipe_private, TRUE);
2008 return;
2012 /* Try to resolve next service */
2013 sipe_private->dns_query = sipe_backend_dns_query_srv(
2014 SIPE_CORE_PUBLIC,
2015 sipe_private->service_data->protocol,
2016 sipe_private->service_data->transport,
2017 sipe_private->public.sip_domain,
2018 (sipe_dns_resolved_cb) sipe_core_dns_resolved,
2019 SIPE_CORE_PUBLIC);
2022 static void resolve_next_address(struct sipe_core_private *sipe_private,
2023 gboolean initial)
2025 gchar *hostname;
2027 if (initial) {
2028 sipe_private->address_data = addresses;
2029 } else {
2030 sipe_private->address_data++;
2031 if (sipe_private->address_data->prefix == NULL) {
2032 guint type = sipe_private->transport_type;
2034 /* We tried all addresss */
2035 sipe_private->address_data = NULL;
2037 /* Try connecting to the SIP hostname directly */
2038 SIPE_DEBUG_INFO_NOFORMAT("no SRV or A records found; using SIP domain as fallback");
2039 if (type == SIPE_TRANSPORT_AUTO)
2040 type = SIPE_TRANSPORT_TLS;
2042 sipe_server_register(sipe_private, type,
2043 g_strdup(sipe_private->public.sip_domain),
2045 return;
2049 /* Try to resolve next address */
2050 hostname = g_strdup_printf("%s.%s",
2051 sipe_private->address_data->prefix,
2052 sipe_private->public.sip_domain);
2053 sipe_private->dns_query = sipe_backend_dns_query_a(
2054 SIPE_CORE_PUBLIC,
2055 hostname,
2056 sipe_private->address_data->port,
2057 (sipe_dns_resolved_cb) sipe_core_dns_resolved,
2058 SIPE_CORE_PUBLIC);
2059 g_free(hostname);
2063 * NOTE: this function can be called before sipe_core_allocate()!
2065 gboolean sipe_core_transport_sip_requires_password(guint authentication,
2066 gboolean sso)
2068 return(sip_sec_requires_password(authentication, sso));
2071 void sipe_core_transport_sip_connect(struct sipe_core_public *sipe_public,
2072 guint transport,
2073 guint authentication,
2074 const gchar *server,
2075 const gchar *port)
2077 struct sipe_core_private *sipe_private = SIPE_CORE_PRIVATE;
2079 /* backend initialization is complete */
2080 sipe_core_backend_initialized(sipe_private, authentication);
2083 * Initializing the certificate sub-system will trigger the generation
2084 * of a cryptographic key pair which takes time. If we do this after we
2085 * have connected to the server then there is a risk that we run into a
2086 * SIP connection timeout. So let's get this out of the way now...
2088 * This is currently only needed if the user has selected TLS-DSK.
2090 if (sipe_private->authentication_type == SIPE_AUTHENTICATION_TYPE_TLS_DSK)
2091 sipe_certificate_init(sipe_private);
2093 if (server) {
2094 /* Use user specified server[:port] */
2095 int port_number = 0;
2097 if (port)
2098 port_number = atoi(port);
2100 SIPE_DEBUG_INFO("sipe_core_connect: user specified SIP server %s:%d",
2101 server, port_number);
2103 sipe_server_register(sipe_private, transport,
2104 g_strdup(server), port_number);
2105 } else {
2106 /* Server auto-discovery */
2108 /* Remember user specified transport type */
2109 sipe_private->transport_type = transport;
2110 resolve_next_service(sipe_private, services[transport]);
2114 const gchar *sipe_core_transport_sip_server_name(struct sipe_core_public *sipe_public)
2116 struct sip_transport *transport = SIPE_CORE_PRIVATE->transport;
2117 return(transport ? transport->server_name : NULL);
2120 int sip_transaction_cseq(struct transaction *trans)
2122 int cseq;
2124 g_return_val_if_fail(trans && trans->key, 0);
2126 sscanf(trans->key, "<%*[a-zA-Z0-9]><%d INVITE>", &cseq);
2127 return cseq;
2131 Local Variables:
2132 mode: c
2133 c-file-style: "bsd"
2134 indent-tabs-mode: t
2135 tab-width: 8
2136 End: