Esempio n. 1
0
bool t_call_record::create_file_record(vector<string> &v) const {
	v.clear();
	
	v.push_back(ulong2str(time_start));
	v.push_back(ulong2str(time_answer));
	v.push_back(ulong2str(time_end));
	v.push_back(get_direction_internal());
	v.push_back(from_display);
	v.push_back(from_uri.encode());
	v.push_back(from_organization);
	v.push_back(to_display);
	v.push_back(to_uri.encode());
	v.push_back(to_organization);
	v.push_back(reply_to_display);
	v.push_back(reply_to_uri.encode());
	v.push_back(referred_by_display);
	v.push_back(referred_by_uri.encode());
	v.push_back(subject);
	v.push_back(get_rel_cause_internal());
	v.push_back(int2str(invite_resp_code));
	v.push_back(invite_resp_reason);
	v.push_back(far_end_device);
	v.push_back(user_profile);
	
	return true;
}
bool t_subscription_dialog::process_initial_subscribe_response(t_response *r, t_tuid tuid, t_tid tid) {
	switch (r->get_class()) {
	case R_2XX:
		remote_tag = r->hdr_to.tag;
		remote_uri = r->hdr_to.uri;
		remote_display = r->hdr_to.display;
		create_route_set(r);
		create_remote_target(r);
		break;
	case R_4XX:
		if (r->code == R_423_INTERVAL_TOO_BRIEF) {
			if (!r->hdr_min_expires.is_populated()) {
				// Violation of RFC 3261 10.3 item 7		
				log_file->write_report("Expires header missing from 423 response.",
					"t_subscription_dialog::process_initial_subscribe_response",
					LOG_NORMAL, LOG_WARNING);
				break;
			}

			if (r->hdr_min_expires.time <= subscription->get_expiry()) {
				// Wrong Min-Expires time
				string s = "Min-Expires (";
				s += ulong2str(r->hdr_min_expires.time);
				s += ") is smaller than the requested ";
				s += "time (";
				s += ulong2str(subscription->get_expiry());
				s += ")";
                                log_file->write_report(s,
                                	"t_subscription_dialog::process_initial_subscribe_response",
                                	LOG_NORMAL, LOG_WARNING);
				break;
			}
			
			// Subscribe with the advised interval
			subscribe(r->hdr_min_expires.time, remote_target_uri, 
				remote_uri, remote_display);
			return true;
		}
		
		break;
	default:
		break;
	}
	
	return false;
}
Esempio n. 3
0
string t_hdr_retry_after::encode_value(void) const {
	string s;

	if (!populated) return s;

	s = ulong2str(time);

	if (comment.size() > 0) {
		s += " (";
		s += comment;
		s += ')';
	}

	if (duration > 0) {
		s += ";duration=";
		s += ulong2str(duration);
	}

	s += param_list2str(params);

	return s;
}
Esempio n. 4
0
string duration2str(unsigned long seconds) {
	string result;
	long remainder, h, m, s;
	
	h = seconds / 3600;
	remainder = seconds % 3600;
	m = remainder / 60;
	s = remainder % 60;

	if (h > 0) {
		result = ulong2str(h);
		result += "h ";
	}
	
	if (!result.empty() || m > 0) {
		result += ulong2str(m);
		result += "m ";
	}
	
	result += ulong2str(s);
	result += "s";

	return result;
}
Esempio n. 5
0
string t_hdr_auth_info::encode_value(void) const {
	string s;
	bool add_comma = false;

	if (!populated) return s;

	if (next_nonce.size() > 0) {
		s += "nextnonce=";
		s += '"';
		s += next_nonce;
		s += '"';
		add_comma = true;
	}

	if (message_qop.size() > 0) {
		if (add_comma) s += ',';
		s += "qop=";
		s += message_qop;
		add_comma = true;
	}

	if (response_auth.size() > 0) {
		if (add_comma) s += ',';
		s += "rspauth=";
		s += '"';
		s += response_auth;
		s += '"';
		add_comma = true;
	}

	if (cnonce.size() > 0) {
		if (add_comma) s += ',';
		s += "cnonce=";
		s += '"';
		s += cnonce;
		s += '"';
		add_comma = true;
	}

	if (nonce_count > 0) {
		if (add_comma) s += ',';
		s += "nc=";
		s += ulong2str(nonce_count, "%08x");
		add_comma = true;
	}

	return s;
}
Esempio n. 6
0
/* returns zero on success, nonzero on error */
static int append_format(
	struct string_builder *bld,
	const struct format_args *args,
	void *argv,
	int *argidx,
	int isval,
	char **errmsg
)
{
	switch (args->spec) {
	case '%':
		append_string(bld, "%", 1);
		break;
	case 's': {
		const char *str;
		size_t len;

		if (isval) {
			SpnString *strobj;

			/* must be a string */
			SpnValue *val = getarg_val(argv, argidx);
			if (!isstring(val)) {
				format_errmsg(
					errmsg,
					TYPE_MISMATCH,
					*argidx,
					SPN_TYPE_STRING,
					val->type
				);
				return -1;
			}

			strobj = stringvalue(val);
			str = strobj->cstr;
			len = strobj->len;
		} else {
			str = getarg_raw(argv, argidx);
			len = strlen(str);
		}

		if (args->precision >= 0 && args->precision < len) {
			len = args->precision;
		}

		if (args->width >= 0 && args->width > len) {
			size_t pad = args->width - len;
			expand_buffer(bld, pad);

			while (pad-- > 0) {
				bld->buf[bld->len++] = ' ';
			}
		}

		append_string(bld, str, len);
		break;
	}
	case 'i':
	case 'd':
	case 'b':
	case 'o':
	case 'u':
	case 'x':
	case 'X': {
		char *buf, *end, *begin;
		size_t len = PR_LONG_DIGITS;
		enum format_flags flags = args->flags;
		unsigned base = base_for_specifier(args->spec);
		long n;
		unsigned long u;

		if (isval) {
			/* must be a number */
			SpnValue *val = getarg_val(argv, argidx);
			if (!isnum(val)) {
				format_errmsg(
					errmsg,
					TYPE_MISMATCH,
					*argidx,
					SPN_TTAG_NUMBER,
					val->type
				);
				return -1;
			}

			if (isint(val)) {
				n = intvalue(val);
			} else {
				n = floatvalue(val); /* truncate */
			}
		} else {
			/* "%i" expects an int, others expect a long */
			if (args->spec == 'i') {
				n = *(const int *)getarg_raw(argv, argidx);
			} else {
				n = *(const long *)getarg_raw(argv, argidx);
			}
		}

		if (args->spec == 'i' || args->spec == 'd') {
			/* signed conversion specifiers */
			if (n < 0) {
				flags |= FLAG_NEGATIVE;
				u = -n;
			} else {
				u = n;
			}
		} else {
			/* unsigned conversion specifiers */
			u = n;
		}

		if (args->spec == 'X') {
			flags |= FLAG_CAPS;
		}

		if (args->width >= 0 && args->width > len) {
			len = args->width;
		}

		buf = spn_malloc(len);
		end = buf + len;
		begin = ulong2str(end, u, base, args->width, flags);

		assert(buf <= begin);
		append_string(bld, begin, end - begin);
		free(buf);

		break;
	}
	case 'c': {
		unsigned char ch;
		int len = 1; /* one character is one character long... */

		if (isval) {
			/* must be an integer */
			SpnValue *val = getarg_val(argv, argidx);

			if (!isnum(val)) {
				format_errmsg(
					errmsg,
					TYPE_MISMATCH,
					*argidx,
					SPN_TTAG_NUMBER,
					val->type
				);
				return -1;
			}

			if (isfloat(val)) {
				format_errmsg(errmsg, EXPECT_INTEGER, *argidx);
				return -1;
			}

			ch = intvalue(val);
		} else {
			ch = *(const long *)getarg_raw(argv, argidx);
		}

		if (args->width > len) {
			len = args->width;
		}

		expand_buffer(bld, len);

		while (len-- > 1) {
			bld->buf[bld->len++] = ' ';
		}

		bld->buf[bld->len++] = ch;

		break;
	}
	case 'f':
	case 'F': {
		char *buf, *end, *begin;
		size_t len;
		int prec;
		double x;
		enum format_flags flags = args->flags;

		if (isval) {
			SpnValue *val = getarg_val(argv, argidx);
			if (!isnum(val)) {
				format_errmsg(
					errmsg,
					TYPE_MISMATCH,
					*argidx,
					SPN_TTAG_NUMBER,
					val->type
				);
				return -1;
			}

			if (isfloat(val)) {
				x = floatvalue(val);
			} else {
				x = intvalue(val);
			}
		} else {
			x = *(const double *)getarg_raw(argv, argidx);
		}

		if (args->spec == 'F') {
			flags |= FLAG_CAPS;
		}

		/* handle special cases */
		if (+1.0 / x == +1.0 / -0.0) {
			/* negative zero: set sign flag and carry on */
			flags |= FLAG_NEGATIVE;
		} else if (
			x != x		/*  NaN */
		     || x == +1.0 / 0.0	/* +inf */
		     || x == -1.0 / 0.0	/* -inf */
		) {
			print_special_fp(bld, flags, args->width, x);
			break;
		}

		if (x < 0.0) {
			flags |= FLAG_NEGATIVE;
			x = -x;
		}

		/* at this point, `x' is non-negative or -0 */

		if (x >= 1.0) {
			len = ceil(log10(x)) + 1; /* 10 ^ n is n + 1 digits long */
		} else {
			len = 1; /* leading zero needs exactly one character */
		}

		prec = args->precision < 0 ? DBL_DIG : args->precision;

		len += prec + 3; /* decimal point, sign, leading zero */

		if (args->width >= 0 && args->width > len) {
			len = args->width;
		}

		buf = spn_malloc(len);
		end = buf + len;
		begin = double2str(end, x, args->width, prec, flags);

		assert(buf <= begin);
		append_string(bld, begin, end - begin);
		free(buf);

		break;
	}
	case 'B': {
		int boolval;
		const char *str;
		size_t len;

		if (isval) {
			/* must be a boolean */
			SpnValue *val = getarg_val(argv, argidx);
			if (!isbool(val)) {
				format_errmsg(
					errmsg,
					TYPE_MISMATCH,
					*argidx,
					SPN_TTAG_BOOL,
					val->type
				);
				return -1;
			}

			boolval = boolvalue(val);
		} else {
			boolval = *(const int *)getarg_raw(argv, argidx);
		}

		str = boolval ? "true" : "false";
		len = strlen(str);

		if (args->precision >= 0 && args->precision < len) {
			len = args->precision;
		}

		if (args->width >= 0 && args->width > len) {
			size_t pad = args->width - len;
			expand_buffer(bld, pad);

			while (pad-- > 0) {
				bld->buf[bld->len++] = ' ';
			}
		}

		append_string(bld, str, len);
		break;
	}
	default:
		format_errmsg(errmsg, INVALID_SPECIFIER, ++*argidx, args->spec);
		return -1;
	}

	return 0;
}
Esempio n. 7
0
string t_digest_response::encode(void) const {
	string s;

	if (username.size() > 0) {
		s += "username="******"';
		s += username;
		s += '"';
	}

	if (realm.size() > 0) {
		if (s.size() > 0) s += ',';
		s += "realm=";
		s += '"';
		s += realm;
		s += '"';
	}

	if (nonce.size() > 0) {
		if (s.size() > 0) s += ',';
		s += "nonce=";
		s += '"';
		s += nonce;
		s += '"';
	}

	if (digest_uri.is_valid()) {
		if (s.size() > 0) s += ',';
		s += "uri=";
		s += '"';
		s += digest_uri.encode();
		s += '"';
	}

	if (dresponse.size() > 0) {
		if (s.size() > 0) s += ',';
		s += "response=";
		s += '"';
		s += dresponse;
		s += '"';
	}

	if (algorithm.size() > 0) {
		if (s.size() > 0) s += ',';
		s += "algorithm=";
		s += algorithm;
	}

	if (cnonce.size() > 0) {
		if (s.size() > 0) s += ',';
		s += "cnonce=";
		s += '"';
		s += cnonce;
		s += '"';
	}

	if (opaque.size() > 0) {
		if (s.size() > 0) s += ',';
		s += "opaque=";
		s += '"';
		s += opaque;
		s += '"';
	}

	if (message_qop.size() > 0) {
		if (s.size() > 0) s += ',';
		s += "qop=";
		s += message_qop;
	}

	if (nonce_count > 0) {
		if (s.size() > 0) s += ',';
		s += "nc=";
		s += ulong2str(nonce_count, "%08x");
	}

	for (list<t_parameter>::const_iterator i = auth_params.begin();
	     i != auth_params.end(); i++)
	{
		if (s.size() > 0) s += ',';
		s += i->encode();
	}

	return s;
}
Esempio n. 8
0
void t_log::write_header(const string &func_name, t_log_class log_class,
	                  t_log_severity severity)
{
	if (log_disabled) return;
	
	mtx_log.lock();
	
	if (severity == LOG_DEBUG) {
		 if (!sys_config->get_log_show_debug()) {
		 	log_report_disabled = true;
		 	return;
		 }
	}
	
	switch (log_class) {
	case LOG_SIP:
		if (!sys_config->get_log_show_sip()) {
			log_report_disabled = true;
			return;
		}
		break;
	case LOG_STUN:
		if (!sys_config->get_log_show_stun()) {
			log_report_disabled = true;
			return;
		}
		break;
	case LOG_MEMORY:
		if (!sys_config->get_log_show_memory()) {
			log_report_disabled = true;
			return;
		}
		break;
	default:
		break;
	}

	struct timeval t;
	struct tm tm;
	time_t	date;

	gettimeofday(&t, NULL);
	date = t.tv_sec;
	::localtime_r(&date, &tm);

	*log_stream << "+++ ";
	*log_stream << tm.tm_mday;
	*log_stream << "-";
	*log_stream << tm.tm_mon + 1;
	*log_stream << "-";
	*log_stream << tm.tm_year + 1900;
	*log_stream << " ";
	*log_stream << int2str(tm.tm_hour, "%02d");
	*log_stream << ":";
	*log_stream << int2str(tm.tm_min, "%02d");
	*log_stream << ":";
	*log_stream << int2str(tm.tm_sec, "%02d");
	*log_stream << ".";
	*log_stream << ulong2str(t.tv_usec, "%06d");
	*log_stream << " ";

	// Severity
	switch (severity) {
	case LOG_INFO:
		*log_stream << "INFO";
		break;
	case LOG_WARNING:
		*log_stream << "WARNING";
		break;
	case LOG_CRITICAL:
		*log_stream << "CRITICAL";
		break;
	case LOG_DEBUG:
		*log_stream << "DEBUG";
		break;
	default:
		*log_stream << "UNNKOWN";
		break;
	}
	*log_stream << " ";

	// Message class
	switch (log_class) {
	case LOG_NORMAL:
		*log_stream << "NORMAL";
		break;
	case LOG_SIP:
		*log_stream << "SIP";
		break;
	case LOG_STUN:
		*log_stream << "STUN";
		break;
	case LOG_MEMORY:
		*log_stream << "MEMORY";
		break;
	default:
		*log_stream << "UNNKOWN";
		break;
	}
	*log_stream << " ";

	*log_stream << func_name;
	*log_stream << endl;
}
Esempio n. 9
0
void t_phone_user::handle_response_register(t_response *r, bool &re_register) {
	t_contact_param *c;
	unsigned long expires;
	unsigned long e;
	bool first_failure, first_success;

	re_register = false;
	
	// Store the destination IP address/port of the REGISTER message.
	// To this destination the NAT keep alive packets will be sent.
	t_request *req = r_register->get_request();
	req->get_destination(register_ip_port, *user_config);

        switch(r->get_class()) {
        case R_2XX:
                last_reg_failed = false;

                // Stop registration timer if one was running
                phone->stop_timer(PTMR_REGISTRATION, this);

                c = r->hdr_contact.find_contact(req->hdr_contact.contact_list.front().uri);
                if (!c) {               	
	               	if (!user_config->get_allow_missing_contact_reg()) {
				is_registered = false;

	              		log_file->write_report(
        	       			"Contact header is missing.",
               				"t_phone_user::handle_response_register",
               				LOG_NORMAL, LOG_WARNING);
				
				ui->cb_invalid_reg_resp(user_config,
					r, "Contact header missing.");
				cleanup_registration_data();
				return;
                        } else {
                        	log_file->write_report(
                        		"Cannot find matching contact header.",
                        		"t_phone_user::handle_response_register",
                        		LOG_NORMAL, LOG_DEBUG);
                        }
                }

                if (c && c->is_expires_present() && c->get_expires() != 0) {
                        expires = c->get_expires();
                }
                else if (r->hdr_expires.is_populated() &&
                         r->hdr_expires.time != 0)
                {
                        expires = r->hdr_expires.time;
                }
                else {	
               		if (!user_config->get_allow_missing_contact_reg()) {
				is_registered = false;
				
               			log_file->write_report(
               				"Expires parameter/header mising.",
               				"t_phone_user::handle_response_register",
               				LOG_NORMAL, LOG_WARNING);
				
				ui->cb_invalid_reg_resp(user_config,
					r, "Expires parameter/header mising.");
				cleanup_registration_data();
				return;
                        }
                        
                        expires = user_config->get_registration_time();
                        
                        // Assume a default expiration of 3600 sec if no expiry
                        // time was returned.
                        if (expires == 0) expires = 3600;
                }

                // Start new registration timer
                // The maximum value of the timer can be 2^32-1 s
                // The maximum timer that we can handle however is 2^31-1 ms
                e = (expires > 2147483 ? 2147483 : expires);
                phone->start_set_timer(PTMR_REGISTRATION, e * 1000, this);
		// Save the Service-Route if present the response contains any

		// RFC 3608 6
		// Collect the service route to route later initial requests.
		if (r->hdr_service_route.is_populated()) {
			service_route = r->hdr_service_route.route_list;
			log_file->write_header("t_phone_user::handle_response_register");
			log_file->write_raw("Store service route:\n");
			for (list<t_route>::const_iterator it = service_route.begin();
			     it != service_route.end(); ++it)
			{
				log_file->write_raw(it->encode());
				log_file->write_endl();
			}
			log_file->write_footer();
		} else {
			if (!service_route.empty())
			{
				log_file->write_report("Clear service route.",
					"t_phone_user::handle_response_register");
				service_route.clear();
			}
		}

		first_success = !is_registered;
                is_registered = true;
		ui->cb_register_success(user_config, r, expires, first_success);
		
		// Start sending NAT keepalive packets when STUN is used
		// (or in case of symmetric firewall)
		if (use_nat_keepalive && id_nat_keepalive == 0) {
			// Just start the NAT keepalive timer. The REGISTER
			// message itself created the NAT binding. So there is
			// no need to send a NAT keep alive packet now.
			phone->start_timer(PTMR_NAT_KEEPALIVE, this);
		}
		
		// Start sending TCP ping packets on persistent TCP connections.
		if (user_config->get_persistent_tcp() && id_tcp_ping == 0) {
			phone->start_timer(PTMR_TCP_PING, this);
		}
		
		// Registration succeeded. If sollicited MWI is provisioned
		// and no MWI subscription is established yet, then subscribe
		// to MWI.
		if (user_config->get_mwi_sollicited() && !mwi_auto_resubscribe) {
			subscribe_mwi();
		}
		
		// Publish presence state if not yet published.
		if (user_config->get_pres_publish_startup() && 
		    presence_epa->get_epa_state() == t_epa::EPA_UNPUBLISHED)
		{
			publish_presence(t_presence_state::ST_BASIC_OPEN);
		}
		
		// Subscribe to buddy list presence if not done so.
		if (!buddy_list->get_is_subscribed()) {
			subscribe_presence();
		}

                break;
        case R_4XX:
                is_registered = false;

                // RFC 3261 10.3
                if (r->code == R_423_INTERVAL_TOO_BRIEF) {
                        if (!r->hdr_min_expires.is_populated()) {
                                // Violation of RFC 3261 10.3 item 7
				log_file->write_report("Min-Expires header missing from 423 response.",
					"t_phone_user::handle_response_register",
					LOG_NORMAL, LOG_WARNING);
                                ui->cb_invalid_reg_resp(user_config, r,
                                        "Min-Expires header missing.");
				cleanup_registration_data();
                                return;
                        }

                        if (r->hdr_min_expires.time <= registration_time) {
                                // Wrong Min-Expires time
                                string s = "Min-Expires (";
                                s += ulong2str(r->hdr_min_expires.time);
                                s += ") is smaller than the requested ";
                                s += "time (";
                                s += ulong2str(registration_time);
                                s += ")";
                                log_file->write_report(s, "t_phone_user::handle_response_register",
                                	LOG_NORMAL, LOG_WARNING);
                                ui->cb_invalid_reg_resp(user_config, r, s);
				cleanup_registration_data();
                                return;
                        }

                        // Automatic re-register with Min-Expires time
                        registration_time = r->hdr_min_expires.time;
                        re_register = true;
                        // No need to cleanup STUN data as a new REGISTER will be
                        // sent immediately.
                        return;
                }

		// If authorization failed, then do not start the continuous
		// re-attempts. When authorization fails the user is asked
		// for credentials (in GUI). So the user cancelled these
		// questions and should not be bothered with the same question
		// again every 30 seconds. The user does not have the
		// credentials.
		if (r->code == R_401_UNAUTHORIZED ||
		    r->code == R_407_PROXY_AUTH_REQUIRED)
		{
			last_reg_failed = true;
			ui->cb_register_failed(user_config, r, true);			
	
			cleanup_registration_data();
			return;
		}

                // fall thru
        default:
		first_failure = !last_reg_failed;
                last_reg_failed = true;
                is_registered = false;
                authorizor.remove_from_cache(""); // Clear credentials cache
		ui->cb_register_failed(user_config, r, first_failure);
                phone->start_set_timer(PTMR_REGISTRATION, DUR_REG_FAILURE * 1000, this);

		cleanup_registration_data();
        }
}
Esempio n. 10
0
string ulong2str(unsigned long i) {
	return ulong2str(i, "%u");
}