django-rest-frameworkのserializerでいろんなメソッドの呼ばれる順番

注釈

この記事の目的

  • django-rest-framework を使っていて、serializerが中でどういう処理をしているのかがわからなくてつらい
  • そうだ、フレームワークの中身を読んでみよう

環境

  • djangorestframework: 3.9.1

見るところ

  • rest_framework/serializers.py
    • class Serializer(BaseSerializer)の辺り
    • とりあえずここ理解すれば他もなんとかなる?

読む

  • renderersとかmixinsとかは後回しでいきなりserializers

to_internal_value(self, data)

 471     def to_internal_value(self, data):
 472         """
 473         Dict of native values <- Dict of primitive datatypes.
 474         """
 475         if not isinstance(data, Mapping):
 476             message = self.error_messages['invalid'].format(
 477                 datatype=type(data).__name__
 478             )
 479             raise ValidationError({
 480                 api_settings.NON_FIELD_ERRORS_KEY: [message]
 481             }, code='invalid')
  • 受け取ったデータ型の検証とか?
 483         ret = OrderedDict()
 484         errors = OrderedDict()
 485         fields = self._writable_fields
  • ret: 最終的な返却値
  • errors: 例外情報
  • fields: to_internal_valueで処理する対象が格納されている。
    • _writable_fieldsは以下の通り。
 367     @cached_property
 368     def _writable_fields(self):
 369         return [
 370             field for field in self.fields.values() if not field.read_only
 371         ]
  • read_onlyプロパティがFalseになっているfieldだけが含まれるらしい。
 487         for field in fields:
 488             validate_method = getattr(self, 'validate_' + field.field_name, None)
 489             primitive_value = field.get_value(data)
 490             try:
 491                 validated_value = field.run_validation(primitive_value)
  • fieldのrun_vaildationを実行
 523     def run_validation(self, data=empty):
 524         """
 525         Validate a simple representation and return the internal value.
 526
 527         The provided data may be `empty` if no representation was included
 528         in the input.
 529
 530         May raise `SkipField` if the field should not be included in the
 531         validated data.
 532         """
 533         (is_empty_value, data) = self.validate_empty_values(data)
 534         if is_empty_value:
 535             return data
 536         value = self.to_internal_value(data)
 537         self.run_validators(value)
 538         return value
  • 渡ってきた値のto_internal_valueを呼び出し。
    • ここの処理はまた今度読む
 492                 if validate_method is not None:
 493                     validated_value = validate_method(validated_value)
  • validate_<field名> という名前でメソッドが宣言されてたらそれを実行する
 494             except ValidationError as exc:
 495                 errors[field.field_name] = exc.detail
 496             except DjangoValidationError as exc:
 497                 errors[field.field_name] = get_error_detail(exc)
 498             except SkipField:
 499                 pass
  • 例外が発生したらerrorsに入れる
 500             else:
 501                 set_value(ret, field.source_attrs, validated_value)
  • validate_<field名>のメソッドを実行した結果をretに入れる
 503         if errors:
 504             raise ValidationError(errors)
  • 何かしらのエラーがあったら例外発火
 506         return ret

to_representation

 508     def to_representation(self, instance):
 509         """
 510         Object instance -> Dict of primitive datatypes.
 511         """
 512         ret = OrderedDict()
 513         fields = self._readable_fields
  • fields: _readable_fieldsで取得
    • _readable_fieldsは以下の処理
    • write_onlyでないフィールドを取得している
 373     @cached_property
 374     def _readable_fields(self):
 375         return [
 376             field for field in self.fields.values()
 377             if not field.write_only
 378         ]
 514
 515         for field in fields:
 516             try:
 517                 attribute = field.get_attribute(instance)
 518             except SkipField:
 519                 continue
  • instanceから指定のフィールドに格納されているデータを取得
 521             # We skip `to_representation` for `None` values so that fields do
 522             # not have to explicitly deal with that case.
 523             #
 524             # For related fields with `use_pk_only_optimization` we need to
 525             # resolve the pk value.
 526             check_for_none = attribute.pk if isinstance(attribute, PKOnlyObject) else attribute
 527             if check_for_none is None:
 528                 ret[field.field_name] = None
 529             else:
 530                 ret[field.field_name] = field.to_representation(attribute)
  • コメントのとおり…
  • to_internal_valueと同様に、fieldのto_representationも順に呼び出される
 531
 532         return ret

まとめ

  • to_internal_value
    • 各fieldに対してto_internal_valueとvalidationを繰り返してる
    • オブジェクトがネストされているときは、深いところからto_internal_valuevalidate_<field名> が実行されることになりそう
  • to_representation
    • fieldto_representationを呼び出してるくらい?
  • field.to_internal_valueとかfield.to_representationはまた今度読む

Cisco 1812j でOSPFを動かすためのコンフィグ

やったこと

Cisco 1812jを用いてマルチエリアOSPFネットワークを構築。
設定を入れて、実際のパケットの流れとか追ってみた。

構成

Endpoint Device1 --- Router1(C1812j) --- Router2(C1812j) --- Endpoint Device2

Cisco 1812jはFastether0とFastether1のインターフェースを持つ。Router間の接続にFastether 0、RouterとEndpoint Deviceの接続にFastether 1を使用した。

コンフィグ

事前準備

IPアドレス設定

Router1

Router1(config)# interface fastether 0
Router1(config-if)# no shutdown
Router1(config-if)# ip address 192.168.0.1 255.255.255.0


Router1(config)# interface fastether 1
Router1(config-if)# no shutdown
Router1(config-if)# ip address 192.168.1.1 255.255.255.0

Router2

Router2(config)# interface fastether 0
Router2(config-if)# no shutdown
Router2(config-if)# ip address 192.168.0.2 255.255.255.0


Router2(config)# interface fastether 1
Router2(config-if)# no shutdown
Router2(config-if)# ip address 192.168.2.1 255.255.255.0
DHCP設定

Router1

Router1(config)# ip dhcp pool network1
Router1(dhcp-config)# network 192.168.1.0 /24
Router(dhcp-config)# default-router 192.168.1.1
Router(dhcp-config)# dns-server 192.168.1.1

Router2

Router2(config)# ip dhcp pool network2
Router2(dhcp-config)# network 192.168.2.0 /24
Router2(dhcp-config)# default-router 192.168.2.1
Router2(dhcp-config)# dns-server 192.168.2.1

本題

OSPF設定

Router1
area 0

Router1(config)# router ospf 1
Router1(config-router)# network 192.168.0.0 0.0.0.255 area 0

area 1

Router1(config)# router ospf 1
Router1(config-router)# network 192.168.1.0 0.0.0.255 area 1

Router2
area 0

Router2(config)# router ospf 1
Router2(config-router)# network 192.168.0.0 0.0.0.255 area 0

area 1

Router2(config)# router ospf 1
Router2(config-router)# network 192.168.2.0 0.0.0.255 area 2

これでコンバージェンスを待つと通信ができるようになる。

仕組みの話は今度調べてまとめる

Ubuntu 14.04でJavaScriptエンジンのSpidermonkeyをビルドして逆アセンブルする

Mozillafirefoxに搭載されているJavaScriptエンジンであるSpidermonkeyをビルドする.
今回は実行したJavaScriptコードを逆アセンブルできるようにする.
公式はこちら

準備

# apt-get install autoconf

ソースの取得

# git clone https://github.com/mozilla/gecko-dev.git

ビルド

# cd gecko-dev/js/src
# autoconf
# mkdir Debug
# cd Debug
# ../configure --enable-debug --disable-optimize
# make

これでdis()とかdissrc()とかできる.

Ubuntu 12.04 LTS で GoogleのJavaScriptエンジンV8をスタンドアロンで動かす

基本的には公式のドキュメントに従って進めるだけ.
今回は実行するJavaScriptを逆アセンブルしたコードを出力させるようにする.

Prepare

$ sudo apt-get install gcc g++ git subversion gcc-multilib g++-multilib

Install depot_tools

$ git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
$ export PATH="$PATH":`pwd`/depot_tools

Get source code

$ svn co http://v8.googlecode.com/svn/trunk v8

Prerequisite: Installing GYP

$ cd v8
$ make dependencies

Building

$ make -j4 release disassembler=on

Run

$ cd out/xxx.release
$ ./d8 hoge.js -print-code

rfc4960 key term

RFC 4960のkey termを日本語っぽくしてみた.

  • active distination transpot address:

 ユーザメッセージを受け取ることができるトランスポートアドレス
 IPアドレスとポート番号の組

  • bundling:

 多重化処理.複数ののユーザメッセージを単一のSCTPパケットで配送できる.

  • chunk:

 SCTPパケットの情報の単位.チャンクヘッダとチャンク本体から成る.

  • congestion window(cwnd):

 確認応答を受け取る前に,送信者が特定のトランスポートアドレスに送信できるデータのバイト数を制限するSCTPの変数.

  • cumulative tsn ack point:

 SACKのCumulative TSN Ackフィールドによって通知された最後のデータチャンクのTSN.
 (TSN: Transmission Sequence Number)

 ある一定期間(ハートビートの間隔またはそれ以上)ユーザメッセージが送られなていないトランスポートアドレス.

  • message(user message):

 上位レイヤプロトコル(ULP)からSCTPに渡されるデータ

  • message authentication code(MAC):

 秘密鍵を用いて暗号ハッシュ関数に基づいて,整合性をチェックするメカニズム.
 主にMAC秘密鍵を共有したパーティの間で,転送された情報の検証のために使われる.SCTPでは,CookieEchoチャンクでピアから返されるState Cookie情報の検証のために用いられる.
 "MAC"という用語は,文脈によって異なる意味を持つ.SCTPはRFC2104と同じ意味を持つ.

  • NetwokByteOrder:

 ビッグエンディアン

  • orderd Message:

 メッセージが送信されたストリームで,以前に送信された全てのユーザメッセージに関して順番に配信されているユーザメッセージ.(←?)

  • outstanding TSN(at an SCTP endpoint):

 送信されたが,確認応答を受け取っていないTSN(またはそれに関連付けられたデータチャンク)

  • Path:

 SCTPエンドポイントの特定の宛先トランスポートアドレスへSCTPエンドポイントのよって送信されたSCTPパケットが通るルート.異なる宛先トランスポートアドレスに送信することはパスが分割されることを保証しない.

  • primary path:

 デフォルトでパケットが出ていく宛先と送信元アドレス.定義が送信元を含むのは,送信者がマルチホームのとき,応答チャンクが通る特定の経路や,パケットが転送されるインターフェースを制御するために,宛先と送信元のアドレスを特定したいかもしれないから.

  • Receiver Window(rwnd):

 データ送信者が,直近で計算した受信者ウィンドウを,バイト単位で格納するために用いる変数.
 受信者が送信者に,受信バッファの空き容量を通知することができるようにする.

  • SCTP Association:

 SCTPエンドポイント間の,二つのSCTPエンドポイントとVerification TagsやアクティブなTSN集合などを含む,プロトコル状態情報からなる関連づけ.アソシエーションは,エンドポイントのトランスポートアドレスによって一意に特定される.二つのSCTPエンドポイントは,常に1つ以上のアソシエーションを持たなければならない.

  • SCTP endpoint:

 SCTPパケットの論理的な送信者と受信者.マルチホームホストにおいて,SCTPエンドポイントは,送信可能なトランスポートアドレスの集合と受信可能なトランスポートアドレスの集合の組合せとして表現されている.一つのSCTPエンドポイントによって用いられるトランスポートアドレスは,同じポート番号を用いなければならない.しかし複数IPアドレスを使用することは可能.つまり,トランスポートアドレスはSCTPエンドポイントで一意である.

  • SCTP packet(packet):

 SCTPとコネクションレスパケットネットワークの間で配送されるデータ単位である.SCTPパケットは,SCTP共通ヘッダ,制御チャンク,DATAチャンクにカプセル化されたユーザデータを含む.

  • SCTP user application(SCTP user):

SCTPのサービスを利用する論理的な上位レイヤアプリケーション.(ULP)

  • Slow-Start Threshold(ssthresh):

 SCTPの変数.特定のトランスポートアドレスにおいて,スロースタートや輻輳回避を用いるかどうかを決定するために使う.バイト単位で表現される.

  • Stream:

 SCTPエンドポイントから関連付けられた他方のエンドポイントに生成される,単方向の論理的な経路.順序付けなし配送サービスでメッセージ以外の全てのユーザメッセージはこれの上で順番に送信される.

  • Stream Sequence Number:

SCTP内部で,ストリームでユーザメッセージの順序付けられた配送を保証するために用いる16ビットのシーケンス番号.一つのStream Sequence Numberは各ユーザメッセージに紐付けられる.

  • Tie-Tags:

 64ビットのnonceを作る二つの32ビット乱数.これらのタグは,新たに再開されるアソシエーションが再開せず,既存のアソシエーションの真のVerification Tagsが明らかになっていないエンドポイントの元のアソシエーションにリンクされるようにするために,StateCookieとTCBに用いられる.

  • Transmission Control Block(TCB):

 他のSCTPエンドポイントへの既存のSCTPアソシエーションのために,SCTPエンドポイントによって生成されるデータの内部構造.TCBはエンドポイントが対応するアソシエーションを維持管理するための全ての状態や処理情報を含む.

  • Transmiission Sequence Number(TSN):

 SCTPが内部で使う32ビットのシーケンス番号.一つのTSNは,受信SCTPエンドポイントに受信や重複検知の確認応答をすること可能にするためにユーザデータを含む各チャンクに紐付けられる.

  • Transpot Address:

 トランスポートアドレスは従来,ネットワーク層のアドレスとトランスポート層プロトコルによって定義されていた.IP上で動作しているSCTPの場合,トランスポートアドレスは,IPアドレスとSCTPポート番号の組合せによって定義される.

  • Unacknowledged TSN(at an SCTP endpoint):

 エンドポイントによって受信はされたが,確認応答が送信されていないTSN,または逆に,送信はしたが確認応答が帰ってきていないパケットのTSN

  • Unordered Message:

 Unordered Messagesは他のメッセージに関して順不同である.これには,他の順不同メッセージだけでなく,他の順序付けられたメッセージも含む.順不同メッセージは,同一ストリームで送信された,順序付けられたメッセージの前や後に配送され得る.

  • User Message:

 SCTPとユーザの間のインターフェース間で配送されるデータ単位.

  • Verification Tag:

 ランダムに生成される32ビット符号なし整数.Verification Tagは,受信者に現在のアソシエーションに属するSCTPパケットを検証し,過去のアソシエーションからの古いパケットではないことを確認することを許す鍵を提供する.


とりあえずこんな感じ.
意味わからんところは随時修正していく.

SCTPを試す

LTEや,LTE Advancedの制御信号の送受信に使われてたり,openflowでサポートされてたりと
最近何かと話題のSCTPを軽く試してみる.
プロトコルの仕様はまだ読み切っていないが,アサーションの生成とデータの送信,アサーションのシャットダウンまでを動かす.

環境:

 Ubuntu14.04 LTS 64bit (VMWare Player上で動作)

準備:

SCTPをコマンドライン上で動かすためのツールをインストールする.

$ apt-get isntall lksctp-tools
実行:

端末を2つ開いて,以下のコマンドを実行する.

  • server
$ sctp_darn -H 127.0.0.1 -P 2500 -l
  • client
$ sctp_darn -H 127.0.0.1 -P 2600 -h 127.0.0.1 -p 2500 -s

クライアント側の端末に,送信する文字列を入力する
f:id:kiri__n:20140528133753p:plain

確認:

wiresharkを用いてキャプチャしてみた.
f:id:kiri__n:20140528133819p:plain
f:id:kiri__n:20140528134049p:plain

アソシエーションの生成はパケットを2往復させる必要がある.
最初の送信データはCOOKIE ECHOと同時に送信される.以降はDATAフレーム単体で送信されるらしい.
切断時は,TCPのような半切断状態とかはなくなってるらしい.