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; }
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; }
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; }
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; }
/* 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; }
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; }
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; }
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(); } }
string ulong2str(unsigned long i) { return ulong2str(i, "%u"); }