core cleanup: move out allow_events field
[siplcs.git] / src / core / sip-transport.c
blobd686bc905d91b7afbbacae79a299294cddbe8e02
1 /**
2 * @file sip-transport.c
4 * pidgin-sipe
6 * Copyright (C) 2010-11 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.
51 #ifdef HAVE_CONFIG_H
52 #include "config.h"
53 #endif
55 #include <stdlib.h>
56 #include <string.h>
57 #include <stdio.h>
59 #include <glib.h>
61 #include "sipe-common.h"
62 #include "sipmsg.h"
63 #include "sip-sec.h"
64 #include "sip-transport.h"
65 #include "sipe-backend.h"
66 #include "sipe-core.h"
67 #include "sipe-core-private.h"
68 #include "sipe-certificate.h"
69 #include "sipe-dialog.h"
70 #include "sipe-incoming.h"
71 #include "sipe-nls.h"
72 #include "sipe-notify.h"
73 #include "sipe-schedule.h"
74 #include "sipe-sign.h"
75 #include "sipe-subscriptions.h"
76 #include "sipe-utils.h"
77 #include "sipe.h"
79 struct sip_auth {
80 guint type;
81 struct sip_sec_context *gssapi_context;
82 gchar *gssapi_data;
83 gchar *opaque;
84 const gchar *protocol;
85 gchar *realm;
86 gchar *sts_uri;
87 gchar *target;
88 int version;
89 int retries;
90 int ntlm_num;
91 int expires;
94 /* sip-transport.c private data */
95 struct sip_transport {
96 struct sipe_transport_connection *connection;
98 gchar *server_name;
99 guint server_port;
100 gchar *server_version;
102 gchar *user_agent;
104 GSList *transactions;
106 struct sip_auth registrar;
107 struct sip_auth proxy;
109 guint cseq;
110 guint register_attempt;
112 gboolean processing_input; /* whether full header received */
113 gboolean auth_incomplete; /* whether authentication not completed */
114 gboolean reregister_set; /* whether reregister timer set */
115 gboolean reauthenticate_set; /* whether reauthenticate timer set */
116 gboolean subscribed; /* whether subscribed to events, except buddies presence */
119 /* Keep in sync with sipe_transport_type! */
120 static const char *transport_descriptor[] = { "", "tls", "tcp"};
121 #define TRANSPORT_DESCRIPTOR (transport_descriptor[transport->connection->type])
123 static char *genbranch()
125 return g_strdup_printf("z9hG4bK%04X%04X%04X%04X%04X",
126 rand() & 0xFFFF, rand() & 0xFFFF, rand() & 0xFFFF,
127 rand() & 0xFFFF, rand() & 0xFFFF);
130 static void sipe_auth_free(struct sip_auth *auth)
132 g_free(auth->opaque);
133 auth->opaque = NULL;
134 auth->protocol = NULL;
135 g_free(auth->realm);
136 auth->realm = NULL;
137 g_free(auth->sts_uri);
138 auth->sts_uri = NULL;
139 g_free(auth->target);
140 auth->target = NULL;
141 auth->version = 0;
142 auth->type = AUTH_TYPE_UNSET;
143 auth->retries = 0;
144 auth->expires = 0;
145 g_free(auth->gssapi_data);
146 auth->gssapi_data = NULL;
147 sip_sec_destroy_context(auth->gssapi_context);
148 auth->gssapi_context = NULL;
151 static void sipe_make_signature(struct sipe_core_private *sipe_private,
152 struct sipmsg *msg)
154 struct sip_transport *transport = sipe_private->transport;
155 if (sip_sec_context_is_ready(transport->registrar.gssapi_context)) {
156 struct sipmsg_breakdown msgbd;
157 gchar *signature_input_str;
158 msgbd.msg = msg;
159 sipmsg_breakdown_parse(&msgbd, transport->registrar.realm, transport->registrar.target,
160 transport->registrar.protocol);
161 msgbd.rand = g_strdup_printf("%08x", g_random_int());
162 transport->registrar.ntlm_num++;
163 msgbd.num = g_strdup_printf("%d", transport->registrar.ntlm_num);
164 signature_input_str = sipmsg_breakdown_get_string(transport->registrar.version, &msgbd);
165 if (signature_input_str != NULL) {
166 char *signature_hex = sip_sec_make_signature(transport->registrar.gssapi_context, signature_input_str);
167 msg->signature = signature_hex;
168 msg->rand = g_strdup(msgbd.rand);
169 msg->num = g_strdup(msgbd.num);
170 g_free(signature_input_str);
172 sipmsg_breakdown_free(&msgbd);
176 static gchar *auth_header_version(struct sip_auth *auth)
178 return(auth->version > 2 ?
179 g_strdup_printf(", version=%d", auth->version) :
180 g_strdup(""));
183 static const gchar *const auth_type_to_protocol[] = {
184 NULL, /* AUTH_TYPE_UNSET */
185 "NTLM", /* AUTH_TYPE_NTLM */
186 "Kerberos", /* AUTH_TYPE_KERBEROS */
187 NULL, /* AUTH_TYPE_NEGOTIATE */
188 "TLS-DSK", /* AUTH_TYPE_TLS_DSK */
190 #define AUTH_PROTOCOLS (sizeof(auth_type_to_protocol)/sizeof(gchar *))
192 static gchar *msg_signature_to_auth(struct sip_auth *auth,
193 struct sipmsg *msg)
195 return(g_strdup_printf("%s qop=\"auth\", opaque=\"%s\", realm=\"%s\", targetname=\"%s\", crand=\"%s\", cnum=\"%s\", response=\"%s\"",
196 auth->protocol,
197 auth->opaque, auth->realm, auth->target,
198 msg->rand, msg->num, msg->signature));
201 static gchar *initialize_auth_context(struct sipe_core_private *sipe_private,
202 struct sip_auth *auth,
203 struct sipmsg *msg)
205 gchar *ret;
206 gchar *gssapi_data = NULL;
207 gchar *sign_str;
208 gchar *gssapi_str;
209 gchar *opaque_str;
210 gchar *version_str;
212 /* Create security context or handshake continuation? */
213 if (auth->gssapi_context) {
214 /* Perform next step in authentication handshake */
215 int status = sip_sec_init_context_step(auth->gssapi_context,
216 auth->target,
217 auth->gssapi_data,
218 &gssapi_data,
219 &auth->expires);
221 /* If authentication is completed gssapi_data can be NULL */
222 if ((status < 0) ||
223 !(sip_sec_context_is_ready(auth->gssapi_context) || gssapi_data)) {
224 SIPE_DEBUG_ERROR_NOFORMAT("initialize_auth_context: security context continuation failed");
225 g_free(gssapi_data);
226 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
227 SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
228 _("Failed to authenticate to server"));
229 return NULL;
232 } else {
233 /* Create security context */
234 struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE;
235 const gchar *authuser = sip->authuser;
236 gpointer password = sip->password;
238 if (is_empty(authuser)) {
239 authuser = sipe_private->username;
242 /* For TLS-DSK the "password" is a certificate */
243 if (auth->type == AUTH_TYPE_TLS_DSK) {
244 password = sipe_certificate_tls_dsk_find(sipe_private,
245 auth->target);
247 if (!password) {
248 if (auth->sts_uri) {
249 SIPE_DEBUG_INFO("initialize_auth_context: TLS-DSK Certificate Provisioning URI %s",
250 auth->sts_uri);
251 if (!sipe_certificate_tls_dsk_generate(sipe_private,
252 auth->target,
253 auth->sts_uri)) {
254 gchar *tmp = g_strdup_printf(_("Can't request certificate from %s"),
255 auth->sts_uri);
256 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
257 SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
258 tmp);
259 g_free(tmp);
261 } else {
262 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
263 SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
264 _("No URI for certificate provisioning service provided"));
267 /* we can't authenticate the message yet */
268 sipe_private->transport->auth_incomplete = TRUE;
270 return(NULL);
271 } else {
272 SIPE_DEBUG_INFO("initialize_auth_context: TLS-DSK certificate for target '%s' found.",
273 auth->target);
277 gssapi_data = sip_sec_init_context(&(auth->gssapi_context),
278 &(auth->expires),
279 auth->type,
280 SIPE_CORE_PUBLIC_FLAG_IS(SSO),
281 sip->authdomain ? sip->authdomain : "",
282 authuser,
283 password,
284 auth->target,
285 auth->gssapi_data);
286 if (!gssapi_data || !auth->gssapi_context) {
287 g_free(gssapi_data);
288 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
289 SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
290 _("Failed to authenticate to server"));
291 return NULL;
295 if ((auth->version > 3) &&
296 sip_sec_context_is_ready(auth->gssapi_context)) {
297 sipe_make_signature(sipe_private, msg);
298 sign_str = g_strdup_printf(", crand=\"%s\", cnum=\"%s\", response=\"%s\"",
299 msg->rand, msg->num, msg->signature);
300 } else {
301 sign_str = g_strdup("");
304 if (gssapi_data) {
305 gssapi_str = g_strdup_printf(", gssapi-data=\"%s\"",
306 gssapi_data);
307 g_free(gssapi_data);
308 } else {
309 gssapi_str = g_strdup("");
312 opaque_str = auth->opaque ? g_strdup_printf(", opaque=\"%s\"", auth->opaque) : g_strdup("");
313 version_str = auth_header_version(auth);
314 ret = g_strdup_printf("%s qop=\"auth\"%s, realm=\"%s\", targetname=\"%s\"%s%s%s",
315 auth->protocol, opaque_str,
316 auth->realm, auth->target,
317 gssapi_str, version_str, sign_str);
318 g_free(version_str);
319 g_free(opaque_str);
320 g_free(gssapi_str);
321 g_free(sign_str);
323 return(ret);
326 static gchar *start_auth_handshake(struct sip_auth *auth)
328 gchar *version_str = auth_header_version(auth);
329 gchar *ret = g_strdup_printf("%s qop=\"auth\", realm=\"%s\", targetname=\"%s\", gssapi-data=\"\"%s",
330 auth->protocol,
331 auth->realm, auth->target,
332 version_str);
333 g_free(version_str);
334 return(ret);
337 static gchar *auth_header(struct sipe_core_private *sipe_private,
338 struct sip_auth *auth,
339 struct sipmsg *msg)
341 gchar *ret = NULL;
344 * If the message is already signed then we have an authentication
345 * context, i.e. the authentication handshake is complete. Generate
346 * authentication header from message signature.
348 if (msg->signature) {
349 ret = msg_signature_to_auth(auth, msg);
352 * If the message isn't signed then we don't have a initialized
353 * authentication context yet.
355 * Start the authentication handshake if NTLM is selected.
357 } else if ((auth->type == AUTH_TYPE_NTLM) && !auth->gssapi_data) {
358 ret = start_auth_handshake(auth);
361 * We should reach this point only when the authentication context
362 * needs to be initialized.
364 } else {
365 ret = initialize_auth_context(sipe_private, auth, msg);
368 return(ret);
371 static void fill_auth(const gchar *hdr, struct sip_auth *auth)
373 const gchar *param;
375 /* skip authentication identifier */
376 hdr = strchr(hdr, ' ');
377 if (!hdr) {
378 SIPE_DEBUG_ERROR_NOFORMAT("fill_auth: corrupted authentication header");
379 return;
381 while (*hdr == ' ')
382 hdr++;
384 /* start of next parameter value */
385 while ((param = strchr(hdr, '=')) != NULL) {
386 const gchar *end;
388 /* parameter value type */
389 param++;
390 if (*param == '"') {
391 /* string: xyz="..."(,) */
392 end = strchr(++param, '"');
393 if (!end) {
394 SIPE_DEBUG_ERROR("fill_auth: corrupted string parameter near '%s'", hdr);
395 break;
397 } else {
398 /* number: xyz=12345(,) */
399 end = strchr(param, ',');
400 if (!end) {
401 /* last parameter */
402 end = param + strlen(param);
406 #if 0
407 SIPE_DEBUG_INFO("fill_auth: hdr '%s'", hdr);
408 SIPE_DEBUG_INFO("fill_auth: param '%s'", param);
409 SIPE_DEBUG_INFO("fill_auth: end '%s'", end);
410 #endif
412 /* parameter type */
413 if (g_str_has_prefix(hdr, "gssapi-data=\"")) {
414 g_free(auth->gssapi_data);
415 auth->gssapi_data = g_strndup(param, end - param);
416 } else if (g_str_has_prefix(hdr, "opaque=\"")) {
417 g_free(auth->opaque);
418 auth->opaque = g_strndup(param, end - param);
419 } else if (g_str_has_prefix(hdr, "realm=\"")) {
420 g_free(auth->realm);
421 auth->realm = g_strndup(param, end - param);
422 } else if (g_str_has_prefix(hdr, "sts-uri=\"")) {
423 /* Only used with AUTH_TYPE_TLS_DSK */
424 g_free(auth->sts_uri);
425 auth->sts_uri = g_strndup(param, end - param);
426 } else if (g_str_has_prefix(hdr, "targetname=\"")) {
427 g_free(auth->target);
428 auth->target = g_strndup(param, end - param);
429 } else if (g_str_has_prefix(hdr, "version=")) {
430 auth->version = atoi(param);
433 /* skip to next parameter */
434 while ((*end == '"') || (*end == ',') || (*end == ' '))
435 end++;
436 hdr = end;
439 return;
442 static void sign_outgoing_message(struct sipe_core_private *sipe_private,
443 struct sipmsg *msg)
445 struct sip_transport *transport = sipe_private->transport;
446 gchar *buf;
448 if (transport->registrar.type == AUTH_TYPE_UNSET) {
449 return;
452 sipe_make_signature(sipe_private, msg);
454 buf = auth_header(sipe_private, &transport->registrar, msg);
455 if (buf) {
456 sipmsg_add_header_now_pos(msg, "Authorization", buf, 5);
457 g_free(buf);
461 static const gchar *sip_transport_user_agent(struct sipe_core_private *sipe_private)
463 struct sip_transport *transport = sipe_private->transport;
465 if (!transport->user_agent) {
466 const gchar *useragent = sipe_backend_setting(SIPE_CORE_PUBLIC,
467 SIPE_SETTING_USER_AGENT);
468 if (is_empty(useragent)) {
469 /*@TODO: better approach to define _user_ OS, it's version and host architecture */
470 /* ref: lzodefs.h */
471 #if defined(__linux__) || defined(__linux) || defined(__LINUX__)
472 #define SIPE_TARGET_PLATFORM "linux"
473 #elif defined(__NetBSD__) ||defined( __OpenBSD__) || defined(__FreeBSD__)
474 #define SIPE_TARGET_PLATFORM "bsd"
475 #elif defined(__APPLE__) || defined(__MACOS__)
476 #define SIPE_TARGET_PLATFORM "macosx"
477 #elif defined(_AIX) || defined(__AIX__) || defined(__aix__)
478 #define SIPE_TARGET_PLATFORM "aix"
479 #elif defined(__solaris__) || defined(__sun)
480 #define SIPE_TARGET_PLATFORM "sun"
481 #elif defined(_WIN32)
482 #define SIPE_TARGET_PLATFORM "win"
483 #elif defined(__CYGWIN__)
484 #define SIPE_TARGET_PLATFORM "cygwin"
485 #elif defined(__hpux__)
486 #define SIPE_TARGET_PLATFORM "hpux"
487 #elif defined(__sgi__)
488 #define SIPE_TARGET_PLATFORM "irix"
489 #else
490 #define SIPE_TARGET_PLATFORM "unknown"
491 #endif
493 #if defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64)
494 #define SIPE_TARGET_ARCH "x86_64"
495 #elif defined(__386__) || defined(__i386__) || defined(__i386) || defined(_M_IX86) || defined(_M_I386)
496 #define SIPE_TARGET_ARCH "i386"
497 #elif defined(__ppc64__)
498 #define SIPE_TARGET_ARCH "ppc64"
499 #elif defined(__powerpc__) || defined(__powerpc) || defined(__ppc__) || defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PWR)
500 #define SIPE_TARGET_ARCH "ppc"
501 #elif defined(__hppa__) || defined(__hppa)
502 #define SIPE_TARGET_ARCH "hppa"
503 #elif defined(__mips__) || defined(__mips) || defined(_MIPS_ARCH) || defined(_M_MRX000)
504 #define SIPE_TARGET_ARCH "mips"
505 #elif defined(__s390__) || defined(__s390) || defined(__s390x__) || defined(__s390x)
506 #define SIPE_TARGET_ARCH "s390"
507 #elif defined(__sparc__) || defined(__sparc) || defined(__sparcv8)
508 #define SIPE_TARGET_ARCH "sparc"
509 #elif defined(__arm__)
510 #define SIPE_TARGET_ARCH "arm"
511 #else
512 #define SIPE_TARGET_ARCH "other"
513 #endif
514 gchar *backend = sipe_backend_version();
515 transport->user_agent = g_strdup_printf("%s Sipe/" PACKAGE_VERSION " (" SIPE_TARGET_PLATFORM "-" SIPE_TARGET_ARCH "; %s)",
516 backend,
517 transport->server_version ? transport->server_version : "");
518 g_free(backend);
519 } else {
520 transport->user_agent = g_strdup(useragent);
523 return(transport->user_agent);
526 void sip_transport_response(struct sipe_core_private *sipe_private,
527 struct sipmsg *msg,
528 guint code,
529 const char *text,
530 const char *body)
532 gchar *name;
533 gchar *value;
534 GString *outstr = g_string_new("");
535 gchar *contact;
536 GSList *tmp;
537 const gchar *keepers[] = { "To", "From", "Call-ID", "CSeq", "Via", "Record-Route", NULL };
539 /* Can return NULL! */
540 contact = get_contact(sipe_private);
541 if (contact) {
542 sipmsg_add_header(msg, "Contact", contact);
543 g_free(contact);
546 if (body) {
547 gchar *len = g_strdup_printf("%" G_GSIZE_FORMAT , (gsize) strlen(body));
548 sipmsg_add_header(msg, "Content-Length", len);
549 g_free(len);
550 } else {
551 sipmsg_add_header(msg, "Content-Length", "0");
554 sipmsg_add_header(msg, "User-Agent", sip_transport_user_agent(sipe_private));
556 msg->response = code;
558 sipmsg_strip_headers(msg, keepers);
559 sipmsg_merge_new_headers(msg);
560 sign_outgoing_message(sipe_private, msg);
562 g_string_append_printf(outstr, "SIP/2.0 %d %s\r\n", code, text);
563 tmp = msg->headers;
564 while (tmp) {
565 name = ((struct sipnameval*) (tmp->data))->name;
566 value = ((struct sipnameval*) (tmp->data))->value;
568 g_string_append_printf(outstr, "%s: %s\r\n", name, value);
569 tmp = g_slist_next(tmp);
571 g_string_append_printf(outstr, "\r\n%s", body ? body : "");
572 sipe_utils_message_debug("SIP", outstr->str, NULL, TRUE);
573 sipe_backend_transport_message(sipe_private->transport->connection, outstr->str);
574 g_string_free(outstr, TRUE);
577 static void transactions_remove(struct sipe_core_private *sipe_private,
578 struct transaction *trans)
580 struct sip_transport *transport = sipe_private->transport;
581 if (transport->transactions) {
582 transport->transactions = g_slist_remove(transport->transactions,
583 trans);
584 SIPE_DEBUG_INFO("SIP transactions count:%d after removal", g_slist_length(transport->transactions));
586 if (trans->msg) sipmsg_free(trans->msg);
587 if (trans->payload) {
588 (*trans->payload->destroy)(trans->payload->data);
589 g_free(trans->payload);
591 g_free(trans->key);
592 if (trans->timeout_key) {
593 sipe_schedule_cancel(sipe_private, trans->timeout_key);
594 g_free(trans->timeout_key);
596 g_free(trans);
600 static struct transaction *transactions_find(struct sip_transport *transport,
601 struct sipmsg *msg)
603 GSList *transactions = transport->transactions;
604 const gchar *call_id = sipmsg_find_header(msg, "Call-ID");
605 const gchar *cseq = sipmsg_find_header(msg, "CSeq");
606 gchar *key;
608 if (!call_id || !cseq) {
609 SIPE_DEBUG_ERROR_NOFORMAT("transaction_find: no Call-ID or CSeq!");
610 return NULL;
613 key = g_strdup_printf("<%s><%s>", call_id, cseq);
614 while (transactions) {
615 struct transaction *trans = transactions->data;
616 if (!g_strcasecmp(trans->key, key)) {
617 g_free(key);
618 return trans;
620 transactions = transactions->next;
622 g_free(key);
624 return NULL;
627 static void transaction_timeout_cb(struct sipe_core_private *sipe_private,
628 gpointer data)
630 struct transaction *trans = data;
631 (trans->timeout_callback)(sipe_private, trans->msg, trans);
632 transactions_remove(sipe_private, trans);
635 struct transaction *sip_transport_request_timeout(struct sipe_core_private *sipe_private,
636 const gchar *method,
637 const gchar *url,
638 const gchar *to,
639 const gchar *addheaders,
640 const gchar *body,
641 struct sip_dialog *dialog,
642 TransCallback callback,
643 guint timeout,
644 TransCallback timeout_callback)
646 struct sip_transport *transport = sipe_private->transport;
647 char *buf;
648 struct sipmsg *msg;
649 gchar *ourtag = dialog && dialog->ourtag ? g_strdup(dialog->ourtag) : NULL;
650 gchar *theirtag = dialog && dialog->theirtag ? g_strdup(dialog->theirtag) : NULL;
651 gchar *theirepid = dialog && dialog->theirepid ? g_strdup(dialog->theirepid) : NULL;
652 gchar *callid = dialog && dialog->callid ? g_strdup(dialog->callid) : gencallid();
653 gchar *branch = dialog && dialog->callid ? NULL : genbranch();
654 gchar *route = g_strdup("");
655 gchar *epid = get_epid(sipe_private);
656 int cseq = dialog ? ++dialog->cseq : 1 /* as Call-Id is new in this case */;
657 struct transaction *trans = NULL;
659 if (dialog && dialog->routes)
661 GSList *iter = dialog->routes;
663 while(iter)
665 char *tmp = route;
666 route = g_strdup_printf("%sRoute: %s\r\n", route, (char *)iter->data);
667 g_free(tmp);
668 iter = g_slist_next(iter);
672 if (!ourtag && !dialog) {
673 ourtag = gentag();
676 if (sipe_strequal(method, "REGISTER")) {
677 if (sipe_private->register_callid) {
678 g_free(callid);
679 callid = g_strdup(sipe_private->register_callid);
680 } else {
681 sipe_private->register_callid = g_strdup(callid);
683 cseq = ++transport->cseq;
686 buf = g_strdup_printf("%s %s SIP/2.0\r\n"
687 "Via: SIP/2.0/%s %s:%d%s%s\r\n"
688 "From: <sip:%s>%s%s;epid=%s\r\n"
689 "To: <%s>%s%s%s%s\r\n"
690 "Max-Forwards: 70\r\n"
691 "CSeq: %d %s\r\n"
692 "User-Agent: %s\r\n"
693 "Call-ID: %s\r\n"
694 "%s%s"
695 "Content-Length: %" G_GSIZE_FORMAT "\r\n\r\n%s",
696 method,
697 dialog && dialog->request ? dialog->request : url,
698 TRANSPORT_DESCRIPTOR,
699 sipe_backend_network_ip_address(),
700 transport->connection->client_port,
701 branch ? ";branch=" : "",
702 branch ? branch : "",
703 sipe_private->username,
704 ourtag ? ";tag=" : "",
705 ourtag ? ourtag : "",
706 epid,
708 theirtag ? ";tag=" : "",
709 theirtag ? theirtag : "",
710 theirepid ? ";epid=" : "",
711 theirepid ? theirepid : "",
712 cseq,
713 method,
714 sip_transport_user_agent(sipe_private),
715 callid,
716 route,
717 addheaders ? addheaders : "",
718 body ? (gsize) strlen(body) : 0,
719 body ? body : "");
722 //printf ("parsing msg buf:\n%s\n\n", buf);
723 msg = sipmsg_parse_msg(buf);
725 g_free(buf);
726 g_free(ourtag);
727 g_free(theirtag);
728 g_free(theirepid);
729 g_free(branch);
730 g_free(route);
731 g_free(epid);
733 sign_outgoing_message(sipe_private, msg);
735 /* The authentication scheme is not ready so we can't send the message.
736 This should only happen for REGISTER messages. */
737 if (!transport->auth_incomplete) {
738 buf = sipmsg_to_string(msg);
740 /* add to ongoing transactions */
741 /* ACK isn't supposed to be answered ever. So we do not keep transaction for it. */
742 if (!sipe_strequal(method, "ACK")) {
743 trans = g_new0(struct transaction, 1);
744 trans->callback = callback;
745 trans->msg = msg;
746 trans->key = g_strdup_printf("<%s><%d %s>", callid, cseq, method);
747 if (timeout_callback) {
748 trans->timeout_callback = timeout_callback;
749 trans->timeout_key = g_strdup_printf("<transaction timeout>%s", trans->key);
750 sipe_schedule_seconds(sipe_private,
751 trans->timeout_key,
752 trans,
753 timeout,
754 transaction_timeout_cb,
755 NULL);
757 transport->transactions = g_slist_append(transport->transactions,
758 trans);
759 SIPE_DEBUG_INFO("SIP transactions count:%d after addition", g_slist_length(transport->transactions));
762 sipe_utils_message_debug("SIP", buf, NULL, TRUE);
763 sipe_backend_transport_message(transport->connection, buf);
764 g_free(buf);
767 if (!trans) sipmsg_free(msg);
768 g_free(callid);
769 return trans;
772 struct transaction *sip_transport_request(struct sipe_core_private *sipe_private,
773 const gchar *method,
774 const gchar *url,
775 const gchar *to,
776 const gchar *addheaders,
777 const gchar *body,
778 struct sip_dialog *dialog,
779 TransCallback callback)
781 return sip_transport_request_timeout(sipe_private,
782 method,
783 url,
785 addheaders,
786 body,
787 dialog,
788 callback,
790 NULL);
793 static void sip_transport_simple_request(struct sipe_core_private *sipe_private,
794 const gchar *method,
795 struct sip_dialog *dialog)
797 sip_transport_request(sipe_private,
798 method,
799 dialog->with,
800 dialog->with,
801 NULL,
802 NULL,
803 dialog,
804 NULL);
807 void sip_transport_ack(struct sipe_core_private *sipe_private,
808 struct sip_dialog *dialog)
810 sip_transport_simple_request(sipe_private, "ACK", dialog);
813 void sip_transport_bye(struct sipe_core_private *sipe_private,
814 struct sip_dialog *dialog)
816 sip_transport_simple_request(sipe_private, "BYE", dialog);
819 struct transaction *sip_transport_info(struct sipe_core_private *sipe_private,
820 const gchar *addheaders,
821 const gchar *body,
822 struct sip_dialog *dialog,
823 TransCallback callback)
825 return sip_transport_request(sipe_private,
826 "INFO",
827 dialog->with,
828 dialog->with,
829 addheaders,
830 body,
831 dialog,
832 callback);
835 struct transaction *sip_transport_invite(struct sipe_core_private *sipe_private,
836 const gchar *addheaders,
837 const gchar *body,
838 struct sip_dialog *dialog,
839 TransCallback callback)
841 return sip_transport_request(sipe_private,
842 "INVITE",
843 dialog->with,
844 dialog->with,
845 addheaders,
846 body,
847 dialog,
848 callback);
851 struct transaction *sip_transport_service(struct sipe_core_private *sipe_private,
852 const gchar *uri,
853 const gchar *addheaders,
854 const gchar *body,
855 TransCallback callback)
857 return sip_transport_request(sipe_private,
858 "SERVICE",
859 uri,
860 uri,
861 addheaders,
862 body,
863 NULL,
864 callback);
867 void sip_transport_subscribe(struct sipe_core_private *sipe_private,
868 const gchar *uri,
869 const gchar *addheaders,
870 const gchar *body,
871 struct sip_dialog *dialog,
872 TransCallback callback)
874 sip_transport_request(sipe_private,
875 "SUBSCRIBE",
876 uri,
877 uri,
878 addheaders,
879 body,
880 dialog,
881 callback);
884 static const gchar *get_auth_header(struct sipe_core_private *sipe_private,
885 struct sip_auth *auth,
886 struct sipmsg *msg)
888 auth->type = AUTH_TYPE_NTLM;
889 #if defined(HAVE_LIBKRB5) || defined(HAVE_SSPI)
890 if (SIPE_CORE_PUBLIC_FLAG_IS(KRB5)) {
891 auth->type = AUTH_TYPE_KERBEROS;
893 #endif
894 if (SIPE_CORE_PUBLIC_FLAG_IS(TLS_DSK)) {
895 auth->type = AUTH_TYPE_TLS_DSK;
897 auth->protocol = auth_type_to_protocol[auth->type];
899 return(sipmsg_find_auth_header(msg, auth->protocol));
902 static void do_register(struct sipe_core_private *sipe_private,
903 gboolean deregister);
905 static void do_reauthenticate_cb(struct sipe_core_private *sipe_private,
906 SIPE_UNUSED_PARAMETER gpointer unused)
908 struct sip_transport *transport = sipe_private->transport;
910 /* register again when security token expires */
911 /* we have to start a new authentication as the security token
912 * is almost expired by sending a not signed REGISTER message */
913 SIPE_DEBUG_INFO_NOFORMAT("do a full reauthentication");
914 sipe_auth_free(&transport->registrar);
915 sipe_auth_free(&transport->proxy);
916 sipe_schedule_cancel(sipe_private, "<registration>");
917 transport->reregister_set = FALSE;
918 transport->register_attempt = 0;
919 do_register(sipe_private, FALSE);
920 transport->reauthenticate_set = FALSE;
923 static void sip_transport_default_contact(struct sipe_core_private *sipe_private)
925 struct sip_transport *transport = sipe_private->transport;
926 sipe_private->contact = g_strdup_printf("<sip:%s:%d;maddr=%s;transport=%s>;proxy=replace",
927 sipe_private->username,
928 transport->connection->client_port,
929 sipe_backend_network_ip_address(),
930 TRANSPORT_DESCRIPTOR);
933 static void do_register_cb(struct sipe_core_private *sipe_private,
934 SIPE_UNUSED_PARAMETER void *unused)
936 do_register(sipe_private, FALSE);
939 static void sip_transport_set_reregister(struct sipe_core_private *sipe_private,
940 int expires)
942 sipe_schedule_seconds(sipe_private,
943 "<registration>",
944 NULL,
945 expires,
946 do_register_cb,
947 NULL);
950 static void sipe_server_register(struct sipe_core_private *sipe_private,
951 guint type,
952 gchar *server_name,
953 guint server_port);
955 static gboolean process_register_response(struct sipe_core_private *sipe_private,
956 struct sipmsg *msg,
957 SIPE_UNUSED_PARAMETER struct transaction *trans)
959 struct sip_transport *transport = sipe_private->transport;
960 const gchar *expires_header;
961 int expires, i;
962 GSList *hdr = msg->headers;
963 struct sipnameval *elem;
965 expires_header = sipmsg_find_header(msg, "Expires");
966 expires = expires_header != NULL ? strtol(expires_header, NULL, 10) : 0;
967 SIPE_DEBUG_INFO("process_register_response: got response to REGISTER; expires = %d", expires);
969 switch (msg->response) {
970 case 200:
971 if (expires) {
972 const gchar *contact_hdr;
973 const gchar *auth_hdr;
974 gchar *gruu = NULL;
975 gchar *uuid;
976 gchar *timeout;
977 const gchar *server_hdr = sipmsg_find_header(msg, "Server");
979 if (!transport->reregister_set) {
980 sip_transport_set_reregister(sipe_private,
981 expires);
982 transport->reregister_set = TRUE;
985 if (server_hdr && !transport->server_version) {
986 transport->server_version = g_strdup(server_hdr);
987 g_free(transport->user_agent);
988 transport->user_agent = NULL;
991 auth_hdr = get_auth_header(sipe_private, &transport->registrar, msg);
992 if (auth_hdr) {
993 SIPE_DEBUG_INFO("process_register_response: Auth header: %s", auth_hdr);
994 fill_auth(auth_hdr, &transport->registrar);
997 if (!transport->reauthenticate_set) {
998 gchar *action_name = g_strdup_printf("<%s>", "+reauthentication");
999 guint reauth_timeout;
1001 SIPE_DEBUG_INFO_NOFORMAT("process_register_response: authentication handshake completed successfully");
1003 if (transport->registrar.type == AUTH_TYPE_KERBEROS && transport->registrar.expires > 0) {
1004 /* assuming normal Kerberos ticket expiration of about 8-10 hours */
1005 reauth_timeout = transport->registrar.expires - 300;
1006 } else {
1007 /* NTLM: we have to reauthenticate as our security token expires
1008 after eight hours (be five minutes early) */
1009 reauth_timeout = (8 * 3600) - 300;
1011 sipe_schedule_seconds(sipe_private,
1012 action_name,
1013 NULL,
1014 reauth_timeout,
1015 do_reauthenticate_cb,
1016 NULL);
1017 g_free(action_name);
1018 transport->reauthenticate_set = TRUE;
1021 sipe_backend_connection_completed(SIPE_CORE_PUBLIC);
1023 uuid = get_uuid(sipe_private);
1025 // There can be multiple Contact headers (one per location where the user is logged in) so
1026 // make sure to only get the one for this uuid
1027 for (i = 0; (contact_hdr = sipmsg_find_header_instance (msg, "Contact", i)); i++) {
1028 gchar * valid_contact = sipmsg_find_part_of_header (contact_hdr, uuid, NULL, NULL);
1029 if (valid_contact) {
1030 gruu = sipmsg_find_part_of_header(contact_hdr, "gruu=\"", "\"", NULL);
1031 //SIPE_DEBUG_INFO("process_register_response: got gruu %s from contact hdr w/ right uuid: %s", gruu, contact_hdr);
1032 g_free(valid_contact);
1033 break;
1034 } else {
1035 //SIPE_DEBUG_INFO("process_register_response: ignoring contact hdr b/c not right uuid: %s", contact_hdr);
1038 g_free(uuid);
1040 g_free(sipe_private->contact);
1041 if(gruu) {
1042 sipe_private->contact = g_strdup_printf("<%s>", gruu);
1043 g_free(gruu);
1044 } else {
1045 //SIPE_DEBUG_INFO_NOFORMAT("process_register_response: didn't find gruu in a Contact hdr");
1046 sip_transport_default_contact(sipe_private);
1048 SIPE_CORE_PRIVATE_FLAG_UNSET(OCS2007);
1049 SIPE_CORE_PRIVATE_FLAG_UNSET(REMOTE_USER);
1050 SIPE_CORE_PRIVATE_FLAG_UNSET(BATCHED_SUPPORT);
1052 while(hdr)
1054 elem = hdr->data;
1055 if (sipe_strcase_equal(elem->name, "Supported")) {
1056 if (sipe_strcase_equal(elem->value, "msrtc-event-categories")) {
1057 /* We interpret this as OCS2007+ indicator */
1058 SIPE_CORE_PRIVATE_FLAG_SET(OCS2007);
1059 SIPE_DEBUG_INFO("Supported: %s (indicates OCS2007+)", elem->value);
1061 if (sipe_strcase_equal(elem->value, "adhoclist")) {
1062 SIPE_CORE_PRIVATE_FLAG_SET(BATCHED_SUPPORT);
1063 SIPE_DEBUG_INFO("Supported: %s", elem->value);
1066 if (sipe_strcase_equal(elem->name, "Allow-Events")){
1067 gchar **caps = g_strsplit(elem->value,",",0);
1068 i = 0;
1069 while (caps[i]) {
1070 sipe_private->allowed_events = g_slist_append(sipe_private->allowed_events, g_strdup(caps[i]));
1071 SIPE_DEBUG_INFO("Allow-Events: %s", caps[i]);
1072 i++;
1074 g_strfreev(caps);
1076 if (sipe_strcase_equal(elem->name, "ms-user-logon-data")) {
1077 if (sipe_strcase_equal(elem->value, "RemoteUser")) {
1078 SIPE_CORE_PRIVATE_FLAG_SET(REMOTE_USER);
1079 SIPE_DEBUG_INFO_NOFORMAT("ms-user-logon-data: RemoteUser (connected "
1080 "via Edge Server)");
1083 hdr = g_slist_next(hdr);
1086 /* rejoin open chats to be able to use them by continue to send messages */
1087 sipe_backend_chat_rejoin_all(SIPE_CORE_PUBLIC);
1089 /* subscriptions */
1090 if (!transport->subscribed) { //do it just once, not every re-register
1092 if (g_slist_find_custom(sipe_private->allowed_events, "vnd-microsoft-roaming-contacts",
1093 (GCompareFunc)g_ascii_strcasecmp)) {
1094 sipe_subscribe_roaming_contacts(sipe_private);
1097 /* For 2007+ it does not make sence to subscribe to:
1098 * vnd-microsoft-roaming-ACL
1099 * vnd-microsoft-provisioning (not v2)
1100 * presence.wpending
1101 * These are for backward compatibility.
1103 if (SIPE_CORE_PRIVATE_FLAG_IS(OCS2007))
1105 if (g_slist_find_custom(sipe_private->allowed_events, "vnd-microsoft-roaming-self",
1106 (GCompareFunc)g_ascii_strcasecmp)) {
1107 sipe_subscribe_roaming_self(sipe_private);
1109 if (g_slist_find_custom(sipe_private->allowed_events, "vnd-microsoft-provisioning-v2",
1110 (GCompareFunc)g_ascii_strcasecmp)) {
1111 sipe_subscribe_roaming_provisioning_v2(sipe_private);
1114 /* For 2005- servers */
1115 else
1117 //sipe_options_request(sip, sipe_private->public.sip_domain);
1119 if (g_slist_find_custom(sipe_private->allowed_events, "vnd-microsoft-roaming-ACL",
1120 (GCompareFunc)g_ascii_strcasecmp)) {
1121 sipe_subscribe_roaming_acl(sipe_private);
1123 if (g_slist_find_custom(sipe_private->allowed_events, "vnd-microsoft-provisioning",
1124 (GCompareFunc)g_ascii_strcasecmp)) {
1125 sipe_subscribe_roaming_provisioning(sipe_private);
1127 if (g_slist_find_custom(sipe_private->allowed_events, "presence.wpending",
1128 (GCompareFunc)g_ascii_strcasecmp)) {
1129 sipe_subscribe_presence_wpending(sipe_private,
1130 NULL);
1133 /* For 2007+ we publish our initial statuses and calendar data only after
1134 * received our existing publications in sipe_process_roaming_self()
1135 * Only in this case we know versions of current publications made
1136 * on our behalf.
1138 /* For 2005- we publish our initial statuses only after
1139 * received our existing UserInfo data in response to
1140 * self subscription.
1141 * Only in this case we won't override existing UserInfo data
1142 * set earlier or by other client on our behalf.
1146 transport->subscribed = TRUE;
1149 timeout = sipmsg_find_part_of_header(sipmsg_find_header(msg, "ms-keep-alive"),
1150 "timeout=", ";", NULL);
1151 if (timeout != NULL) {
1152 sscanf(timeout, "%u", &sipe_private->public.keepalive_timeout);
1153 SIPE_DEBUG_INFO("process_register_response: server determined keep alive timeout is %u seconds",
1154 sipe_private->public.keepalive_timeout);
1155 g_free(timeout);
1158 SIPE_DEBUG_INFO("process_register_response: got 200, removing CSeq: %d", transport->cseq);
1160 break;
1161 case 301:
1163 gchar *redirect = parse_from(sipmsg_find_header(msg, "Contact"));
1165 SIPE_DEBUG_INFO_NOFORMAT("process_register_response: authentication handshake completed successfully");
1167 if (redirect && (g_strncasecmp("sip:", redirect, 4) == 0)) {
1168 gchar **parts = g_strsplit(redirect + 4, ";", 0);
1169 gchar **tmp;
1170 gchar *hostname;
1171 int port = 0;
1172 guint transport = SIPE_TRANSPORT_TLS;
1173 int i = 1;
1175 tmp = g_strsplit(parts[0], ":", 0);
1176 hostname = g_strdup(tmp[0]);
1177 if (tmp[1]) port = strtoul(tmp[1], NULL, 10);
1178 g_strfreev(tmp);
1180 while (parts[i]) {
1181 tmp = g_strsplit(parts[i], "=", 0);
1182 if (tmp[1]) {
1183 if (g_strcasecmp("transport", tmp[0]) == 0) {
1184 if (g_strcasecmp("tcp", tmp[1]) == 0) {
1185 transport = SIPE_TRANSPORT_TCP;
1189 g_strfreev(tmp);
1190 i++;
1192 g_strfreev(parts);
1194 /* Close old connection */
1195 sipe_core_connection_cleanup(sipe_private);
1197 /* Create new connection */
1198 sipe_server_register(sipe_private, transport, hostname, port);
1199 SIPE_DEBUG_INFO("process_register_response: redirected to host %s port %d transport %d",
1200 hostname, port, transport);
1202 g_free(redirect);
1204 break;
1205 case 401:
1207 const char *auth_hdr;
1209 SIPE_DEBUG_INFO("process_register_response: REGISTER retries %d", transport->registrar.retries);
1210 if (sip_sec_context_is_ready(transport->registrar.gssapi_context)) {
1211 SIPE_DEBUG_INFO_NOFORMAT("process_register_response: authentication handshake failed - giving up.");
1212 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1213 SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
1214 _("Authentication failed"));
1215 return TRUE;
1218 if (transport->reauthenticate_set) {
1219 SIPE_DEBUG_ERROR_NOFORMAT("process_register_response: RE-REGISTER rejected, triggering re-authentication");
1220 do_reauthenticate_cb(sipe_private, NULL);
1221 return TRUE;
1224 auth_hdr = get_auth_header(sipe_private, &transport->registrar, msg);
1225 if (!auth_hdr) {
1226 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1227 SIPE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE,
1228 _("Incompatible authentication scheme chosen"));
1229 return TRUE;
1231 SIPE_DEBUG_INFO("process_register_response: Auth header: %s", auth_hdr);
1232 fill_auth(auth_hdr, &transport->registrar);
1233 transport->reregister_set = FALSE;
1234 transport->register_attempt = 0;
1235 do_register(sipe_private,
1236 sipe_backend_connection_is_disconnecting(SIPE_CORE_PUBLIC));
1238 break;
1239 case 403:
1241 gchar *reason;
1242 gchar *warning;
1243 sipmsg_parse_warning(msg, &reason);
1244 reason = reason ? reason : sipmsg_get_ms_diagnostics_public_reason(msg);
1245 warning = g_strdup_printf(_("You have been rejected by the server: %s"),
1246 reason ? reason : _("no reason given"));
1247 g_free(reason);
1249 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1250 SIPE_CONNECTION_ERROR_INVALID_SETTINGS,
1251 warning);
1252 g_free(warning);
1253 return TRUE;
1255 break;
1256 case 404:
1258 const gchar *diagnostics = sipmsg_find_header(msg, "ms-diagnostics");
1259 gchar *reason = sipmsg_get_ms_diagnostics_reason(msg);
1260 gchar *warning;
1261 warning = g_strdup_printf(_("Not found: %s. Please contact your Administrator"),
1262 diagnostics ? (reason ? reason : _("no reason given")) :
1263 _("SIP is either not enabled for the destination URI or it does not exist"));
1264 g_free(reason);
1266 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1267 SIPE_CONNECTION_ERROR_INVALID_USERNAME,
1268 warning);
1269 g_free(warning);
1270 return TRUE;
1272 break;
1273 case 504: /* Server time-out */
1274 /* first attempt + 5 retries */
1275 if (transport->register_attempt < 6) {
1276 SIPE_DEBUG_INFO("process_register_response: RE-REGISTER timeout on attempt %d, retrying later",
1277 transport->register_attempt);
1278 sip_transport_set_reregister(sipe_private, 60);
1279 return TRUE;
1281 /* FALLTHROUGH */
1282 case 503:
1284 gchar *reason = sipmsg_get_ms_diagnostics_reason(msg);
1285 gchar *warning;
1286 warning = g_strdup_printf(_("Service unavailable: %s"), reason ? reason : _("no reason given"));
1287 g_free(reason);
1289 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1290 SIPE_CONNECTION_ERROR_NETWORK,
1291 warning);
1292 g_free(warning);
1293 return TRUE;
1295 break;
1297 return TRUE;
1300 static gboolean register_response_timeout(struct sipe_core_private *sipe_private,
1301 SIPE_UNUSED_PARAMETER struct sipmsg *msg,
1302 SIPE_UNUSED_PARAMETER struct transaction *trans)
1304 struct sip_transport *transport = sipe_private->transport;
1305 if (transport->register_attempt < 6) {
1306 SIPE_DEBUG_INFO("register_response_timeout: no answer to attempt %d, retrying",
1307 transport->register_attempt);
1308 do_register(sipe_private, FALSE);
1309 } else {
1310 gchar *warning = g_strdup_printf(_("Service unavailable: %s"), _("no reason given"));
1311 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1312 SIPE_CONNECTION_ERROR_NETWORK,
1313 warning);
1314 g_free(warning);
1316 return TRUE;
1319 static void do_register(struct sipe_core_private *sipe_private,
1320 gboolean deregister)
1322 struct sip_transport *transport = sipe_private->transport;
1323 char *uri;
1324 char *to;
1325 char *hdr;
1326 char *uuid;
1328 if (!sipe_private->public.sip_domain) return;
1330 if (!deregister) {
1331 if (transport->reregister_set) {
1332 transport->reregister_set = FALSE;
1333 transport->register_attempt = 1;
1334 } else {
1335 transport->register_attempt++;
1339 transport->auth_incomplete = FALSE;
1341 uuid = get_uuid(sipe_private);
1342 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"
1343 "Supported: gruu-10, adhoclist, msrtc-event-categories, com.microsoft.msrtc.presence\r\n"
1344 "Event: registration\r\n"
1345 "Allow-Events: presence\r\n"
1346 "ms-keep-alive: UAC;hop-hop=yes\r\n"
1347 "%s",
1348 sipe_backend_network_ip_address(),
1349 transport->connection->client_port,
1350 TRANSPORT_DESCRIPTOR,
1351 uuid,
1352 deregister ? "Expires: 0\r\n" : "");
1353 g_free(uuid);
1355 uri = sip_uri_from_name(sipe_private->public.sip_domain);
1356 to = sip_uri_self(sipe_private);
1357 sip_transport_request_timeout(sipe_private,
1358 "REGISTER",
1359 uri,
1361 hdr,
1363 NULL,
1364 process_register_response,
1366 deregister ? NULL : register_response_timeout);
1367 g_free(to);
1368 g_free(uri);
1369 g_free(hdr);
1371 if (deregister) {
1372 /* Make sure that all messages are pushed to the server
1373 before the connection gets shut down */
1374 SIPE_DEBUG_INFO_NOFORMAT("De-register from server. Flushing outstanding messages.");
1375 sipe_backend_transport_flush(transport->connection);
1379 void sip_transport_deregister(struct sipe_core_private *sipe_private)
1381 do_register(sipe_private, TRUE);
1384 void sip_transport_disconnect(struct sipe_core_private *sipe_private)
1386 struct sip_transport *transport = sipe_private->transport;
1388 /* transport can be NULL during connection setup */
1389 if (transport) {
1390 sipe_backend_transport_disconnect(transport->connection);
1392 sipe_auth_free(&transport->registrar);
1393 sipe_auth_free(&transport->proxy);
1395 g_free(transport->server_name);
1396 g_free(transport->server_version);
1397 g_free(transport->user_agent);
1399 while (transport->transactions)
1400 transactions_remove(sipe_private,
1401 transport->transactions->data);
1403 g_free(transport);
1406 sipe_private->transport = NULL;
1407 sipe_private->service_data = NULL;
1409 if (sipe_private->dns_query)
1410 sipe_backend_dns_query_cancel(sipe_private->dns_query);
1414 void sip_transport_authentication_completed(struct sipe_core_private *sipe_private)
1416 do_reauthenticate_cb(sipe_private, NULL);
1419 guint sip_transport_port(struct sipe_core_private *sipe_private)
1421 return sipe_private->transport->server_port;
1424 static void process_input_message(struct sipe_core_private *sipe_private,
1425 struct sipmsg *msg)
1427 struct sip_transport *transport = sipe_private->transport;
1428 gboolean notfound = FALSE;
1429 const char *method = msg->method ? msg->method : "NOT FOUND";
1431 SIPE_DEBUG_INFO("process_input_message: msg->response(%d),msg->method(%s)",
1432 msg->response, method);
1434 if (msg->response == 0) { /* request */
1435 if (sipe_strequal(method, "MESSAGE")) {
1436 process_incoming_message(sipe_private, msg);
1437 } else if (sipe_strequal(method, "NOTIFY")) {
1438 SIPE_DEBUG_INFO_NOFORMAT("send->process_incoming_notify");
1439 process_incoming_notify(sipe_private, msg, TRUE, FALSE);
1440 } else if (sipe_strequal(method, "BENOTIFY")) {
1441 SIPE_DEBUG_INFO_NOFORMAT("send->process_incoming_benotify");
1442 process_incoming_notify(sipe_private, msg, TRUE, TRUE);
1443 } else if (sipe_strequal(method, "INVITE")) {
1444 process_incoming_invite(sipe_private, msg);
1445 } else if (sipe_strequal(method, "REFER")) {
1446 process_incoming_refer(sipe_private, msg);
1447 } else if (sipe_strequal(method, "OPTIONS")) {
1448 process_incoming_options(sipe_private, msg);
1449 } else if (sipe_strequal(method, "INFO")) {
1450 process_incoming_info(sipe_private, msg);
1451 } else if (sipe_strequal(method, "ACK")) {
1452 /* ACK's don't need any response */
1453 } else if (sipe_strequal(method, "PRACK")) {
1454 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
1455 } else if (sipe_strequal(method, "SUBSCRIBE")) {
1456 /* LCS 2005 sends us these - just respond 200 OK */
1457 sip_transport_response(sipe_private, msg, 200, "OK", NULL);
1458 } else if (sipe_strequal(method, "CANCEL")) {
1459 process_incoming_cancel(sipe_private, msg);
1460 } else if (sipe_strequal(method, "BYE")) {
1461 process_incoming_bye(sipe_private, msg);
1462 } else {
1463 sip_transport_response(sipe_private, msg, 501, "Not implemented", NULL);
1464 notfound = TRUE;
1467 } else { /* response */
1468 struct transaction *trans = transactions_find(transport, msg);
1469 if (trans) {
1470 if (msg->response < 200) {
1471 /* ignore provisional response */
1472 SIPE_DEBUG_INFO("process_input_message: got provisional (%d) response, ignoring", msg->response);
1474 /* Transaction not yet completed */
1475 trans = NULL;
1477 } else if (msg->response == 401) { /* Unauthorized */
1479 if (sipe_strequal(trans->msg->method, "REGISTER")) {
1480 /* Expected response during authentication handshake */
1481 transport->registrar.retries++;
1482 SIPE_DEBUG_INFO("process_input_message: RE-REGISTER CSeq: %d", transport->cseq);
1483 } else {
1484 gchar *resend;
1486 /* Are we registered? */
1487 if (transport->reregister_set) {
1488 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: 401 response to non-REGISTER message. Retrying with new authentication.");
1489 sign_outgoing_message(sipe_private,
1490 trans->msg);
1491 } else {
1493 * We don't have a valid authentication at the moment.
1494 * Resend message unchanged. It will be rejected again
1495 * and hopefully by then we have a valid authentication.
1497 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: 401 response to non-REGISTER message. Bouncing...");
1500 /* Resend request */
1501 resend = sipmsg_to_string(trans->msg);
1502 sipe_utils_message_debug("SIP", resend, NULL, TRUE);
1503 sipe_backend_transport_message(sipe_private->transport->connection, resend);
1504 g_free(resend);
1506 /* Transaction not yet completed */
1507 trans = NULL;
1510 } else if (msg->response == 407) { /* Proxy Authentication Required */
1512 if (transport->proxy.retries > 30) {
1513 SIPE_DEBUG_ERROR_NOFORMAT("process_input_message: too many proxy authentication retries. Giving up.");
1514 } else {
1515 gchar *resend, *auth;
1516 const gchar *auth_hdr;
1518 transport->proxy.retries++;
1520 /* do proxy authentication */
1521 auth_hdr = sipmsg_find_header(msg, "Proxy-Authenticate");
1522 if (auth_hdr) {
1523 guint i;
1524 transport->proxy.type = AUTH_TYPE_UNSET;
1525 for (i = 0; i < AUTH_PROTOCOLS; i++) {
1526 const gchar *protocol = auth_type_to_protocol[i];
1527 if (protocol &&
1528 !g_strncasecmp(auth_hdr, protocol, strlen(protocol))) {
1529 SIPE_DEBUG_INFO("proxy auth: type %s", protocol);
1530 transport->proxy.type = i;
1531 transport->proxy.protocol = protocol;
1532 break;
1535 if (transport->proxy.type == AUTH_TYPE_UNSET)
1536 SIPE_DEBUG_ERROR("Unknown proxy authentication: %s", auth_hdr);
1537 fill_auth(auth_hdr, &transport->proxy);
1539 auth = auth_header(sipe_private, &transport->proxy, trans->msg);
1540 if (auth) {
1541 sipmsg_remove_header_now(trans->msg, "Proxy-Authorization");
1542 sipmsg_add_header_now_pos(trans->msg, "Proxy-Authorization", auth, 5);
1543 g_free(auth);
1546 /* resend request */
1547 resend = sipmsg_to_string(trans->msg);
1548 sipe_utils_message_debug("SIP", resend, NULL, TRUE);
1549 sipe_backend_transport_message(sipe_private->transport->connection, resend);
1550 g_free(resend);
1552 /* Transaction not yet completed */
1553 trans = NULL;
1556 } else {
1557 transport->registrar.retries = 0;
1558 transport->proxy.retries = 0;
1561 /* Is transaction completed? */
1562 if (trans) {
1563 if (trans->callback) {
1564 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: we have a transaction callback");
1565 /* call the callback to process response */
1566 (trans->callback)(sipe_private, msg, trans);
1569 SIPE_DEBUG_INFO("process_input_message: removing CSeq %d", transport->cseq);
1570 transactions_remove(sipe_private, trans);
1572 } else {
1573 SIPE_DEBUG_INFO_NOFORMAT("process_input_message: received response to unknown transaction");
1574 notfound = TRUE;
1578 if (notfound) {
1579 SIPE_DEBUG_INFO("received a unknown sip message with method %s and response %d", method, msg->response);
1583 static void sip_transport_input(struct sipe_transport_connection *conn)
1585 struct sipe_core_private *sipe_private = conn->user_data;
1586 struct sip_transport *transport = sipe_private->transport;
1587 gchar *cur = conn->buffer;
1589 /* according to the RFC remove CRLF at the beginning */
1590 while (*cur == '\r' || *cur == '\n') {
1591 cur++;
1593 if (cur != conn->buffer)
1594 sipe_utils_shrink_buffer(conn, cur);
1596 /* Received a full Header? */
1597 transport->processing_input = TRUE;
1598 while (transport->processing_input &&
1599 ((cur = strstr(conn->buffer, "\r\n\r\n")) != NULL)) {
1600 struct sipmsg *msg;
1601 guint remainder;
1603 cur += 2;
1604 cur[0] = '\0';
1605 msg = sipmsg_parse_header(conn->buffer);
1607 cur += 2;
1608 remainder = conn->buffer_used - (cur - conn->buffer);
1609 if (msg && remainder >= (guint) msg->bodylen) {
1610 char *dummy = g_malloc(msg->bodylen + 1);
1611 memcpy(dummy, cur, msg->bodylen);
1612 dummy[msg->bodylen] = '\0';
1613 msg->body = dummy;
1614 cur += msg->bodylen;
1615 sipe_utils_message_debug("SIP",
1616 conn->buffer,
1617 msg->body,
1618 FALSE);
1619 sipe_utils_shrink_buffer(conn, cur);
1620 } else {
1621 if (msg){
1622 SIPE_DEBUG_INFO("sipe_transport_input: body too short (%d < %d, strlen %d) - ignoring message", remainder, msg->bodylen, (int)strlen(conn->buffer));
1623 sipmsg_free(msg);
1626 /* restore header for next try */
1627 cur[-2] = '\r';
1628 return;
1631 // Verify the signature before processing it
1632 if (sip_sec_context_is_ready(transport->registrar.gssapi_context)) {
1633 struct sipmsg_breakdown msgbd;
1634 gchar *signature_input_str;
1635 gchar *rspauth;
1636 msgbd.msg = msg;
1637 sipmsg_breakdown_parse(&msgbd, transport->registrar.realm, transport->registrar.target,
1638 transport->registrar.protocol);
1639 signature_input_str = sipmsg_breakdown_get_string(transport->registrar.version, &msgbd);
1641 rspauth = sipmsg_find_part_of_header(sipmsg_find_header(msg, "Authentication-Info"), "rspauth=\"", "\"", NULL);
1643 if (rspauth != NULL) {
1644 if (!sip_sec_verify_signature(transport->registrar.gssapi_context, signature_input_str, rspauth)) {
1645 SIPE_DEBUG_INFO_NOFORMAT("sip_transport_input: signature of incoming message validated");
1646 process_input_message(sipe_private, msg);
1647 } else {
1648 SIPE_DEBUG_INFO_NOFORMAT("sip_transport_input: signature of incoming message is invalid.");
1649 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1650 SIPE_CONNECTION_ERROR_NETWORK,
1651 _("Invalid message signature received"));
1653 } else if ((msg->response == 401) ||
1654 sipe_strequal(msg->method, "REGISTER")) {
1655 /* a) Retry non-REGISTER requests with updated authentication */
1656 /* b) We must always process REGISTER responses */
1657 process_input_message(sipe_private, msg);
1658 } else {
1659 /* OCS sends provisional messages that are *not* signed */
1660 if (msg->response >= 200) {
1661 /* We are not calling process_input_message(),
1662 so we need to drop the transaction here. */
1663 struct transaction *trans = transactions_find(transport, msg);
1664 if (trans) transactions_remove(sipe_private, trans);
1666 SIPE_DEBUG_INFO_NOFORMAT("sip_transport_input: message without authentication data - ignoring");
1668 g_free(signature_input_str);
1670 g_free(rspauth);
1671 sipmsg_breakdown_free(&msgbd);
1672 } else {
1673 process_input_message(sipe_private, msg);
1676 sipmsg_free(msg);
1678 /* Redirect: old content of "transport" is no longer valid */
1679 transport = sipe_private->transport;
1683 static void sip_transport_connected(struct sipe_transport_connection *conn)
1685 struct sipe_core_private *sipe_private = conn->user_data;
1686 sipe_private->service_data = NULL;
1687 do_register(sipe_private, FALSE);
1690 static void resolve_next_service(struct sipe_core_private *sipe_private,
1691 const struct sip_service_data *start);
1692 static void sip_transport_error(struct sipe_transport_connection *conn,
1693 const gchar *msg)
1695 struct sipe_core_private *sipe_private = conn->user_data;
1697 /* This failed attempt was based on a DNS SRV record */
1698 if (sipe_private->service_data) {
1699 resolve_next_service(sipe_private, NULL);
1700 } else {
1701 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
1702 SIPE_CONNECTION_ERROR_NETWORK,
1703 msg);
1707 /* server_name must be g_alloc()'ed */
1708 static void sipe_server_register(struct sipe_core_private *sipe_private,
1709 guint type,
1710 gchar *server_name,
1711 guint server_port)
1713 sipe_connect_setup setup = {
1714 type,
1715 server_name,
1716 (server_port != 0) ? server_port :
1717 (type == SIPE_TRANSPORT_TLS) ? 5061 : 5060,
1718 sipe_private,
1719 sip_transport_connected,
1720 sip_transport_input,
1721 sip_transport_error
1723 struct sip_transport *transport = g_new0(struct sip_transport, 1);
1725 transport->server_name = server_name;
1726 transport->server_port = setup.server_port;
1727 transport->connection = sipe_backend_transport_connect(SIPE_CORE_PUBLIC,
1728 &setup);
1729 sipe_private->transport = transport;
1732 struct sip_service_data {
1733 const char *protocol;
1734 const char *transport;
1735 guint type;
1738 /* Service list for autodection */
1739 static const struct sip_service_data service_autodetect[] = {
1740 { "sipinternaltls", "tcp", SIPE_TRANSPORT_TLS }, /* for internal TLS connections */
1741 { "sipinternal", "tcp", SIPE_TRANSPORT_TCP }, /* for internal TCP connections */
1742 { "sip", "tls", SIPE_TRANSPORT_TLS }, /* for external TLS connections */
1743 { "sip", "tcp", SIPE_TRANSPORT_TCP }, /*.for external TCP connections */
1744 { NULL, NULL, 0 }
1747 /* Service list for SSL/TLS */
1748 static const struct sip_service_data service_tls[] = {
1749 { "sipinternaltls", "tcp", SIPE_TRANSPORT_TLS }, /* for internal TLS connections */
1750 { "sip", "tls", SIPE_TRANSPORT_TLS }, /* for external TLS connections */
1751 { NULL, NULL, 0 }
1754 /* Service list for TCP */
1755 static const struct sip_service_data service_tcp[] = {
1756 { "sipinternal", "tcp", SIPE_TRANSPORT_TCP }, /* for internal TCP connections */
1757 { "sip", "tcp", SIPE_TRANSPORT_TCP }, /*.for external TCP connections */
1758 { NULL, NULL, 0 }
1761 static const struct sip_service_data *services[] = {
1762 service_autodetect, /* SIPE_TRANSPORT_AUTO */
1763 service_tls, /* SIPE_TRANSPORT_TLS */
1764 service_tcp /* SIPE_TRANSPORT_TCP */
1767 static void sipe_core_dns_resolved(struct sipe_core_public *sipe_public,
1768 const gchar *hostname, guint port)
1770 struct sipe_core_private *sipe_private = SIPE_CORE_PRIVATE;
1772 sipe_private->dns_query = NULL;
1774 if (hostname) {
1775 SIPE_DEBUG_INFO("sipe_core_dns_resolved - SRV hostname: %s port: %d",
1776 hostname, port);
1777 sipe_server_register(sipe_private,
1778 sipe_private->service_data->type,
1779 g_strdup(hostname), port);
1780 } else {
1781 resolve_next_service(SIPE_CORE_PRIVATE, NULL);
1785 static void resolve_next_service(struct sipe_core_private *sipe_private,
1786 const struct sip_service_data *start)
1788 if (start) {
1789 sipe_private->service_data = start;
1790 } else {
1791 sipe_private->service_data++;
1792 if (sipe_private->service_data->protocol == NULL) {
1793 guint type = sipe_private->transport_type;
1795 /* We tried all services */
1796 sipe_private->service_data = NULL;
1798 /* Try connecting to the SIP hostname directly */
1799 SIPE_DEBUG_INFO_NOFORMAT("no SRV records found; using SIP domain as fallback");
1800 if (type == SIPE_TRANSPORT_AUTO)
1801 type = SIPE_TRANSPORT_TLS;
1803 sipe_server_register(sipe_private, type,
1804 g_strdup(sipe_private->public.sip_domain),
1806 return;
1810 /* Try to resolve next service */
1811 sipe_private->dns_query = sipe_backend_dns_query_srv(
1812 sipe_private->service_data->protocol,
1813 sipe_private->service_data->transport,
1814 sipe_private->public.sip_domain,
1815 (sipe_dns_resolved_cb) sipe_core_dns_resolved,
1816 SIPE_CORE_PUBLIC);
1819 void sipe_core_transport_sip_connect(struct sipe_core_public *sipe_public,
1820 guint transport,
1821 const gchar *server,
1822 const gchar *port)
1824 struct sipe_core_private *sipe_private = SIPE_CORE_PRIVATE;
1826 if (server) {
1827 /* Use user specified server[:port] */
1828 int port_number = 0;
1830 if (port)
1831 port_number = atoi(port);
1833 SIPE_DEBUG_INFO("sipe_core_connect: user specified SIP server %s:%d",
1834 server, port_number);
1836 sipe_server_register(sipe_private, transport,
1837 g_strdup(server), port_number);
1838 } else {
1839 /* Server auto-discovery */
1841 /* Remember user specified transport type */
1842 sipe_private->transport_type = transport;
1843 resolve_next_service(sipe_private, services[transport]);
1847 void sipe_core_transport_sip_keepalive(struct sipe_core_public *sipe_public)
1849 SIPE_DEBUG_INFO("sending keep alive %d",
1850 sipe_public->keepalive_timeout);
1851 sipe_utils_message_debug("SIP", "", NULL, TRUE);
1852 sipe_backend_transport_message(SIPE_CORE_PRIVATE->transport->connection,
1853 "\r\n\r\n");
1856 int sip_transaction_cseq(struct transaction *trans)
1858 int cseq;
1860 g_return_val_if_fail(trans && trans->key, 0);
1862 sscanf(trans->key, "<%*[a-zA-Z0-9]><%d INVITE>", &cseq);
1863 return cseq;
1867 Local Variables:
1868 mode: c
1869 c-file-style: "bsd"
1870 indent-tabs-mode: t
1871 tab-width: 8
1872 End: