mingw: fix build break
[siplcs.git] / src / core / sip-transport.c
blobfc6f3138c1abb087eb0c4cb5aae0821baff0e892
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 "sdpmsg.h"
72 #include "sipe-core.h"
73 #include "sipe-core-private.h"
74 #include "sipe-certificate.h"
75 #include "sipe-dialog.h"
76 #include "sipe-incoming.h"
77 #include "sipe-lync-autodiscover.h"
78 #include "sipe-nls.h"
79 #include "sipe-notify.h"
80 #include "sipe-schedule.h"
81 #include "sipe-sign.h"
82 #include "sipe-subscriptions.h"
83 #include "sipe-utils.h"
84 #include "uuid.h"
86 struct sip_auth {
87 guint type;
88 struct sip_sec_context *gssapi_context;
89 gchar *gssapi_data;
90 gchar *opaque;
91 const gchar *protocol;
92 gchar *realm;
93 gchar *sts_uri;
94 gchar *target;
95 guint version;
96 guint retries;
97 guint ntlm_num;
98 guint expires;
99 gboolean can_retry;
102 /* sip-transport.c private data */
103 struct sip_transport {
104 struct sipe_transport_connection *connection;
106 gchar *server_name;
107 guint server_port;
108 gchar *server_version;
110 gchar *epid;
111 /* local IP address of transport socket */
112 gchar *ip_address; /* RAW X.X.X.X (IPv4), X:X:...:X (IPv6) */
113 gchar *uri_address; /* URI X.X.X.X (IPv4), [X:X:...:X] (IPv6) */
114 const gchar *sdp_marker; /* SDP address marker: "IP4" or "IP6" */
116 gchar *user_agent;
118 GSList *transactions;
120 struct sip_auth registrar;
121 struct sip_auth proxy;
123 guint cseq;
124 guint register_attempt;
126 guint keepalive_timeout;
127 time_t last_message;
129 gboolean processing_input; /* whether full header received */
130 gboolean auth_incomplete; /* whether authentication not completed */
131 gboolean auth_retry; /* whether next authentication should be tried */
132 gboolean reregister_set; /* whether reregister timer set */
133 gboolean reauthenticate_set; /* whether reauthenticate timer set */
134 gboolean subscribed; /* whether subscribed to events, except buddies presence */
135 gboolean deregister; /* whether in deregistration */
138 /* Keep in sync with sipe_transport_type! */
139 static const char *transport_descriptor[] = { "", "tls", "tcp"};
140 #define TRANSPORT_DESCRIPTOR (transport_descriptor[transport->connection->type])
142 static char *genbranch()
144 return g_strdup_printf("z9hG4bK%04X%04X%04X%04X%04X",
145 rand() & 0xFFFF, rand() & 0xFFFF, rand() & 0xFFFF,
146 rand() & 0xFFFF, rand() & 0xFFFF);
149 static void sipe_auth_free(struct sip_auth *auth)
151 g_free(auth->opaque);
152 auth->opaque = NULL;
153 auth->protocol = NULL;
154 g_free(auth->realm);
155 auth->realm = NULL;
156 g_free(auth->sts_uri);
157 auth->sts_uri = NULL;
158 g_free(auth->target);
159 auth->target = NULL;
160 auth->version = 0;
161 auth->type = SIPE_AUTHENTICATION_TYPE_UNSET;
162 auth->retries = 0;
163 auth->expires = 0;
164 auth->can_retry = FALSE;
165 g_free(auth->gssapi_data);
166 auth->gssapi_data = NULL;
167 sip_sec_destroy_context(auth->gssapi_context);
168 auth->gssapi_context = NULL;
171 static void sipe_make_signature(struct sipe_core_private *sipe_private,
172 struct sipmsg *msg)
174 struct sip_transport *transport = sipe_private->transport;
175 if (sip_sec_context_is_ready(transport->registrar.gssapi_context)) {
176 struct sipmsg_breakdown msgbd;
177 gchar *signature_input_str;
178 msgbd.msg = msg;
179 sipmsg_breakdown_parse(&msgbd, transport->registrar.realm, transport->registrar.target,
180 transport->registrar.protocol);
181 msgbd.rand = g_strdup_printf("%08x", g_random_int());
182 transport->registrar.ntlm_num++;
183 msgbd.num = g_strdup_printf("%d", transport->registrar.ntlm_num);
184 signature_input_str = sipmsg_breakdown_get_string(transport->registrar.version, &msgbd);
185 if (signature_input_str != NULL) {
186 char *signature_hex = sip_sec_make_signature(transport->registrar.gssapi_context, signature_input_str);
187 g_free(msg->signature);
188 msg->signature = signature_hex;
189 g_free(msg->rand);
190 msg->rand = g_strdup(msgbd.rand);
191 g_free(msg->num);
192 msg->num = g_strdup(msgbd.num);
193 g_free(signature_input_str);
195 sipmsg_breakdown_free(&msgbd);
199 static const gchar *const auth_type_to_protocol[] = {
200 NULL, /* SIPE_AUTHENTICATION_TYPE_UNSET */
201 NULL, /* SIPE_AUTHENTICATION_TYPE_BASIC */
202 "NTLM", /* SIPE_AUTHENTICATION_TYPE_NTLM */
203 "Kerberos", /* SIPE_AUTHENTICATION_TYPE_KERBEROS */
204 NULL, /* SIPE_AUTHENTICATION_TYPE_NEGOTIATE */
205 "TLS-DSK", /* SIPE_AUTHENTICATION_TYPE_TLS_DSK */
206 NULL, /* SIPE_AUTHENTICATION_TYPE_AUTOMATIC */
208 #define AUTH_PROTOCOLS (sizeof(auth_type_to_protocol)/sizeof(gchar *))
210 static gchar *msg_signature_to_auth(struct sip_auth *auth,
211 struct sipmsg *msg)
213 return(g_strdup_printf("%s qop=\"auth\", opaque=\"%s\", realm=\"%s\", targetname=\"%s\", crand=\"%s\", cnum=\"%s\", response=\"%s\"",
214 auth->protocol,
215 auth->opaque, auth->realm, auth->target,
216 msg->rand, msg->num, msg->signature));
219 static gboolean auth_can_retry(struct sip_transport *transport,
220 const struct sip_auth *auth)
222 /* NTLM is the scheme with lowest priority - don't retry */
223 gboolean retry =
224 auth->can_retry &&
225 (auth->type != SIPE_AUTHENTICATION_TYPE_NTLM);
226 if (retry)
227 transport->auth_retry = TRUE;
228 return(retry);
231 static void initialize_auth_retry(struct sipe_core_private *sipe_private,
232 struct sip_auth *auth)
234 struct sip_transport *transport = sipe_private->transport;
236 if (auth_can_retry(transport, auth)) {
237 if (auth->gssapi_context) {
238 /* need to drop context for retry */
239 sip_sec_destroy_context(auth->gssapi_context);
240 auth->gssapi_context = NULL;
242 } else {
243 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
244 SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
245 _("Failed to authenticate to server"));
249 static gchar *initialize_auth_context(struct sipe_core_private *sipe_private,
250 struct sip_auth *auth,
251 struct sipmsg *msg)
253 struct sip_transport *transport = sipe_private->transport;
254 gchar *ret;
255 gchar *gssapi_data = NULL;
256 gchar *sign_str;
257 gchar *gssapi_str;
258 gchar *opaque_str;
259 gchar *version_str;
262 * If transport is de-registering when we reach this point then we
263 * are in the middle of the previous authentication context setup
264 * attempt. So we shouldn't try another attempt.
266 if (transport->deregister)
267 return NULL;
269 /* Create security context or handshake continuation? */
270 if (auth->gssapi_context) {
271 /* Perform next step in authentication handshake */
272 gboolean status = sip_sec_init_context_step(auth->gssapi_context,
273 auth->target,
274 auth->gssapi_data,
275 &gssapi_data,
276 &auth->expires);
278 /* If authentication is completed gssapi_data can be NULL */
279 if (!(status &&
280 (sip_sec_context_is_ready(auth->gssapi_context) || gssapi_data))) {
281 SIPE_DEBUG_ERROR_NOFORMAT("initialize_auth_context: security context continuation failed");
282 g_free(gssapi_data);
283 initialize_auth_retry(sipe_private, auth);
284 return NULL;
287 } else {
288 /* Create security context */
289 gpointer password = sipe_private->password;
291 /* For TLS-DSK the "password" is a certificate */
292 if (auth->type == SIPE_AUTHENTICATION_TYPE_TLS_DSK) {
293 password = sipe_certificate_tls_dsk_find(sipe_private,
294 auth->target);
296 if (!password) {
297 if (auth->sts_uri) {
298 SIPE_DEBUG_INFO("initialize_auth_context: TLS-DSK Certificate Provisioning URI %s",
299 auth->sts_uri);
300 if (!sipe_certificate_tls_dsk_generate(sipe_private,
301 auth->target,
302 auth->sts_uri)) {
303 gchar *tmp = g_strdup_printf(_("Can't request certificate from %s"),
304 auth->sts_uri);
305 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
306 SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
307 tmp);
308 g_free(tmp);
310 } else {
311 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
312 SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
313 _("No URI for certificate provisioning service provided"));
316 /* we can't authenticate the message yet */
317 transport->auth_incomplete = TRUE;
319 return(NULL);
320 } else {
321 SIPE_DEBUG_INFO("initialize_auth_context: TLS-DSK certificate for target '%s' found.",
322 auth->target);
326 auth->gssapi_context = sip_sec_create_context(auth->type,
327 SIPE_CORE_PRIVATE_FLAG_IS(SSO),
328 FALSE, /* connection-less for SIP */
329 sipe_private->authuser,
330 password);
332 if (auth->gssapi_context) {
333 sip_sec_init_context_step(auth->gssapi_context,
334 auth->target,
335 NULL,
336 &gssapi_data,
337 &(auth->expires));
340 /* if auth->gssapi_context is NULL then gssapi_data is still NULL */
341 if (!gssapi_data) {
342 SIPE_DEBUG_ERROR_NOFORMAT("initialize_auth_context: security context initialization failed");
343 initialize_auth_retry(sipe_private, auth);
344 return NULL;
348 if ((auth->version > 3) &&
349 sip_sec_context_is_ready(auth->gssapi_context)) {
350 sipe_make_signature(sipe_private, msg);
351 sign_str = g_strdup_printf(", crand=\"%s\", cnum=\"%s\", response=\"%s\"",
352 msg->rand, msg->num, msg->signature);
353 } else {
354 sign_str = g_strdup("");
357 if (gssapi_data) {
358 gssapi_str = g_strdup_printf(", gssapi-data=\"%s\"",
359 gssapi_data);
360 g_free(gssapi_data);
361 } else {
362 gssapi_str = g_strdup("");
365 opaque_str = auth->opaque ? g_strdup_printf(", opaque=\"%s\"", auth->opaque) : g_strdup("");
367 if (auth->version > 2) {
368 version_str = g_strdup_printf(", version=%d", auth->version);
369 } else {
370 version_str = g_strdup("");
373 ret = g_strdup_printf("%s qop=\"auth\"%s, realm=\"%s\", targetname=\"%s\"%s%s%s",
374 auth->protocol, opaque_str,
375 auth->realm, auth->target,
376 gssapi_str, version_str, sign_str);
377 g_free(version_str);
378 g_free(opaque_str);
379 g_free(gssapi_str);
380 g_free(sign_str);
382 return(ret);
385 static gchar *auth_header(struct sipe_core_private *sipe_private,
386 struct sip_auth *auth,
387 struct sipmsg *msg)
389 gchar *ret = NULL;
392 * If the message is already signed then we have an authentication
393 * context, i.e. the authentication handshake is complete. Generate
394 * authentication header from message signature.
396 if (msg->signature) {
397 ret = msg_signature_to_auth(auth, msg);
400 * We should reach this point only when the authentication context
401 * needs to be initialized.
403 } else {
404 ret = initialize_auth_context(sipe_private, auth, msg);
407 return(ret);
410 static void fill_auth(const gchar *hdr, struct sip_auth *auth)
412 const gchar *param;
414 /* skip authentication identifier */
415 hdr = strchr(hdr, ' ');
416 if (!hdr) {
417 SIPE_DEBUG_ERROR_NOFORMAT("fill_auth: corrupted authentication header");
418 return;
420 while (*hdr == ' ')
421 hdr++;
423 /* start of next parameter value */
424 while ((param = strchr(hdr, '=')) != NULL) {
425 const gchar *end;
427 /* parameter value type */
428 param++;
429 if (*param == '"') {
430 /* string: xyz="..."(,) */
431 end = strchr(++param, '"');
432 if (!end) {
433 SIPE_DEBUG_ERROR("fill_auth: corrupted string parameter near '%s'", hdr);
434 break;
436 } else {
437 /* number: xyz=12345(,) */
438 end = strchr(param, ',');
439 if (!end) {
440 /* last parameter */
441 end = param + strlen(param);
445 #if 0
446 SIPE_DEBUG_INFO("fill_auth: hdr '%s'", hdr);
447 SIPE_DEBUG_INFO("fill_auth: param '%s'", param);
448 SIPE_DEBUG_INFO("fill_auth: end '%s'", end);
449 #endif
451 /* parameter type */
452 if (g_str_has_prefix(hdr, "gssapi-data=\"")) {
453 g_free(auth->gssapi_data);
454 auth->gssapi_data = g_strndup(param, end - param);
455 } else if (g_str_has_prefix(hdr, "opaque=\"")) {
456 g_free(auth->opaque);
457 auth->opaque = g_strndup(param, end - param);
458 } else if (g_str_has_prefix(hdr, "realm=\"")) {
459 g_free(auth->realm);
460 auth->realm = g_strndup(param, end - param);
461 } else if (g_str_has_prefix(hdr, "sts-uri=\"")) {
462 /* Only used with SIPE_AUTHENTICATION_TYPE_TLS_DSK */
463 g_free(auth->sts_uri);
464 auth->sts_uri = g_strndup(param, end - param);
465 } else if (g_str_has_prefix(hdr, "targetname=\"")) {
466 g_free(auth->target);
467 auth->target = g_strndup(param, end - param);
468 } else if (g_str_has_prefix(hdr, "version=")) {
469 auth->version = atoi(param);
472 /* skip to next parameter */
473 while ((*end == '"') || (*end == ',') || (*end == ' '))
474 end++;
475 hdr = end;
478 return;
481 static void sign_outgoing_message(struct sipe_core_private *sipe_private,
482 struct sipmsg *msg)
484 struct sip_transport *transport = sipe_private->transport;
485 gchar *buf;
487 if (transport->registrar.type == SIPE_AUTHENTICATION_TYPE_UNSET) {
488 return;
491 sipe_make_signature(sipe_private, msg);
493 buf = auth_header(sipe_private, &transport->registrar, msg);
494 if (buf) {
495 sipmsg_add_header_now(msg, "Authorization", buf);
496 g_free(buf);
500 static const gchar *sip_transport_user_agent(struct sipe_core_private *sipe_private)
502 struct sip_transport *transport = sipe_private->transport;
504 if (!transport->user_agent) {
505 const gchar *useragent = sipe_backend_setting(SIPE_CORE_PUBLIC,
506 SIPE_SETTING_USER_AGENT);
507 if (is_empty(useragent)) {
508 /*@TODO: better approach to define _user_ OS, it's version and host architecture */
509 /* ref: lzodefs.h */
510 #if defined(__linux__) || defined(__linux) || defined(__LINUX__)
511 #define SIPE_TARGET_PLATFORM "linux"
512 #elif defined(__NetBSD__) ||defined( __OpenBSD__) || defined(__FreeBSD__)
513 #define SIPE_TARGET_PLATFORM "bsd"
514 #elif defined(__APPLE__) || defined(__MACOS__)
515 #define SIPE_TARGET_PLATFORM "macosx"
516 #elif defined(_AIX) || defined(__AIX__) || defined(__aix__)
517 #define SIPE_TARGET_PLATFORM "aix"
518 #elif defined(__solaris__) || defined(__sun)
519 #define SIPE_TARGET_PLATFORM "sun"
520 #elif defined(_WIN32)
521 #define SIPE_TARGET_PLATFORM "win"
522 #elif defined(__CYGWIN__)
523 #define SIPE_TARGET_PLATFORM "cygwin"
524 #elif defined(__hpux__)
525 #define SIPE_TARGET_PLATFORM "hpux"
526 #elif defined(__sgi__)
527 #define SIPE_TARGET_PLATFORM "irix"
528 #else
529 #define SIPE_TARGET_PLATFORM "unknown"
530 #endif
532 #if defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64)
533 #define SIPE_TARGET_ARCH "x86_64"
534 #elif defined(__386__) || defined(__i386__) || defined(__i386) || defined(_M_IX86) || defined(_M_I386)
535 #define SIPE_TARGET_ARCH "i386"
536 #elif defined(__ppc64__)
537 #define SIPE_TARGET_ARCH "ppc64"
538 #elif defined(__powerpc__) || defined(__powerpc) || defined(__ppc__) || defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PWR)
539 #define SIPE_TARGET_ARCH "ppc"
540 #elif defined(__hppa__) || defined(__hppa)
541 #define SIPE_TARGET_ARCH "hppa"
542 #elif defined(__mips__) || defined(__mips) || defined(_MIPS_ARCH) || defined(_M_MRX000)
543 #define SIPE_TARGET_ARCH "mips"
544 #elif defined(__s390__) || defined(__s390) || defined(__s390x__) || defined(__s390x)
545 #define SIPE_TARGET_ARCH "s390"
546 #elif defined(__sparc__) || defined(__sparc) || defined(__sparcv8)
547 #define SIPE_TARGET_ARCH "sparc"
548 #elif defined(__arm__)
549 #define SIPE_TARGET_ARCH "arm"
550 #else
551 #define SIPE_TARGET_ARCH "other"
552 #endif
553 gchar *backend = sipe_backend_version();
554 transport->user_agent = g_strdup_printf("%s Sipe/" PACKAGE_VERSION " (" SIPE_TARGET_PLATFORM "-" SIPE_TARGET_ARCH "; %s)",
555 backend,
556 transport->server_version ? transport->server_version : "");
557 g_free(backend);
558 } else {
559 transport->user_agent = g_strdup(useragent);
562 return(transport->user_agent);
566 * NOTE: Do *NOT* call sipe_backend_transport_message(...) directly!
568 * All SIP messages must pass through this function in order to update
569 * the timestamp for keepalive tracking.
571 static void send_sip_message(struct sip_transport *transport,
572 const gchar *string)
574 sipe_utils_message_debug("SIP", string, NULL, TRUE);
575 transport->last_message = time(NULL);
576 sipe_backend_transport_message(transport->connection, string);
579 static void start_keepalive_timer(struct sipe_core_private *sipe_private,
580 guint seconds);
581 static void keepalive_timeout(struct sipe_core_private *sipe_private,
582 SIPE_UNUSED_PARAMETER gpointer data)
584 struct sip_transport *transport = sipe_private->transport;
585 if (transport) {
586 guint since_last = time(NULL) - transport->last_message;
587 guint restart = transport->keepalive_timeout;
588 if (since_last >= restart) {
589 SIPE_DEBUG_INFO("keepalive_timeout: expired %d", restart);
590 send_sip_message(transport, "\r\n\r\n");
591 } else {
592 /* timeout not reached since last message -> reschedule */
593 restart -= since_last;
595 start_keepalive_timer(sipe_private, restart);
599 static void start_keepalive_timer(struct sipe_core_private *sipe_private,
600 guint seconds)
602 sipe_schedule_seconds(sipe_private,
603 "<+keepalive-timeout>",
604 NULL,
605 seconds,
606 keepalive_timeout,
607 NULL);
610 void sip_transport_response(struct sipe_core_private *sipe_private,
611 struct sipmsg *msg,
612 guint code,
613 const char *text,
614 const char *body)
616 gchar *name;
617 gchar *value;
618 GString *outstr = g_string_new("");
619 gchar *contact;
620 GSList *tmp;
621 static const gchar *keepers[] = { "To", "From", "Call-ID", "CSeq", "Via", "Record-Route", NULL };
623 /* Can return NULL! */
624 contact = get_contact(sipe_private);
625 if (contact) {
626 sipmsg_add_header(msg, "Contact", contact);
627 g_free(contact);
630 if (body) {
631 gchar *len = g_strdup_printf("%" G_GSIZE_FORMAT , (gsize) strlen(body));
632 sipmsg_add_header(msg, "Content-Length", len);
633 g_free(len);
634 } else {
635 sipmsg_add_header(msg, "Content-Length", "0");
638 sipmsg_add_header(msg, "User-Agent", sip_transport_user_agent(sipe_private));
640 msg->response = code;
642 sipmsg_strip_headers(msg, keepers);
643 sipmsg_merge_new_headers(msg);
644 sign_outgoing_message(sipe_private, msg);
646 g_string_append_printf(outstr, "SIP/2.0 %d %s\r\n", code, text);
647 tmp = msg->headers;
648 while (tmp) {
649 name = ((struct sipnameval*) (tmp->data))->name;
650 value = ((struct sipnameval*) (tmp->data))->value;
652 g_string_append_printf(outstr, "%s: %s\r\n", name, value);
653 tmp = g_slist_next(tmp);
655 g_string_append_printf(outstr, "\r\n%s", body ? body : "");
656 send_sip_message(sipe_private->transport, outstr->str);
657 g_string_free(outstr, TRUE);
660 static void transactions_remove(struct sipe_core_private *sipe_private,
661 struct transaction *trans)
663 struct sip_transport *transport = sipe_private->transport;
664 if (transport->transactions) {
665 transport->transactions = g_slist_remove(transport->transactions,
666 trans);
667 SIPE_DEBUG_INFO("SIP transactions count:%d after removal", g_slist_length(transport->transactions));
669 if (trans->msg) sipmsg_free(trans->msg);
670 if (trans->payload) {
671 if (trans->payload->destroy)
672 (*trans->payload->destroy)(trans->payload->data);
673 g_free(trans->payload);
675 g_free(trans->key);
676 if (trans->timeout_key) {
677 sipe_schedule_cancel(sipe_private, trans->timeout_key);
678 g_free(trans->timeout_key);
680 g_free(trans);
684 static struct transaction *transactions_find(struct sip_transport *transport,
685 struct sipmsg *msg)
687 GSList *transactions = transport->transactions;
688 const gchar *call_id = sipmsg_find_header(msg, "Call-ID");
689 const gchar *cseq = sipmsg_find_header(msg, "CSeq");
690 gchar *key;
692 if (!call_id || !cseq) {
693 SIPE_DEBUG_ERROR_NOFORMAT("transaction_find: no Call-ID or CSeq!");
694 return NULL;
697 key = g_strdup_printf("<%s><%s>", call_id, cseq);
698 while (transactions) {
699 struct transaction *trans = transactions->data;
700 if (!g_ascii_strcasecmp(trans->key, key)) {
701 g_free(key);
702 return trans;
704 transactions = transactions->next;
706 g_free(key);
708 return NULL;
711 static void transaction_timeout_cb(struct sipe_core_private *sipe_private,
712 gpointer data)
714 struct transaction *trans = data;
715 (trans->timeout_callback)(sipe_private, trans->msg, trans);
716 transactions_remove(sipe_private, trans);
719 struct transaction *sip_transport_request_timeout(struct sipe_core_private *sipe_private,
720 const gchar *method,
721 const gchar *url,
722 const gchar *to,
723 const gchar *addheaders,
724 const gchar *body,
725 struct sip_dialog *dialog,
726 TransCallback callback,
727 guint timeout,
728 TransCallback timeout_callback)
730 struct sip_transport *transport = sipe_private->transport;
731 char *buf;
732 struct sipmsg *msg;
733 gchar *ourtag = dialog && dialog->ourtag ? g_strdup(dialog->ourtag) : NULL;
734 gchar *theirtag = dialog && dialog->theirtag ? g_strdup(dialog->theirtag) : NULL;
735 gchar *theirepid = dialog && dialog->theirepid ? g_strdup(dialog->theirepid) : NULL;
736 gchar *callid = dialog && dialog->callid ? g_strdup(dialog->callid) : gencallid();
737 gchar *branch = dialog && dialog->callid ? NULL : genbranch();
738 gchar *route = g_strdup("");
739 const gchar *epid = transport->epid;
740 int cseq = dialog ? ++dialog->cseq : 1 /* as Call-Id is new in this case */;
741 struct transaction *trans = NULL;
743 if (dialog && dialog->routes)
745 GSList *iter = dialog->routes;
747 while(iter)
749 char *tmp = route;
750 route = g_strdup_printf("%sRoute: %s\r\n", route, (char *)iter->data);
751 g_free(tmp);
752 iter = g_slist_next(iter);
756 if (!ourtag && !dialog) {
757 ourtag = gentag();
760 if (sipe_strequal(method, "REGISTER")) {
761 if (sipe_private->register_callid) {
762 g_free(callid);
763 callid = g_strdup(sipe_private->register_callid);
764 } else {
765 sipe_private->register_callid = g_strdup(callid);
767 cseq = ++transport->cseq;
770 buf = g_strdup_printf("%s %s SIP/2.0\r\n"
771 "Via: SIP/2.0/%s %s:%d%s%s\r\n"
772 "From: <sip:%s>%s%s;epid=%s\r\n"
773 "To: <%s>%s%s%s%s\r\n"
774 "Max-Forwards: 70\r\n"
775 "CSeq: %d %s\r\n"
776 "User-Agent: %s\r\n"
777 "Call-ID: %s\r\n"
778 "%s%s"
779 "Content-Length: %" G_GSIZE_FORMAT "\r\n\r\n%s",
780 method,
781 dialog && dialog->request ? dialog->request : url,
782 TRANSPORT_DESCRIPTOR,
783 transport->uri_address,
784 transport->connection->client_port,
785 branch ? ";branch=" : "",
786 branch ? branch : "",
787 sipe_private->username,
788 ourtag ? ";tag=" : "",
789 ourtag ? ourtag : "",
790 epid,
792 theirtag ? ";tag=" : "",
793 theirtag ? theirtag : "",
794 theirepid ? ";epid=" : "",
795 theirepid ? theirepid : "",
796 cseq,
797 method,
798 sip_transport_user_agent(sipe_private),
799 callid,
800 route,
801 addheaders ? addheaders : "",
802 body ? (gsize) strlen(body) : 0,
803 body ? body : "");
806 //printf ("parsing msg buf:\n%s\n\n", buf);
807 msg = sipmsg_parse_msg(buf);
809 g_free(buf);
810 g_free(ourtag);
811 g_free(theirtag);
812 g_free(theirepid);
813 g_free(branch);
814 g_free(route);
816 sign_outgoing_message(sipe_private, msg);
818 /* The authentication scheme is not ready so we can't send the message.
819 This should only happen for REGISTER messages. */
820 if (!transport->auth_incomplete) {
821 buf = sipmsg_to_string(msg);
823 /* add to ongoing transactions */
824 /* ACK isn't supposed to be answered ever. So we do not keep transaction for it. */
825 if (!sipe_strequal(method, "ACK")) {
826 trans = g_new0(struct transaction, 1);
827 trans->callback = callback;
828 trans->msg = msg;
829 trans->key = g_strdup_printf("<%s><%d %s>", callid, cseq, method);
830 if (timeout_callback) {
831 trans->timeout_callback = timeout_callback;
832 trans->timeout_key = g_strdup_printf("<transaction timeout>%s", trans->key);
833 sipe_schedule_seconds(sipe_private,
834 trans->timeout_key,
835 trans,
836 timeout,
837 transaction_timeout_cb,
838 NULL);
840 transport->transactions = g_slist_append(transport->transactions,
841 trans);
842 SIPE_DEBUG_INFO("SIP transactions count:%d after addition", g_slist_length(transport->transactions));
845 send_sip_message(transport, buf);
846 g_free(buf);
849 if (!trans) sipmsg_free(msg);
850 g_free(callid);
851 return trans;
854 struct transaction *sip_transport_request(struct sipe_core_private *sipe_private,
855 const gchar *method,
856 const gchar *url,
857 const gchar *to,
858 const gchar *addheaders,
859 const gchar *body,
860 struct sip_dialog *dialog,
861 TransCallback callback)
863 return sip_transport_request_timeout(sipe_private,
864 method,
865 url,
867 addheaders,
868 body,
869 dialog,
870 callback,
872 NULL);
875 static void sip_transport_simple_request(struct sipe_core_private *sipe_private,
876 const gchar *method,
877 struct sip_dialog *dialog)
879 sip_transport_request(sipe_private,
880 method,
881 dialog->with,
882 dialog->with,
883 NULL,
884 NULL,
885 dialog,
886 NULL);
889 void sip_transport_ack(struct sipe_core_private *sipe_private,
890 struct sip_dialog *dialog)
892 sip_transport_simple_request(sipe_private, "ACK", dialog);
895 void sip_transport_bye(struct sipe_core_private *sipe_private,
896 struct sip_dialog *dialog)
898 sip_transport_simple_request(sipe_private, "BYE", dialog);
901 struct transaction *sip_transport_info(struct sipe_core_private *sipe_private,
902 const gchar *addheaders,
903 const gchar *body,
904 struct sip_dialog *dialog,
905 TransCallback callback)
907 return sip_transport_request(sipe_private,
908 "INFO",
909 dialog->with,
910 dialog->with,
911 addheaders,
912 body,
913 dialog,
914 callback);
917 struct transaction *sip_transport_invite(struct sipe_core_private *sipe_private,
918 const gchar *addheaders,
919 const gchar *body,
920 struct sip_dialog *dialog,
921 TransCallback callback)
923 return sip_transport_request(sipe_private,
924 "INVITE",
925 dialog->with,
926 dialog->with,
927 addheaders,
928 body,
929 dialog,
930 callback);
933 struct transaction *sip_transport_service(struct sipe_core_private *sipe_private,
934 const gchar *uri,
935 const gchar *addheaders,
936 const gchar *body,
937 TransCallback callback)
939 return sip_transport_request(sipe_private,
940 "SERVICE",
941 uri,
942 uri,
943 addheaders,
944 body,
945 NULL,
946 callback);
949 void sip_transport_subscribe(struct sipe_core_private *sipe_private,
950 const gchar *uri,
951 const gchar *addheaders,
952 const gchar *body,
953 struct sip_dialog *dialog,
954 TransCallback callback)
956 sip_transport_request(sipe_private,
957 "SUBSCRIBE",
958 uri,
959 uri,
960 addheaders,
961 body,
962 dialog,
963 callback);
966 void sip_transport_update(struct sipe_core_private *sipe_private,
967 struct sip_dialog *dialog,
968 TransCallback callback)
970 sip_transport_request(sipe_private,
971 "UPDATE",
972 dialog->with,
973 dialog->with,
974 NULL,
975 NULL,
976 dialog,
977 callback);
980 static const gchar *get_auth_header(struct sipe_core_private *sipe_private,
981 guint type,
982 struct sipmsg *msg)
984 struct sip_auth *auth = &sipe_private->transport->registrar;
986 auth->type = type;
987 auth->protocol = auth_type_to_protocol[auth->type];
989 return(sipmsg_find_auth_header(msg, auth->protocol));
992 static void do_register(struct sipe_core_private *sipe_private,
993 gboolean deregister);
995 static void do_reauthenticate_cb(struct sipe_core_private *sipe_private,
996 SIPE_UNUSED_PARAMETER gpointer unused)
998 struct sip_transport *transport = sipe_private->transport;
1000 /* register again when security token expires */
1001 /* we have to start a new authentication as the security token
1002 * is almost expired by sending a not signed REGISTER message */
1003 SIPE_LOG_INFO_NOFORMAT("do_reauthenticate_cb: do a full reauthentication");
1004 sipe_auth_free(&transport->registrar);
1005 sipe_auth_free(&transport->proxy);
1006 sipe_schedule_cancel(sipe_private, "<registration>");
1007 transport->auth_retry = TRUE;
1008 transport->reregister_set = FALSE;
1009 transport->register_attempt = 0;
1010 do_register(sipe_private, FALSE);
1011 transport->reauthenticate_set = FALSE;
1014 static void sip_transport_default_contact(struct sipe_core_private *sipe_private)
1016 struct sip_transport *transport = sipe_private->transport;
1017 sipe_private->contact = g_strdup_printf("<sip:%s:%d;maddr=%s;transport=%s>;proxy=replace",
1018 sipe_private->username,
1019 transport->connection->client_port,
1020 transport->uri_address,
1021 TRANSPORT_DESCRIPTOR);
1024 static void do_register_cb(struct sipe_core_private *sipe_private,
1025 SIPE_UNUSED_PARAMETER void *unused)
1027 do_register(sipe_private, FALSE);
1030 static void sip_transport_set_reregister(struct sipe_core_private *sipe_private,
1031 int expires)
1033 sipe_schedule_seconds(sipe_private,
1034 "<registration>",
1035 NULL,
1036 expires,
1037 do_register_cb,
1038 NULL);
1041 static void sipe_server_register(struct sipe_core_private *sipe_private,
1042 guint type,
1043 gchar *server_name,
1044 guint server_port);
1046 static gboolean process_register_response(struct sipe_core_private *sipe_private,
1047 struct sipmsg *msg,
1048 SIPE_UNUSED_PARAMETER struct transaction *trans)
1050 struct sip_transport *transport = sipe_private->transport;
1051 const gchar *expires_header;
1052 int expires, i;
1053 GSList *hdr = msg->headers;
1054 struct sipnameval *elem;
1056 expires_header = sipmsg_find_header(msg, "Expires");
1057 expires = expires_header != NULL ? strtol(expires_header, NULL, 10) : 0;
1058 SIPE_DEBUG_INFO("process_register_response: got response to REGISTER; expires = %d", expires);
1060 switch (msg->response) {
1061 case 200:
1062 if (expires) {
1063 const gchar *contact_hdr;
1064 const gchar *auth_hdr;
1065 gchar *gruu = NULL;
1066 gchar *uuid;
1067 gchar *timeout;
1068 const gchar *server_hdr = sipmsg_find_header(msg, "Server");
1070 if (!transport->reregister_set) {
1071 /* Schedule re-register 30 seconds before expiration */
1072 if (expires > 30)
1073 expires -= 30;
1074 sip_transport_set_reregister(sipe_private,
1075 expires);
1076 transport->reregister_set = TRUE;
1079 if (server_hdr && !transport->server_version) {
1080 transport->server_version = g_strdup(server_hdr);
1081 g_free(transport->user_agent);
1082 transport->user_agent = NULL;
1085 auth_hdr = sipmsg_find_auth_header(msg,
1086 transport->registrar.protocol);
1087 if (auth_hdr) {
1088 SIPE_DEBUG_INFO("process_register_response: Auth header: %s", auth_hdr);
1089 fill_auth(auth_hdr, &transport->registrar);
1092 if (!transport->reauthenticate_set) {
1093 /* [MS-SIPAE] Section 3.2.2 Timers
1095 * When the ... authentication handshake completes
1096 * and the SA enters the "established" state, the
1097 * SIP protocol client MUST start an SA expiration
1098 * timer.
1099 * ...
1100 * The expiration timer value is the lesser of
1102 * - Kerberos: the service ticket expiry time
1103 * - TLS-DSK: the certificate expiration time
1105 * and eight hours, further reduced by some buffer
1106 * time.
1107 * ...
1108 * The protocol client MUST choose a sufficient
1109 * buffer time to allow for the ... authentication
1110 * handshake that reestablishes the SA to complete
1111 * ... This value SHOULD be five (5) minutes or
1112 * longer.
1114 guint reauth_timeout = transport->registrar.expires;
1116 SIPE_LOG_INFO_NOFORMAT("process_register_response: authentication handshake completed successfully");
1118 if ((reauth_timeout == 0) ||
1119 (reauth_timeout > 8 * 60 * 60))
1120 reauth_timeout = 8 * 60 * 60;
1121 if (reauth_timeout > 5 * 60)
1122 reauth_timeout -= 5 * 60;
1124 sipe_schedule_seconds(sipe_private,
1125 "<+reauthentication>",
1126 NULL,
1127 reauth_timeout,
1128 do_reauthenticate_cb,
1129 NULL);
1130 transport->reauthenticate_set = TRUE;
1133 uuid = get_uuid(sipe_private);
1135 // There can be multiple Contact headers (one per location where the user is logged in) so
1136 // make sure to only get the one for this uuid
1137 for (i = 0; (contact_hdr = sipmsg_find_header_instance (msg, "Contact", i)); i++) {
1138 gchar * valid_contact = sipmsg_find_part_of_header (contact_hdr, uuid, NULL, NULL);
1139 if (valid_contact) {
1140 gruu = sipmsg_find_part_of_header(contact_hdr, "gruu=\"", "\"", NULL);
1141 //SIPE_DEBUG_INFO("process_register_response: got gruu %s from contact hdr w/ right uuid: %s", gruu, contact_hdr);
1142 g_free(valid_contact);
1143 break;
1144 } else {
1145 //SIPE_DEBUG_INFO("process_register_response: ignoring contact hdr b/c not right uuid: %s", contact_hdr);
1148 g_free(uuid);
1150 g_free(sipe_private->contact);
1151 if(gruu) {
1152 sipe_private->contact = g_strdup_printf("<%s>", gruu);
1153 g_free(gruu);
1154 } else {
1155 //SIPE_DEBUG_INFO_NOFORMAT("process_register_response: didn't find gruu in a Contact hdr");
1156 sip_transport_default_contact(sipe_private);
1158 SIPE_CORE_PRIVATE_FLAG_UNSET(OCS2007);
1159 SIPE_CORE_PRIVATE_FLAG_UNSET(REMOTE_USER);
1160 SIPE_CORE_PRIVATE_FLAG_UNSET(BATCHED_SUPPORT);
1161 SIPE_CORE_PRIVATE_FLAG_UNSET(SFB);
1163 while(hdr)
1165 elem = hdr->data;
1166 if (sipe_strcase_equal(elem->name, "Supported")) {
1167 if (sipe_strcase_equal(elem->value, "msrtc-event-categories")) {
1168 /* We interpret this as OCS2007+ indicator */
1169 SIPE_CORE_PRIVATE_FLAG_SET(OCS2007);
1170 SIPE_LOG_INFO("process_register_response: Supported: %s (indicates OCS2007+)", elem->value);
1172 if (sipe_strcase_equal(elem->value, "adhoclist")) {
1173 SIPE_CORE_PRIVATE_FLAG_SET(BATCHED_SUPPORT);
1174 SIPE_DEBUG_INFO("process_register_response: Supported: %s", elem->value);
1176 } else if (sipe_strcase_equal(elem->name, "Allow-Events")){
1177 gchar **caps = g_strsplit(elem->value,",",0);
1178 i = 0;
1179 while (caps[i]) {
1180 sipe_private->allowed_events = g_slist_append(sipe_private->allowed_events, g_strdup(caps[i]));
1181 SIPE_DEBUG_INFO("process_register_response: Allow-Events: %s", caps[i]);
1182 i++;
1184 g_strfreev(caps);
1185 } else if (sipe_strcase_equal(elem->name, "ms-user-logon-data")) {
1186 if (sipe_strcase_equal(elem->value, "RemoteUser")) {
1187 SIPE_CORE_PRIVATE_FLAG_SET(REMOTE_USER);
1188 SIPE_DEBUG_INFO_NOFORMAT("process_register_response: ms-user-logon-data: RemoteUser (connected "
1189 "via Edge Server)");
1191 } else if (sipe_strcase_equal(elem->name, "Server")) {
1192 /* Server string has format like 'RTC/6.0'.
1193 * We want to check the first digit. */
1194 gchar **parts = g_strsplit_set(elem->value, "/.", 3);
1195 if (g_strv_length(parts) > 1) {
1196 guint version = atoi(parts[1]);
1197 if (version >= 6) {
1198 SIPE_CORE_PRIVATE_FLAG_SET(SFB);
1199 SIPE_LOG_INFO("process_register_response: server version is %d >= 6 (indicates Skype for Business+)", version);
1202 g_strfreev(parts);
1204 hdr = g_slist_next(hdr);
1207 sipe_backend_connection_completed(SIPE_CORE_PUBLIC);
1209 /* rejoin open chats to be able to use them by continue to send messages */
1210 sipe_backend_chat_rejoin_all(SIPE_CORE_PUBLIC);
1212 /* subscriptions, done only once */
1213 if (!transport->subscribed) {
1214 sipe_subscription_self_events(sipe_private);
1215 transport->subscribed = TRUE;
1218 timeout = sipmsg_find_part_of_header(sipmsg_find_header(msg, "ms-keep-alive"),
1219 "timeout=", ";", NULL);
1220 if (timeout != NULL) {
1221 sscanf(timeout, "%u", &transport->keepalive_timeout);
1222 SIPE_DEBUG_INFO("process_register_response: server determined keep alive timeout is %u seconds",
1223 transport->keepalive_timeout);
1224 g_free(timeout);
1227 SIPE_DEBUG_INFO("process_register_response: got 200, removing CSeq: %d", transport->cseq);
1229 break;
1230 case 301:
1232 gchar *redirect = parse_from(sipmsg_find_header(msg, "Contact"));
1234 SIPE_LOG_INFO_NOFORMAT("process_register_response: authentication handshake completed successfully (with redirect)");
1236 if (redirect && (g_ascii_strncasecmp("sip:", redirect, 4) == 0)) {
1237 gchar **parts = g_strsplit(redirect + 4, ";", 0);
1238 gchar **tmp;
1239 gchar *hostname;
1240 int port = 0;
1241 guint transport_type = SIPE_TRANSPORT_TLS;
1242 int i = 1;
1244 tmp = g_strsplit(parts[0], ":", 0);
1245 hostname = g_strdup(tmp[0]);
1246 if (tmp[1]) port = strtoul(tmp[1], NULL, 10);
1247 g_strfreev(tmp);
1249 while (parts[i]) {
1250 tmp = g_strsplit(parts[i], "=", 0);
1251 if (tmp[1]) {
1252 if (g_ascii_strcasecmp("transport", tmp[0]) == 0) {
1253 if (g_ascii_strcasecmp("tcp", tmp[1]) == 0) {
1254 transport_type = SIPE_TRANSPORT_TCP;
1258 g_strfreev(tmp);
1259 i++;
1261 g_strfreev(parts);
1263 /* Close old connection */
1264 sipe_core_connection_cleanup(sipe_private);
1265 /* transport and sipe_private->transport are invalid after this */
1267 /* Create new connection */
1268 sipe_server_register(sipe_private, transport_type, hostname, port);
1269 /* sipe_private->transport has a new value */
1270 SIPE_DEBUG_INFO("process_register_response: redirected to host %s port %d transport %d",
1271 hostname, port, transport_type);
1273 g_free(redirect);
1275 break;
1276 case 401:
1278 const char *auth_hdr = NULL;
1280 SIPE_DEBUG_INFO("process_register_response: REGISTER retries %d", transport->registrar.retries);
1282 if (transport->reauthenticate_set) {
1283 SIPE_DEBUG_ERROR_NOFORMAT("process_register_response: RE-REGISTER rejected, triggering re-authentication");
1284 do_reauthenticate_cb(sipe_private, NULL);
1285 return TRUE;
1288 if (sip_sec_context_is_ready(transport->registrar.gssapi_context)) {
1289 struct sip_auth *auth = &transport->registrar;
1291 /* NTLM is the scheme with lowest priority - don't retry */
1292 if (auth_can_retry(transport, auth)) {
1293 guint failed = auth->type;
1294 SIPE_DEBUG_INFO_NOFORMAT("process_register_response: authentication handshake failed - trying next authentication scheme.");
1295 sipe_auth_free(auth);
1296 auth->type = failed;
1297 } else {
1298 SIPE_LOG_ERROR_NOFORMAT("process_register_response: authentication handshake failed - giving up.");
1299 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1300 SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
1301 _("Authentication failed"));
1302 return TRUE;
1306 if (sipe_private->authentication_type == SIPE_AUTHENTICATION_TYPE_AUTOMATIC) {
1307 struct sip_auth *auth = &transport->registrar;
1308 guint try = auth->type;
1310 while (!auth_hdr) {
1312 * Determine next authentication
1313 * scheme in priority order
1315 if (transport->auth_retry)
1316 switch (try) {
1317 case SIPE_AUTHENTICATION_TYPE_UNSET:
1318 try = SIPE_AUTHENTICATION_TYPE_TLS_DSK;
1319 break;
1321 case SIPE_AUTHENTICATION_TYPE_TLS_DSK:
1322 #if defined(HAVE_GSSAPI_GSSAPI_H) || defined(HAVE_SSPI)
1323 try = SIPE_AUTHENTICATION_TYPE_KERBEROS;
1324 break;
1326 case SIPE_AUTHENTICATION_TYPE_KERBEROS:
1327 #endif
1328 try = SIPE_AUTHENTICATION_TYPE_NTLM;
1329 break;
1331 default:
1332 try = SIPE_AUTHENTICATION_TYPE_UNSET;
1333 break;
1336 auth->can_retry = (try != SIPE_AUTHENTICATION_TYPE_UNSET);
1338 if (!auth->can_retry) {
1339 SIPE_DEBUG_INFO_NOFORMAT("process_register_response: no more authentication schemes to try");
1340 break;
1343 auth_hdr = get_auth_header(sipe_private,
1344 try,
1345 msg);
1348 transport->auth_retry = FALSE;
1350 } else
1351 auth_hdr = get_auth_header(sipe_private,
1352 sipe_private->authentication_type,
1353 msg);
1355 if (!auth_hdr) {
1356 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1357 SIPE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE,
1358 _("Incompatible authentication scheme chosen"));
1359 return TRUE;
1361 SIPE_DEBUG_INFO("process_register_response: Auth header: %s", auth_hdr);
1362 fill_auth(auth_hdr, &transport->registrar);
1363 transport->reregister_set = FALSE;
1364 transport->register_attempt = 0;
1365 do_register(sipe_private,
1366 sipe_backend_connection_is_disconnecting(SIPE_CORE_PUBLIC));
1368 break;
1369 case 403:
1371 gchar *reason;
1372 gchar *warning;
1373 sipmsg_parse_warning(msg, &reason);
1374 reason = reason ? reason : sipmsg_get_ms_diagnostics_public_reason(msg);
1375 warning = g_strdup_printf(_("You have been rejected by the server: %s"),
1376 reason ? reason : _("no reason given"));
1377 g_free(reason);
1379 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1380 SIPE_CONNECTION_ERROR_INVALID_SETTINGS,
1381 warning);
1382 g_free(warning);
1383 return TRUE;
1385 break;
1386 case 404:
1388 const gchar *diagnostics = sipmsg_find_header(msg, "ms-diagnostics");
1389 gchar *reason = sipmsg_get_ms_diagnostics_reason(msg);
1390 gchar *warning;
1391 warning = g_strdup_printf(_("Not found: %s. Please contact your Administrator"),
1392 diagnostics ? (reason ? reason : _("no reason given")) :
1393 _("SIP is either not enabled for the destination URI or it does not exist"));
1394 g_free(reason);
1396 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1397 SIPE_CONNECTION_ERROR_INVALID_USERNAME,
1398 warning);
1399 g_free(warning);
1400 return TRUE;
1402 break;
1403 case 504: /* Server time-out */
1404 /* first attempt + 5 retries */
1405 if (transport->register_attempt < 6) {
1406 SIPE_DEBUG_INFO("process_register_response: RE-REGISTER timeout on attempt %d, retrying later",
1407 transport->register_attempt);
1408 sip_transport_set_reregister(sipe_private, 60);
1409 return TRUE;
1411 /* FALLTHROUGH */
1412 case 503:
1414 gchar *reason = sipmsg_get_ms_diagnostics_reason(msg);
1415 gchar *warning;
1416 warning = g_strdup_printf(_("Service unavailable: %s"), reason ? reason : _("no reason given"));
1417 g_free(reason);
1419 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1420 SIPE_CONNECTION_ERROR_NETWORK,
1421 warning);
1422 g_free(warning);
1423 return TRUE;
1425 break;
1427 return TRUE;
1430 static gboolean register_response_timeout(struct sipe_core_private *sipe_private,
1431 SIPE_UNUSED_PARAMETER struct sipmsg *msg,
1432 SIPE_UNUSED_PARAMETER struct transaction *trans)
1434 struct sip_transport *transport = sipe_private->transport;
1435 if (transport->register_attempt < 6) {
1436 SIPE_DEBUG_INFO("register_response_timeout: no answer to attempt %d, retrying",
1437 transport->register_attempt);
1438 do_register(sipe_private, FALSE);
1439 } else {
1440 gchar *warning = g_strdup_printf(_("Service unavailable: %s"), _("no reason given"));
1441 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1442 SIPE_CONNECTION_ERROR_NETWORK,
1443 warning);
1444 g_free(warning);
1446 return TRUE;
1449 static void do_register(struct sipe_core_private *sipe_private,
1450 gboolean deregister)
1452 struct sip_transport *transport = sipe_private->transport;
1453 char *uri;
1454 char *to;
1455 char *hdr;
1456 char *uuid;
1458 if (!sipe_private->public.sip_domain) return;
1460 if (!deregister) {
1461 if (transport->reregister_set) {
1462 transport->reregister_set = FALSE;
1463 transport->register_attempt = 1;
1464 } else {
1465 transport->register_attempt++;
1469 transport->deregister = deregister;
1470 transport->auth_incomplete = FALSE;
1472 uuid = get_uuid(sipe_private);
1473 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"
1474 "Supported: gruu-10, adhoclist, msrtc-event-categories, com.microsoft.msrtc.presence\r\n"
1475 "Event: registration\r\n"
1476 "Allow-Events: presence\r\n"
1477 "ms-keep-alive: UAC;hop-hop=yes\r\n"
1478 "%s",
1479 transport->uri_address,
1480 transport->connection->client_port,
1481 TRANSPORT_DESCRIPTOR,
1482 uuid,
1483 deregister ? "Expires: 0\r\n" : "");
1484 g_free(uuid);
1486 uri = sip_uri_from_name(sipe_private->public.sip_domain);
1487 to = sip_uri_self(sipe_private);
1488 sip_transport_request_timeout(sipe_private,
1489 "REGISTER",
1490 uri,
1492 hdr,
1494 NULL,
1495 process_register_response,
1497 deregister ? NULL : register_response_timeout);
1498 g_free(to);
1499 g_free(uri);
1500 g_free(hdr);
1502 if (deregister) {
1503 /* Make sure that all messages are pushed to the server
1504 before the connection gets shut down */
1505 SIPE_LOG_INFO_NOFORMAT("De-register from server. Flushing outstanding messages.");
1506 sipe_backend_transport_flush(transport->connection);
1510 void sip_transport_deregister(struct sipe_core_private *sipe_private)
1512 do_register(sipe_private, TRUE);
1515 void sip_transport_disconnect(struct sipe_core_private *sipe_private)
1517 struct sip_transport *transport = sipe_private->transport;
1519 /* transport can be NULL during connection setup */
1520 if (transport) {
1521 SIPE_LOG_INFO("sip_transport_disconnect: dropping connection '%s:%u'",
1522 transport->server_name, transport->server_port);
1524 sipe_backend_transport_disconnect(transport->connection);
1526 sipe_auth_free(&transport->registrar);
1527 sipe_auth_free(&transport->proxy);
1529 g_free(transport->server_name);
1530 g_free(transport->server_version);
1531 g_free(transport->uri_address);
1532 g_free(transport->ip_address);
1533 g_free(transport->epid);
1534 g_free(transport->user_agent);
1536 while (transport->transactions)
1537 transactions_remove(sipe_private,
1538 transport->transactions->data);
1540 g_free(transport);
1543 sipe_private->transport = NULL;
1544 sipe_private->service_data = NULL;
1545 sipe_private->address_data = NULL;
1547 sipe_schedule_cancel(sipe_private, "<+keepalive-timeout>");
1549 if (sipe_private->dns_query)
1550 sipe_backend_dns_query_cancel(sipe_private->dns_query);
1554 void sip_transport_authentication_completed(struct sipe_core_private *sipe_private)
1556 do_reauthenticate_cb(sipe_private, NULL);
1559 guint sip_transport_port(struct sipe_core_private *sipe_private)
1561 return sipe_private->transport->server_port;
1564 static void process_input_message(struct sipe_core_private *sipe_private,
1565 struct sipmsg *msg)
1567 struct sip_transport *transport = sipe_private->transport;
1568 gboolean notfound = FALSE;
1569 const char *method = msg->method ? msg->method : "NOT FOUND";
1571 SIPE_DEBUG_INFO("process_input_message: msg->response(%d),msg->method(%s)",
1572 msg->response, method);
1574 if (msg->response == 0) { /* request */
1575 if (sipe_strequal(method, "MESSAGE")) {
1576 process_incoming_message(sipe_private, msg);
1577 } else if (sipe_strequal(method, "NOTIFY")) {
1578 SIPE_DEBUG_INFO_NOFORMAT("send->process_incoming_notify");
1579 process_incoming_notify(sipe_private, msg);
1580 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
1581 } else if (sipe_strequal(method, "BENOTIFY")) {
1582 SIPE_DEBUG_INFO_NOFORMAT("send->process_incoming_benotify");
1583 process_incoming_notify(sipe_private, msg);
1584 } else if (sipe_strequal(method, "INVITE")) {
1585 process_incoming_invite(sipe_private, msg);
1586 } else if (sipe_strequal(method, "REFER")) {
1587 process_incoming_refer(sipe_private, msg);
1588 } else if (sipe_strequal(method, "OPTIONS")) {
1589 process_incoming_options(sipe_private, msg);
1590 } else if (sipe_strequal(method, "INFO")) {
1591 process_incoming_info(sipe_private, msg);
1592 } else if (sipe_strequal(method, "ACK")) {
1593 /* ACK's don't need any response */
1594 } else if (sipe_strequal(method, "PRACK")) {
1595 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
1596 } else if (sipe_strequal(method, "SUBSCRIBE")) {
1597 /* LCS 2005 sends us these - just respond 200 OK */
1598 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
1599 } else if (sipe_strequal(method, "CANCEL")) {
1600 process_incoming_cancel(sipe_private, msg);
1601 } else if (sipe_strequal(method, "BYE")) {
1602 process_incoming_bye(sipe_private, msg);
1603 } else {
1604 sip_transport_response(sipe_private, msg, 501, "Not implemented", NULL);
1605 notfound = TRUE;
1608 } else { /* response */
1609 struct transaction *trans = transactions_find(transport, msg);
1610 if (trans) {
1611 if (msg->response < 200) {
1612 /* ignore provisional response */
1613 SIPE_DEBUG_INFO("process_input_message: got provisional (%d) response, ignoring", msg->response);
1615 /* Transaction not yet completed */
1616 trans = NULL;
1618 } else if (msg->response == 401) { /* Unauthorized */
1620 if (sipe_strequal(trans->msg->method, "REGISTER")) {
1621 /* Expected response during authentication handshake */
1622 transport->registrar.retries++;
1623 SIPE_DEBUG_INFO("process_input_message: RE-REGISTER CSeq: %d", transport->cseq);
1624 } else {
1625 gchar *resend;
1627 /* Are we registered? */
1628 if (transport->reregister_set) {
1629 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: 401 response to non-REGISTER message. Retrying with new authentication.");
1630 sipmsg_remove_header_now(trans->msg, "Authorization");
1631 sign_outgoing_message(sipe_private,
1632 trans->msg);
1633 } else {
1635 * We don't have a valid authentication at the moment.
1636 * Resend message unchanged. It will be rejected again
1637 * and hopefully by then we have a valid authentication.
1639 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: 401 response to non-REGISTER message. Bouncing...");
1642 /* Resend request */
1643 resend = sipmsg_to_string(trans->msg);
1644 send_sip_message(sipe_private->transport, resend);
1645 g_free(resend);
1647 /* Transaction not yet completed */
1648 trans = NULL;
1651 } else if (msg->response == 407) { /* Proxy Authentication Required */
1653 if (transport->proxy.retries++ <= 30) {
1654 const gchar *proxy_hdr = sipmsg_find_header(msg, "Proxy-Authenticate");
1656 if (proxy_hdr) {
1657 gchar *auth = NULL;
1659 if (!g_ascii_strncasecmp(proxy_hdr, "Digest", 6)) {
1660 auth = sip_sec_digest_authorization(sipe_private,
1661 proxy_hdr + 7,
1662 msg->method,
1663 msg->target);
1664 } else {
1665 guint i;
1667 transport->proxy.type = SIPE_AUTHENTICATION_TYPE_UNSET;
1668 for (i = 0; i < AUTH_PROTOCOLS; i++) {
1669 const gchar *protocol = auth_type_to_protocol[i];
1670 if (protocol &&
1671 !g_ascii_strncasecmp(proxy_hdr, protocol, strlen(protocol))) {
1672 SIPE_DEBUG_INFO("process_input_message: proxy authentication scheme '%s'", protocol);
1673 transport->proxy.type = i;
1674 transport->proxy.protocol = protocol;
1675 fill_auth(proxy_hdr, &transport->proxy);
1676 auth = auth_header(sipe_private, &transport->proxy, trans->msg);
1677 break;
1682 if (auth) {
1683 gchar *resend;
1685 /* replace old proxy authentication with new one */
1686 sipmsg_remove_header_now(trans->msg, "Proxy-Authorization");
1687 sipmsg_add_header_now(trans->msg, "Proxy-Authorization", auth);
1688 g_free(auth);
1690 /* resend request with proxy authentication */
1691 resend = sipmsg_to_string(trans->msg);
1692 send_sip_message(sipe_private->transport, resend);
1693 g_free(resend);
1695 /* Transaction not yet completed */
1696 trans = NULL;
1698 } else
1699 SIPE_DEBUG_ERROR_NOFORMAT("process_input_message: can't generate proxy authentication. Giving up.");
1700 } else
1701 SIPE_DEBUG_ERROR_NOFORMAT("process_input_message: 407 response without 'Proxy-Authenticate' header. Giving up.");
1702 } else
1703 SIPE_DEBUG_ERROR_NOFORMAT("process_input_message: too many proxy authentication retries. Giving up.");
1705 } else {
1706 transport->registrar.retries = 0;
1707 transport->proxy.retries = 0;
1710 /* Is transaction completed? */
1711 if (trans) {
1712 if (trans->callback) {
1713 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: we have a transaction callback");
1714 /* call the callback to process response */
1715 (trans->callback)(sipe_private, msg, trans);
1716 /* transport && trans no longer valid after redirect */
1720 * Redirect case: sipe_private->transport is
1721 * the new transport with empty queue
1723 if (sipe_private->transport->transactions) {
1724 SIPE_DEBUG_INFO("process_input_message: removing CSeq %d", transport->cseq);
1725 transactions_remove(sipe_private, trans);
1728 } else {
1729 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: received response to unknown transaction");
1730 notfound = TRUE;
1734 if (notfound) {
1735 SIPE_DEBUG_INFO("received a unknown sip message with method %s and response %d", method, msg->response);
1739 static void sip_transport_input(struct sipe_transport_connection *conn)
1741 struct sipe_core_private *sipe_private = conn->user_data;
1742 struct sip_transport *transport = sipe_private->transport;
1743 gchar *cur = conn->buffer;
1745 /* according to the RFC remove CRLF at the beginning */
1746 while (*cur == '\r' || *cur == '\n') {
1747 cur++;
1749 if (cur != conn->buffer)
1750 sipe_utils_shrink_buffer(conn, cur);
1752 /* Received a full Header? */
1753 transport->processing_input = TRUE;
1754 while (transport->processing_input &&
1755 ((cur = strstr(conn->buffer, "\r\n\r\n")) != NULL)) {
1756 struct sipmsg *msg;
1757 guint remainder;
1759 cur += 2;
1760 cur[0] = '\0';
1761 msg = sipmsg_parse_header(conn->buffer);
1763 cur += 2;
1764 remainder = conn->buffer_used - (cur - conn->buffer);
1765 if (msg && remainder >= (guint) msg->bodylen) {
1766 char *dummy = g_malloc(msg->bodylen + 1);
1767 memcpy(dummy, cur, msg->bodylen);
1768 dummy[msg->bodylen] = '\0';
1769 msg->body = dummy;
1770 cur += msg->bodylen;
1771 sipe_utils_message_debug("SIP",
1772 conn->buffer,
1773 msg->body,
1774 FALSE);
1775 sipe_utils_shrink_buffer(conn, cur);
1776 } else {
1777 if (msg) {
1778 SIPE_DEBUG_INFO("sipe_transport_input: body too short (%d < %d, strlen %d) - ignoring message", remainder, msg->bodylen, (int)strlen(conn->buffer));
1779 sipmsg_free(msg);
1782 /* restore header for next try */
1783 cur[-2] = '\r';
1784 return;
1787 /* Fatal header parse error? */
1788 if (msg->response == SIPMSG_RESPONSE_FATAL_ERROR) {
1789 /* can't proceed -> drop connection */
1790 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1791 SIPE_CONNECTION_ERROR_NETWORK,
1792 _("Corrupted message received"));
1793 transport->processing_input = FALSE;
1795 /* Verify the signature before processing it */
1796 } else if (sip_sec_context_is_ready(transport->registrar.gssapi_context)) {
1797 struct sipmsg_breakdown msgbd;
1798 gchar *signature_input_str;
1799 gchar *rspauth;
1800 msgbd.msg = msg;
1801 sipmsg_breakdown_parse(&msgbd, transport->registrar.realm, transport->registrar.target,
1802 transport->registrar.protocol);
1803 signature_input_str = sipmsg_breakdown_get_string(transport->registrar.version, &msgbd);
1805 rspauth = sipmsg_find_part_of_header(sipmsg_find_header(msg, "Authentication-Info"), "rspauth=\"", "\"", NULL);
1807 if (rspauth != NULL) {
1808 if (sip_sec_verify_signature(transport->registrar.gssapi_context, signature_input_str, rspauth)) {
1809 SIPE_DEBUG_INFO_NOFORMAT("sip_transport_input: signature of incoming message validated");
1810 process_input_message(sipe_private, msg);
1811 /* transport is invalid after redirect */
1812 } else {
1813 SIPE_DEBUG_INFO_NOFORMAT("sip_transport_input: signature of incoming message is invalid.");
1814 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1815 SIPE_CONNECTION_ERROR_NETWORK,
1816 _("Invalid message signature received"));
1817 transport->processing_input = FALSE;
1819 } else if ((msg->response == 401) ||
1820 sipe_strequal(msg->method, "REGISTER")) {
1821 /* a) Retry non-REGISTER requests with updated authentication */
1822 /* b) We must always process REGISTER responses */
1823 process_input_message(sipe_private, msg);
1824 } else {
1825 /* OCS sends provisional messages that are *not* signed */
1826 if (msg->response >= 200) {
1827 /* We are not calling process_input_message(),
1828 so we need to drop the transaction here. */
1829 struct transaction *trans = transactions_find(transport, msg);
1830 if (trans) transactions_remove(sipe_private, trans);
1832 SIPE_DEBUG_INFO_NOFORMAT("sip_transport_input: message without authentication data - ignoring");
1834 g_free(signature_input_str);
1836 g_free(rspauth);
1837 sipmsg_breakdown_free(&msgbd);
1838 } else {
1839 process_input_message(sipe_private, msg);
1842 sipmsg_free(msg);
1844 /* Redirect: old content of "transport" & "conn" is no longer valid */
1845 transport = sipe_private->transport;
1846 conn = transport->connection;
1850 static void sip_transport_connected(struct sipe_transport_connection *conn)
1852 struct sipe_core_private *sipe_private = conn->user_data;
1853 struct sip_transport *transport = sipe_private->transport;
1854 gchar *self_sip_uri = sip_uri_self(sipe_private);
1856 SIPE_LOG_INFO("sip_transport_connected: %s:%u",
1857 transport->server_name, transport->server_port);
1859 while (sipe_private->lync_autodiscover_servers)
1860 sipe_private->lync_autodiscover_servers =
1861 sipe_lync_autodiscover_pop(sipe_private->lync_autodiscover_servers);
1863 sipe_private->service_data = NULL;
1864 sipe_private->address_data = NULL;
1867 * Initial keepalive timeout during REGISTER phase
1869 * NOTE: 60 seconds is a guess. Needs more testing!
1871 transport->keepalive_timeout = 60;
1872 start_keepalive_timer(sipe_private, transport->keepalive_timeout);
1874 transport->ip_address = sipe_backend_transport_ip_address(conn);
1875 if (strchr(transport->ip_address, ':') != NULL)
1876 /* RFC2732: Format for Literal IPv6 Addresses in URL's */
1877 transport->uri_address = g_strdup_printf("[%s]", transport->ip_address);
1878 else
1879 transport->uri_address = g_strdup(transport->ip_address);
1880 transport->sdp_marker = sdpmsg_address_marker(transport->ip_address);
1881 transport->epid = sipe_get_epid(self_sip_uri,
1882 g_get_host_name(),
1883 transport->ip_address);
1884 g_free(self_sip_uri);
1886 do_register(sipe_private, FALSE);
1889 static void resolve_next_lync(struct sipe_core_private *sipe_private);
1890 static void resolve_next_service(struct sipe_core_private *sipe_private,
1891 const struct sip_service_data *start);
1892 static void resolve_next_address(struct sipe_core_private *sipe_private,
1893 gboolean initial);
1894 static void sip_transport_error(struct sipe_transport_connection *conn,
1895 const gchar *msg)
1897 struct sipe_core_private *sipe_private = conn->user_data;
1899 /* This failed attempt was based on a Lync Autodiscover result */
1900 if (sipe_private->lync_autodiscover_servers) {
1901 resolve_next_lync(sipe_private);
1902 /* This failed attempt was based on a DNS SRV record */
1903 } else if (sipe_private->service_data) {
1904 resolve_next_service(sipe_private, NULL);
1905 /* This failed attempt was based on a DNS A record */
1906 } else if (sipe_private->address_data) {
1907 resolve_next_address(sipe_private, FALSE);
1908 } else {
1909 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1910 SIPE_CONNECTION_ERROR_NETWORK,
1911 msg);
1915 /* server_name must be g_alloc()'ed */
1916 static void sipe_server_register(struct sipe_core_private *sipe_private,
1917 guint type,
1918 gchar *server_name,
1919 guint server_port)
1921 sipe_connect_setup setup = {
1922 type,
1923 server_name,
1924 (server_port != 0) ? server_port :
1925 (type == SIPE_TRANSPORT_TLS) ? 5061 : 5060,
1926 sipe_private,
1927 sip_transport_connected,
1928 sip_transport_input,
1929 sip_transport_error
1931 struct sip_transport *transport = g_new0(struct sip_transport, 1);
1933 transport->auth_retry = TRUE;
1934 transport->server_name = server_name;
1935 transport->server_port = setup.server_port;
1936 transport->connection = sipe_backend_transport_connect(SIPE_CORE_PUBLIC,
1937 &setup);
1938 sipe_private->transport = transport;
1941 struct sip_service_data {
1942 const char *protocol;
1943 const char *transport;
1944 guint type;
1948 * Autodiscover using DNS SRV records. See RFC2782/3263
1950 * Service list for AUTO
1952 static const struct sip_service_data service_autodetect[] = {
1953 { "sipinternaltls", "tcp", SIPE_TRANSPORT_TLS }, /* for internal TLS connections */
1954 { "sipinternal", "tcp", SIPE_TRANSPORT_TCP }, /* for internal TCP connections */
1955 { "sip", "tls", SIPE_TRANSPORT_TLS }, /* for external TLS connections */
1956 { "sip", "tcp", SIPE_TRANSPORT_TCP }, /*.for external TCP connections */
1957 { NULL, NULL, 0 }
1960 /* Service list for SSL/TLS */
1961 static const struct sip_service_data service_tls[] = {
1962 { "sipinternaltls", "tcp", SIPE_TRANSPORT_TLS }, /* for internal TLS connections */
1963 { "sip", "tls", SIPE_TRANSPORT_TLS }, /* for external TLS connections */
1964 { NULL, NULL, 0 }
1967 /* Service list for TCP */
1968 static const struct sip_service_data service_tcp[] = {
1969 { "sipinternal", "tcp", SIPE_TRANSPORT_TCP }, /* for internal TCP connections */
1970 { "sip", "tcp", SIPE_TRANSPORT_TCP }, /*.for external TCP connections */
1971 { NULL, NULL, 0 }
1974 static const struct sip_service_data *services[] = {
1975 service_autodetect, /* SIPE_TRANSPORT_AUTO */
1976 service_tls, /* SIPE_TRANSPORT_TLS */
1977 service_tcp /* SIPE_TRANSPORT_TCP */
1980 struct sip_address_data {
1981 const char *prefix;
1982 guint port;
1986 * Autodiscover using DNS A records. This is an extension addded
1987 * by Microsoft. See http://support.microsoft.com/kb/2619522
1989 static const struct sip_address_data addresses[] = {
1990 { "sipinternal", 5061 },
1991 { "sipexternal", 443 },
1993 * Our implementation supports only one port per host name. If the host name
1994 * resolves OK, we abort the search and try to connect. If we would know if we
1995 * are trying to connect from "Intranet" or "Internet" then we could choose
1996 * between those two ports.
1998 * We drop port 5061 in order to cover the "Internet" case.
2000 * { "sip", 5061 },
2002 { "sip", 443 },
2003 { NULL, 0 }
2006 static void sipe_core_dns_resolved(struct sipe_core_public *sipe_public,
2007 const gchar *hostname, guint port)
2009 struct sipe_core_private *sipe_private = SIPE_CORE_PRIVATE;
2010 gboolean service = sipe_private->service_data != NULL;
2012 sipe_private->dns_query = NULL;
2014 if (hostname) {
2015 gchar *host;
2016 guint type;
2018 if (service) {
2019 host = g_strdup(hostname);
2020 type = sipe_private->service_data->type;
2021 } else {
2022 /* DNS A resolver returns an IP address */
2023 host = g_strdup_printf("%s.%s",
2024 sipe_private->address_data->prefix,
2025 sipe_private->public.sip_domain);
2026 port = sipe_private->address_data->port;
2027 type = sipe_private->transport_type;
2028 if (type == SIPE_TRANSPORT_AUTO)
2029 type = SIPE_TRANSPORT_TLS;
2032 SIPE_DEBUG_INFO("sipe_core_dns_resolved - %s hostname: %s port: %d",
2033 service ? "SRV" : "A", hostname, port);
2034 sipe_server_register(sipe_private, type, host, port);
2035 } else {
2036 if (service)
2037 resolve_next_service(SIPE_CORE_PRIVATE, NULL);
2038 else
2039 resolve_next_address(SIPE_CORE_PRIVATE, FALSE);
2043 static void resolve_next_lync(struct sipe_core_private *sipe_private)
2045 struct sipe_lync_autodiscover_data *lync_data = sipe_private->lync_autodiscover_servers->data;
2046 guint type = sipe_private->transport_type;
2048 if (lync_data) {
2049 /* Try to connect to next server on the list */
2050 if (type == SIPE_TRANSPORT_AUTO)
2051 type = SIPE_TRANSPORT_TLS;
2053 sipe_server_register(sipe_private,
2054 type,
2055 g_strdup(lync_data->server),
2056 lync_data->port);
2058 } else {
2059 /* We tried all servers -> try DNS SRV next */
2060 SIPE_LOG_INFO_NOFORMAT("no Lync Autodiscover servers found; trying SRV records next");
2061 resolve_next_service(sipe_private, services[type]);
2064 sipe_private->lync_autodiscover_servers =
2065 sipe_lync_autodiscover_pop(sipe_private->lync_autodiscover_servers);
2068 static void resolve_next_service(struct sipe_core_private *sipe_private,
2069 const struct sip_service_data *start)
2071 if (start) {
2072 sipe_private->service_data = start;
2073 } else {
2074 sipe_private->service_data++;
2075 if (sipe_private->service_data->protocol == NULL) {
2077 /* We tried all services */
2078 sipe_private->service_data = NULL;
2080 /* Try A records list next */
2081 SIPE_LOG_INFO_NOFORMAT("no SRV records found; trying A records next");
2082 resolve_next_address(sipe_private, TRUE);
2083 return;
2087 /* Try to resolve next service */
2088 sipe_private->dns_query = sipe_backend_dns_query_srv(
2089 SIPE_CORE_PUBLIC,
2090 sipe_private->service_data->protocol,
2091 sipe_private->service_data->transport,
2092 sipe_private->public.sip_domain,
2093 (sipe_dns_resolved_cb) sipe_core_dns_resolved,
2094 SIPE_CORE_PUBLIC);
2097 static void resolve_next_address(struct sipe_core_private *sipe_private,
2098 gboolean initial)
2100 gchar *hostname;
2102 if (initial) {
2103 sipe_private->address_data = addresses;
2104 } else {
2105 sipe_private->address_data++;
2106 if (sipe_private->address_data->prefix == NULL) {
2107 guint type = sipe_private->transport_type;
2109 /* We tried all addresss */
2110 sipe_private->address_data = NULL;
2112 /* Try connecting to the SIP hostname directly */
2113 SIPE_LOG_INFO_NOFORMAT("no SRV or A records found; using SIP domain as fallback");
2114 if (type == SIPE_TRANSPORT_AUTO)
2115 type = SIPE_TRANSPORT_TLS;
2117 sipe_server_register(sipe_private, type,
2118 g_strdup(sipe_private->public.sip_domain),
2120 return;
2124 /* Try to resolve next address */
2125 hostname = g_strdup_printf("%s.%s",
2126 sipe_private->address_data->prefix,
2127 sipe_private->public.sip_domain);
2128 sipe_private->dns_query = sipe_backend_dns_query_a(
2129 SIPE_CORE_PUBLIC,
2130 hostname,
2131 sipe_private->address_data->port,
2132 (sipe_dns_resolved_cb) sipe_core_dns_resolved,
2133 SIPE_CORE_PUBLIC);
2134 g_free(hostname);
2137 static void lync_autodiscover_cb(struct sipe_core_private *sipe_private,
2138 GSList *servers,
2139 SIPE_UNUSED_PARAMETER gpointer callback_data)
2141 if (servers) {
2142 /* Lync Autodiscover succeeded */
2143 SIPE_DEBUG_INFO_NOFORMAT("lync_autodiscover_cb: got server list");
2145 sipe_private->lync_autodiscover_servers = servers;
2146 resolve_next_lync(sipe_private);
2151 * NOTE: this function can be called before sipe_core_allocate()!
2153 gboolean sipe_core_transport_sip_requires_password(guint authentication,
2154 gboolean sso)
2156 return(sip_sec_requires_password(authentication, sso));
2159 void sipe_core_transport_sip_connect(struct sipe_core_public *sipe_public,
2160 guint transport,
2161 guint authentication,
2162 const gchar *server,
2163 const gchar *port)
2165 struct sipe_core_private *sipe_private = SIPE_CORE_PRIVATE;
2167 /* backend initialization is complete */
2168 sipe_core_backend_initialized(sipe_private, authentication);
2171 * Initializing the certificate sub-system will trigger the generation
2172 * of a cryptographic key pair which takes time. If we do this after we
2173 * have connected to the server then there is a risk that we run into a
2174 * SIP connection timeout. So let's get this out of the way now...
2176 * This is currently only needed if the user has selected TLS-DSK.
2178 if (sipe_private->authentication_type == SIPE_AUTHENTICATION_TYPE_TLS_DSK)
2179 sipe_certificate_init(sipe_private);
2181 if (server) {
2182 /* Use user specified server[:port] */
2183 int port_number = 0;
2185 if (port)
2186 port_number = atoi(port);
2188 SIPE_LOG_INFO("sipe_core_connect: user specified SIP server %s:%d",
2189 server, port_number);
2191 sipe_server_register(sipe_private, transport,
2192 g_strdup(server), port_number);
2193 } else {
2194 /* Server auto-discovery */
2196 /* Remember user specified transport type */
2197 sipe_private->transport_type = transport;
2199 /* Start with Lync Autodiscover first */
2200 sipe_lync_autodiscover_start(sipe_private,
2201 lync_autodiscover_cb,
2202 NULL);
2206 const gchar *sipe_core_transport_sip_server_name(struct sipe_core_public *sipe_public)
2208 struct sip_transport *transport = SIPE_CORE_PRIVATE->transport;
2209 return(transport ? transport->server_name : NULL);
2212 int sip_transaction_cseq(struct transaction *trans)
2214 int cseq;
2216 g_return_val_if_fail(trans && trans->key, 0);
2218 sscanf(trans->key, "<%*[a-zA-Z0-9]><%d INVITE>", &cseq);
2219 return cseq;
2222 const gchar *sip_transport_epid(struct sipe_core_private *sipe_private)
2224 return(sipe_private->transport ?
2225 sipe_private->transport->epid :
2226 "0123456789ab");
2229 const gchar *sip_transport_ip_address(struct sipe_core_private *sipe_private)
2231 return(sipe_private->transport ?
2232 sipe_private->transport->ip_address :
2233 "0.0.0.0");
2236 const gchar *sip_transport_sdp_address_marker(struct sipe_core_private *sipe_private)
2238 return(sipe_private->transport ?
2239 sipe_private->transport->sdp_marker :
2240 "IP4");
2244 Local Variables:
2245 mode: c
2246 c-file-style: "bsd"
2247 indent-tabs-mode: t
2248 tab-width: 8
2249 End: