Release 1.25.0 -- Buddy Idle Time, RTF
[siplcs.git] / src / core / sip-transport.c
blobd6a1493321ed171c9c45047c5e8a2cac08703a69
1 /**
2 * @file sip-transport.c
4 * pidgin-sipe
6 * Copyright (C) 2010-2019 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;
108 gchar *epid;
109 /* local IP address of transport socket */
110 gchar *ip_address; /* RAW X.X.X.X (IPv4), X:X:...:X (IPv6) */
111 gchar *uri_address; /* URI X.X.X.X (IPv4), [X:X:...:X] (IPv6) */
112 const gchar *sdp_marker; /* SDP address marker: "IP4" or "IP6" */
114 GSList *transactions;
116 struct sip_auth registrar;
117 struct sip_auth proxy;
119 guint cseq;
120 guint register_attempt;
122 guint keepalive_timeout;
123 time_t last_message;
125 gboolean processing_input; /* whether full header received */
126 gboolean auth_incomplete; /* whether authentication not completed */
127 gboolean auth_retry; /* whether next authentication should be tried */
128 gboolean reregister_set; /* whether reregister timer set */
129 gboolean reauthenticate_set; /* whether reauthenticate timer set */
130 gboolean subscribed; /* whether subscribed to events, except buddies presence */
131 gboolean deregister; /* whether in deregistration */
134 /* Keep in sync with sipe_transport_type! */
135 static const char *transport_descriptor[] = { "", "tls", "tcp"};
136 #define TRANSPORT_DESCRIPTOR (transport_descriptor[transport->connection->type])
138 static char *genbranch()
140 return g_strdup_printf("z9hG4bK%04X%04X%04X%04X%04X",
141 rand() & 0xFFFF, rand() & 0xFFFF, rand() & 0xFFFF,
142 rand() & 0xFFFF, rand() & 0xFFFF);
145 static void sipe_auth_free(struct sip_auth *auth)
147 g_free(auth->opaque);
148 auth->opaque = NULL;
149 auth->protocol = NULL;
150 g_free(auth->realm);
151 auth->realm = NULL;
152 g_free(auth->sts_uri);
153 auth->sts_uri = NULL;
154 g_free(auth->target);
155 auth->target = NULL;
156 auth->version = 0;
157 auth->type = SIPE_AUTHENTICATION_TYPE_UNSET;
158 auth->retries = 0;
159 auth->expires = 0;
160 auth->can_retry = FALSE;
161 g_free(auth->gssapi_data);
162 auth->gssapi_data = NULL;
163 sip_sec_destroy_context(auth->gssapi_context);
164 auth->gssapi_context = NULL;
167 static void sipe_make_signature(struct sipe_core_private *sipe_private,
168 struct sipmsg *msg)
170 struct sip_transport *transport = sipe_private->transport;
171 if (sip_sec_context_is_ready(transport->registrar.gssapi_context)) {
172 struct sipmsg_breakdown msgbd;
173 gchar *signature_input_str;
174 msgbd.msg = msg;
175 sipmsg_breakdown_parse(&msgbd, transport->registrar.realm, transport->registrar.target,
176 transport->registrar.protocol);
177 msgbd.rand = g_strdup_printf("%08x", g_random_int());
178 transport->registrar.ntlm_num++;
179 msgbd.num = g_strdup_printf("%d", transport->registrar.ntlm_num);
180 signature_input_str = sipmsg_breakdown_get_string(transport->registrar.version, &msgbd);
181 if (signature_input_str != NULL) {
182 char *signature_hex = sip_sec_make_signature(transport->registrar.gssapi_context, signature_input_str);
183 g_free(msg->signature);
184 msg->signature = signature_hex;
185 g_free(msg->rand);
186 msg->rand = g_strdup(msgbd.rand);
187 g_free(msg->num);
188 msg->num = g_strdup(msgbd.num);
189 g_free(signature_input_str);
191 sipmsg_breakdown_free(&msgbd);
195 static const gchar *const auth_type_to_protocol[] = {
196 NULL, /* SIPE_AUTHENTICATION_TYPE_UNSET */
197 NULL, /* SIPE_AUTHENTICATION_TYPE_BASIC */
198 "NTLM", /* SIPE_AUTHENTICATION_TYPE_NTLM */
199 "Kerberos", /* SIPE_AUTHENTICATION_TYPE_KERBEROS */
200 NULL, /* SIPE_AUTHENTICATION_TYPE_NEGOTIATE */
201 "TLS-DSK", /* SIPE_AUTHENTICATION_TYPE_TLS_DSK */
202 NULL, /* SIPE_AUTHENTICATION_TYPE_AUTOMATIC */
204 #define AUTH_PROTOCOLS (sizeof(auth_type_to_protocol)/sizeof(gchar *))
206 static gchar *msg_signature_to_auth(struct sip_auth *auth,
207 struct sipmsg *msg)
209 return(g_strdup_printf("%s qop=\"auth\", opaque=\"%s\", realm=\"%s\", targetname=\"%s\", crand=\"%s\", cnum=\"%s\", response=\"%s\"",
210 auth->protocol,
211 auth->opaque, auth->realm, auth->target,
212 msg->rand, msg->num, msg->signature));
215 static gboolean auth_can_retry(struct sip_transport *transport,
216 const struct sip_auth *auth)
218 /* NTLM is the scheme with lowest priority - don't retry */
219 gboolean retry =
220 auth->can_retry &&
221 (auth->type != SIPE_AUTHENTICATION_TYPE_NTLM);
222 if (retry)
223 transport->auth_retry = TRUE;
224 return(retry);
227 static void initialize_auth_retry(struct sipe_core_private *sipe_private,
228 struct sip_auth *auth)
230 struct sip_transport *transport = sipe_private->transport;
232 if (auth_can_retry(transport, auth)) {
233 if (auth->gssapi_context) {
234 /* need to drop context for retry */
235 sip_sec_destroy_context(auth->gssapi_context);
236 auth->gssapi_context = NULL;
238 } else {
239 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
240 SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
241 _("Failed to authenticate to server"));
245 static gchar *initialize_auth_context(struct sipe_core_private *sipe_private,
246 struct sip_auth *auth,
247 struct sipmsg *msg)
249 struct sip_transport *transport = sipe_private->transport;
250 gchar *ret;
251 gchar *gssapi_data = NULL;
252 gchar *sign_str;
253 gchar *gssapi_str;
254 gchar *opaque_str;
255 gchar *version_str;
258 * If transport is de-registering when we reach this point then we
259 * are in the middle of the previous authentication context setup
260 * attempt. So we shouldn't try another attempt.
262 if (transport->deregister)
263 return NULL;
265 /* Create security context or handshake continuation? */
266 if (auth->gssapi_context) {
267 /* Perform next step in authentication handshake */
268 gboolean status = sip_sec_init_context_step(auth->gssapi_context,
269 auth->target,
270 auth->gssapi_data,
271 &gssapi_data,
272 &auth->expires);
274 /* If authentication is completed gssapi_data can be NULL */
275 if (!(status &&
276 (sip_sec_context_is_ready(auth->gssapi_context) || gssapi_data))) {
277 SIPE_DEBUG_ERROR_NOFORMAT("initialize_auth_context: security context continuation failed");
278 g_free(gssapi_data);
279 initialize_auth_retry(sipe_private, auth);
280 return NULL;
283 } else {
284 /* Create security context */
285 gpointer password = sipe_private->password;
287 /* For TLS-DSK the "password" is a certificate */
288 if (auth->type == SIPE_AUTHENTICATION_TYPE_TLS_DSK) {
289 password = sipe_certificate_tls_dsk_find(sipe_private,
290 auth->target);
292 if (!password) {
293 if (auth->sts_uri) {
294 SIPE_DEBUG_INFO("initialize_auth_context: TLS-DSK Certificate Provisioning URI %s",
295 auth->sts_uri);
296 if (!sipe_certificate_tls_dsk_generate(sipe_private,
297 auth->target,
298 auth->sts_uri)) {
299 gchar *tmp = g_strdup_printf(_("Can't request certificate from %s"),
300 auth->sts_uri);
301 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
302 SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
303 tmp);
304 g_free(tmp);
306 } else {
307 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
308 SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
309 _("No URI for certificate provisioning service provided"));
312 /* we can't authenticate the message yet */
313 transport->auth_incomplete = TRUE;
315 return(NULL);
316 } else {
317 SIPE_DEBUG_INFO("initialize_auth_context: TLS-DSK certificate for target '%s' found.",
318 auth->target);
322 auth->gssapi_context = sip_sec_create_context(auth->type,
323 SIPE_CORE_PRIVATE_FLAG_IS(SSO),
324 FALSE, /* connection-less for SIP */
325 sipe_private->authuser,
326 password);
328 if (auth->gssapi_context) {
329 sip_sec_init_context_step(auth->gssapi_context,
330 auth->target,
331 NULL,
332 &gssapi_data,
333 &(auth->expires));
336 /* if auth->gssapi_context is NULL then gssapi_data is still NULL */
337 if (!gssapi_data) {
338 SIPE_DEBUG_ERROR_NOFORMAT("initialize_auth_context: security context initialization failed");
339 initialize_auth_retry(sipe_private, auth);
340 return NULL;
344 if ((auth->version > 3) &&
345 sip_sec_context_is_ready(auth->gssapi_context)) {
346 sipe_make_signature(sipe_private, msg);
347 sign_str = g_strdup_printf(", crand=\"%s\", cnum=\"%s\", response=\"%s\"",
348 msg->rand, msg->num, msg->signature);
349 } else {
350 sign_str = g_strdup("");
353 if (gssapi_data) {
354 gssapi_str = g_strdup_printf(", gssapi-data=\"%s\"",
355 gssapi_data);
356 g_free(gssapi_data);
357 } else {
358 gssapi_str = g_strdup("");
361 opaque_str = auth->opaque ? g_strdup_printf(", opaque=\"%s\"", auth->opaque) : g_strdup("");
363 if (auth->version > 2) {
364 version_str = g_strdup_printf(", version=%d", auth->version);
365 } else {
366 version_str = g_strdup("");
369 ret = g_strdup_printf("%s qop=\"auth\"%s, realm=\"%s\", targetname=\"%s\"%s%s%s",
370 auth->protocol, opaque_str,
371 auth->realm, auth->target,
372 gssapi_str, version_str, sign_str);
373 g_free(version_str);
374 g_free(opaque_str);
375 g_free(gssapi_str);
376 g_free(sign_str);
378 return(ret);
381 static gchar *auth_header(struct sipe_core_private *sipe_private,
382 struct sip_auth *auth,
383 struct sipmsg *msg)
385 gchar *ret = NULL;
388 * If the message is already signed then we have an authentication
389 * context, i.e. the authentication handshake is complete. Generate
390 * authentication header from message signature.
392 if (msg->signature) {
393 ret = msg_signature_to_auth(auth, msg);
396 * We should reach this point only when the authentication context
397 * needs to be initialized.
399 } else {
400 ret = initialize_auth_context(sipe_private, auth, msg);
403 return(ret);
406 static void fill_auth(const gchar *hdr, struct sip_auth *auth)
408 const gchar *param;
410 /* skip authentication identifier */
411 hdr = strchr(hdr, ' ');
412 if (!hdr) {
413 SIPE_DEBUG_ERROR_NOFORMAT("fill_auth: corrupted authentication header");
414 return;
416 while (*hdr == ' ')
417 hdr++;
419 /* start of next parameter value */
420 while ((param = strchr(hdr, '=')) != NULL) {
421 const gchar *end;
423 /* parameter value type */
424 param++;
425 if (*param == '"') {
426 /* string: xyz="..."(,) */
427 end = strchr(++param, '"');
428 if (!end) {
429 SIPE_DEBUG_ERROR("fill_auth: corrupted string parameter near '%s'", hdr);
430 break;
432 } else {
433 /* number: xyz=12345(,) */
434 end = strchr(param, ',');
435 if (!end) {
436 /* last parameter */
437 end = param + strlen(param);
441 #if 0
442 SIPE_DEBUG_INFO("fill_auth: hdr '%s'", hdr);
443 SIPE_DEBUG_INFO("fill_auth: param '%s'", param);
444 SIPE_DEBUG_INFO("fill_auth: end '%s'", end);
445 #endif
447 /* parameter type */
448 if (g_str_has_prefix(hdr, "gssapi-data=\"")) {
449 g_free(auth->gssapi_data);
450 auth->gssapi_data = g_strndup(param, end - param);
451 } else if (g_str_has_prefix(hdr, "opaque=\"")) {
452 g_free(auth->opaque);
453 auth->opaque = g_strndup(param, end - param);
454 } else if (g_str_has_prefix(hdr, "realm=\"")) {
455 g_free(auth->realm);
456 auth->realm = g_strndup(param, end - param);
457 } else if (g_str_has_prefix(hdr, "sts-uri=\"")) {
458 /* Only used with SIPE_AUTHENTICATION_TYPE_TLS_DSK */
459 g_free(auth->sts_uri);
460 auth->sts_uri = g_strndup(param, end - param);
461 } else if (g_str_has_prefix(hdr, "targetname=\"")) {
462 g_free(auth->target);
463 auth->target = g_strndup(param, end - param);
464 } else if (g_str_has_prefix(hdr, "version=")) {
465 auth->version = atoi(param);
468 /* skip to next parameter */
469 while ((*end == '"') || (*end == ',') || (*end == ' '))
470 end++;
471 hdr = end;
474 return;
477 static void sign_outgoing_message(struct sipe_core_private *sipe_private,
478 struct sipmsg *msg)
480 struct sip_transport *transport = sipe_private->transport;
481 gchar *buf;
483 if (transport->registrar.type == SIPE_AUTHENTICATION_TYPE_UNSET) {
484 return;
487 sipe_make_signature(sipe_private, msg);
489 buf = auth_header(sipe_private, &transport->registrar, msg);
490 if (buf) {
491 sipmsg_add_header_now(msg, "Authorization", buf);
492 g_free(buf);
497 * NOTE: Do *NOT* call sipe_backend_transport_message(...) directly!
499 * All SIP messages must pass through this function in order to update
500 * the timestamp for keepalive tracking.
502 static void send_sip_message(struct sip_transport *transport,
503 const gchar *string)
505 sipe_utils_message_debug(transport->connection, "SIP", string, NULL, TRUE);
506 transport->last_message = time(NULL);
507 sipe_backend_transport_message(transport->connection, string);
510 static void start_keepalive_timer(struct sipe_core_private *sipe_private,
511 guint seconds);
512 static void keepalive_timeout(struct sipe_core_private *sipe_private,
513 SIPE_UNUSED_PARAMETER gpointer data)
515 struct sip_transport *transport = sipe_private->transport;
516 if (transport) {
517 guint since_last = time(NULL) - transport->last_message;
518 guint restart = transport->keepalive_timeout;
519 if (since_last >= restart) {
520 SIPE_DEBUG_INFO("keepalive_timeout: expired %d", restart);
521 send_sip_message(transport, "\r\n\r\n");
522 } else {
523 /* timeout not reached since last message -> reschedule */
524 restart -= since_last;
526 start_keepalive_timer(sipe_private, restart);
530 static void start_keepalive_timer(struct sipe_core_private *sipe_private,
531 guint seconds)
533 sipe_schedule_seconds(sipe_private,
534 "<+keepalive-timeout>",
535 NULL,
536 seconds,
537 keepalive_timeout,
538 NULL);
541 void sip_transport_response(struct sipe_core_private *sipe_private,
542 struct sipmsg *msg,
543 guint code,
544 const char *text,
545 const char *body)
547 gchar *name;
548 gchar *value;
549 GString *outstr = g_string_new("");
550 gchar *contact;
551 GSList *tmp;
552 static const gchar *keepers[] = { "To", "From", "Call-ID", "CSeq", "Via", "Record-Route", NULL };
554 /* Can return NULL! */
555 contact = get_contact(sipe_private);
556 if (contact) {
557 sipmsg_add_header(msg, "Contact", contact);
558 g_free(contact);
561 if (body) {
562 gchar *len = g_strdup_printf("%" G_GSIZE_FORMAT , (gsize) strlen(body));
563 sipmsg_add_header(msg, "Content-Length", len);
564 g_free(len);
565 } else {
566 sipmsg_add_header(msg, "Content-Length", "0");
569 sipmsg_add_header(msg, "User-Agent", sipe_core_user_agent(sipe_private));
571 msg->response = code;
573 sipmsg_strip_headers(msg, keepers);
574 sipmsg_merge_new_headers(msg);
575 sign_outgoing_message(sipe_private, msg);
577 g_string_append_printf(outstr, "SIP/2.0 %d %s\r\n", code, text);
578 tmp = msg->headers;
579 while (tmp) {
580 name = ((struct sipnameval*) (tmp->data))->name;
581 value = ((struct sipnameval*) (tmp->data))->value;
583 g_string_append_printf(outstr, "%s: %s\r\n", name, value);
584 tmp = g_slist_next(tmp);
586 g_string_append_printf(outstr, "\r\n%s", body ? body : "");
587 send_sip_message(sipe_private->transport, outstr->str);
588 g_string_free(outstr, TRUE);
591 static void transactions_remove(struct sipe_core_private *sipe_private,
592 struct transaction *trans)
594 struct sip_transport *transport = sipe_private->transport;
595 if (transport->transactions) {
596 transport->transactions = g_slist_remove(transport->transactions,
597 trans);
598 SIPE_DEBUG_INFO("SIP transactions count:%d after removal", g_slist_length(transport->transactions));
600 if (trans->msg) sipmsg_free(trans->msg);
601 if (trans->payload) {
602 if (trans->payload->destroy)
603 (*trans->payload->destroy)(trans->payload->data);
604 g_free(trans->payload);
606 g_free(trans->key);
607 if (trans->timeout_key) {
608 sipe_schedule_cancel(sipe_private, trans->timeout_key);
609 g_free(trans->timeout_key);
611 g_free(trans);
615 static struct transaction *transactions_find(struct sip_transport *transport,
616 struct sipmsg *msg)
618 GSList *transactions = transport->transactions;
619 const gchar *call_id = sipmsg_find_call_id_header(msg);
620 const gchar *cseq = sipmsg_find_cseq_header(msg);
621 gchar *key;
623 if (!call_id || !cseq) {
624 SIPE_DEBUG_ERROR_NOFORMAT("transaction_find: no Call-ID or CSeq!");
625 return NULL;
628 key = g_strdup_printf("<%s><%s>", call_id, cseq);
629 while (transactions) {
630 struct transaction *trans = transactions->data;
631 if (!g_ascii_strcasecmp(trans->key, key)) {
632 g_free(key);
633 return trans;
635 transactions = transactions->next;
637 g_free(key);
639 return NULL;
642 static void transaction_timeout_cb(struct sipe_core_private *sipe_private,
643 gpointer data)
645 struct transaction *trans = data;
646 (trans->timeout_callback)(sipe_private, trans->msg, trans);
647 transactions_remove(sipe_private, trans);
650 struct transaction *sip_transport_request_timeout(struct sipe_core_private *sipe_private,
651 const gchar *method,
652 const gchar *url,
653 const gchar *to,
654 const gchar *addheaders,
655 const gchar *body,
656 struct sip_dialog *dialog,
657 TransCallback callback,
658 guint timeout,
659 TransCallback timeout_callback)
661 struct sip_transport *transport = sipe_private->transport;
662 char *buf;
663 struct sipmsg *msg;
664 gchar *ourtag = dialog && dialog->ourtag ? g_strdup(dialog->ourtag) : NULL;
665 gchar *theirtag = dialog && dialog->theirtag ? g_strdup(dialog->theirtag) : NULL;
666 gchar *theirepid = dialog && dialog->theirepid ? g_strdup(dialog->theirepid) : NULL;
667 gchar *callid = dialog && dialog->callid ? g_strdup(dialog->callid) : gencallid();
668 gchar *branch = dialog && dialog->callid ? NULL : genbranch();
669 gchar *route = g_strdup("");
670 const gchar *epid = transport->epid;
671 int cseq = dialog ? ++dialog->cseq : 1 /* as Call-Id is new in this case */;
672 struct transaction *trans = NULL;
674 if (dialog && dialog->routes)
676 GSList *iter = dialog->routes;
678 while(iter)
680 char *tmp = route;
681 route = g_strdup_printf("%sRoute: %s\r\n", route, (char *)iter->data);
682 g_free(tmp);
683 iter = g_slist_next(iter);
687 if (!ourtag && !dialog) {
688 ourtag = gentag();
691 if (sipe_strequal(method, "REGISTER")) {
692 if (sipe_private->register_callid) {
693 g_free(callid);
694 callid = g_strdup(sipe_private->register_callid);
695 } else {
696 sipe_private->register_callid = g_strdup(callid);
698 cseq = ++transport->cseq;
701 buf = g_strdup_printf("%s %s SIP/2.0\r\n"
702 "Via: SIP/2.0/%s %s:%d%s%s\r\n"
703 "From: <sip:%s>%s%s;epid=%s\r\n"
704 "To: <%s>%s%s%s%s\r\n"
705 "Max-Forwards: 70\r\n"
706 "CSeq: %d %s\r\n"
707 "User-Agent: %s\r\n"
708 "Call-ID: %s\r\n"
709 "%s%s"
710 "Content-Length: %" G_GSIZE_FORMAT "\r\n\r\n%s",
711 method,
712 dialog && dialog->request ? dialog->request : url,
713 TRANSPORT_DESCRIPTOR,
714 transport->uri_address,
715 transport->connection->client_port,
716 branch ? ";branch=" : "",
717 branch ? branch : "",
718 sipe_private->username,
719 ourtag ? ";tag=" : "",
720 ourtag ? ourtag : "",
721 epid,
723 theirtag ? ";tag=" : "",
724 theirtag ? theirtag : "",
725 theirepid ? ";epid=" : "",
726 theirepid ? theirepid : "",
727 cseq,
728 method,
729 sipe_core_user_agent(sipe_private),
730 callid,
731 route,
732 addheaders ? addheaders : "",
733 body ? (gsize) strlen(body) : 0,
734 body ? body : "");
737 //printf ("parsing msg buf:\n%s\n\n", buf);
738 msg = sipmsg_parse_msg(buf);
740 g_free(buf);
741 g_free(ourtag);
742 g_free(theirtag);
743 g_free(theirepid);
744 g_free(branch);
745 g_free(route);
747 sign_outgoing_message(sipe_private, msg);
749 /* The authentication scheme is not ready so we can't send the message.
750 This should only happen for REGISTER messages. */
751 if (!transport->auth_incomplete) {
752 buf = sipmsg_to_string(msg);
754 /* add to ongoing transactions */
755 /* ACK isn't supposed to be answered ever. So we do not keep transaction for it. */
756 if (!sipe_strequal(method, "ACK")) {
757 trans = g_new0(struct transaction, 1);
758 trans->callback = callback;
759 trans->msg = msg;
760 trans->key = g_strdup_printf("<%s><%d %s>", callid, cseq, method);
761 if (timeout_callback) {
762 trans->timeout_callback = timeout_callback;
763 trans->timeout_key = g_strdup_printf("<transaction timeout>%s", trans->key);
764 sipe_schedule_seconds(sipe_private,
765 trans->timeout_key,
766 trans,
767 timeout,
768 transaction_timeout_cb,
769 NULL);
771 transport->transactions = g_slist_append(transport->transactions,
772 trans);
773 SIPE_DEBUG_INFO("SIP transactions count:%d after addition", g_slist_length(transport->transactions));
776 send_sip_message(transport, buf);
777 g_free(buf);
780 if (!trans) sipmsg_free(msg);
781 g_free(callid);
782 return trans;
785 struct transaction *sip_transport_request(struct sipe_core_private *sipe_private,
786 const gchar *method,
787 const gchar *url,
788 const gchar *to,
789 const gchar *addheaders,
790 const gchar *body,
791 struct sip_dialog *dialog,
792 TransCallback callback)
794 return sip_transport_request_timeout(sipe_private,
795 method,
796 url,
798 addheaders,
799 body,
800 dialog,
801 callback,
803 NULL);
806 static void sip_transport_simple_request(struct sipe_core_private *sipe_private,
807 const gchar *method,
808 struct sip_dialog *dialog)
810 sip_transport_request(sipe_private,
811 method,
812 dialog->with,
813 dialog->with,
814 NULL,
815 NULL,
816 dialog,
817 NULL);
820 void sip_transport_ack(struct sipe_core_private *sipe_private,
821 struct sip_dialog *dialog)
823 sip_transport_simple_request(sipe_private, "ACK", dialog);
826 void sip_transport_bye(struct sipe_core_private *sipe_private,
827 struct sip_dialog *dialog)
829 sip_transport_simple_request(sipe_private, "BYE", dialog);
832 struct transaction *sip_transport_info(struct sipe_core_private *sipe_private,
833 const gchar *addheaders,
834 const gchar *body,
835 struct sip_dialog *dialog,
836 TransCallback callback)
838 return sip_transport_request(sipe_private,
839 "INFO",
840 dialog->with,
841 dialog->with,
842 addheaders,
843 body,
844 dialog,
845 callback);
848 struct transaction *sip_transport_invite(struct sipe_core_private *sipe_private,
849 const gchar *addheaders,
850 const gchar *body,
851 struct sip_dialog *dialog,
852 TransCallback callback)
854 return sip_transport_request(sipe_private,
855 "INVITE",
856 dialog->with,
857 dialog->with,
858 addheaders,
859 body,
860 dialog,
861 callback);
864 struct transaction *sip_transport_service(struct sipe_core_private *sipe_private,
865 const gchar *uri,
866 const gchar *addheaders,
867 const gchar *body,
868 TransCallback callback)
870 return sip_transport_request(sipe_private,
871 "SERVICE",
872 uri,
873 uri,
874 addheaders,
875 body,
876 NULL,
877 callback);
880 void sip_transport_subscribe(struct sipe_core_private *sipe_private,
881 const gchar *uri,
882 const gchar *addheaders,
883 const gchar *body,
884 struct sip_dialog *dialog,
885 TransCallback callback)
887 sip_transport_request(sipe_private,
888 "SUBSCRIBE",
889 uri,
890 uri,
891 addheaders,
892 body,
893 dialog,
894 callback);
897 void sip_transport_update(struct sipe_core_private *sipe_private,
898 struct sip_dialog *dialog,
899 TransCallback callback)
901 sip_transport_request(sipe_private,
902 "UPDATE",
903 dialog->with,
904 dialog->with,
905 NULL,
906 NULL,
907 dialog,
908 callback);
911 static const gchar *get_auth_header(struct sipe_core_private *sipe_private,
912 guint type,
913 struct sipmsg *msg)
915 struct sip_auth *auth = &sipe_private->transport->registrar;
917 auth->type = type;
918 auth->protocol = auth_type_to_protocol[auth->type];
920 return(sipmsg_find_auth_header(msg, auth->protocol));
923 static void do_register(struct sipe_core_private *sipe_private,
924 gboolean deregister);
926 static void do_reauthenticate_cb(struct sipe_core_private *sipe_private,
927 SIPE_UNUSED_PARAMETER gpointer unused)
929 struct sip_transport *transport = sipe_private->transport;
931 /* register again when security token expires */
932 /* we have to start a new authentication as the security token
933 * is almost expired by sending a not signed REGISTER message */
934 SIPE_LOG_INFO_NOFORMAT("do_reauthenticate_cb: do a full reauthentication");
935 sipe_auth_free(&transport->registrar);
936 sipe_auth_free(&transport->proxy);
937 sipe_schedule_cancel(sipe_private, "<registration>");
938 transport->auth_retry = TRUE;
939 transport->reregister_set = FALSE;
940 transport->register_attempt = 0;
941 do_register(sipe_private, FALSE);
942 transport->reauthenticate_set = FALSE;
945 static void sip_transport_default_contact(struct sipe_core_private *sipe_private)
947 struct sip_transport *transport = sipe_private->transport;
948 sipe_private->contact = g_strdup_printf("<sip:%s:%d;maddr=%s;transport=%s>;proxy=replace",
949 sipe_private->username,
950 transport->connection->client_port,
951 transport->uri_address,
952 TRANSPORT_DESCRIPTOR);
955 static void do_register_cb(struct sipe_core_private *sipe_private,
956 SIPE_UNUSED_PARAMETER void *unused)
958 do_register(sipe_private, FALSE);
961 static void sip_transport_set_reregister(struct sipe_core_private *sipe_private,
962 int expires)
964 sipe_schedule_seconds(sipe_private,
965 "<registration>",
966 NULL,
967 expires,
968 do_register_cb,
969 NULL);
972 static void sipe_server_register(struct sipe_core_private *sipe_private,
973 guint type,
974 gchar *server_name,
975 guint server_port);
977 static gboolean process_register_response(struct sipe_core_private *sipe_private,
978 struct sipmsg *msg,
979 SIPE_UNUSED_PARAMETER struct transaction *trans)
981 struct sip_transport *transport = sipe_private->transport;
982 const gchar *expires_header;
983 int expires, i;
984 GSList *hdr = msg->headers;
985 struct sipnameval *elem;
987 expires_header = sipmsg_find_expires_header(msg);
988 expires = expires_header != NULL ? strtol(expires_header, NULL, 10) : 0;
989 SIPE_DEBUG_INFO("process_register_response: got response to REGISTER; expires = %d", expires);
991 switch (msg->response) {
992 case 200:
993 if (expires) {
994 const gchar *contact_hdr;
995 const gchar *auth_hdr;
996 gchar *gruu = NULL;
997 gchar *uuid;
998 gchar *timeout;
1000 if (!transport->reregister_set) {
1001 /* Schedule re-register 30 seconds before expiration */
1002 if (expires > 30)
1003 expires -= 30;
1004 sip_transport_set_reregister(sipe_private,
1005 expires);
1006 transport->reregister_set = TRUE;
1009 auth_hdr = sipmsg_find_auth_header(msg,
1010 transport->registrar.protocol);
1011 if (auth_hdr) {
1012 SIPE_DEBUG_INFO("process_register_response: Auth header: %s", auth_hdr);
1013 fill_auth(auth_hdr, &transport->registrar);
1016 if (!transport->reauthenticate_set) {
1017 /* [MS-SIPAE] Section 3.2.2 Timers
1019 * When the ... authentication handshake completes
1020 * and the SA enters the "established" state, the
1021 * SIP protocol client MUST start an SA expiration
1022 * timer.
1023 * ...
1024 * The expiration timer value is the lesser of
1026 * - Kerberos: the service ticket expiry time
1027 * - TLS-DSK: the certificate expiration time
1029 * and eight hours, further reduced by some buffer
1030 * time.
1031 * ...
1032 * The protocol client MUST choose a sufficient
1033 * buffer time to allow for the ... authentication
1034 * handshake that reestablishes the SA to complete
1035 * ... This value SHOULD be five (5) minutes or
1036 * longer.
1038 guint reauth_timeout = transport->registrar.expires;
1040 SIPE_LOG_INFO_NOFORMAT("process_register_response: authentication handshake completed successfully");
1042 if ((reauth_timeout == 0) ||
1043 (reauth_timeout > 8 * 60 * 60))
1044 reauth_timeout = 8 * 60 * 60;
1045 if (reauth_timeout > 5 * 60)
1046 reauth_timeout -= 5 * 60;
1048 sipe_schedule_seconds(sipe_private,
1049 "<+reauthentication>",
1050 NULL,
1051 reauth_timeout,
1052 do_reauthenticate_cb,
1053 NULL);
1054 transport->reauthenticate_set = TRUE;
1057 uuid = get_uuid(sipe_private);
1059 // There can be multiple Contact headers (one per location where the user is logged in) so
1060 // make sure to only get the one for this uuid
1061 for (i = 0; (contact_hdr = sipmsg_find_header_instance (msg, "Contact", i)); i++) {
1062 gchar * valid_contact = sipmsg_find_part_of_header (contact_hdr, uuid, NULL, NULL);
1063 if (valid_contact) {
1064 gruu = sipmsg_find_part_of_header(contact_hdr, "gruu=\"", "\"", NULL);
1065 //SIPE_DEBUG_INFO("process_register_response: got gruu %s from contact hdr w/ right uuid: %s", gruu, contact_hdr);
1066 g_free(valid_contact);
1067 break;
1068 } else {
1069 //SIPE_DEBUG_INFO("process_register_response: ignoring contact hdr b/c not right uuid: %s", contact_hdr);
1072 g_free(uuid);
1074 g_free(sipe_private->contact);
1075 if(gruu) {
1076 sipe_private->contact = g_strdup_printf("<%s>", gruu);
1077 g_free(gruu);
1078 } else {
1079 //SIPE_DEBUG_INFO_NOFORMAT("process_register_response: didn't find gruu in a Contact hdr");
1080 sip_transport_default_contact(sipe_private);
1082 SIPE_CORE_PRIVATE_FLAG_UNSET(OCS2007);
1083 SIPE_CORE_PRIVATE_FLAG_UNSET(REMOTE_USER);
1084 SIPE_CORE_PRIVATE_FLAG_UNSET(BATCHED_SUPPORT);
1085 SIPE_CORE_PRIVATE_FLAG_UNSET(SFB);
1087 while(hdr)
1089 elem = hdr->data;
1090 if (sipe_strcase_equal(elem->name, "Supported")) {
1091 if (sipe_strcase_equal(elem->value, "msrtc-event-categories")) {
1092 /* We interpret this as OCS2007+ indicator */
1093 SIPE_CORE_PRIVATE_FLAG_SET(OCS2007);
1094 SIPE_LOG_INFO("process_register_response: Supported: %s (indicates OCS2007+)", elem->value);
1096 if (sipe_strcase_equal(elem->value, "adhoclist")) {
1097 SIPE_CORE_PRIVATE_FLAG_SET(BATCHED_SUPPORT);
1098 SIPE_DEBUG_INFO("process_register_response: Supported: %s", elem->value);
1100 } else if (sipe_strcase_equal(elem->name, "Allow-Events")){
1101 gchar **caps = g_strsplit(elem->value,",",0);
1102 i = 0;
1103 while (caps[i]) {
1104 sipe_private->allowed_events = g_slist_append(sipe_private->allowed_events, g_strdup(caps[i]));
1105 SIPE_DEBUG_INFO("process_register_response: Allow-Events: %s", caps[i]);
1106 i++;
1108 g_strfreev(caps);
1109 } else if (sipe_strcase_equal(elem->name, "ms-user-logon-data")) {
1110 if (sipe_strcase_equal(elem->value, "RemoteUser")) {
1111 SIPE_CORE_PRIVATE_FLAG_SET(REMOTE_USER);
1112 SIPE_DEBUG_INFO_NOFORMAT("process_register_response: ms-user-logon-data: RemoteUser (connected "
1113 "via Edge Server)");
1115 } else if (sipe_strcase_equal(elem->name, "Server")) {
1116 /* Server string has format like 'RTC/6.0'.
1117 * We want to check the first digit. */
1118 gchar **parts = g_strsplit_set(elem->value, "/.", 3);
1119 if (g_strv_length(parts) > 1) {
1120 guint version = atoi(parts[1]);
1121 if (version >= 6) {
1122 SIPE_CORE_PRIVATE_FLAG_SET(SFB);
1123 SIPE_LOG_INFO("process_register_response: server version is %d >= 6 (indicates Skype for Business+)", version);
1126 g_strfreev(parts);
1128 hdr = g_slist_next(hdr);
1131 sipe_backend_connection_completed(SIPE_CORE_PUBLIC);
1133 /* rejoin open chats to be able to use them by continue to send messages */
1134 sipe_backend_chat_rejoin_all(SIPE_CORE_PUBLIC);
1136 /* subscriptions, done only once */
1137 if (!transport->subscribed) {
1138 sipe_subscription_self_events(sipe_private);
1139 transport->subscribed = TRUE;
1142 timeout = sipmsg_find_part_of_header(sipmsg_find_header(msg, "ms-keep-alive"),
1143 "timeout=", ";", NULL);
1144 if (timeout != NULL) {
1145 sscanf(timeout, "%u", &transport->keepalive_timeout);
1146 SIPE_DEBUG_INFO("process_register_response: server determined keep alive timeout is %u seconds",
1147 transport->keepalive_timeout);
1148 g_free(timeout);
1151 SIPE_DEBUG_INFO("process_register_response: got 200, removing CSeq: %d", transport->cseq);
1153 break;
1154 case 301:
1156 gchar *redirect = sipmsg_parse_contact_address(msg);
1158 SIPE_LOG_INFO_NOFORMAT("process_register_response: authentication handshake completed successfully (with redirect)");
1160 if (redirect && (g_ascii_strncasecmp("sip:", redirect, 4) == 0)) {
1161 gchar **parts = g_strsplit(redirect + 4, ";", 0);
1162 gchar **tmp;
1163 gchar *hostname;
1164 int port = 0;
1165 guint transport_type = SIPE_TRANSPORT_TLS;
1166 int i = 1;
1168 tmp = g_strsplit(parts[0], ":", 0);
1169 hostname = g_strdup(tmp[0]);
1170 if (tmp[1]) port = strtoul(tmp[1], NULL, 10);
1171 g_strfreev(tmp);
1173 while (parts[i]) {
1174 tmp = g_strsplit(parts[i], "=", 0);
1175 if (tmp[1]) {
1176 if (g_ascii_strcasecmp("transport", tmp[0]) == 0) {
1177 if (g_ascii_strcasecmp("tcp", tmp[1]) == 0) {
1178 transport_type = SIPE_TRANSPORT_TCP;
1182 g_strfreev(tmp);
1183 i++;
1185 g_strfreev(parts);
1187 /* Close old connection */
1188 sipe_core_connection_cleanup(sipe_private);
1189 /* transport and sipe_private->transport are invalid after this */
1191 /* Create new connection */
1192 sipe_server_register(sipe_private, transport_type, hostname, port);
1193 /* sipe_private->transport has a new value */
1194 SIPE_DEBUG_INFO("process_register_response: redirected to host %s port %d transport %d",
1195 hostname, port, transport_type);
1197 g_free(redirect);
1199 break;
1200 case 401:
1202 const char *auth_hdr = NULL;
1204 SIPE_DEBUG_INFO("process_register_response: REGISTER retries %d", transport->registrar.retries);
1206 if (transport->reauthenticate_set) {
1207 SIPE_DEBUG_ERROR_NOFORMAT("process_register_response: RE-REGISTER rejected, triggering re-authentication");
1208 do_reauthenticate_cb(sipe_private, NULL);
1209 return TRUE;
1212 if (sip_sec_context_is_ready(transport->registrar.gssapi_context)) {
1213 struct sip_auth *auth = &transport->registrar;
1215 /* NTLM is the scheme with lowest priority - don't retry */
1216 if (auth_can_retry(transport, auth)) {
1217 guint failed = auth->type;
1218 SIPE_DEBUG_INFO_NOFORMAT("process_register_response: authentication handshake failed - trying next authentication scheme.");
1219 sipe_auth_free(auth);
1220 auth->type = failed;
1221 } else {
1222 SIPE_LOG_ERROR_NOFORMAT("process_register_response: authentication handshake failed - giving up.");
1223 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1224 SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
1225 _("Authentication failed"));
1226 return TRUE;
1230 if (sipe_private->authentication_type == SIPE_AUTHENTICATION_TYPE_AUTOMATIC) {
1231 struct sip_auth *auth = &transport->registrar;
1232 guint try = auth->type;
1234 while (!auth_hdr) {
1236 * Determine next authentication
1237 * scheme in priority order
1239 if (transport->auth_retry)
1240 switch (try) {
1241 case SIPE_AUTHENTICATION_TYPE_UNSET:
1242 try = SIPE_AUTHENTICATION_TYPE_TLS_DSK;
1243 break;
1245 case SIPE_AUTHENTICATION_TYPE_TLS_DSK:
1246 #if defined(HAVE_GSSAPI_GSSAPI_H) || defined(HAVE_SSPI)
1247 try = SIPE_AUTHENTICATION_TYPE_KERBEROS;
1248 break;
1250 case SIPE_AUTHENTICATION_TYPE_KERBEROS:
1251 #endif
1252 try = SIPE_AUTHENTICATION_TYPE_NTLM;
1253 break;
1255 default:
1256 try = SIPE_AUTHENTICATION_TYPE_UNSET;
1257 break;
1260 auth->can_retry = (try != SIPE_AUTHENTICATION_TYPE_UNSET);
1262 if (!auth->can_retry) {
1263 SIPE_DEBUG_INFO_NOFORMAT("process_register_response: no more authentication schemes to try");
1264 break;
1267 auth_hdr = get_auth_header(sipe_private,
1268 try,
1269 msg);
1272 transport->auth_retry = FALSE;
1274 } else
1275 auth_hdr = get_auth_header(sipe_private,
1276 sipe_private->authentication_type,
1277 msg);
1279 if (!auth_hdr) {
1280 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1281 SIPE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE,
1282 _("Incompatible authentication scheme chosen"));
1283 return TRUE;
1285 SIPE_DEBUG_INFO("process_register_response: Auth header: %s", auth_hdr);
1286 fill_auth(auth_hdr, &transport->registrar);
1287 transport->reregister_set = FALSE;
1288 transport->register_attempt = 0;
1289 do_register(sipe_private,
1290 sipe_backend_connection_is_disconnecting(SIPE_CORE_PUBLIC));
1292 break;
1293 case 403:
1295 gchar *reason;
1296 gchar *warning;
1297 sipmsg_parse_warning(msg, &reason);
1298 reason = reason ? reason : sipmsg_get_ms_diagnostics_public_reason(msg);
1299 warning = g_strdup_printf(_("You have been rejected by the server: %s"),
1300 reason ? reason : _("no reason given"));
1301 g_free(reason);
1303 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1304 SIPE_CONNECTION_ERROR_INVALID_SETTINGS,
1305 warning);
1306 g_free(warning);
1307 return TRUE;
1309 break;
1310 case 404:
1312 const gchar *diagnostics = sipmsg_find_header(msg, "ms-diagnostics");
1313 gchar *reason = sipmsg_get_ms_diagnostics_reason(msg);
1314 gchar *warning;
1315 warning = g_strdup_printf(_("Not found: %s. Please contact your Administrator"),
1316 diagnostics ? (reason ? reason : _("no reason given")) :
1317 _("SIP is either not enabled for the destination URI or it does not exist"));
1318 g_free(reason);
1320 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1321 SIPE_CONNECTION_ERROR_INVALID_USERNAME,
1322 warning);
1323 g_free(warning);
1324 return TRUE;
1326 break;
1327 case 504: /* Server time-out */
1328 /* first attempt + 5 retries */
1329 if (transport->register_attempt < 6) {
1330 SIPE_DEBUG_INFO("process_register_response: RE-REGISTER timeout on attempt %d, retrying later",
1331 transport->register_attempt);
1332 sip_transport_set_reregister(sipe_private, 60);
1333 return TRUE;
1335 /* FALLTHROUGH */
1336 case 503:
1338 gchar *reason = sipmsg_get_ms_diagnostics_reason(msg);
1339 gchar *warning;
1340 warning = g_strdup_printf(_("Service unavailable: %s"), reason ? reason : _("no reason given"));
1341 g_free(reason);
1343 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1344 SIPE_CONNECTION_ERROR_NETWORK,
1345 warning);
1346 g_free(warning);
1347 return TRUE;
1349 break;
1351 return TRUE;
1354 static gboolean register_response_timeout(struct sipe_core_private *sipe_private,
1355 SIPE_UNUSED_PARAMETER struct sipmsg *msg,
1356 SIPE_UNUSED_PARAMETER struct transaction *trans)
1358 struct sip_transport *transport = sipe_private->transport;
1359 if (transport->register_attempt < 6) {
1360 SIPE_DEBUG_INFO("register_response_timeout: no answer to attempt %d, retrying",
1361 transport->register_attempt);
1362 do_register(sipe_private, FALSE);
1363 } else {
1364 gchar *warning = g_strdup_printf(_("Service unavailable: %s"), _("no reason given"));
1365 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1366 SIPE_CONNECTION_ERROR_NETWORK,
1367 warning);
1368 g_free(warning);
1370 return TRUE;
1373 static void do_register(struct sipe_core_private *sipe_private,
1374 gboolean deregister)
1376 struct sip_transport *transport = sipe_private->transport;
1377 char *uri;
1378 char *to;
1379 char *hdr;
1380 char *uuid;
1382 if (!sipe_private->public.sip_domain) return;
1384 if (!deregister) {
1385 if (transport->reregister_set) {
1386 transport->reregister_set = FALSE;
1387 transport->register_attempt = 1;
1388 } else {
1389 transport->register_attempt++;
1393 transport->deregister = deregister;
1394 transport->auth_incomplete = FALSE;
1396 uuid = get_uuid(sipe_private);
1397 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"
1398 "Supported: gruu-10, adhoclist, msrtc-event-categories, com.microsoft.msrtc.presence\r\n"
1399 "Event: registration\r\n"
1400 "Allow-Events: presence\r\n"
1401 "ms-keep-alive: UAC;hop-hop=yes\r\n"
1402 "%s",
1403 transport->uri_address,
1404 transport->connection->client_port,
1405 TRANSPORT_DESCRIPTOR,
1406 uuid,
1407 deregister ? "Expires: 0\r\n" : "");
1408 g_free(uuid);
1410 uri = sip_uri_from_name(sipe_private->public.sip_domain);
1411 to = sip_uri_self(sipe_private);
1412 sip_transport_request_timeout(sipe_private,
1413 "REGISTER",
1414 uri,
1416 hdr,
1418 NULL,
1419 process_register_response,
1421 deregister ? NULL : register_response_timeout);
1422 g_free(to);
1423 g_free(uri);
1424 g_free(hdr);
1426 if (deregister) {
1427 /* Make sure that all messages are pushed to the server
1428 before the connection gets shut down */
1429 SIPE_LOG_INFO_NOFORMAT("De-register from server. Flushing outstanding messages.");
1430 sipe_backend_transport_flush(transport->connection);
1434 void sip_transport_deregister(struct sipe_core_private *sipe_private)
1436 do_register(sipe_private, TRUE);
1439 void sip_transport_drop(struct sipe_core_private *sipe_private)
1441 struct sip_transport *transport = sipe_private->transport;
1443 /* transport can be NULL during connection setup */
1444 if (transport) {
1445 SIPE_LOG_INFO("sip_transport_drop: '%s:%u'(%p)",
1446 transport->server_name,
1447 transport->server_port,
1448 transport->connection);
1450 sipe_backend_transport_disconnect(transport->connection);
1452 sipe_auth_free(&transport->registrar);
1453 sipe_auth_free(&transport->proxy);
1455 g_free(transport->server_name);
1456 g_free(transport->uri_address);
1457 g_free(transport->ip_address);
1458 g_free(transport->epid);
1460 while (transport->transactions)
1461 transactions_remove(sipe_private,
1462 transport->transactions->data);
1464 g_free(transport);
1467 sipe_private->transport = NULL;
1468 sipe_private->service_data = NULL;
1469 sipe_private->address_data = NULL;
1471 sipe_schedule_cancel(sipe_private, "<+keepalive-timeout>");
1473 if (sipe_private->dns_query)
1474 sipe_backend_dns_query_cancel(sipe_private->dns_query);
1478 void sip_transport_authentication_completed(struct sipe_core_private *sipe_private)
1480 do_reauthenticate_cb(sipe_private, NULL);
1483 guint sip_transport_port(struct sipe_core_private *sipe_private)
1485 return sipe_private->transport->server_port;
1488 static void process_input_message(struct sipe_core_private *sipe_private,
1489 struct sipmsg *msg)
1491 struct sip_transport *transport = sipe_private->transport;
1492 gboolean notfound = FALSE;
1493 const char *method = msg->method ? msg->method : "NOT FOUND";
1495 SIPE_DEBUG_INFO("process_input_message: msg->response(%d),msg->method(%s)",
1496 msg->response, method);
1498 if (msg->response == 0) { /* request */
1499 if (sipe_strequal(method, "MESSAGE")) {
1500 process_incoming_message(sipe_private, msg);
1501 } else if (sipe_strequal(method, "NOTIFY")) {
1502 SIPE_DEBUG_INFO_NOFORMAT("send->process_incoming_notify");
1503 process_incoming_notify(sipe_private, msg);
1504 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
1505 } else if (sipe_strequal(method, "BENOTIFY")) {
1506 SIPE_DEBUG_INFO_NOFORMAT("send->process_incoming_benotify");
1507 process_incoming_notify(sipe_private, msg);
1508 } else if (sipe_strequal(method, "INVITE")) {
1509 process_incoming_invite(sipe_private, msg);
1510 } else if (sipe_strequal(method, "REFER")) {
1511 process_incoming_refer(sipe_private, msg);
1512 } else if (sipe_strequal(method, "OPTIONS")) {
1513 process_incoming_options(sipe_private, msg);
1514 } else if (sipe_strequal(method, "INFO")) {
1515 process_incoming_info(sipe_private, msg);
1516 } else if (sipe_strequal(method, "ACK")) {
1517 /* ACK's don't need any response */
1518 } else if (sipe_strequal(method, "PRACK")) {
1519 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
1520 } else if (sipe_strequal(method, "SUBSCRIBE")) {
1521 /* LCS 2005 sends us these - just respond 200 OK */
1522 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
1523 } else if (sipe_strequal(method, "CANCEL")) {
1524 process_incoming_cancel(sipe_private, msg);
1525 } else if (sipe_strequal(method, "BYE")) {
1526 process_incoming_bye(sipe_private, msg);
1527 } else {
1528 sip_transport_response(sipe_private, msg, 501, "Not implemented", NULL);
1529 notfound = TRUE;
1532 } else { /* response */
1533 struct transaction *trans = transactions_find(transport, msg);
1534 if (trans) {
1535 if (msg->response < 200) {
1536 /* ignore provisional response */
1537 SIPE_DEBUG_INFO("process_input_message: got provisional (%d) response, ignoring", msg->response);
1539 /* Transaction not yet completed */
1540 trans = NULL;
1542 } else if (msg->response == 401) { /* Unauthorized */
1544 if (sipe_strequal(trans->msg->method, "REGISTER")) {
1545 /* Expected response during authentication handshake */
1546 transport->registrar.retries++;
1547 SIPE_DEBUG_INFO("process_input_message: RE-REGISTER CSeq: %d", transport->cseq);
1548 } else {
1549 gchar *resend;
1551 /* Are we registered? */
1552 if (transport->reregister_set) {
1553 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: 401 response to non-REGISTER message. Retrying with new authentication.");
1554 sipmsg_remove_header_now(trans->msg, "Authorization");
1555 sign_outgoing_message(sipe_private,
1556 trans->msg);
1557 } else {
1559 * We don't have a valid authentication at the moment.
1560 * Resend message unchanged. It will be rejected again
1561 * and hopefully by then we have a valid authentication.
1563 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: 401 response to non-REGISTER message. Bouncing...");
1566 /* Resend request */
1567 resend = sipmsg_to_string(trans->msg);
1568 send_sip_message(sipe_private->transport, resend);
1569 g_free(resend);
1571 /* Transaction not yet completed */
1572 trans = NULL;
1575 } else if (msg->response == 407) { /* Proxy Authentication Required */
1577 if (transport->proxy.retries++ <= 30) {
1578 const gchar *proxy_hdr = sipmsg_find_header(msg, "Proxy-Authenticate");
1580 if (proxy_hdr) {
1581 gchar *auth = NULL;
1583 if (!g_ascii_strncasecmp(proxy_hdr, "Digest", 6)) {
1584 auth = sip_sec_digest_authorization(sipe_private,
1585 proxy_hdr + 7,
1586 msg->method,
1587 msg->target);
1588 } else {
1589 guint i;
1591 transport->proxy.type = SIPE_AUTHENTICATION_TYPE_UNSET;
1592 for (i = 0; i < AUTH_PROTOCOLS; i++) {
1593 const gchar *protocol = auth_type_to_protocol[i];
1594 if (protocol &&
1595 !g_ascii_strncasecmp(proxy_hdr, protocol, strlen(protocol))) {
1596 SIPE_DEBUG_INFO("process_input_message: proxy authentication scheme '%s'", protocol);
1597 transport->proxy.type = i;
1598 transport->proxy.protocol = protocol;
1599 fill_auth(proxy_hdr, &transport->proxy);
1600 auth = auth_header(sipe_private, &transport->proxy, trans->msg);
1601 break;
1606 if (auth) {
1607 gchar *resend;
1609 /* replace old proxy authentication with new one */
1610 sipmsg_remove_header_now(trans->msg, "Proxy-Authorization");
1611 sipmsg_add_header_now(trans->msg, "Proxy-Authorization", auth);
1612 g_free(auth);
1614 /* resend request with proxy authentication */
1615 resend = sipmsg_to_string(trans->msg);
1616 send_sip_message(sipe_private->transport, resend);
1617 g_free(resend);
1619 /* Transaction not yet completed */
1620 trans = NULL;
1622 } else
1623 SIPE_DEBUG_ERROR_NOFORMAT("process_input_message: can't generate proxy authentication. Giving up.");
1624 } else
1625 SIPE_DEBUG_ERROR_NOFORMAT("process_input_message: 407 response without 'Proxy-Authenticate' header. Giving up.");
1626 } else
1627 SIPE_DEBUG_ERROR_NOFORMAT("process_input_message: too many proxy authentication retries. Giving up.");
1629 } else {
1630 transport->registrar.retries = 0;
1631 transport->proxy.retries = 0;
1634 /* Is transaction completed? */
1635 if (trans) {
1636 if (trans->callback) {
1637 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: we have a transaction callback");
1638 /* call the callback to process response */
1639 (trans->callback)(sipe_private, msg, trans);
1640 /* transport && trans no longer valid after redirect */
1644 * Redirect case: sipe_private->transport is
1645 * the new transport with empty queue
1647 if (sipe_private->transport->transactions) {
1648 SIPE_DEBUG_INFO("process_input_message: removing CSeq %d", transport->cseq);
1649 transactions_remove(sipe_private, trans);
1652 } else {
1653 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: received response to unknown transaction");
1654 notfound = TRUE;
1658 if (notfound) {
1659 SIPE_DEBUG_INFO("received a unknown sip message with method %s and response %d", method, msg->response);
1663 static void sip_transport_input(struct sipe_transport_connection *conn)
1665 struct sipe_core_private *sipe_private = conn->user_data;
1666 struct sip_transport *transport = sipe_private->transport;
1667 gchar *cur = conn->buffer;
1669 /* according to the RFC remove CRLF at the beginning */
1670 while (*cur == '\r' || *cur == '\n') {
1671 cur++;
1673 if (cur != conn->buffer)
1674 sipe_utils_shrink_buffer(conn, cur);
1676 /* Received a full Header? */
1677 transport->processing_input = TRUE;
1678 while (transport->processing_input &&
1679 ((cur = strstr(conn->buffer, "\r\n\r\n")) != NULL)) {
1680 struct sipmsg *msg;
1681 guint remainder;
1683 cur += 2;
1684 cur[0] = '\0';
1685 msg = sipmsg_parse_header(conn->buffer);
1687 cur += 2;
1688 remainder = conn->buffer_used - (cur - conn->buffer);
1689 if (msg && remainder >= (guint) msg->bodylen) {
1690 char *dummy = g_malloc(msg->bodylen + 1);
1691 memcpy(dummy, cur, msg->bodylen);
1692 dummy[msg->bodylen] = '\0';
1693 msg->body = dummy;
1694 cur += msg->bodylen;
1695 sipe_utils_message_debug(conn,
1696 "SIP",
1697 conn->buffer,
1698 msg->body,
1699 FALSE);
1700 sipe_utils_shrink_buffer(conn, cur);
1701 } else {
1702 if (msg) {
1703 SIPE_DEBUG_INFO("sipe_transport_input: body too short (%d < %d, strlen %d) - ignoring message", remainder, msg->bodylen, (int)strlen(conn->buffer));
1704 sipmsg_free(msg);
1707 /* restore header for next try */
1708 cur[-2] = '\r';
1709 return;
1712 /* Fatal header parse error? */
1713 if (msg->response == SIPMSG_RESPONSE_FATAL_ERROR) {
1714 /* can't proceed -> drop connection */
1715 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1716 SIPE_CONNECTION_ERROR_NETWORK,
1717 _("Corrupted message received"));
1718 transport->processing_input = FALSE;
1720 /* Verify the signature before processing it */
1721 } else if (sip_sec_context_is_ready(transport->registrar.gssapi_context)) {
1722 struct sipmsg_breakdown msgbd;
1723 gchar *signature_input_str;
1724 gchar *rspauth;
1725 msgbd.msg = msg;
1726 sipmsg_breakdown_parse(&msgbd, transport->registrar.realm, transport->registrar.target,
1727 transport->registrar.protocol);
1728 signature_input_str = sipmsg_breakdown_get_string(transport->registrar.version, &msgbd);
1730 rspauth = sipmsg_find_part_of_header(sipmsg_find_header(msg, "Authentication-Info"), "rspauth=\"", "\"", NULL);
1732 if (rspauth != NULL) {
1733 if (sip_sec_verify_signature(transport->registrar.gssapi_context, signature_input_str, rspauth)) {
1734 SIPE_DEBUG_INFO_NOFORMAT("sip_transport_input: signature of incoming message validated");
1735 process_input_message(sipe_private, msg);
1736 /* transport is invalid after redirect */
1737 } else {
1738 SIPE_DEBUG_INFO_NOFORMAT("sip_transport_input: signature of incoming message is invalid.");
1739 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1740 SIPE_CONNECTION_ERROR_NETWORK,
1741 _("Invalid message signature received"));
1742 transport->processing_input = FALSE;
1744 } else if ((msg->response == 401) ||
1745 sipe_strequal(msg->method, "REGISTER")) {
1746 /* a) Retry non-REGISTER requests with updated authentication */
1747 /* b) We must always process REGISTER responses */
1748 process_input_message(sipe_private, msg);
1749 } else {
1750 /* OCS sends provisional messages that are *not* signed */
1751 if (msg->response >= 200) {
1752 /* We are not calling process_input_message(),
1753 so we need to drop the transaction here. */
1754 struct transaction *trans = transactions_find(transport, msg);
1755 if (trans) transactions_remove(sipe_private, trans);
1757 SIPE_DEBUG_INFO_NOFORMAT("sip_transport_input: message without authentication data - ignoring");
1759 g_free(signature_input_str);
1761 g_free(rspauth);
1762 sipmsg_breakdown_free(&msgbd);
1763 } else {
1764 process_input_message(sipe_private, msg);
1767 sipmsg_free(msg);
1769 /* Redirect: old content of "transport" & "conn" is no longer valid */
1770 transport = sipe_private->transport;
1771 conn = transport->connection;
1775 static void sip_transport_connected(struct sipe_transport_connection *conn)
1777 struct sipe_core_private *sipe_private = conn->user_data;
1778 struct sip_transport *transport = sipe_private->transport;
1779 gchar *self_sip_uri = sip_uri_self(sipe_private);
1781 SIPE_LOG_INFO("sip_transport_connected: '%s:%u'(%p)",
1782 transport->server_name, transport->server_port, conn);
1784 while (sipe_private->lync_autodiscover_servers)
1785 sipe_private->lync_autodiscover_servers =
1786 sipe_lync_autodiscover_pop(sipe_private->lync_autodiscover_servers);
1788 sipe_private->service_data = NULL;
1789 sipe_private->address_data = NULL;
1792 * Initial keepalive timeout during REGISTER phase
1794 * NOTE: 60 seconds is a guess. Needs more testing!
1796 transport->keepalive_timeout = 60;
1797 start_keepalive_timer(sipe_private, transport->keepalive_timeout);
1799 transport->ip_address = sipe_backend_transport_ip_address(conn);
1800 if (strchr(transport->ip_address, ':') != NULL)
1801 /* RFC2732: Format for Literal IPv6 Addresses in URL's */
1802 transport->uri_address = g_strdup_printf("[%s]", transport->ip_address);
1803 else
1804 transport->uri_address = g_strdup(transport->ip_address);
1805 transport->sdp_marker = sipe_utils_ip_sdp_address_marker(transport->ip_address);
1806 transport->epid = sipe_get_epid(self_sip_uri,
1807 g_get_host_name(),
1808 transport->ip_address);
1809 g_free(self_sip_uri);
1811 do_register(sipe_private, FALSE);
1814 static void resolve_next_lync(struct sipe_core_private *sipe_private);
1815 static void resolve_next_service(struct sipe_core_private *sipe_private,
1816 const struct sip_service_data *start);
1817 static void resolve_next_address(struct sipe_core_private *sipe_private,
1818 gboolean initial);
1819 static void sip_transport_error(struct sipe_transport_connection *conn,
1820 const gchar *msg)
1822 struct sipe_core_private *sipe_private = conn->user_data;
1824 /* This failed attempt was based on a Lync Autodiscover result */
1825 if (sipe_private->lync_autodiscover_servers) {
1826 resolve_next_lync(sipe_private);
1827 /* This failed attempt was based on a DNS SRV record */
1828 } else if (sipe_private->service_data) {
1829 resolve_next_service(sipe_private, NULL);
1830 /* This failed attempt was based on a DNS A record */
1831 } else if (sipe_private->address_data) {
1832 resolve_next_address(sipe_private, FALSE);
1833 } else {
1834 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1835 SIPE_CONNECTION_ERROR_NETWORK,
1836 msg);
1840 /* server_name must be g_alloc()'ed */
1841 static void sipe_server_register(struct sipe_core_private *sipe_private,
1842 guint type,
1843 gchar *server_name,
1844 guint server_port)
1846 sipe_connect_setup setup = {
1847 type,
1848 server_name,
1849 (server_port != 0) ? server_port :
1850 (type == SIPE_TRANSPORT_TLS) ? 5061 : 5060,
1851 sipe_private,
1852 sip_transport_connected,
1853 sip_transport_input,
1854 sip_transport_error
1856 struct sip_transport *transport = g_new0(struct sip_transport, 1);
1858 transport->auth_retry = TRUE;
1859 transport->server_name = server_name;
1860 transport->server_port = setup.server_port;
1861 transport->connection = sipe_backend_transport_connect(SIPE_CORE_PUBLIC,
1862 &setup);
1863 sipe_private->transport = transport;
1866 struct sip_service_data {
1867 const char *protocol;
1868 const char *transport;
1869 guint type;
1873 * Autodiscover using DNS SRV records. See RFC2782/3263
1875 * Service list for AUTO
1877 static const struct sip_service_data service_autodetect[] = {
1878 { "sipinternaltls", "tcp", SIPE_TRANSPORT_TLS }, /* for internal TLS connections */
1879 { "sipinternal", "tcp", SIPE_TRANSPORT_TCP }, /* for internal TCP connections */
1880 { "sip", "tls", SIPE_TRANSPORT_TLS }, /* for external TLS connections */
1881 { "sip", "tcp", SIPE_TRANSPORT_TCP }, /*.for external TCP connections */
1882 { NULL, NULL, 0 }
1885 /* Service list for SSL/TLS */
1886 static const struct sip_service_data service_tls[] = {
1887 { "sipinternaltls", "tcp", SIPE_TRANSPORT_TLS }, /* for internal TLS connections */
1888 { "sip", "tls", SIPE_TRANSPORT_TLS }, /* for external TLS connections */
1889 { NULL, NULL, 0 }
1892 /* Service list for TCP */
1893 static const struct sip_service_data service_tcp[] = {
1894 { "sipinternal", "tcp", SIPE_TRANSPORT_TCP }, /* for internal TCP connections */
1895 { "sip", "tcp", SIPE_TRANSPORT_TCP }, /*.for external TCP connections */
1896 { NULL, NULL, 0 }
1899 static const struct sip_service_data *services[] = {
1900 service_autodetect, /* SIPE_TRANSPORT_AUTO */
1901 service_tls, /* SIPE_TRANSPORT_TLS */
1902 service_tcp /* SIPE_TRANSPORT_TCP */
1905 struct sip_address_data {
1906 const char *prefix;
1907 guint port;
1911 * Autodiscover using DNS A records. This is an extension addded
1912 * by Microsoft. See http://support.microsoft.com/kb/2619522
1914 static const struct sip_address_data addresses[] = {
1915 { "sipinternal", 5061 },
1916 { "sipexternal", 443 },
1918 * Our implementation supports only one port per host name. If the host name
1919 * resolves OK, we abort the search and try to connect. If we would know if we
1920 * are trying to connect from "Intranet" or "Internet" then we could choose
1921 * between those two ports.
1923 * We drop port 5061 in order to cover the "Internet" case.
1925 * { "sip", 5061 },
1927 { "sip", 443 },
1928 { NULL, 0 }
1931 static void sipe_core_dns_resolved(struct sipe_core_public *sipe_public,
1932 const gchar *hostname, guint port)
1934 struct sipe_core_private *sipe_private = SIPE_CORE_PRIVATE;
1935 gboolean service = sipe_private->service_data != NULL;
1937 sipe_private->dns_query = NULL;
1939 if (hostname) {
1940 gchar *host;
1941 guint type;
1943 if (service) {
1944 host = g_strdup(hostname);
1945 type = sipe_private->service_data->type;
1946 } else {
1947 /* DNS A resolver returns an IP address */
1948 host = g_strdup_printf("%s.%s",
1949 sipe_private->address_data->prefix,
1950 sipe_private->public.sip_domain);
1951 port = sipe_private->address_data->port;
1952 type = sipe_private->transport_type;
1953 if (type == SIPE_TRANSPORT_AUTO)
1954 type = SIPE_TRANSPORT_TLS;
1957 SIPE_DEBUG_INFO("sipe_core_dns_resolved - %s hostname: %s port: %d",
1958 service ? "SRV" : "A", hostname, port);
1959 sipe_server_register(sipe_private, type, host, port);
1960 } else {
1961 if (service)
1962 resolve_next_service(SIPE_CORE_PRIVATE, NULL);
1963 else
1964 resolve_next_address(SIPE_CORE_PRIVATE, FALSE);
1968 static void resolve_next_lync(struct sipe_core_private *sipe_private)
1970 struct sipe_lync_autodiscover_data *lync_data = sipe_private->lync_autodiscover_servers->data;
1971 guint type = sipe_private->transport_type;
1973 if (lync_data) {
1974 /* Try to connect to next server on the list */
1975 if (type == SIPE_TRANSPORT_AUTO)
1976 type = SIPE_TRANSPORT_TLS;
1978 sipe_server_register(sipe_private,
1979 type,
1980 g_strdup(lync_data->server),
1981 lync_data->port);
1983 } else {
1984 /* We tried all servers -> try DNS SRV next */
1985 SIPE_LOG_INFO_NOFORMAT("no Lync Autodiscover servers found; trying SRV records next");
1986 resolve_next_service(sipe_private, services[type]);
1989 sipe_private->lync_autodiscover_servers =
1990 sipe_lync_autodiscover_pop(sipe_private->lync_autodiscover_servers);
1993 static void resolve_next_service(struct sipe_core_private *sipe_private,
1994 const struct sip_service_data *start)
1996 if (start) {
1997 sipe_private->service_data = start;
1998 } else {
1999 sipe_private->service_data++;
2000 if (sipe_private->service_data->protocol == NULL) {
2002 /* We tried all services */
2003 sipe_private->service_data = NULL;
2005 /* Try A records list next */
2006 SIPE_LOG_INFO_NOFORMAT("no SRV records found; trying A records next");
2007 resolve_next_address(sipe_private, TRUE);
2008 return;
2012 /* Try to resolve next service */
2013 sipe_private->dns_query = sipe_backend_dns_query_srv(
2014 SIPE_CORE_PUBLIC,
2015 sipe_private->service_data->protocol,
2016 sipe_private->service_data->transport,
2017 sipe_private->public.sip_domain,
2018 (sipe_dns_resolved_cb) sipe_core_dns_resolved,
2019 SIPE_CORE_PUBLIC);
2022 static void resolve_next_address(struct sipe_core_private *sipe_private,
2023 gboolean initial)
2025 gchar *hostname;
2027 if (initial) {
2028 sipe_private->address_data = addresses;
2029 } else {
2030 sipe_private->address_data++;
2031 if (sipe_private->address_data->prefix == NULL) {
2032 guint type = sipe_private->transport_type;
2034 /* We tried all addresss */
2035 sipe_private->address_data = NULL;
2037 /* Try connecting to the SIP hostname directly */
2038 SIPE_LOG_INFO_NOFORMAT("no SRV or A records found; using SIP domain as fallback");
2039 if (type == SIPE_TRANSPORT_AUTO)
2040 type = SIPE_TRANSPORT_TLS;
2042 sipe_server_register(sipe_private, type,
2043 g_strdup(sipe_private->public.sip_domain),
2045 return;
2049 /* Try to resolve next address */
2050 hostname = g_strdup_printf("%s.%s",
2051 sipe_private->address_data->prefix,
2052 sipe_private->public.sip_domain);
2053 sipe_private->dns_query = sipe_backend_dns_query_a(
2054 SIPE_CORE_PUBLIC,
2055 hostname,
2056 sipe_private->address_data->port,
2057 (sipe_dns_resolved_cb) sipe_core_dns_resolved,
2058 SIPE_CORE_PUBLIC);
2059 g_free(hostname);
2062 static void lync_autodiscover_cb(struct sipe_core_private *sipe_private,
2063 GSList *servers,
2064 SIPE_UNUSED_PARAMETER gpointer callback_data)
2066 if (servers) {
2067 /* Lync Autodiscover succeeded */
2068 SIPE_DEBUG_INFO_NOFORMAT("lync_autodiscover_cb: got server list");
2070 sipe_private->lync_autodiscover_servers = servers;
2071 resolve_next_lync(sipe_private);
2076 * NOTE: this function can be called before sipe_core_allocate()!
2078 gboolean sipe_core_transport_sip_requires_password(guint authentication,
2079 gboolean sso)
2081 return(sip_sec_requires_password(authentication, sso));
2084 void sipe_core_transport_sip_connect(struct sipe_core_public *sipe_public,
2085 guint transport,
2086 guint authentication,
2087 const gchar *server,
2088 const gchar *port)
2090 struct sipe_core_private *sipe_private = SIPE_CORE_PRIVATE;
2092 /* backend initialization is complete */
2093 sipe_core_backend_initialized(sipe_private, authentication);
2096 * Initializing the certificate sub-system will trigger the generation
2097 * of a cryptographic key pair which takes time. If we do this after we
2098 * have connected to the server then there is a risk that we run into a
2099 * SIP connection timeout. So let's get this out of the way now...
2101 * This is currently only needed if the user has selected TLS-DSK.
2103 if (sipe_private->authentication_type == SIPE_AUTHENTICATION_TYPE_TLS_DSK)
2104 sipe_certificate_init(sipe_private);
2106 if (server) {
2107 /* Use user specified server[:port] */
2108 int port_number = 0;
2110 if (port)
2111 port_number = atoi(port);
2113 SIPE_LOG_INFO("sipe_core_connect: user specified SIP server %s:%d",
2114 server, port_number);
2116 sipe_server_register(sipe_private, transport,
2117 g_strdup(server), port_number);
2118 } else {
2119 /* Server auto-discovery */
2121 /* Remember user specified transport type */
2122 sipe_private->transport_type = transport;
2124 /* Start with Lync Autodiscover first */
2125 sipe_lync_autodiscover_start(sipe_private,
2126 lync_autodiscover_cb,
2127 NULL);
2131 const gchar *sipe_core_transport_sip_server_name(struct sipe_core_public *sipe_public)
2133 struct sip_transport *transport = SIPE_CORE_PRIVATE->transport;
2134 return(transport ? transport->server_name : NULL);
2137 int sip_transaction_cseq(struct transaction *trans)
2139 int cseq;
2141 g_return_val_if_fail(trans && trans->key, 0);
2143 sscanf(trans->key, "<%*[a-zA-Z0-9]><%d INVITE>", &cseq);
2144 return cseq;
2147 const gchar *sip_transport_epid(struct sipe_core_private *sipe_private)
2149 return(sipe_private->transport ?
2150 sipe_private->transport->epid :
2151 "0123456789ab");
2154 const gchar *sip_transport_ip_address(struct sipe_core_private *sipe_private)
2156 return(sipe_private->transport ?
2157 sipe_private->transport->ip_address :
2158 "0.0.0.0");
2161 const gchar *sip_transport_sdp_address_marker(struct sipe_core_private *sipe_private)
2163 return(sipe_private->transport ?
2164 sipe_private->transport->sdp_marker :
2165 "IP4");
2169 Local Variables:
2170 mode: c
2171 c-file-style: "bsd"
2172 indent-tabs-mode: t
2173 tab-width: 8
2174 End: