purple: work around broken dbus-server.h
[siplcs.git] / src / core / sip-transport.c
blobd20acfd8fe1bbb63d2f359403de3aa1a51cbba05
1 /**
2 * @file sip-transport.c
4 * pidgin-sipe
6 * Copyright (C) 2010-2017 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
52 * - RFC2732: http://www.ietf.org/rfc/rfc2732.txt
55 #ifdef HAVE_CONFIG_H
56 #include "config.h"
57 #endif
59 #include <stdlib.h>
60 #include <string.h>
61 #include <stdio.h>
63 #include <glib.h>
65 #include "sipe-common.h"
66 #include "sipmsg.h"
67 #include "sip-sec.h"
68 #include "sip-sec-digest.h"
69 #include "sip-transport.h"
70 #include "sipe-backend.h"
71 #include "sipe-core.h"
72 #include "sipe-core-private.h"
73 #include "sipe-certificate.h"
74 #include "sipe-dialog.h"
75 #include "sipe-incoming.h"
76 #include "sipe-lync-autodiscover.h"
77 #include "sipe-nls.h"
78 #include "sipe-notify.h"
79 #include "sipe-schedule.h"
80 #include "sipe-sign.h"
81 #include "sipe-subscriptions.h"
82 #include "sipe-utils.h"
83 #include "uuid.h"
85 struct sip_auth {
86 guint type;
87 struct sip_sec_context *gssapi_context;
88 gchar *gssapi_data;
89 gchar *opaque;
90 const gchar *protocol;
91 gchar *realm;
92 gchar *sts_uri;
93 gchar *target;
94 guint version;
95 guint retries;
96 guint ntlm_num;
97 guint expires;
98 gboolean can_retry;
101 /* sip-transport.c private data */
102 struct sip_transport {
103 struct sipe_transport_connection *connection;
105 gchar *server_name;
106 guint server_port;
107 gchar *server_version;
109 gchar *epid;
110 /* local IP address of transport socket */
111 gchar *ip_address; /* RAW X.X.X.X (IPv4), X:X:...:X (IPv6) */
112 gchar *uri_address; /* URI X.X.X.X (IPv4), [X:X:...:X] (IPv6) */
113 const gchar *sdp_marker; /* SDP address marker: "IP4" or "IP6" */
115 gchar *user_agent;
117 GSList *transactions;
119 struct sip_auth registrar;
120 struct sip_auth proxy;
122 guint cseq;
123 guint register_attempt;
125 guint keepalive_timeout;
126 time_t last_message;
128 gboolean processing_input; /* whether full header received */
129 gboolean auth_incomplete; /* whether authentication not completed */
130 gboolean auth_retry; /* whether next authentication should be tried */
131 gboolean reregister_set; /* whether reregister timer set */
132 gboolean reauthenticate_set; /* whether reauthenticate timer set */
133 gboolean subscribed; /* whether subscribed to events, except buddies presence */
134 gboolean deregister; /* whether in deregistration */
137 /* Keep in sync with sipe_transport_type! */
138 static const char *transport_descriptor[] = { "", "tls", "tcp"};
139 #define TRANSPORT_DESCRIPTOR (transport_descriptor[transport->connection->type])
141 static char *genbranch()
143 return g_strdup_printf("z9hG4bK%04X%04X%04X%04X%04X",
144 rand() & 0xFFFF, rand() & 0xFFFF, rand() & 0xFFFF,
145 rand() & 0xFFFF, rand() & 0xFFFF);
148 static void sipe_auth_free(struct sip_auth *auth)
150 g_free(auth->opaque);
151 auth->opaque = NULL;
152 auth->protocol = NULL;
153 g_free(auth->realm);
154 auth->realm = NULL;
155 g_free(auth->sts_uri);
156 auth->sts_uri = NULL;
157 g_free(auth->target);
158 auth->target = NULL;
159 auth->version = 0;
160 auth->type = SIPE_AUTHENTICATION_TYPE_UNSET;
161 auth->retries = 0;
162 auth->expires = 0;
163 auth->can_retry = FALSE;
164 g_free(auth->gssapi_data);
165 auth->gssapi_data = NULL;
166 sip_sec_destroy_context(auth->gssapi_context);
167 auth->gssapi_context = NULL;
170 static void sipe_make_signature(struct sipe_core_private *sipe_private,
171 struct sipmsg *msg)
173 struct sip_transport *transport = sipe_private->transport;
174 if (sip_sec_context_is_ready(transport->registrar.gssapi_context)) {
175 struct sipmsg_breakdown msgbd;
176 gchar *signature_input_str;
177 msgbd.msg = msg;
178 sipmsg_breakdown_parse(&msgbd, transport->registrar.realm, transport->registrar.target,
179 transport->registrar.protocol);
180 msgbd.rand = g_strdup_printf("%08x", g_random_int());
181 transport->registrar.ntlm_num++;
182 msgbd.num = g_strdup_printf("%d", transport->registrar.ntlm_num);
183 signature_input_str = sipmsg_breakdown_get_string(transport->registrar.version, &msgbd);
184 if (signature_input_str != NULL) {
185 char *signature_hex = sip_sec_make_signature(transport->registrar.gssapi_context, signature_input_str);
186 g_free(msg->signature);
187 msg->signature = signature_hex;
188 g_free(msg->rand);
189 msg->rand = g_strdup(msgbd.rand);
190 g_free(msg->num);
191 msg->num = g_strdup(msgbd.num);
192 g_free(signature_input_str);
194 sipmsg_breakdown_free(&msgbd);
198 static const gchar *const auth_type_to_protocol[] = {
199 NULL, /* SIPE_AUTHENTICATION_TYPE_UNSET */
200 NULL, /* SIPE_AUTHENTICATION_TYPE_BASIC */
201 "NTLM", /* SIPE_AUTHENTICATION_TYPE_NTLM */
202 "Kerberos", /* SIPE_AUTHENTICATION_TYPE_KERBEROS */
203 NULL, /* SIPE_AUTHENTICATION_TYPE_NEGOTIATE */
204 "TLS-DSK", /* SIPE_AUTHENTICATION_TYPE_TLS_DSK */
205 NULL, /* SIPE_AUTHENTICATION_TYPE_AUTOMATIC */
207 #define AUTH_PROTOCOLS (sizeof(auth_type_to_protocol)/sizeof(gchar *))
209 static gchar *msg_signature_to_auth(struct sip_auth *auth,
210 struct sipmsg *msg)
212 return(g_strdup_printf("%s qop=\"auth\", opaque=\"%s\", realm=\"%s\", targetname=\"%s\", crand=\"%s\", cnum=\"%s\", response=\"%s\"",
213 auth->protocol,
214 auth->opaque, auth->realm, auth->target,
215 msg->rand, msg->num, msg->signature));
218 static gboolean auth_can_retry(struct sip_transport *transport,
219 const struct sip_auth *auth)
221 /* NTLM is the scheme with lowest priority - don't retry */
222 gboolean retry =
223 auth->can_retry &&
224 (auth->type != SIPE_AUTHENTICATION_TYPE_NTLM);
225 if (retry)
226 transport->auth_retry = TRUE;
227 return(retry);
230 static void initialize_auth_retry(struct sipe_core_private *sipe_private,
231 struct sip_auth *auth)
233 struct sip_transport *transport = sipe_private->transport;
235 if (auth_can_retry(transport, auth)) {
236 if (auth->gssapi_context) {
237 /* need to drop context for retry */
238 sip_sec_destroy_context(auth->gssapi_context);
239 auth->gssapi_context = NULL;
241 } else {
242 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
243 SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
244 _("Failed to authenticate to server"));
248 static gchar *initialize_auth_context(struct sipe_core_private *sipe_private,
249 struct sip_auth *auth,
250 struct sipmsg *msg)
252 struct sip_transport *transport = sipe_private->transport;
253 gchar *ret;
254 gchar *gssapi_data = NULL;
255 gchar *sign_str;
256 gchar *gssapi_str;
257 gchar *opaque_str;
258 gchar *version_str;
261 * If transport is de-registering when we reach this point then we
262 * are in the middle of the previous authentication context setup
263 * attempt. So we shouldn't try another attempt.
265 if (transport->deregister)
266 return NULL;
268 /* Create security context or handshake continuation? */
269 if (auth->gssapi_context) {
270 /* Perform next step in authentication handshake */
271 gboolean status = sip_sec_init_context_step(auth->gssapi_context,
272 auth->target,
273 auth->gssapi_data,
274 &gssapi_data,
275 &auth->expires);
277 /* If authentication is completed gssapi_data can be NULL */
278 if (!(status &&
279 (sip_sec_context_is_ready(auth->gssapi_context) || gssapi_data))) {
280 SIPE_DEBUG_ERROR_NOFORMAT("initialize_auth_context: security context continuation failed");
281 g_free(gssapi_data);
282 initialize_auth_retry(sipe_private, auth);
283 return NULL;
286 } else {
287 /* Create security context */
288 gpointer password = sipe_private->password;
290 /* For TLS-DSK the "password" is a certificate */
291 if (auth->type == SIPE_AUTHENTICATION_TYPE_TLS_DSK) {
292 password = sipe_certificate_tls_dsk_find(sipe_private,
293 auth->target);
295 if (!password) {
296 if (auth->sts_uri) {
297 SIPE_DEBUG_INFO("initialize_auth_context: TLS-DSK Certificate Provisioning URI %s",
298 auth->sts_uri);
299 if (!sipe_certificate_tls_dsk_generate(sipe_private,
300 auth->target,
301 auth->sts_uri)) {
302 gchar *tmp = g_strdup_printf(_("Can't request certificate from %s"),
303 auth->sts_uri);
304 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
305 SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
306 tmp);
307 g_free(tmp);
309 } else {
310 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
311 SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
312 _("No URI for certificate provisioning service provided"));
315 /* we can't authenticate the message yet */
316 transport->auth_incomplete = TRUE;
318 return(NULL);
319 } else {
320 SIPE_DEBUG_INFO("initialize_auth_context: TLS-DSK certificate for target '%s' found.",
321 auth->target);
325 auth->gssapi_context = sip_sec_create_context(auth->type,
326 SIPE_CORE_PRIVATE_FLAG_IS(SSO),
327 FALSE, /* connection-less for SIP */
328 sipe_private->authuser,
329 password);
331 if (auth->gssapi_context) {
332 sip_sec_init_context_step(auth->gssapi_context,
333 auth->target,
334 NULL,
335 &gssapi_data,
336 &(auth->expires));
339 /* if auth->gssapi_context is NULL then gssapi_data is still NULL */
340 if (!gssapi_data) {
341 SIPE_DEBUG_ERROR_NOFORMAT("initialize_auth_context: security context initialization failed");
342 initialize_auth_retry(sipe_private, auth);
343 return NULL;
347 if ((auth->version > 3) &&
348 sip_sec_context_is_ready(auth->gssapi_context)) {
349 sipe_make_signature(sipe_private, msg);
350 sign_str = g_strdup_printf(", crand=\"%s\", cnum=\"%s\", response=\"%s\"",
351 msg->rand, msg->num, msg->signature);
352 } else {
353 sign_str = g_strdup("");
356 if (gssapi_data) {
357 gssapi_str = g_strdup_printf(", gssapi-data=\"%s\"",
358 gssapi_data);
359 g_free(gssapi_data);
360 } else {
361 gssapi_str = g_strdup("");
364 opaque_str = auth->opaque ? g_strdup_printf(", opaque=\"%s\"", auth->opaque) : g_strdup("");
366 if (auth->version > 2) {
367 version_str = g_strdup_printf(", version=%d", auth->version);
368 } else {
369 version_str = g_strdup("");
372 ret = g_strdup_printf("%s qop=\"auth\"%s, realm=\"%s\", targetname=\"%s\"%s%s%s",
373 auth->protocol, opaque_str,
374 auth->realm, auth->target,
375 gssapi_str, version_str, sign_str);
376 g_free(version_str);
377 g_free(opaque_str);
378 g_free(gssapi_str);
379 g_free(sign_str);
381 return(ret);
384 static gchar *auth_header(struct sipe_core_private *sipe_private,
385 struct sip_auth *auth,
386 struct sipmsg *msg)
388 gchar *ret = NULL;
391 * If the message is already signed then we have an authentication
392 * context, i.e. the authentication handshake is complete. Generate
393 * authentication header from message signature.
395 if (msg->signature) {
396 ret = msg_signature_to_auth(auth, msg);
399 * We should reach this point only when the authentication context
400 * needs to be initialized.
402 } else {
403 ret = initialize_auth_context(sipe_private, auth, msg);
406 return(ret);
409 static void fill_auth(const gchar *hdr, struct sip_auth *auth)
411 const gchar *param;
413 /* skip authentication identifier */
414 hdr = strchr(hdr, ' ');
415 if (!hdr) {
416 SIPE_DEBUG_ERROR_NOFORMAT("fill_auth: corrupted authentication header");
417 return;
419 while (*hdr == ' ')
420 hdr++;
422 /* start of next parameter value */
423 while ((param = strchr(hdr, '=')) != NULL) {
424 const gchar *end;
426 /* parameter value type */
427 param++;
428 if (*param == '"') {
429 /* string: xyz="..."(,) */
430 end = strchr(++param, '"');
431 if (!end) {
432 SIPE_DEBUG_ERROR("fill_auth: corrupted string parameter near '%s'", hdr);
433 break;
435 } else {
436 /* number: xyz=12345(,) */
437 end = strchr(param, ',');
438 if (!end) {
439 /* last parameter */
440 end = param + strlen(param);
444 #if 0
445 SIPE_DEBUG_INFO("fill_auth: hdr '%s'", hdr);
446 SIPE_DEBUG_INFO("fill_auth: param '%s'", param);
447 SIPE_DEBUG_INFO("fill_auth: end '%s'", end);
448 #endif
450 /* parameter type */
451 if (g_str_has_prefix(hdr, "gssapi-data=\"")) {
452 g_free(auth->gssapi_data);
453 auth->gssapi_data = g_strndup(param, end - param);
454 } else if (g_str_has_prefix(hdr, "opaque=\"")) {
455 g_free(auth->opaque);
456 auth->opaque = g_strndup(param, end - param);
457 } else if (g_str_has_prefix(hdr, "realm=\"")) {
458 g_free(auth->realm);
459 auth->realm = g_strndup(param, end - param);
460 } else if (g_str_has_prefix(hdr, "sts-uri=\"")) {
461 /* Only used with SIPE_AUTHENTICATION_TYPE_TLS_DSK */
462 g_free(auth->sts_uri);
463 auth->sts_uri = g_strndup(param, end - param);
464 } else if (g_str_has_prefix(hdr, "targetname=\"")) {
465 g_free(auth->target);
466 auth->target = g_strndup(param, end - param);
467 } else if (g_str_has_prefix(hdr, "version=")) {
468 auth->version = atoi(param);
471 /* skip to next parameter */
472 while ((*end == '"') || (*end == ',') || (*end == ' '))
473 end++;
474 hdr = end;
477 return;
480 static void sign_outgoing_message(struct sipe_core_private *sipe_private,
481 struct sipmsg *msg)
483 struct sip_transport *transport = sipe_private->transport;
484 gchar *buf;
486 if (transport->registrar.type == SIPE_AUTHENTICATION_TYPE_UNSET) {
487 return;
490 sipe_make_signature(sipe_private, msg);
492 buf = auth_header(sipe_private, &transport->registrar, msg);
493 if (buf) {
494 sipmsg_add_header_now(msg, "Authorization", buf);
495 g_free(buf);
499 static const gchar *sip_transport_user_agent(struct sipe_core_private *sipe_private)
501 struct sip_transport *transport = sipe_private->transport;
503 if (!transport->user_agent) {
504 const gchar *useragent = sipe_backend_setting(SIPE_CORE_PUBLIC,
505 SIPE_SETTING_USER_AGENT);
506 if (is_empty(useragent)) {
507 /*@TODO: better approach to define _user_ OS, it's version and host architecture */
508 /* ref: lzodefs.h */
509 #if defined(__linux__) || defined(__linux) || defined(__LINUX__)
510 #define SIPE_TARGET_PLATFORM "linux"
511 #elif defined(__NetBSD__) ||defined( __OpenBSD__) || defined(__FreeBSD__)
512 #define SIPE_TARGET_PLATFORM "bsd"
513 #elif defined(__APPLE__) || defined(__MACOS__)
514 #define SIPE_TARGET_PLATFORM "macosx"
515 #elif defined(_AIX) || defined(__AIX__) || defined(__aix__)
516 #define SIPE_TARGET_PLATFORM "aix"
517 #elif defined(__solaris__) || defined(__sun)
518 #define SIPE_TARGET_PLATFORM "sun"
519 #elif defined(_WIN32)
520 #define SIPE_TARGET_PLATFORM "win"
521 #elif defined(__CYGWIN__)
522 #define SIPE_TARGET_PLATFORM "cygwin"
523 #elif defined(__hpux__)
524 #define SIPE_TARGET_PLATFORM "hpux"
525 #elif defined(__sgi__)
526 #define SIPE_TARGET_PLATFORM "irix"
527 #else
528 #define SIPE_TARGET_PLATFORM "unknown"
529 #endif
531 #if defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64)
532 #define SIPE_TARGET_ARCH "x86_64"
533 #elif defined(__386__) || defined(__i386__) || defined(__i386) || defined(_M_IX86) || defined(_M_I386)
534 #define SIPE_TARGET_ARCH "i386"
535 #elif defined(__ppc64__)
536 #define SIPE_TARGET_ARCH "ppc64"
537 #elif defined(__powerpc__) || defined(__powerpc) || defined(__ppc__) || defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PWR)
538 #define SIPE_TARGET_ARCH "ppc"
539 #elif defined(__hppa__) || defined(__hppa)
540 #define SIPE_TARGET_ARCH "hppa"
541 #elif defined(__mips__) || defined(__mips) || defined(_MIPS_ARCH) || defined(_M_MRX000)
542 #define SIPE_TARGET_ARCH "mips"
543 #elif defined(__s390__) || defined(__s390) || defined(__s390x__) || defined(__s390x)
544 #define SIPE_TARGET_ARCH "s390"
545 #elif defined(__sparc__) || defined(__sparc) || defined(__sparcv8)
546 #define SIPE_TARGET_ARCH "sparc"
547 #elif defined(__arm__)
548 #define SIPE_TARGET_ARCH "arm"
549 #else
550 #define SIPE_TARGET_ARCH "other"
551 #endif
552 gchar *backend = sipe_backend_version();
553 transport->user_agent = g_strdup_printf("%s Sipe/" PACKAGE_VERSION " (" SIPE_TARGET_PLATFORM "-" SIPE_TARGET_ARCH "; %s)",
554 backend,
555 transport->server_version ? transport->server_version : "");
556 g_free(backend);
557 } else {
558 transport->user_agent = g_strdup(useragent);
561 return(transport->user_agent);
565 * NOTE: Do *NOT* call sipe_backend_transport_message(...) directly!
567 * All SIP messages must pass through this function in order to update
568 * the timestamp for keepalive tracking.
570 static void send_sip_message(struct sip_transport *transport,
571 const gchar *string)
573 sipe_utils_message_debug("SIP", string, NULL, TRUE);
574 transport->last_message = time(NULL);
575 sipe_backend_transport_message(transport->connection, string);
578 static void start_keepalive_timer(struct sipe_core_private *sipe_private,
579 guint seconds);
580 static void keepalive_timeout(struct sipe_core_private *sipe_private,
581 SIPE_UNUSED_PARAMETER gpointer data)
583 struct sip_transport *transport = sipe_private->transport;
584 if (transport) {
585 guint since_last = time(NULL) - transport->last_message;
586 guint restart = transport->keepalive_timeout;
587 if (since_last >= restart) {
588 SIPE_DEBUG_INFO("keepalive_timeout: expired %d", restart);
589 send_sip_message(transport, "\r\n\r\n");
590 } else {
591 /* timeout not reached since last message -> reschedule */
592 restart -= since_last;
594 start_keepalive_timer(sipe_private, restart);
598 static void start_keepalive_timer(struct sipe_core_private *sipe_private,
599 guint seconds)
601 sipe_schedule_seconds(sipe_private,
602 "<+keepalive-timeout>",
603 NULL,
604 seconds,
605 keepalive_timeout,
606 NULL);
609 void sip_transport_response(struct sipe_core_private *sipe_private,
610 struct sipmsg *msg,
611 guint code,
612 const char *text,
613 const char *body)
615 gchar *name;
616 gchar *value;
617 GString *outstr = g_string_new("");
618 gchar *contact;
619 GSList *tmp;
620 static const gchar *keepers[] = { "To", "From", "Call-ID", "CSeq", "Via", "Record-Route", NULL };
622 /* Can return NULL! */
623 contact = get_contact(sipe_private);
624 if (contact) {
625 sipmsg_add_header(msg, "Contact", contact);
626 g_free(contact);
629 if (body) {
630 gchar *len = g_strdup_printf("%" G_GSIZE_FORMAT , (gsize) strlen(body));
631 sipmsg_add_header(msg, "Content-Length", len);
632 g_free(len);
633 } else {
634 sipmsg_add_header(msg, "Content-Length", "0");
637 sipmsg_add_header(msg, "User-Agent", sip_transport_user_agent(sipe_private));
639 msg->response = code;
641 sipmsg_strip_headers(msg, keepers);
642 sipmsg_merge_new_headers(msg);
643 sign_outgoing_message(sipe_private, msg);
645 g_string_append_printf(outstr, "SIP/2.0 %d %s\r\n", code, text);
646 tmp = msg->headers;
647 while (tmp) {
648 name = ((struct sipnameval*) (tmp->data))->name;
649 value = ((struct sipnameval*) (tmp->data))->value;
651 g_string_append_printf(outstr, "%s: %s\r\n", name, value);
652 tmp = g_slist_next(tmp);
654 g_string_append_printf(outstr, "\r\n%s", body ? body : "");
655 send_sip_message(sipe_private->transport, outstr->str);
656 g_string_free(outstr, TRUE);
659 static void transactions_remove(struct sipe_core_private *sipe_private,
660 struct transaction *trans)
662 struct sip_transport *transport = sipe_private->transport;
663 if (transport->transactions) {
664 transport->transactions = g_slist_remove(transport->transactions,
665 trans);
666 SIPE_DEBUG_INFO("SIP transactions count:%d after removal", g_slist_length(transport->transactions));
668 if (trans->msg) sipmsg_free(trans->msg);
669 if (trans->payload) {
670 if (trans->payload->destroy)
671 (*trans->payload->destroy)(trans->payload->data);
672 g_free(trans->payload);
674 g_free(trans->key);
675 if (trans->timeout_key) {
676 sipe_schedule_cancel(sipe_private, trans->timeout_key);
677 g_free(trans->timeout_key);
679 g_free(trans);
683 static struct transaction *transactions_find(struct sip_transport *transport,
684 struct sipmsg *msg)
686 GSList *transactions = transport->transactions;
687 const gchar *call_id = sipmsg_find_header(msg, "Call-ID");
688 const gchar *cseq = sipmsg_find_header(msg, "CSeq");
689 gchar *key;
691 if (!call_id || !cseq) {
692 SIPE_DEBUG_ERROR_NOFORMAT("transaction_find: no Call-ID or CSeq!");
693 return NULL;
696 key = g_strdup_printf("<%s><%s>", call_id, cseq);
697 while (transactions) {
698 struct transaction *trans = transactions->data;
699 if (!g_ascii_strcasecmp(trans->key, key)) {
700 g_free(key);
701 return trans;
703 transactions = transactions->next;
705 g_free(key);
707 return NULL;
710 static void transaction_timeout_cb(struct sipe_core_private *sipe_private,
711 gpointer data)
713 struct transaction *trans = data;
714 (trans->timeout_callback)(sipe_private, trans->msg, trans);
715 transactions_remove(sipe_private, trans);
718 struct transaction *sip_transport_request_timeout(struct sipe_core_private *sipe_private,
719 const gchar *method,
720 const gchar *url,
721 const gchar *to,
722 const gchar *addheaders,
723 const gchar *body,
724 struct sip_dialog *dialog,
725 TransCallback callback,
726 guint timeout,
727 TransCallback timeout_callback)
729 struct sip_transport *transport = sipe_private->transport;
730 char *buf;
731 struct sipmsg *msg;
732 gchar *ourtag = dialog && dialog->ourtag ? g_strdup(dialog->ourtag) : NULL;
733 gchar *theirtag = dialog && dialog->theirtag ? g_strdup(dialog->theirtag) : NULL;
734 gchar *theirepid = dialog && dialog->theirepid ? g_strdup(dialog->theirepid) : NULL;
735 gchar *callid = dialog && dialog->callid ? g_strdup(dialog->callid) : gencallid();
736 gchar *branch = dialog && dialog->callid ? NULL : genbranch();
737 gchar *route = g_strdup("");
738 const gchar *epid = transport->epid;
739 int cseq = dialog ? ++dialog->cseq : 1 /* as Call-Id is new in this case */;
740 struct transaction *trans = NULL;
742 if (dialog && dialog->routes)
744 GSList *iter = dialog->routes;
746 while(iter)
748 char *tmp = route;
749 route = g_strdup_printf("%sRoute: %s\r\n", route, (char *)iter->data);
750 g_free(tmp);
751 iter = g_slist_next(iter);
755 if (!ourtag && !dialog) {
756 ourtag = gentag();
759 if (sipe_strequal(method, "REGISTER")) {
760 if (sipe_private->register_callid) {
761 g_free(callid);
762 callid = g_strdup(sipe_private->register_callid);
763 } else {
764 sipe_private->register_callid = g_strdup(callid);
766 cseq = ++transport->cseq;
769 buf = g_strdup_printf("%s %s SIP/2.0\r\n"
770 "Via: SIP/2.0/%s %s:%d%s%s\r\n"
771 "From: <sip:%s>%s%s;epid=%s\r\n"
772 "To: <%s>%s%s%s%s\r\n"
773 "Max-Forwards: 70\r\n"
774 "CSeq: %d %s\r\n"
775 "User-Agent: %s\r\n"
776 "Call-ID: %s\r\n"
777 "%s%s"
778 "Content-Length: %" G_GSIZE_FORMAT "\r\n\r\n%s",
779 method,
780 dialog && dialog->request ? dialog->request : url,
781 TRANSPORT_DESCRIPTOR,
782 transport->uri_address,
783 transport->connection->client_port,
784 branch ? ";branch=" : "",
785 branch ? branch : "",
786 sipe_private->username,
787 ourtag ? ";tag=" : "",
788 ourtag ? ourtag : "",
789 epid,
791 theirtag ? ";tag=" : "",
792 theirtag ? theirtag : "",
793 theirepid ? ";epid=" : "",
794 theirepid ? theirepid : "",
795 cseq,
796 method,
797 sip_transport_user_agent(sipe_private),
798 callid,
799 route,
800 addheaders ? addheaders : "",
801 body ? (gsize) strlen(body) : 0,
802 body ? body : "");
805 //printf ("parsing msg buf:\n%s\n\n", buf);
806 msg = sipmsg_parse_msg(buf);
808 g_free(buf);
809 g_free(ourtag);
810 g_free(theirtag);
811 g_free(theirepid);
812 g_free(branch);
813 g_free(route);
815 sign_outgoing_message(sipe_private, msg);
817 /* The authentication scheme is not ready so we can't send the message.
818 This should only happen for REGISTER messages. */
819 if (!transport->auth_incomplete) {
820 buf = sipmsg_to_string(msg);
822 /* add to ongoing transactions */
823 /* ACK isn't supposed to be answered ever. So we do not keep transaction for it. */
824 if (!sipe_strequal(method, "ACK")) {
825 trans = g_new0(struct transaction, 1);
826 trans->callback = callback;
827 trans->msg = msg;
828 trans->key = g_strdup_printf("<%s><%d %s>", callid, cseq, method);
829 if (timeout_callback) {
830 trans->timeout_callback = timeout_callback;
831 trans->timeout_key = g_strdup_printf("<transaction timeout>%s", trans->key);
832 sipe_schedule_seconds(sipe_private,
833 trans->timeout_key,
834 trans,
835 timeout,
836 transaction_timeout_cb,
837 NULL);
839 transport->transactions = g_slist_append(transport->transactions,
840 trans);
841 SIPE_DEBUG_INFO("SIP transactions count:%d after addition", g_slist_length(transport->transactions));
844 send_sip_message(transport, buf);
845 g_free(buf);
848 if (!trans) sipmsg_free(msg);
849 g_free(callid);
850 return trans;
853 struct transaction *sip_transport_request(struct sipe_core_private *sipe_private,
854 const gchar *method,
855 const gchar *url,
856 const gchar *to,
857 const gchar *addheaders,
858 const gchar *body,
859 struct sip_dialog *dialog,
860 TransCallback callback)
862 return sip_transport_request_timeout(sipe_private,
863 method,
864 url,
866 addheaders,
867 body,
868 dialog,
869 callback,
871 NULL);
874 static void sip_transport_simple_request(struct sipe_core_private *sipe_private,
875 const gchar *method,
876 struct sip_dialog *dialog)
878 sip_transport_request(sipe_private,
879 method,
880 dialog->with,
881 dialog->with,
882 NULL,
883 NULL,
884 dialog,
885 NULL);
888 void sip_transport_ack(struct sipe_core_private *sipe_private,
889 struct sip_dialog *dialog)
891 sip_transport_simple_request(sipe_private, "ACK", dialog);
894 void sip_transport_bye(struct sipe_core_private *sipe_private,
895 struct sip_dialog *dialog)
897 sip_transport_simple_request(sipe_private, "BYE", dialog);
900 struct transaction *sip_transport_info(struct sipe_core_private *sipe_private,
901 const gchar *addheaders,
902 const gchar *body,
903 struct sip_dialog *dialog,
904 TransCallback callback)
906 return sip_transport_request(sipe_private,
907 "INFO",
908 dialog->with,
909 dialog->with,
910 addheaders,
911 body,
912 dialog,
913 callback);
916 struct transaction *sip_transport_invite(struct sipe_core_private *sipe_private,
917 const gchar *addheaders,
918 const gchar *body,
919 struct sip_dialog *dialog,
920 TransCallback callback)
922 return sip_transport_request(sipe_private,
923 "INVITE",
924 dialog->with,
925 dialog->with,
926 addheaders,
927 body,
928 dialog,
929 callback);
932 struct transaction *sip_transport_service(struct sipe_core_private *sipe_private,
933 const gchar *uri,
934 const gchar *addheaders,
935 const gchar *body,
936 TransCallback callback)
938 return sip_transport_request(sipe_private,
939 "SERVICE",
940 uri,
941 uri,
942 addheaders,
943 body,
944 NULL,
945 callback);
948 void sip_transport_subscribe(struct sipe_core_private *sipe_private,
949 const gchar *uri,
950 const gchar *addheaders,
951 const gchar *body,
952 struct sip_dialog *dialog,
953 TransCallback callback)
955 sip_transport_request(sipe_private,
956 "SUBSCRIBE",
957 uri,
958 uri,
959 addheaders,
960 body,
961 dialog,
962 callback);
965 void sip_transport_update(struct sipe_core_private *sipe_private,
966 struct sip_dialog *dialog,
967 TransCallback callback)
969 sip_transport_request(sipe_private,
970 "UPDATE",
971 dialog->with,
972 dialog->with,
973 NULL,
974 NULL,
975 dialog,
976 callback);
979 static const gchar *get_auth_header(struct sipe_core_private *sipe_private,
980 guint type,
981 struct sipmsg *msg)
983 struct sip_auth *auth = &sipe_private->transport->registrar;
985 auth->type = type;
986 auth->protocol = auth_type_to_protocol[auth->type];
988 return(sipmsg_find_auth_header(msg, auth->protocol));
991 static void do_register(struct sipe_core_private *sipe_private,
992 gboolean deregister);
994 static void do_reauthenticate_cb(struct sipe_core_private *sipe_private,
995 SIPE_UNUSED_PARAMETER gpointer unused)
997 struct sip_transport *transport = sipe_private->transport;
999 /* register again when security token expires */
1000 /* we have to start a new authentication as the security token
1001 * is almost expired by sending a not signed REGISTER message */
1002 SIPE_LOG_INFO_NOFORMAT("do_reauthenticate_cb: do a full reauthentication");
1003 sipe_auth_free(&transport->registrar);
1004 sipe_auth_free(&transport->proxy);
1005 sipe_schedule_cancel(sipe_private, "<registration>");
1006 transport->auth_retry = TRUE;
1007 transport->reregister_set = FALSE;
1008 transport->register_attempt = 0;
1009 do_register(sipe_private, FALSE);
1010 transport->reauthenticate_set = FALSE;
1013 static void sip_transport_default_contact(struct sipe_core_private *sipe_private)
1015 struct sip_transport *transport = sipe_private->transport;
1016 sipe_private->contact = g_strdup_printf("<sip:%s:%d;maddr=%s;transport=%s>;proxy=replace",
1017 sipe_private->username,
1018 transport->connection->client_port,
1019 transport->uri_address,
1020 TRANSPORT_DESCRIPTOR);
1023 static void do_register_cb(struct sipe_core_private *sipe_private,
1024 SIPE_UNUSED_PARAMETER void *unused)
1026 do_register(sipe_private, FALSE);
1029 static void sip_transport_set_reregister(struct sipe_core_private *sipe_private,
1030 int expires)
1032 sipe_schedule_seconds(sipe_private,
1033 "<registration>",
1034 NULL,
1035 expires,
1036 do_register_cb,
1037 NULL);
1040 static void sipe_server_register(struct sipe_core_private *sipe_private,
1041 guint type,
1042 gchar *server_name,
1043 guint server_port);
1045 static gboolean process_register_response(struct sipe_core_private *sipe_private,
1046 struct sipmsg *msg,
1047 SIPE_UNUSED_PARAMETER struct transaction *trans)
1049 struct sip_transport *transport = sipe_private->transport;
1050 const gchar *expires_header;
1051 int expires, i;
1052 GSList *hdr = msg->headers;
1053 struct sipnameval *elem;
1055 expires_header = sipmsg_find_header(msg, "Expires");
1056 expires = expires_header != NULL ? strtol(expires_header, NULL, 10) : 0;
1057 SIPE_DEBUG_INFO("process_register_response: got response to REGISTER; expires = %d", expires);
1059 switch (msg->response) {
1060 case 200:
1061 if (expires) {
1062 const gchar *contact_hdr;
1063 const gchar *auth_hdr;
1064 gchar *gruu = NULL;
1065 gchar *uuid;
1066 gchar *timeout;
1067 const gchar *server_hdr = sipmsg_find_header(msg, "Server");
1069 if (!transport->reregister_set) {
1070 /* Schedule re-register 30 seconds before expiration */
1071 if (expires > 30)
1072 expires -= 30;
1073 sip_transport_set_reregister(sipe_private,
1074 expires);
1075 transport->reregister_set = TRUE;
1078 if (server_hdr && !transport->server_version) {
1079 transport->server_version = g_strdup(server_hdr);
1080 g_free(transport->user_agent);
1081 transport->user_agent = NULL;
1084 auth_hdr = sipmsg_find_auth_header(msg,
1085 transport->registrar.protocol);
1086 if (auth_hdr) {
1087 SIPE_DEBUG_INFO("process_register_response: Auth header: %s", auth_hdr);
1088 fill_auth(auth_hdr, &transport->registrar);
1091 if (!transport->reauthenticate_set) {
1092 /* [MS-SIPAE] Section 3.2.2 Timers
1094 * When the ... authentication handshake completes
1095 * and the SA enters the "established" state, the
1096 * SIP protocol client MUST start an SA expiration
1097 * timer.
1098 * ...
1099 * The expiration timer value is the lesser of
1101 * - Kerberos: the service ticket expiry time
1102 * - TLS-DSK: the certificate expiration time
1104 * and eight hours, further reduced by some buffer
1105 * time.
1106 * ...
1107 * The protocol client MUST choose a sufficient
1108 * buffer time to allow for the ... authentication
1109 * handshake that reestablishes the SA to complete
1110 * ... This value SHOULD be five (5) minutes or
1111 * longer.
1113 guint reauth_timeout = transport->registrar.expires;
1115 SIPE_LOG_INFO_NOFORMAT("process_register_response: authentication handshake completed successfully");
1117 if ((reauth_timeout == 0) ||
1118 (reauth_timeout > 8 * 60 * 60))
1119 reauth_timeout = 8 * 60 * 60;
1120 if (reauth_timeout > 5 * 60)
1121 reauth_timeout -= 5 * 60;
1123 sipe_schedule_seconds(sipe_private,
1124 "<+reauthentication>",
1125 NULL,
1126 reauth_timeout,
1127 do_reauthenticate_cb,
1128 NULL);
1129 transport->reauthenticate_set = TRUE;
1132 uuid = get_uuid(sipe_private);
1134 // There can be multiple Contact headers (one per location where the user is logged in) so
1135 // make sure to only get the one for this uuid
1136 for (i = 0; (contact_hdr = sipmsg_find_header_instance (msg, "Contact", i)); i++) {
1137 gchar * valid_contact = sipmsg_find_part_of_header (contact_hdr, uuid, NULL, NULL);
1138 if (valid_contact) {
1139 gruu = sipmsg_find_part_of_header(contact_hdr, "gruu=\"", "\"", NULL);
1140 //SIPE_DEBUG_INFO("process_register_response: got gruu %s from contact hdr w/ right uuid: %s", gruu, contact_hdr);
1141 g_free(valid_contact);
1142 break;
1143 } else {
1144 //SIPE_DEBUG_INFO("process_register_response: ignoring contact hdr b/c not right uuid: %s", contact_hdr);
1147 g_free(uuid);
1149 g_free(sipe_private->contact);
1150 if(gruu) {
1151 sipe_private->contact = g_strdup_printf("<%s>", gruu);
1152 g_free(gruu);
1153 } else {
1154 //SIPE_DEBUG_INFO_NOFORMAT("process_register_response: didn't find gruu in a Contact hdr");
1155 sip_transport_default_contact(sipe_private);
1157 SIPE_CORE_PRIVATE_FLAG_UNSET(OCS2007);
1158 SIPE_CORE_PRIVATE_FLAG_UNSET(REMOTE_USER);
1159 SIPE_CORE_PRIVATE_FLAG_UNSET(BATCHED_SUPPORT);
1160 SIPE_CORE_PRIVATE_FLAG_UNSET(SFB);
1162 while(hdr)
1164 elem = hdr->data;
1165 if (sipe_strcase_equal(elem->name, "Supported")) {
1166 if (sipe_strcase_equal(elem->value, "msrtc-event-categories")) {
1167 /* We interpret this as OCS2007+ indicator */
1168 SIPE_CORE_PRIVATE_FLAG_SET(OCS2007);
1169 SIPE_LOG_INFO("process_register_response: Supported: %s (indicates OCS2007+)", elem->value);
1171 if (sipe_strcase_equal(elem->value, "adhoclist")) {
1172 SIPE_CORE_PRIVATE_FLAG_SET(BATCHED_SUPPORT);
1173 SIPE_DEBUG_INFO("process_register_response: Supported: %s", elem->value);
1175 } else if (sipe_strcase_equal(elem->name, "Allow-Events")){
1176 gchar **caps = g_strsplit(elem->value,",",0);
1177 i = 0;
1178 while (caps[i]) {
1179 sipe_private->allowed_events = g_slist_append(sipe_private->allowed_events, g_strdup(caps[i]));
1180 SIPE_DEBUG_INFO("process_register_response: Allow-Events: %s", caps[i]);
1181 i++;
1183 g_strfreev(caps);
1184 } else if (sipe_strcase_equal(elem->name, "ms-user-logon-data")) {
1185 if (sipe_strcase_equal(elem->value, "RemoteUser")) {
1186 SIPE_CORE_PRIVATE_FLAG_SET(REMOTE_USER);
1187 SIPE_DEBUG_INFO_NOFORMAT("process_register_response: ms-user-logon-data: RemoteUser (connected "
1188 "via Edge Server)");
1190 } else if (sipe_strcase_equal(elem->name, "Server")) {
1191 /* Server string has format like 'RTC/6.0'.
1192 * We want to check the first digit. */
1193 gchar **parts = g_strsplit_set(elem->value, "/.", 3);
1194 if (g_strv_length(parts) > 1) {
1195 guint version = atoi(parts[1]);
1196 if (version >= 6) {
1197 SIPE_CORE_PRIVATE_FLAG_SET(SFB);
1198 SIPE_LOG_INFO("process_register_response: server version is %d >= 6 (indicates Skype for Business+)", version);
1201 g_strfreev(parts);
1203 hdr = g_slist_next(hdr);
1206 sipe_backend_connection_completed(SIPE_CORE_PUBLIC);
1208 /* rejoin open chats to be able to use them by continue to send messages */
1209 sipe_backend_chat_rejoin_all(SIPE_CORE_PUBLIC);
1211 /* subscriptions, done only once */
1212 if (!transport->subscribed) {
1213 sipe_subscription_self_events(sipe_private);
1214 transport->subscribed = TRUE;
1217 timeout = sipmsg_find_part_of_header(sipmsg_find_header(msg, "ms-keep-alive"),
1218 "timeout=", ";", NULL);
1219 if (timeout != NULL) {
1220 sscanf(timeout, "%u", &transport->keepalive_timeout);
1221 SIPE_DEBUG_INFO("process_register_response: server determined keep alive timeout is %u seconds",
1222 transport->keepalive_timeout);
1223 g_free(timeout);
1226 SIPE_DEBUG_INFO("process_register_response: got 200, removing CSeq: %d", transport->cseq);
1228 break;
1229 case 301:
1231 gchar *redirect = parse_from(sipmsg_find_header(msg, "Contact"));
1233 SIPE_LOG_INFO_NOFORMAT("process_register_response: authentication handshake completed successfully (with redirect)");
1235 if (redirect && (g_ascii_strncasecmp("sip:", redirect, 4) == 0)) {
1236 gchar **parts = g_strsplit(redirect + 4, ";", 0);
1237 gchar **tmp;
1238 gchar *hostname;
1239 int port = 0;
1240 guint transport_type = SIPE_TRANSPORT_TLS;
1241 int i = 1;
1243 tmp = g_strsplit(parts[0], ":", 0);
1244 hostname = g_strdup(tmp[0]);
1245 if (tmp[1]) port = strtoul(tmp[1], NULL, 10);
1246 g_strfreev(tmp);
1248 while (parts[i]) {
1249 tmp = g_strsplit(parts[i], "=", 0);
1250 if (tmp[1]) {
1251 if (g_ascii_strcasecmp("transport", tmp[0]) == 0) {
1252 if (g_ascii_strcasecmp("tcp", tmp[1]) == 0) {
1253 transport_type = SIPE_TRANSPORT_TCP;
1257 g_strfreev(tmp);
1258 i++;
1260 g_strfreev(parts);
1262 /* Close old connection */
1263 sipe_core_connection_cleanup(sipe_private);
1264 /* transport and sipe_private->transport are invalid after this */
1266 /* Create new connection */
1267 sipe_server_register(sipe_private, transport_type, hostname, port);
1268 /* sipe_private->transport has a new value */
1269 SIPE_DEBUG_INFO("process_register_response: redirected to host %s port %d transport %d",
1270 hostname, port, transport_type);
1272 g_free(redirect);
1274 break;
1275 case 401:
1277 const char *auth_hdr = NULL;
1279 SIPE_DEBUG_INFO("process_register_response: REGISTER retries %d", transport->registrar.retries);
1281 if (transport->reauthenticate_set) {
1282 SIPE_DEBUG_ERROR_NOFORMAT("process_register_response: RE-REGISTER rejected, triggering re-authentication");
1283 do_reauthenticate_cb(sipe_private, NULL);
1284 return TRUE;
1287 if (sip_sec_context_is_ready(transport->registrar.gssapi_context)) {
1288 struct sip_auth *auth = &transport->registrar;
1290 /* NTLM is the scheme with lowest priority - don't retry */
1291 if (auth_can_retry(transport, auth)) {
1292 guint failed = auth->type;
1293 SIPE_DEBUG_INFO_NOFORMAT("process_register_response: authentication handshake failed - trying next authentication scheme.");
1294 sipe_auth_free(auth);
1295 auth->type = failed;
1296 } else {
1297 SIPE_LOG_ERROR_NOFORMAT("process_register_response: authentication handshake failed - giving up.");
1298 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1299 SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
1300 _("Authentication failed"));
1301 return TRUE;
1305 if (sipe_private->authentication_type == SIPE_AUTHENTICATION_TYPE_AUTOMATIC) {
1306 struct sip_auth *auth = &transport->registrar;
1307 guint try = auth->type;
1309 while (!auth_hdr) {
1311 * Determine next authentication
1312 * scheme in priority order
1314 if (transport->auth_retry)
1315 switch (try) {
1316 case SIPE_AUTHENTICATION_TYPE_UNSET:
1317 try = SIPE_AUTHENTICATION_TYPE_TLS_DSK;
1318 break;
1320 case SIPE_AUTHENTICATION_TYPE_TLS_DSK:
1321 #if defined(HAVE_GSSAPI_GSSAPI_H) || defined(HAVE_SSPI)
1322 try = SIPE_AUTHENTICATION_TYPE_KERBEROS;
1323 break;
1325 case SIPE_AUTHENTICATION_TYPE_KERBEROS:
1326 #endif
1327 try = SIPE_AUTHENTICATION_TYPE_NTLM;
1328 break;
1330 default:
1331 try = SIPE_AUTHENTICATION_TYPE_UNSET;
1332 break;
1335 auth->can_retry = (try != SIPE_AUTHENTICATION_TYPE_UNSET);
1337 if (!auth->can_retry) {
1338 SIPE_DEBUG_INFO_NOFORMAT("process_register_response: no more authentication schemes to try");
1339 break;
1342 auth_hdr = get_auth_header(sipe_private,
1343 try,
1344 msg);
1347 transport->auth_retry = FALSE;
1349 } else
1350 auth_hdr = get_auth_header(sipe_private,
1351 sipe_private->authentication_type,
1352 msg);
1354 if (!auth_hdr) {
1355 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1356 SIPE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE,
1357 _("Incompatible authentication scheme chosen"));
1358 return TRUE;
1360 SIPE_DEBUG_INFO("process_register_response: Auth header: %s", auth_hdr);
1361 fill_auth(auth_hdr, &transport->registrar);
1362 transport->reregister_set = FALSE;
1363 transport->register_attempt = 0;
1364 do_register(sipe_private,
1365 sipe_backend_connection_is_disconnecting(SIPE_CORE_PUBLIC));
1367 break;
1368 case 403:
1370 gchar *reason;
1371 gchar *warning;
1372 sipmsg_parse_warning(msg, &reason);
1373 reason = reason ? reason : sipmsg_get_ms_diagnostics_public_reason(msg);
1374 warning = g_strdup_printf(_("You have been rejected by the server: %s"),
1375 reason ? reason : _("no reason given"));
1376 g_free(reason);
1378 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1379 SIPE_CONNECTION_ERROR_INVALID_SETTINGS,
1380 warning);
1381 g_free(warning);
1382 return TRUE;
1384 break;
1385 case 404:
1387 const gchar *diagnostics = sipmsg_find_header(msg, "ms-diagnostics");
1388 gchar *reason = sipmsg_get_ms_diagnostics_reason(msg);
1389 gchar *warning;
1390 warning = g_strdup_printf(_("Not found: %s. Please contact your Administrator"),
1391 diagnostics ? (reason ? reason : _("no reason given")) :
1392 _("SIP is either not enabled for the destination URI or it does not exist"));
1393 g_free(reason);
1395 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1396 SIPE_CONNECTION_ERROR_INVALID_USERNAME,
1397 warning);
1398 g_free(warning);
1399 return TRUE;
1401 break;
1402 case 504: /* Server time-out */
1403 /* first attempt + 5 retries */
1404 if (transport->register_attempt < 6) {
1405 SIPE_DEBUG_INFO("process_register_response: RE-REGISTER timeout on attempt %d, retrying later",
1406 transport->register_attempt);
1407 sip_transport_set_reregister(sipe_private, 60);
1408 return TRUE;
1410 /* FALLTHROUGH */
1411 case 503:
1413 gchar *reason = sipmsg_get_ms_diagnostics_reason(msg);
1414 gchar *warning;
1415 warning = g_strdup_printf(_("Service unavailable: %s"), reason ? reason : _("no reason given"));
1416 g_free(reason);
1418 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1419 SIPE_CONNECTION_ERROR_NETWORK,
1420 warning);
1421 g_free(warning);
1422 return TRUE;
1424 break;
1426 return TRUE;
1429 static gboolean register_response_timeout(struct sipe_core_private *sipe_private,
1430 SIPE_UNUSED_PARAMETER struct sipmsg *msg,
1431 SIPE_UNUSED_PARAMETER struct transaction *trans)
1433 struct sip_transport *transport = sipe_private->transport;
1434 if (transport->register_attempt < 6) {
1435 SIPE_DEBUG_INFO("register_response_timeout: no answer to attempt %d, retrying",
1436 transport->register_attempt);
1437 do_register(sipe_private, FALSE);
1438 } else {
1439 gchar *warning = g_strdup_printf(_("Service unavailable: %s"), _("no reason given"));
1440 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1441 SIPE_CONNECTION_ERROR_NETWORK,
1442 warning);
1443 g_free(warning);
1445 return TRUE;
1448 static void do_register(struct sipe_core_private *sipe_private,
1449 gboolean deregister)
1451 struct sip_transport *transport = sipe_private->transport;
1452 char *uri;
1453 char *to;
1454 char *hdr;
1455 char *uuid;
1457 if (!sipe_private->public.sip_domain) return;
1459 if (!deregister) {
1460 if (transport->reregister_set) {
1461 transport->reregister_set = FALSE;
1462 transport->register_attempt = 1;
1463 } else {
1464 transport->register_attempt++;
1468 transport->deregister = deregister;
1469 transport->auth_incomplete = FALSE;
1471 uuid = get_uuid(sipe_private);
1472 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"
1473 "Supported: gruu-10, adhoclist, msrtc-event-categories, com.microsoft.msrtc.presence\r\n"
1474 "Event: registration\r\n"
1475 "Allow-Events: presence\r\n"
1476 "ms-keep-alive: UAC;hop-hop=yes\r\n"
1477 "%s",
1478 transport->uri_address,
1479 transport->connection->client_port,
1480 TRANSPORT_DESCRIPTOR,
1481 uuid,
1482 deregister ? "Expires: 0\r\n" : "");
1483 g_free(uuid);
1485 uri = sip_uri_from_name(sipe_private->public.sip_domain);
1486 to = sip_uri_self(sipe_private);
1487 sip_transport_request_timeout(sipe_private,
1488 "REGISTER",
1489 uri,
1491 hdr,
1493 NULL,
1494 process_register_response,
1496 deregister ? NULL : register_response_timeout);
1497 g_free(to);
1498 g_free(uri);
1499 g_free(hdr);
1501 if (deregister) {
1502 /* Make sure that all messages are pushed to the server
1503 before the connection gets shut down */
1504 SIPE_LOG_INFO_NOFORMAT("De-register from server. Flushing outstanding messages.");
1505 sipe_backend_transport_flush(transport->connection);
1509 void sip_transport_deregister(struct sipe_core_private *sipe_private)
1511 do_register(sipe_private, TRUE);
1514 void sip_transport_disconnect(struct sipe_core_private *sipe_private)
1516 struct sip_transport *transport = sipe_private->transport;
1518 /* transport can be NULL during connection setup */
1519 if (transport) {
1520 SIPE_LOG_INFO("sip_transport_disconnect: dropping connection '%s:%u'",
1521 transport->server_name, transport->server_port);
1523 sipe_backend_transport_disconnect(transport->connection);
1525 sipe_auth_free(&transport->registrar);
1526 sipe_auth_free(&transport->proxy);
1528 g_free(transport->server_name);
1529 g_free(transport->server_version);
1530 g_free(transport->uri_address);
1531 g_free(transport->ip_address);
1532 g_free(transport->epid);
1533 g_free(transport->user_agent);
1535 while (transport->transactions)
1536 transactions_remove(sipe_private,
1537 transport->transactions->data);
1539 g_free(transport);
1542 sipe_private->transport = NULL;
1543 sipe_private->service_data = NULL;
1544 sipe_private->address_data = NULL;
1546 sipe_schedule_cancel(sipe_private, "<+keepalive-timeout>");
1548 if (sipe_private->dns_query)
1549 sipe_backend_dns_query_cancel(sipe_private->dns_query);
1553 void sip_transport_authentication_completed(struct sipe_core_private *sipe_private)
1555 do_reauthenticate_cb(sipe_private, NULL);
1558 guint sip_transport_port(struct sipe_core_private *sipe_private)
1560 return sipe_private->transport->server_port;
1563 static void process_input_message(struct sipe_core_private *sipe_private,
1564 struct sipmsg *msg)
1566 struct sip_transport *transport = sipe_private->transport;
1567 gboolean notfound = FALSE;
1568 const char *method = msg->method ? msg->method : "NOT FOUND";
1570 SIPE_DEBUG_INFO("process_input_message: msg->response(%d),msg->method(%s)",
1571 msg->response, method);
1573 if (msg->response == 0) { /* request */
1574 if (sipe_strequal(method, "MESSAGE")) {
1575 process_incoming_message(sipe_private, msg);
1576 } else if (sipe_strequal(method, "NOTIFY")) {
1577 SIPE_DEBUG_INFO_NOFORMAT("send->process_incoming_notify");
1578 process_incoming_notify(sipe_private, msg);
1579 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
1580 } else if (sipe_strequal(method, "BENOTIFY")) {
1581 SIPE_DEBUG_INFO_NOFORMAT("send->process_incoming_benotify");
1582 process_incoming_notify(sipe_private, msg);
1583 } else if (sipe_strequal(method, "INVITE")) {
1584 process_incoming_invite(sipe_private, msg);
1585 } else if (sipe_strequal(method, "REFER")) {
1586 process_incoming_refer(sipe_private, msg);
1587 } else if (sipe_strequal(method, "OPTIONS")) {
1588 process_incoming_options(sipe_private, msg);
1589 } else if (sipe_strequal(method, "INFO")) {
1590 process_incoming_info(sipe_private, msg);
1591 } else if (sipe_strequal(method, "ACK")) {
1592 /* ACK's don't need any response */
1593 } else if (sipe_strequal(method, "PRACK")) {
1594 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
1595 } else if (sipe_strequal(method, "SUBSCRIBE")) {
1596 /* LCS 2005 sends us these - just respond 200 OK */
1597 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
1598 } else if (sipe_strequal(method, "CANCEL")) {
1599 process_incoming_cancel(sipe_private, msg);
1600 } else if (sipe_strequal(method, "BYE")) {
1601 process_incoming_bye(sipe_private, msg);
1602 } else {
1603 sip_transport_response(sipe_private, msg, 501, "Not implemented", NULL);
1604 notfound = TRUE;
1607 } else { /* response */
1608 struct transaction *trans = transactions_find(transport, msg);
1609 if (trans) {
1610 if (msg->response < 200) {
1611 /* ignore provisional response */
1612 SIPE_DEBUG_INFO("process_input_message: got provisional (%d) response, ignoring", msg->response);
1614 /* Transaction not yet completed */
1615 trans = NULL;
1617 } else if (msg->response == 401) { /* Unauthorized */
1619 if (sipe_strequal(trans->msg->method, "REGISTER")) {
1620 /* Expected response during authentication handshake */
1621 transport->registrar.retries++;
1622 SIPE_DEBUG_INFO("process_input_message: RE-REGISTER CSeq: %d", transport->cseq);
1623 } else {
1624 gchar *resend;
1626 /* Are we registered? */
1627 if (transport->reregister_set) {
1628 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: 401 response to non-REGISTER message. Retrying with new authentication.");
1629 sipmsg_remove_header_now(trans->msg, "Authorization");
1630 sign_outgoing_message(sipe_private,
1631 trans->msg);
1632 } else {
1634 * We don't have a valid authentication at the moment.
1635 * Resend message unchanged. It will be rejected again
1636 * and hopefully by then we have a valid authentication.
1638 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: 401 response to non-REGISTER message. Bouncing...");
1641 /* Resend request */
1642 resend = sipmsg_to_string(trans->msg);
1643 send_sip_message(sipe_private->transport, resend);
1644 g_free(resend);
1646 /* Transaction not yet completed */
1647 trans = NULL;
1650 } else if (msg->response == 407) { /* Proxy Authentication Required */
1652 if (transport->proxy.retries++ <= 30) {
1653 const gchar *proxy_hdr = sipmsg_find_header(msg, "Proxy-Authenticate");
1655 if (proxy_hdr) {
1656 gchar *auth = NULL;
1658 if (!g_ascii_strncasecmp(proxy_hdr, "Digest", 6)) {
1659 auth = sip_sec_digest_authorization(sipe_private,
1660 proxy_hdr + 7,
1661 msg->method,
1662 msg->target);
1663 } else {
1664 guint i;
1666 transport->proxy.type = SIPE_AUTHENTICATION_TYPE_UNSET;
1667 for (i = 0; i < AUTH_PROTOCOLS; i++) {
1668 const gchar *protocol = auth_type_to_protocol[i];
1669 if (protocol &&
1670 !g_ascii_strncasecmp(proxy_hdr, protocol, strlen(protocol))) {
1671 SIPE_DEBUG_INFO("process_input_message: proxy authentication scheme '%s'", protocol);
1672 transport->proxy.type = i;
1673 transport->proxy.protocol = protocol;
1674 fill_auth(proxy_hdr, &transport->proxy);
1675 auth = auth_header(sipe_private, &transport->proxy, trans->msg);
1676 break;
1681 if (auth) {
1682 gchar *resend;
1684 /* replace old proxy authentication with new one */
1685 sipmsg_remove_header_now(trans->msg, "Proxy-Authorization");
1686 sipmsg_add_header_now(trans->msg, "Proxy-Authorization", auth);
1687 g_free(auth);
1689 /* resend request with proxy authentication */
1690 resend = sipmsg_to_string(trans->msg);
1691 send_sip_message(sipe_private->transport, resend);
1692 g_free(resend);
1694 /* Transaction not yet completed */
1695 trans = NULL;
1697 } else
1698 SIPE_DEBUG_ERROR_NOFORMAT("process_input_message: can't generate proxy authentication. Giving up.");
1699 } else
1700 SIPE_DEBUG_ERROR_NOFORMAT("process_input_message: 407 response without 'Proxy-Authenticate' header. Giving up.");
1701 } else
1702 SIPE_DEBUG_ERROR_NOFORMAT("process_input_message: too many proxy authentication retries. Giving up.");
1704 } else {
1705 transport->registrar.retries = 0;
1706 transport->proxy.retries = 0;
1709 /* Is transaction completed? */
1710 if (trans) {
1711 if (trans->callback) {
1712 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: we have a transaction callback");
1713 /* call the callback to process response */
1714 (trans->callback)(sipe_private, msg, trans);
1715 /* transport && trans no longer valid after redirect */
1719 * Redirect case: sipe_private->transport is
1720 * the new transport with empty queue
1722 if (sipe_private->transport->transactions) {
1723 SIPE_DEBUG_INFO("process_input_message: removing CSeq %d", transport->cseq);
1724 transactions_remove(sipe_private, trans);
1727 } else {
1728 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: received response to unknown transaction");
1729 notfound = TRUE;
1733 if (notfound) {
1734 SIPE_DEBUG_INFO("received a unknown sip message with method %s and response %d", method, msg->response);
1738 static void sip_transport_input(struct sipe_transport_connection *conn)
1740 struct sipe_core_private *sipe_private = conn->user_data;
1741 struct sip_transport *transport = sipe_private->transport;
1742 gchar *cur = conn->buffer;
1744 /* according to the RFC remove CRLF at the beginning */
1745 while (*cur == '\r' || *cur == '\n') {
1746 cur++;
1748 if (cur != conn->buffer)
1749 sipe_utils_shrink_buffer(conn, cur);
1751 /* Received a full Header? */
1752 transport->processing_input = TRUE;
1753 while (transport->processing_input &&
1754 ((cur = strstr(conn->buffer, "\r\n\r\n")) != NULL)) {
1755 struct sipmsg *msg;
1756 guint remainder;
1758 cur += 2;
1759 cur[0] = '\0';
1760 msg = sipmsg_parse_header(conn->buffer);
1762 cur += 2;
1763 remainder = conn->buffer_used - (cur - conn->buffer);
1764 if (msg && remainder >= (guint) msg->bodylen) {
1765 char *dummy = g_malloc(msg->bodylen + 1);
1766 memcpy(dummy, cur, msg->bodylen);
1767 dummy[msg->bodylen] = '\0';
1768 msg->body = dummy;
1769 cur += msg->bodylen;
1770 sipe_utils_message_debug("SIP",
1771 conn->buffer,
1772 msg->body,
1773 FALSE);
1774 sipe_utils_shrink_buffer(conn, cur);
1775 } else {
1776 if (msg) {
1777 SIPE_DEBUG_INFO("sipe_transport_input: body too short (%d < %d, strlen %d) - ignoring message", remainder, msg->bodylen, (int)strlen(conn->buffer));
1778 sipmsg_free(msg);
1781 /* restore header for next try */
1782 cur[-2] = '\r';
1783 return;
1786 /* Fatal header parse error? */
1787 if (msg->response == SIPMSG_RESPONSE_FATAL_ERROR) {
1788 /* can't proceed -> drop connection */
1789 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1790 SIPE_CONNECTION_ERROR_NETWORK,
1791 _("Corrupted message received"));
1792 transport->processing_input = FALSE;
1794 /* Verify the signature before processing it */
1795 } else if (sip_sec_context_is_ready(transport->registrar.gssapi_context)) {
1796 struct sipmsg_breakdown msgbd;
1797 gchar *signature_input_str;
1798 gchar *rspauth;
1799 msgbd.msg = msg;
1800 sipmsg_breakdown_parse(&msgbd, transport->registrar.realm, transport->registrar.target,
1801 transport->registrar.protocol);
1802 signature_input_str = sipmsg_breakdown_get_string(transport->registrar.version, &msgbd);
1804 rspauth = sipmsg_find_part_of_header(sipmsg_find_header(msg, "Authentication-Info"), "rspauth=\"", "\"", NULL);
1806 if (rspauth != NULL) {
1807 if (sip_sec_verify_signature(transport->registrar.gssapi_context, signature_input_str, rspauth)) {
1808 SIPE_DEBUG_INFO_NOFORMAT("sip_transport_input: signature of incoming message validated");
1809 process_input_message(sipe_private, msg);
1810 /* transport is invalid after redirect */
1811 } else {
1812 SIPE_DEBUG_INFO_NOFORMAT("sip_transport_input: signature of incoming message is invalid.");
1813 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1814 SIPE_CONNECTION_ERROR_NETWORK,
1815 _("Invalid message signature received"));
1816 transport->processing_input = FALSE;
1818 } else if ((msg->response == 401) ||
1819 sipe_strequal(msg->method, "REGISTER")) {
1820 /* a) Retry non-REGISTER requests with updated authentication */
1821 /* b) We must always process REGISTER responses */
1822 process_input_message(sipe_private, msg);
1823 } else {
1824 /* OCS sends provisional messages that are *not* signed */
1825 if (msg->response >= 200) {
1826 /* We are not calling process_input_message(),
1827 so we need to drop the transaction here. */
1828 struct transaction *trans = transactions_find(transport, msg);
1829 if (trans) transactions_remove(sipe_private, trans);
1831 SIPE_DEBUG_INFO_NOFORMAT("sip_transport_input: message without authentication data - ignoring");
1833 g_free(signature_input_str);
1835 g_free(rspauth);
1836 sipmsg_breakdown_free(&msgbd);
1837 } else {
1838 process_input_message(sipe_private, msg);
1841 sipmsg_free(msg);
1843 /* Redirect: old content of "transport" & "conn" is no longer valid */
1844 transport = sipe_private->transport;
1845 conn = transport->connection;
1849 static void sip_transport_connected(struct sipe_transport_connection *conn)
1851 struct sipe_core_private *sipe_private = conn->user_data;
1852 struct sip_transport *transport = sipe_private->transport;
1853 gchar *self_sip_uri = sip_uri_self(sipe_private);
1855 SIPE_LOG_INFO("sip_transport_connected: %s:%u",
1856 transport->server_name, transport->server_port);
1858 while (sipe_private->lync_autodiscover_servers)
1859 sipe_private->lync_autodiscover_servers =
1860 sipe_lync_autodiscover_pop(sipe_private->lync_autodiscover_servers);
1862 sipe_private->service_data = NULL;
1863 sipe_private->address_data = NULL;
1866 * Initial keepalive timeout during REGISTER phase
1868 * NOTE: 60 seconds is a guess. Needs more testing!
1870 transport->keepalive_timeout = 60;
1871 start_keepalive_timer(sipe_private, transport->keepalive_timeout);
1873 transport->ip_address = sipe_backend_transport_ip_address(conn);
1874 if (strchr(transport->ip_address, ':') != NULL)
1875 /* RFC2732: Format for Literal IPv6 Addresses in URL's */
1876 transport->uri_address = g_strdup_printf("[%s]", transport->ip_address);
1877 else
1878 transport->uri_address = g_strdup(transport->ip_address);
1879 transport->sdp_marker = sipe_utils_ip_sdp_address_marker(transport->ip_address);
1880 transport->epid = sipe_get_epid(self_sip_uri,
1881 g_get_host_name(),
1882 transport->ip_address);
1883 g_free(self_sip_uri);
1885 do_register(sipe_private, FALSE);
1888 static void resolve_next_lync(struct sipe_core_private *sipe_private);
1889 static void resolve_next_service(struct sipe_core_private *sipe_private,
1890 const struct sip_service_data *start);
1891 static void resolve_next_address(struct sipe_core_private *sipe_private,
1892 gboolean initial);
1893 static void sip_transport_error(struct sipe_transport_connection *conn,
1894 const gchar *msg)
1896 struct sipe_core_private *sipe_private = conn->user_data;
1898 /* This failed attempt was based on a Lync Autodiscover result */
1899 if (sipe_private->lync_autodiscover_servers) {
1900 resolve_next_lync(sipe_private);
1901 /* This failed attempt was based on a DNS SRV record */
1902 } else if (sipe_private->service_data) {
1903 resolve_next_service(sipe_private, NULL);
1904 /* This failed attempt was based on a DNS A record */
1905 } else if (sipe_private->address_data) {
1906 resolve_next_address(sipe_private, FALSE);
1907 } else {
1908 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1909 SIPE_CONNECTION_ERROR_NETWORK,
1910 msg);
1914 /* server_name must be g_alloc()'ed */
1915 static void sipe_server_register(struct sipe_core_private *sipe_private,
1916 guint type,
1917 gchar *server_name,
1918 guint server_port)
1920 sipe_connect_setup setup = {
1921 type,
1922 server_name,
1923 (server_port != 0) ? server_port :
1924 (type == SIPE_TRANSPORT_TLS) ? 5061 : 5060,
1925 sipe_private,
1926 sip_transport_connected,
1927 sip_transport_input,
1928 sip_transport_error
1930 struct sip_transport *transport = g_new0(struct sip_transport, 1);
1932 transport->auth_retry = TRUE;
1933 transport->server_name = server_name;
1934 transport->server_port = setup.server_port;
1935 transport->connection = sipe_backend_transport_connect(SIPE_CORE_PUBLIC,
1936 &setup);
1937 sipe_private->transport = transport;
1940 struct sip_service_data {
1941 const char *protocol;
1942 const char *transport;
1943 guint type;
1947 * Autodiscover using DNS SRV records. See RFC2782/3263
1949 * Service list for AUTO
1951 static const struct sip_service_data service_autodetect[] = {
1952 { "sipinternaltls", "tcp", SIPE_TRANSPORT_TLS }, /* for internal TLS connections */
1953 { "sipinternal", "tcp", SIPE_TRANSPORT_TCP }, /* for internal TCP connections */
1954 { "sip", "tls", SIPE_TRANSPORT_TLS }, /* for external TLS connections */
1955 { "sip", "tcp", SIPE_TRANSPORT_TCP }, /*.for external TCP connections */
1956 { NULL, NULL, 0 }
1959 /* Service list for SSL/TLS */
1960 static const struct sip_service_data service_tls[] = {
1961 { "sipinternaltls", "tcp", SIPE_TRANSPORT_TLS }, /* for internal TLS connections */
1962 { "sip", "tls", SIPE_TRANSPORT_TLS }, /* for external TLS connections */
1963 { NULL, NULL, 0 }
1966 /* Service list for TCP */
1967 static const struct sip_service_data service_tcp[] = {
1968 { "sipinternal", "tcp", SIPE_TRANSPORT_TCP }, /* for internal TCP connections */
1969 { "sip", "tcp", SIPE_TRANSPORT_TCP }, /*.for external TCP connections */
1970 { NULL, NULL, 0 }
1973 static const struct sip_service_data *services[] = {
1974 service_autodetect, /* SIPE_TRANSPORT_AUTO */
1975 service_tls, /* SIPE_TRANSPORT_TLS */
1976 service_tcp /* SIPE_TRANSPORT_TCP */
1979 struct sip_address_data {
1980 const char *prefix;
1981 guint port;
1985 * Autodiscover using DNS A records. This is an extension addded
1986 * by Microsoft. See http://support.microsoft.com/kb/2619522
1988 static const struct sip_address_data addresses[] = {
1989 { "sipinternal", 5061 },
1990 { "sipexternal", 443 },
1992 * Our implementation supports only one port per host name. If the host name
1993 * resolves OK, we abort the search and try to connect. If we would know if we
1994 * are trying to connect from "Intranet" or "Internet" then we could choose
1995 * between those two ports.
1997 * We drop port 5061 in order to cover the "Internet" case.
1999 * { "sip", 5061 },
2001 { "sip", 443 },
2002 { NULL, 0 }
2005 static void sipe_core_dns_resolved(struct sipe_core_public *sipe_public,
2006 const gchar *hostname, guint port)
2008 struct sipe_core_private *sipe_private = SIPE_CORE_PRIVATE;
2009 gboolean service = sipe_private->service_data != NULL;
2011 sipe_private->dns_query = NULL;
2013 if (hostname) {
2014 gchar *host;
2015 guint type;
2017 if (service) {
2018 host = g_strdup(hostname);
2019 type = sipe_private->service_data->type;
2020 } else {
2021 /* DNS A resolver returns an IP address */
2022 host = g_strdup_printf("%s.%s",
2023 sipe_private->address_data->prefix,
2024 sipe_private->public.sip_domain);
2025 port = sipe_private->address_data->port;
2026 type = sipe_private->transport_type;
2027 if (type == SIPE_TRANSPORT_AUTO)
2028 type = SIPE_TRANSPORT_TLS;
2031 SIPE_DEBUG_INFO("sipe_core_dns_resolved - %s hostname: %s port: %d",
2032 service ? "SRV" : "A", hostname, port);
2033 sipe_server_register(sipe_private, type, host, port);
2034 } else {
2035 if (service)
2036 resolve_next_service(SIPE_CORE_PRIVATE, NULL);
2037 else
2038 resolve_next_address(SIPE_CORE_PRIVATE, FALSE);
2042 static void resolve_next_lync(struct sipe_core_private *sipe_private)
2044 struct sipe_lync_autodiscover_data *lync_data = sipe_private->lync_autodiscover_servers->data;
2045 guint type = sipe_private->transport_type;
2047 if (lync_data) {
2048 /* Try to connect to next server on the list */
2049 if (type == SIPE_TRANSPORT_AUTO)
2050 type = SIPE_TRANSPORT_TLS;
2052 sipe_server_register(sipe_private,
2053 type,
2054 g_strdup(lync_data->server),
2055 lync_data->port);
2057 } else {
2058 /* We tried all servers -> try DNS SRV next */
2059 SIPE_LOG_INFO_NOFORMAT("no Lync Autodiscover servers found; trying SRV records next");
2060 resolve_next_service(sipe_private, services[type]);
2063 sipe_private->lync_autodiscover_servers =
2064 sipe_lync_autodiscover_pop(sipe_private->lync_autodiscover_servers);
2067 static void resolve_next_service(struct sipe_core_private *sipe_private,
2068 const struct sip_service_data *start)
2070 if (start) {
2071 sipe_private->service_data = start;
2072 } else {
2073 sipe_private->service_data++;
2074 if (sipe_private->service_data->protocol == NULL) {
2076 /* We tried all services */
2077 sipe_private->service_data = NULL;
2079 /* Try A records list next */
2080 SIPE_LOG_INFO_NOFORMAT("no SRV records found; trying A records next");
2081 resolve_next_address(sipe_private, TRUE);
2082 return;
2086 /* Try to resolve next service */
2087 sipe_private->dns_query = sipe_backend_dns_query_srv(
2088 SIPE_CORE_PUBLIC,
2089 sipe_private->service_data->protocol,
2090 sipe_private->service_data->transport,
2091 sipe_private->public.sip_domain,
2092 (sipe_dns_resolved_cb) sipe_core_dns_resolved,
2093 SIPE_CORE_PUBLIC);
2096 static void resolve_next_address(struct sipe_core_private *sipe_private,
2097 gboolean initial)
2099 gchar *hostname;
2101 if (initial) {
2102 sipe_private->address_data = addresses;
2103 } else {
2104 sipe_private->address_data++;
2105 if (sipe_private->address_data->prefix == NULL) {
2106 guint type = sipe_private->transport_type;
2108 /* We tried all addresss */
2109 sipe_private->address_data = NULL;
2111 /* Try connecting to the SIP hostname directly */
2112 SIPE_LOG_INFO_NOFORMAT("no SRV or A records found; using SIP domain as fallback");
2113 if (type == SIPE_TRANSPORT_AUTO)
2114 type = SIPE_TRANSPORT_TLS;
2116 sipe_server_register(sipe_private, type,
2117 g_strdup(sipe_private->public.sip_domain),
2119 return;
2123 /* Try to resolve next address */
2124 hostname = g_strdup_printf("%s.%s",
2125 sipe_private->address_data->prefix,
2126 sipe_private->public.sip_domain);
2127 sipe_private->dns_query = sipe_backend_dns_query_a(
2128 SIPE_CORE_PUBLIC,
2129 hostname,
2130 sipe_private->address_data->port,
2131 (sipe_dns_resolved_cb) sipe_core_dns_resolved,
2132 SIPE_CORE_PUBLIC);
2133 g_free(hostname);
2136 static void lync_autodiscover_cb(struct sipe_core_private *sipe_private,
2137 GSList *servers,
2138 SIPE_UNUSED_PARAMETER gpointer callback_data)
2140 if (servers) {
2141 /* Lync Autodiscover succeeded */
2142 SIPE_DEBUG_INFO_NOFORMAT("lync_autodiscover_cb: got server list");
2144 sipe_private->lync_autodiscover_servers = servers;
2145 resolve_next_lync(sipe_private);
2150 * NOTE: this function can be called before sipe_core_allocate()!
2152 gboolean sipe_core_transport_sip_requires_password(guint authentication,
2153 gboolean sso)
2155 return(sip_sec_requires_password(authentication, sso));
2158 void sipe_core_transport_sip_connect(struct sipe_core_public *sipe_public,
2159 guint transport,
2160 guint authentication,
2161 const gchar *server,
2162 const gchar *port)
2164 struct sipe_core_private *sipe_private = SIPE_CORE_PRIVATE;
2166 /* backend initialization is complete */
2167 sipe_core_backend_initialized(sipe_private, authentication);
2170 * Initializing the certificate sub-system will trigger the generation
2171 * of a cryptographic key pair which takes time. If we do this after we
2172 * have connected to the server then there is a risk that we run into a
2173 * SIP connection timeout. So let's get this out of the way now...
2175 * This is currently only needed if the user has selected TLS-DSK.
2177 if (sipe_private->authentication_type == SIPE_AUTHENTICATION_TYPE_TLS_DSK)
2178 sipe_certificate_init(sipe_private);
2180 if (server) {
2181 /* Use user specified server[:port] */
2182 int port_number = 0;
2184 if (port)
2185 port_number = atoi(port);
2187 SIPE_LOG_INFO("sipe_core_connect: user specified SIP server %s:%d",
2188 server, port_number);
2190 sipe_server_register(sipe_private, transport,
2191 g_strdup(server), port_number);
2192 } else {
2193 /* Server auto-discovery */
2195 /* Remember user specified transport type */
2196 sipe_private->transport_type = transport;
2198 /* Start with Lync Autodiscover first */
2199 sipe_lync_autodiscover_start(sipe_private,
2200 lync_autodiscover_cb,
2201 NULL);
2205 const gchar *sipe_core_transport_sip_server_name(struct sipe_core_public *sipe_public)
2207 struct sip_transport *transport = SIPE_CORE_PRIVATE->transport;
2208 return(transport ? transport->server_name : NULL);
2211 int sip_transaction_cseq(struct transaction *trans)
2213 int cseq;
2215 g_return_val_if_fail(trans && trans->key, 0);
2217 sscanf(trans->key, "<%*[a-zA-Z0-9]><%d INVITE>", &cseq);
2218 return cseq;
2221 const gchar *sip_transport_epid(struct sipe_core_private *sipe_private)
2223 return(sipe_private->transport ?
2224 sipe_private->transport->epid :
2225 "0123456789ab");
2228 const gchar *sip_transport_ip_address(struct sipe_core_private *sipe_private)
2230 return(sipe_private->transport ?
2231 sipe_private->transport->ip_address :
2232 "0.0.0.0");
2235 const gchar *sip_transport_sdp_address_marker(struct sipe_core_private *sipe_private)
2237 return(sipe_private->transport ?
2238 sipe_private->transport->sdp_marker :
2239 "IP4");
2243 Local Variables:
2244 mode: c
2245 c-file-style: "bsd"
2246 indent-tabs-mode: t
2247 tab-width: 8
2248 End: