Min-SE 対応
ネゴシエーション対応
http://zzaj.net/chan_sip-se-timer-20060426.diff
sip.conf で設定した session-expires の値が、網側の要求する Min-SE 値より小さい場合は Session-Expires の値を要求された値にするようにしました。
これで一連の draft-ietf-sip-session-timer-08 対応はおしまい。
ネゴシエーション対応
http://zzaj.net/chan_sip-se-timer-20060426.diff
sip.conf で設定した session-expires の値が、網側の要求する Min-SE 値より小さい場合は Session-Expires の値を要求された値にするようにしました。
これで一連の draft-ietf-sip-session-timer-08 対応はおしまい。
refresher の入れ替え要求対応と、受信側の際のタイマ処理まで入れてみました。
http://zzaj.net/chan_sip-se-timer-20060425.diff
ネゴシエーションはまだね。
昨日実家に行って母の車の修理 - バンパーが壊れたので交換 - していて、ヘッドライトの裏のねじを外そうと前かがみになった瞬間に「ピキッ」ときました。
つらいのはやはり翌朝ですね。どうしても起き上がれません。まず起きる体勢に体の向きを変えるのに5分。そこから上体を起こすのに5分。立ち上がるのに5分と合計15分位かかってました。
一度起き上がりさえすれば何とか動けるのですが、しばらく毎朝これが続くと思うと気が滅入ります。
いいかげん Asterisk ネタを引っ張りすぎのような気がしますが、re-INVITE の処理が気になるので書き換えました。説明するのも面倒なのでパッチにします。(Version 1.2.7.1 で作ってあります)
http://zzaj.net/chan_sip-se-timer-20060422.diff
これあてて、sip.conf の該当するチャンネル設定のところに…
session-expires=300
…と記述すると、150秒ごとに re-INVITE を行うようになってます。基本的にはパッチの内容を見てわかる人だけが使って下さい。それから動作の保証はできませんし、このパッチを使ったことによる不具合・不利益にたいしても全く保証はできません。
一応簡単に全体の処理を説明しておくと、session-expires が設定されたチャンネルに発信するときにはヘッダに Session-expires:秒数;refresher=uac と Supported:timer をつけて発信し、接続が成功したら ast_sched_add 関数を用いて session-expires で指定された秒数の半分の間隔で INVITE を送信し続けます。
そして BYE の送信または受信をしたら、ast_sched_del 関数を用いて INVITE の再送のためのタイマを削除します。
本当は refresher の入れ替えや、再送間隔のネゴシエーションも必要なのでしょうけど、とりあえず必要なさそうなので先送りです。
着信時に切れてしまう件ですけど、これはただのチョンボでした。発信時に Session-Expires: 300;refresher=uac と Supported: timer を“全ての発信”に付加していたので、GXP-2000 が“正しく動作”して切断されていたのです。
じゃあ Asahi ネット F に発信するときだけ付加するようにしようというわけでもう少し手を加えました。sip.conf の個別接続に session-expires というパラメータを追加し、秒数を指定させます。(0で無効)
session-expires 保存用の変数を追加
[sip_peer 構造体]
名称は任意
int session_expires;
設定値の読み込み処理を追加
[build_peer 関数]
while ループの中に以下を追加
else if (!strcasecmp(v->name, “session-expires”)) {
if ((sscanf(v->value, “%d”, &peer->session_expires) !=1) || (peer->session_expires < 0)) {
ast_log(LOG_WARNING, "'%s' is not a valid Session-Expires time value at line %d. Using default.\n", v->value, v->
lineno);
peer->session_expires = 0;
}
}
peer 情報を検索する関数を追加
find_peer 関数は sip_peer 構造体の name (sip.conf のカテゴリ名) をキーに peer を検索するのですが、sip_pvt 構造体が持っている peername は peer のカテゴリ名ではなく username なので、 username をキーに peer を検索する関数が必要になります。
static struct sip_peer *find_peer_by_username(const char *peer)
{
struct sip_peer *p = NULL;
ASTOBJ_CONTAINER_TRAVERSE(&peerl, !p, do {
if (!(strcasecmp(iterator->username, peer)))
p = ASTOBJ_REF(iterator);
} while (0));
return p;
}
ヘッダ追加処理を修正
add_header を行っていた2行を修正します。
char expstr[64];
struct sip_peer *peer = NULL;
peer = find_peer_by_username(p->peername);
if (peer != NULL && peer->session_expires > 0) {
memset(expstr, 0, sizeof(expstr));
snprintf(expstr, sizeof(expstr), “%d;refresher=uac”, peer->session_expires);
p->sip_reinvite_timer = 0;
add_header(&req, “Session-Expires”, expstr);
add_header(&req, “Supported”, “timer”);
}
これで Asahi ネットの IP 電話 F を asterisk に収容することができました。めでたしめでたし。
結局のところ 1 回 re-INVITE を送信したら、その後の通話は継続されています。おそらくひかり電話と同じ実装になっているのではないかと思われます。
つまりこの実装では re-INVITE 時に「re-INVITE 送信側の変更」というのを行うことができ、 Session-Expires と Supported を指定しないで re-INVITE を行ったために 「re-INVITE の送信側」が網 (Asahiネット側) に移ったということです。ですから一度 re-INVITE を送信した後は、re-INVITE が Asahi ネット側から送信されるようになりました。
ただ正確に対応するためには、相手側からの送信側変更要求にも対応する必要があるのですが、とりあえず通話できるようになったので手をつけていません。
で、どこを変更すればよいかということなのですが、まともに実装しているわけではないのでパッチの公開はやめておきます。プログラムを変更できる人がわかる程度に記載することにしますね。
内容は発信時にヘッダを追加するという処理と、 INVITE に成功したら (200 OK を受け取ったら) タイマ処理をセットし、タイマ処理実行前に BYE を送信または受信したらタイマ処理をキャンセルするという処理です。
変更は chan_sip.c です。
タイマ ID の追加
[sip_pvt 構造体]
名称は任意
int sip_reinvite_timer;
タイマ処理後にタイマ ID をクリア
[transmit_reinvite_with_sdp 関数
先頭で sip_reinvite_timer を 0 でクリア
p->sip_reinvite_timer = 0;
タイマ関連のヘッダを追加
[transmit_invite 関数]
p->sip_reinvite_timer = 0;
add_header(&req, “Session-Expires”, “300;refresher=uac”);
add_header(&req, “Supported”, “timer”);
BYE 送信時のタイマキャンセル処理
[transmit_request, transmit_request_with_auth 関数]
if (sipmethod == SIP_BYE && p->sip_reinvite_timer != 0)
ast_sched_del(sched, p->sip_reinvite_timer);
タイマを設定
[handle_response_invite 関数]
case 200: の break の前 (秒数はおそらく300秒以内であればOK、ここでは30秒を設定)
if (!strcasecmp(get_header(req, “x”), “300;refresher=uac”))
p->sip_reinvite_timer = ast_sched_add(sched, 30000, transmit_reinvite_with_sdp, p);
BYE 要求時のタイマキャンセル処理
[handle_request_bye 関数]
if (p->sip_reinvite_timer != 0)
ast_sched_del(sched, p->sip_reinvite_timer);
ちなみに voip-info.jp で質問したけど、AsahiネットFには誰も興味ないみたいでスルーされてます。でもこの re-INVITE をちゃんと実装すれば, RT-200{KI | NE} を使わなくてもひかり電話に接続できそうな気がするのだけどどうだろう。あそこではひかり電話がホットな話題みたいですが。
さらに調査を進めると、着信で切れるのは IP 電話機の方に原因があるようでした。Asahiネット側からは150秒ごとに re-INVITE が送信されてきて、Asterisk ではそれに対して 200 OK を返しているので問題はありません。
電話機は Grandstream GXP-2000 なのですが、なぜ切れるのかはまた後日調査することにします。
さて発信ですが、chan_sip.c をもう少しいじって INVITE が成功したら 30 秒後に timer なしで re-INVITE を送信するようにしてみたところ、300 秒を超えても通話を続けることができるようになりました。
なんか Asahi ネットの F も使えそうです。
発信の出来なかった Asahi ネット F ですが、ソースコード (chan_sip.c の transmit_invite) に…
add_header(&req, “Session-Expires”, “300;refresher=uac”);
add_header(&req, “Supported”, “timer”);
…の2行を追加して“発信することだけ”は出来るようになりました。もちろんタイマが実装されていないのに「タイマをサポートしてるし、300秒ごとに re-INVITE をするよ」という意味のヘッダだけを追加しているので、300秒後には切れてしまいます。
それから今まで気付かなかったのだけど、着信のときも一定時間が過ぎると切れてしまいます。
これはバージョン 1.4 になったら実装されるのかな。実装されるのなら待つんだけど。
さて 702NKII を買ってから1ヶ月以上が過ぎ、ハッピーパケットレギュラーが適用された料金内訳が郵送されてきました。
この1ヶ月はウェブをほぼ閲覧せず、Eメールは週に2〜3回外出するときだけ受信するという使い方です。ただ、通話料には国際電話料金が含まれています。
| 基本料金(ライトコールパック) | 3,500 |
|---|---|
| ハッピーボーナス | -3,500 |
| 通話料 | 2,210 |
| MMS | 33 |
| パケット | 983 |
| LOVE定額 | 300 |
| ハッピーパケット定額 | 1,200 |
| ハッピーPktR MMS割引 | -22 |
| ハッピーPktR 無料対象額 | -1,200 |
| ライトコールパック 無料対象額 | -1,000 |
| ボーダフォンアフターサービス | 300 |
| ボーダフォンライブ!基本料 | 300 |
| 合計 | 3,104 |
| 消費税 | 155 |
| ご請求金額 | 3,259 |
今月は基本料がタダなのですが、通常はこれにプラス約3,100円、国際電話分を差し引くとだいたい5,000円位になるのでしょうか。ちなみにこれとは別に au を2回線持っているのですが、こちらは毎月7,000円弱ですので、ちょっと高いという印象です。
HTML convert time: 0.197 sec. Powered by WordPress