Telegram のプロトコルず組織的アプロヌチに察する批刀。 パヌト 1、技術: クラむアントを最初から䜜成した経隓 - TL、MT

最近、Telegram がいかに優れおいるか、Durov 兄匟がネットワヌク システムの構築においおどれほど優秀で経隓豊富であるかなどに぀いおの投皿が Habré に頻繁に衚瀺されるようになりたした。 同時に、技術的なデバむスに実際に没頭しおいる人はほずんどいたせん。せいぜい、かなり単玔な (MTProto ずは倧きく異なる) JSON ベヌスの Bot API を䜿甚するだけで、通垞は単に受け入れるだけです。 信仰に぀いお すべおの賞賛や PR はメッセンゞャヌを䞭心に展開されたす。 ほが XNUMX 幎半前、NPO Echelon Vasily の私の同僚 (残念なこずに、Habré に関する圌のアカりントは草皿ずずもに削陀されたした) が Perl で独自の Telegram クラむアントを䞀から曞き始め、その埌、これらの行の著者も加わりたした。 なぜ Perl なのでしょうか?ずすぐに疑問に思う人もいるでしょう。 なぜなら、他の蚀語でもそのようなプロゞェクトがすでに存圚するからです。実際、これは重芁ではなく、他の蚀語でも可胜です。 完成したラむブラリしたがっお、䜜者は最埌たで行かなければなりたせん れロから。 さらに、暗号化ずは、信頌するものですが、怜蚌するものです。 セキュリティに重点を眮いた補品では、ベンダヌの既補ラむブラリに䟝存しお盲目的に信じるこずはできたせん (ただし、これに぀いおは第 XNUMX 郚で詳しく説明したす)。 珟時点では、ラむブラリは「䞭間」レベルで非垞にうたく機胜したす (あらゆる API リク゚ストを行うこずができたす)。

ただし、この䞀連の投皿には暗号孊ず数孊はあたり含たれたせん。 ただし、他にも倚くの技術的な詳现やアヌキテクチャ䞊の芁点が存圚したす (れロから䜜成するのではなく、任意の蚀語でラむブラリを䜿甚する人にも圹立ちたす)。 したがっお、䞻な目暙は、クラむアントを最初から実装しおみるこずでした 公匏ドキュメントによるず。 ぀たり、公匏クラむアントの゜ヌスコヌドがクロヌズされおいるず仮定したすこれも実際には䜕であるかに぀いおは、埌半でさらに詳しく明らかにしたす 起こりたす そう) しかし、昔ず同じように、たずえば、RFC のような暙準がありたす。公匏 (Telegram デスクトップ、モバむル) であっおも、゜ヌスを「芗くこずなく」、仕様だけに埓っおクラむアントを䜜成するこずは可胜ですか? 、非公匏のテレ゜ンでも

目次

ドキュメント ありたすか 本圓ですか?.

この蚘事のためのメモの断片は、昚幎の倏から収集され始めたした。 今回は公匏サむトで https://core.telegram.org ドキュメントはレむダヌ 23 の時点のものでした。぀たり、 2014 幎のどこかで行き詰たっおいたした (圓時はただチャンネルすらなかったこずを芚えおいたすか?)。 もちろん理論的には、これにより 2014 幎の圓時の機胜を備えたクラむアントを実装できるはずです。 しかし、この状態であっおも、文曞は第䞀に䞍完党であり、第二に、ずころどころ矛盟しおいたした。 2019か月ほど前のXNUMX幎XNUMX月、 誀っお このサむトには完党に新しいレむダヌ 105 に関するドキュメントが倧幅に曎新されおおり、すべおをもう䞀床読む必芁があるずの泚蚘が蚘茉されおいるこずがわかりたした。 実際、倚くの蚘事が改蚂されたしたが、倚くは倉曎されおいたせん。 したがっお、このドキュメントに関する以䞋の批刀を読むずきは、これらの事柄の䞀郚はもはや関連性がありたせんが、䞀郚は䟝然ずしお適切であるこずに留意する必芁がありたす。 結局のずころ、珟代瀟䌚における 5 幎は単に長いだけではありたせん。 非垞に たくさんの。 それ以来 (特に、それ以降に砎棄され埩掻したゞオチャットを考慮しない堎合)、スキヌム内の API メ゜ッドの数は XNUMX から XNUMX 以䞊に増加したした。

若い䜜家ずしおどこから始めたすか

最初から䜜成するか、たずえば次のような既補のラむブラリを䜿甚するかは関係ありたせん。 Python のテレ゜ン たたは PHP 甚マデリンいずれにしおも、最初に必芁ずなるのは アプリケヌションを登録する - パラメヌタを取埗する api_id О api_hash (VKontakte API を䜿甚したこずのある人はすぐに理解できたす) サヌバヌはこれによっおアプリケヌションを識別したす。 これ 〜する必芁がありたす 法的な理由からです。ただし、ラむブラリの著者がそれを出版できない理由に぀いおは、第 XNUMX 郚で詳しく説明したす。 おそらく、テスト倀は非垞に限られおいたすが、満足できるでしょう。実際、今では自分の番号に登録できるのです。 XNUMX぀だけ 急いで申請しないでください。

さお、技術的な芳点から芋るず、登録埌にドキュメントやプロトコルなどの曎新に関する通知を Telegram から受信する必芁があるずいう事実に興味があるはずです。 ぀たり、ドックのあるサむトは単に「スコアリング」され、クラむアントを䜜り始めたサむトず特別に連携し続けたず考えるこずができたす。 そのほうが簡単です。 しかし、いいえ、そのようなものは䜕も芳察されず、情報も来たせんでした。

たた、最初から䜜成した堎合、受け取ったパラメヌタを䜿甚するのは実際にはただ遠いです。 それでも https://core.telegram.org/ それらに぀いおは「はじめに」で最初に説明したすが、実際には最初に実装する必芁がありたす。 MTProtoプロトコル - でも、もしあなたが信じおいるなら OSIモデルに埓ったレむアりト プロトコルの䞀般的な説明のペヌゞの最埌にありたすが、完党に無駄です。

実際、MTProto の導入前も導入埌も、䞀床に耇数のレベル (OS カヌネルで働く海倖のネットワヌカヌが蚀うように、レむダヌ違反) で、倧きく、痛たしい、恐ろしいトピックが邪魔をするこずになりたす...

バむナリ シリアル化: TL (Type Language) ずそのスキヌム、レむダヌ、その他の恐ろしい単語の数々

実際、このトピックは Telegram の問題の鍵です。 そしお、それを掘り䞋げようずするず、ひどい蚀葉がたくさんありたす。

それで、蚈画。 この蚀葉を芚えおいるなら、こう蚀っおください。 JSONスキヌマあなたは正しく考えたした。 目暙は同じです。送信されるデヌタの可胜なセットを蚘述するための蚀語です。 実際、類䌌点はここで終わりたす。 ペヌゞからの堎合 MTProtoプロトコル、たたは公匏クラむアントの゜ヌス ツリヌからスキヌムを開こうずするず、次のようなものが衚瀺されたす。

int ? = Int;
long ? = Long;
double ? = Double;
string ? = String;

vector#1cb5c415 {t:Type} # [ t ] = Vector t;

rpc_error#2144ca19 error_code:int error_message:string = RpcError;

rpc_answer_unknown#5e2ad36e = RpcDropAnswer;
rpc_answer_dropped_running#cd78e586 = RpcDropAnswer;
rpc_answer_dropped#a43ad8b7 msg_id:long seq_no:int bytes:int = RpcDropAnswer;

msg_container#73f1f8dc messages:vector<%Message> = MessageContainer;

---functions---

set_client_DH_params#f5045f1f nonce:int128 server_nonce:int128 encrypted_data:bytes = Set_client_DH_params_answer;

ping#7abe77ec ping_id:long = Pong;
ping_delay_disconnect#f3427b8c ping_id:long disconnect_delay:int = Pong;

invokeAfterMsg#cb9f372d msg_id:long query:!X = X;
invokeAfterMsgs#3dc4b4f0 msg_ids:Vector<long> query:!X = X;

account.updateProfile#78515775 flags:# first_name:flags.0?string last_name:flags.1?string about:flags.2?string = User;
account.sendChangePhoneCode#8e57deb flags:# allow_flashcall:flags.0?true phone_number:string current_number:flags.0?Bool = auth.SentCode;

これを初めお芋た人は、曞かれおいるこずの䞀郚だけを盎感的に認識するでしょう。これらは明らかに構造物です (ただし、名前は巊偎たたは右偎のどこにありたすか?)。その䞭にはフィヌルドがあり、その埌にフィヌルドがありたす。型はコロンを通過したす...おそらく。 ここで、山括匧内には、おそらく C++ のようなテンプレヌトがありたす (実際には、 かなりではない。 そしお、他のすべおの蚘号は䜕を意味するのか、疑問笊、感嘆笊、パヌセンテヌゞ、栌子そしお明らかに、堎所によっお異なる意味を持ちたす、どこかに存圚するが、どこかには存圚しない、XNUMX 進数、そしお最も重芁なのは、ここからどのように取埗するかです。 右 (サヌバヌによっお拒吊されたせん) バむトストリヌム? ドキュメントを読たなければなりたせん (はい、近くに JSON バヌゞョンのスキヌマぞのリンクがありたすが、これでは明確になりたせん).

ペヌゞを開く バむナリデヌタのシリアル化 4幎生のマタンに䌌た、キノコず離散数孊の魔法の䞖界に飛び蟌みたす。 アルファベット、型、倀、コンビネヌタ、関数型コンビネヌタ、正芏圢、耇合型、倚態型...そしおこれは最初のペヌゞにすぎたせん。 次はあなたを埅っおいたす TL蚀語これには、些现な芁求ず応答の䟋がすでに含たれおいたすが、より兞型的なケヌスに察する答えはたったく提䟛されおいたせん。぀たり、さらに XNUMX ぀のネストされた数孊をロシア語から英語に翻蚳しお読み盎す必芁がありたす。ペヌゞ

関数型蚀語ず自動型掚論に粟通しおいる読者は、もちろん、この蚀語の説明を䟋から芋おもはるかに芪しみやすく、これは原理的には䞀般的に悪くないず蚀えるでしょう。 これに察する反論は次のずおりです。

  • はい、 目暙 良さそうですが、残念ながら 達成されおいない
  • ロシアの倧孊での教育はIT専門分野によっおも異なり、誰もが察応するコヌスを読んでいるわけではない
  • 最埌に、これから芋るように、実際には次のようになりたす。 䞍芁、蚘述された TL の限られたサブセットのみが䜿甚されるため、

蚀ったように レオナヌド チャンネル䞊で #perl FreeNode IRC ネットワヌク䞊で、Telegram から Matrix ぞのゲヌトを実装しようずしおいたす (匕甚笊の翻蚳はメモリからでは䞍正確です)。

初めお型理論を玹介されお、それが実際に必芁かどうかなどあたり気にせず、興奮しおそれをいじり始めた人のように感じたす。

基本的なものずしお裞の型 (int、long など) が必芁かどうかは自分の目で確認しおください。最終的には手動で実装する必芁がありたす。たずえば、それらから掟生しおみたす。 ベクトル。 ぀たり、実際には、 配列, 結果ずしお埗られたものを固有名で呌ぶ堎合。

しかし前に

公匏ドキュメントを読たない人のための TL 構文のサブセットの簡単な説明

constructor = Type;
myVec ids:Vector<long> = Type;

fixed#abcdef34 id:int = Type2;

fixedVec set:Vector<Type2> = FixedVec;

constructorOne#crc32 field1:int = PolymorType;
constructorTwo#2crc32 field_a:long field_b:Type3 field_c:int = PolymorType;
constructorThree#deadcrc bit_flags_of_what_really_present:# optional_field4:bit_flags_of_what_really_present.1?Type = PolymorType;

an_id#12abcd34 id:int = Type3;
a_null#6789cdef = Type3;

垞に定矩を開始したす コンストラクタ、その埌、オプションで (実際には垞に) シンボルを介しお # でなければなりたせん CRC32 指定されたタむプの正芏化された説明文字列から。 次に、フィヌルドの説明が続きたす (フィヌルドがある堎合、タむプは空にするこずができたす)。 すべおは等号で終わりたす。これは、指定されたコンストラクタヌ (実際にはサブタむプ) が属する型の名前です。 等号の右偎の型は次のずおりです。 倚態性の - ぀たり、いく぀かの特定のタむプに察応できたす。

定矩が次の行の埌にある堎合 ---functions---その堎合、構文は同じたたですが、意味は異なりたす。コンストラクタヌは RPC 関数の名前になり、フィヌルドはパラメヌタヌになりたす (぀たり、以䞋で説明するように、䞎えられた構造はたったく同じたたになりたす。それは単に䞎えられた意味になりたす)、「倚態性型 」は返される結果の型です。 確かに、それはただ倚態性のたたです - セクションで定矩されおいるだけです ---types---、このコンストラクタヌは考慮されたせん。 匕数による呌び出される関数の型オヌバヌロヌド。 䜕らかの理由で、C++ のように、名前は同じだがシグネチャが異なるいく぀かの関数は TL では提䟛されたせん。

OOP ではないのに、なぜ「コンストラクタヌ」ず「ポリモヌフィック」なのでしょうか? 実際、OOP の芳点から考える方が簡単です。OOP は抜象クラスずしおの倚態性型であり、コンストラクタヌはその盎接の子孫クラスです。 final 倚くの蚀語の甚語で。 実はここでももちろん 類䌌性 OO プログラミング蚀語の実際のオヌバヌロヌドされたコンストラクタヌ メ゜ッドを䜿甚したす。 ここにはデヌタ構造だけがあるため、メ゜ッドはありたせん (ただし、以䞋の関数ずメ゜ッドの説明では、それらが䜕であるかに぀いお頭の䞭に混乱を匕き起こす可胜性がありたすが、それは別のこずです)。コンストラクタヌは次のように考えるこずができたす。どの倀から 建蚭䞭 バむトのストリヌムを読み取るずきのタむプ。

これはどうしお起こるのでしょうか? 垞に 4 バむトを読み取るデシリアラむザヌは、その倀を参照したす。 0xcrc32 - そしお次に䜕が起こるかを理解しおいたす field1 タむプ付き int、぀たりtype を持぀この䞊にあるフィヌルドで、正確に 4 バむトを読み取りたす PolymorType 読む。 芋る 0x2crc32 さらに XNUMX ぀のフィヌルドがあるこずを理解しおいたす。 long, したがっお、8バむトを読み取りたす。 次に、同じ方法で逆シリアル化された耇合型です。 䟋えば、 Type3 XNUMX ぀のコンストラクタヌがそれぞれ、さらに次のいずれかを満たさなければならないずすぐにスキヌマ内で宣蚀できたす。 0x12abcd34、その埌さらに 4 バむトを読み取る必芁がありたす intたたは 0x6789cdef、その埌は䜕もなくなりたす。 それ以倖の堎合は、䟋倖をスロヌする必芁がありたす。 いずれにせよ、その埌は 4 バむトの読み取りに戻りたす。 int 䜙癜 field_c в constructorTwo そしおそれを螏たえお私たちは読み終えたす PolymorType.

最埌に、捕たった堎合は、 0xdeadcrc のために constructorThree, その埌、事態はさらに耇雑になりたす。 私たちの最初のフィヌルド bit_flags_of_what_really_present タむプ付き # - 実際、これは型の単なる゚むリアスです nat「自然数」ずいう意味。 ぀たり、実際のスキヌムで笊号なし数倀が芋぀かる堎合は、実際には unsigned int だけです。 したがっお、次は疑問笊の付いた構造です。これは、これがフィヌルドであるこずを意味したす。参照されるフィヌルドに察応するビットが蚭定されおいる堎合にのみ、このフィヌルドがネットワヌク䞊に存圚したす (䞉項挔算子ずほが同じです)。 したがっお、このビットがオンだったず仮定するず、次のようなフィヌルドを読み取る必芁がありたす。 Type、この䟋では 2 ぀のコンストラクタヌがありたす。 XNUMX ぀は空 (識別子のみで構成される) で、もう XNUMX ぀はフィヌルドがありたす ids タむプ付き ids:Vector<long>.

テンプレヌトずゞェネリックの䞡方が良い、たたは Java が良いず思うかもしれたせん。 しかし、そうではありたせん。 ほずんど。 これ シングル 実際の回路では山括匧の堎合に䜿甚され、ベクトルにのみ䜿甚されたす。 バむト ストリヌムでは、これは Vector 型自䜓の 4 CRC32 バむト (垞に同じ)、次に 4 バむト (配列芁玠の数)、そしおこれらの芁玠自䜓になりたす。

これに加えお、シリアル化は垞に 4 バむトのワヌドで発生し、すべおの型はその倍数になりたす。組み蟌み型に぀いおも説明したす。 bytes О string 長さを手動でシリアル化し、この䜍眮を 4 で調敎するず、正垞に聞こえるようになり、比范的効率的になるように思えたすか? TL は効率的なバむナリ シリアル化であるず䞻匵されおいたすが、ずんでもなく、ブヌル倀や最倧 4 バむトの単䞀文字列を含むあらゆるものを拡匵するず、JSON はさらに厚くなるのでしょうか? ほら、䞍芁なフィヌルドもビット フラグでスキップできたす。すべお問題なく、将来に向けお拡匵可胜です。埌でコンストラクタヌに新しいオプションのフィヌルドを远加したしたか?

しかし、私の簡単な説明ではなく、完党なドキュメントを読んで実装に぀いお考えおいただければ、そうではありたせん。 たず、コンストラクタヌの CRC32 は、正芏化されたスキヌマ テキストの説明文字列 (䜙分な空癜などを削陀する) によっお蚈算されたす。そのため、新しいフィヌルドが远加されるず、型の説明文字列が倉曎され、その結果 CRC32 が倉曎され、その結果シリアル化も倉曎されたす。 そしお、叀いクラむアントは、新しいフラグが蚭定されたフィヌルドを受け取ったものの、次にそれをどうすればよいか分からなかった堎合、どうするでしょうか? ..

第二に、芚えおおきたしょう CRC32、ここでは基本的に次のように䜿甚されたす ハッシュ関数 どの型が (逆) シリアル化されおいるかを䞀意に決定したす。 ここで私たちは衝突の問題に盎面したす。いや、その確率は 232 分の 32 ではなく、それよりはるかに高いのです。 CRC32 が通信チャネル内の゚ラヌを怜出 (および修正) するように蚭蚈されおおり、それに応じおこれらの特性を改善しお他のものに䞍利益をもたらすこずを誰が芚えおいるでしょうか。 たずえば、圌女はバむトの䞊べ替えを気にしたせん。4 ぀の行から CRC4 を数えるず、XNUMX 番目の行では最初の XNUMX バむトず次の XNUMX バむトを亀換したす - それは同じになりたす。 入力ずしおラテン語のアルファベットのテキスト文字列 (および少しの句読点) があり、これらの名前が特にランダムではない堎合、そのような順列が発生する確率は倧幅に増加したす。

ずころで、誰がそこに䜕があるかをチェックしたしたか 本圓に CRC32? 初期の情報源の 239 ぀ (りォルトマン以前) には、各文字に XNUMX ずいう数字を掛けるハッシュ関数があり、この関数はこれらの人々にずおも愛されおいたした。

最埌に、フィヌルド型を持぀コンストラクタヌが Vector<int> О Vector<PolymorType> CRC32が異なりたす。 では、オンラむンでのプレれンテヌションに぀いおはどうでしょうか? そしお理論的に蚀えば、 それは型の䞀郚になりたすか? XNUMX 䞇の数倀の配列を枡すずしたしょう。 Vector<int> 長さずさらに 40000 バむトはすべお明らかです。 そしお、これなら Vector<Type2>、フィヌルドは XNUMX ぀だけで構成されたす int そしおそれはこの型の唯䞀のものです - 10000xabcdef0 を 34 回繰り返しおから 4 バむトにする必芁がありたすか? int、たたは蚀語がコンストラクタヌからこれを衚瀺できる fixedVec 80000 バむトの代わりに、40000 バむトだけを再転送したすか?

これはたったく無意味な理論的な質問ではありたせん。グルヌプ ナヌザヌのリストを取埗し、各ナヌザヌに ID、名、姓があるず想像しおください。モバむル接続を介しお転送されるデヌタ量の違いは、重倧な堎合がありたす。 私たちに宣䌝されおいるのは、テレグラム連茉の有効性です。

だから... ...

掚定できなかったベクトル

コンビネヌタなどの説明ペヌゞを読み進めおみるず、ベクトル (さらには行列) がタプルを通じお圢匏的に耇数のシヌトを掚定しようずしおいるこずがわかりたす。 しかし、最終的には、それらは打ちのめされ、最埌のステップはスキップされ、単にベクトルの定矩が䞎えられるだけですが、これも型に束瞛されたせん。 ここで䜕が問題ですか 蚀語で プログラミング特に関数型のものでは、構造を再垰的に蚘述するのが非垞に䞀般的です。遅延評䟡を備えたコンパむラヌはすべおを理解しおそれを実行したす。 蚀語で デヌタのシリアル化 しかし、効率性が必芁です。簡単に説明するだけで十分です。 リスト、぀たりXNUMX ぀の芁玠の構造 - 最初の芁玠はデヌタ芁玠、XNUMX 番目は同じ構造自䜓、たたは末尟の空のスペヌス (パック) (cons) Lisp では)。 しかし、これには明らかに必芁になりたす それぞれの 芁玠は、そのタむプを蚘述するためにさらに 4 バむト (TL の堎合は CRC32) を費やしたす。 配列の蚘述が簡単 固定サむズただし、以前に未知の長さの配列の堎合は䞭断されたす。

したがっお、TL ではベクトルを出力できないため、偎にベクトルを远加する必芁がありたした。 最終的にドキュメントには次のように曞かれおいたす。

シリアル化では、型 t の倉数の特定の倀に䟝存しない同じコンストラクタヌ "vector" (const 0x1cb5c415 = crc32("vector t:Type # [ t ] = Vector t") が垞に䜿甚されたす。

オプションのパラメヌタヌ t の倀は、結果の型から掟生するため (逆シリアル化の前に垞に既知である)、シリアル化には関䞎したせん。

もっずよく芋なさい vector {t:Type} # [ t ] = Vector t - しかし どこにも 定矩自䜓は、最初の数倀がベクトルの長さず等しくなければならないずは蚀っおいたせん。 そしおそれはどこからでも続くものではありたせん。 これは圓然のこずですが、念頭に眮いお実際に実行する必芁がありたす。 ドキュメントの他の堎所では、型が停であるず正盎に述べおいたす。

Vector t 倚態性擬䌌型は、その倀がボックス化たたはベアの任意の型 t の倀のシヌケンスである「型」です。

 しかし、そこには焊点を圓おおいたせん。 耇雑な数孊 (倧孊の授業で知っおいるかもしれたせん) を歩き回るのにうんざりし、採点を決めお、実際に数孊を実際にどのように扱うかを芳察するず、その印象が頭の䞭に残りたす。ここでの本栌的な数孊は、以䞋に基づいおいたす。 、明らかにクヌルピヌプルXNUMX人の数孊者 - ACMの優勝者であり、誰でもではありたせん。 散財するずいう目暙は達成されたした。

ずころで、数字に぀いお。 想起 # それは同矩語です nat、 自然数

型匏がありたす (typeexpr) および数倀匏 (nat-expr。 ただし、それらは同じように定矩されたす。

type-expr ::= expr
nat-expr ::= expr

しかし、文法では同じように蚘述されたす。 この違いもたた芚えおおいお、手䜜業で実装する必芁がありたす。

そうですね、テンプレヌトの皮類 (vector<int>, vector<User>) 共通の識別子 (#1cb5c415)、぀たり呌び出しが次のように宣蚀されおいるこずがわかっおいる堎合

users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;

その堎合、単なるベクトルではなく、ナヌザヌのベクトルを埅っおいるこずになりたす。 より正確に、 すべきである 埅っおください - 実際のコヌドでは、裞の型ではないにしおも、各芁玠にはコンストラクタヌがあり、実装では良い意味でチェックする必芁がありたす - そしお、このベクトルの各芁玠で正確に送信されたした そのタむプ? そしお、それが、配列のさたざたな芁玠にさたざたな型を含めるこずができる、ある皮の PHP だったらどうでしょうか?

この時点で、「そのような TL は必芁なのでしょうか?」ず疑問に思い始めたす。 おそらくカヌトには、圓時既に存圚しおいたものず同じ protobuf である人間のシリアラむザヌを䜿甚できるのではないでしょうか? これは理論でした。実践を芋おみたしょう。

コヌド内の既存の TL 実装

TLは、ドゥロフの株の売华ずいう有名な出来事が起きる前に、フコンタクテの内郚で生たれたした。確かに、テレグラムが開発される前からです。 そしおオヌプン゜ヌスでは 最初の実装の゜ヌス 面癜い束葉杖がたくさん芋぀かりたす。 そしお蚀語自䜓は、珟圚の Telegram よりも完党に実装されたした。 たずえば、スキヌムではハッシュはたったく䜿甚されたせん (逞脱した動䜜を持぀組み蟌みの疑䌌型 (ベクトルのような) を意味したす)。 たた

Templates are not used now. Instead, the same universal constructors (for example, vector {t:Type} [t] = Vector t) are used w

しかし、完党を期すために、いわば思考の巚人の進化をたどるために、その党䜓像を考えおみたしょう。

#define ZHUKOV_BYTES_HACK

#ifdef ZHUKOV_BYTES_HACK

/* dirty hack for Zhukov request */

あるいは、この矎しいもの:

    static const char *reserved_words_polymorhic[] = {

      "alpha", "beta", "gamma", "delta", "epsilon", "zeta", "eta", "theta", NULL

      };

このフラグメントは次のようなテンプレヌトに関するものです。

intHash {alpha:Type} vector<coupleInt<alpha>> = IntHash<alpha>;

これは、 int ず Type のペアのベクトルずしおのハッシュマップ テンプレヌト タむプの定矩です。 C++ では次のようになりたす。

    template <T> class IntHash {
      vector<pair<int,T>> _map;
    }

それで、 alpha - キヌワヌド ただし、T を蚘述できるのは C++ だけですが、アルファ、ベヌタを蚘述する必芁がありたす。ただし、パラメヌタは 8 ぀たでであり、幻想はシヌタで終わりたした。 それで、か぀おサンクトペテルブルクではほが次のような察話があったようです。

-- НаЎП сЎелать в TL шаблПМы
-- Бл... Ну пусть параЌетры зПвут альфа, бета,... КакОе таЌ ещё буквы есть... О, тэта!
-- ГраЌЌатОка? Ну пПтПЌ МапОшеЌ

-- СЌПтрОте, какПй я сОМтаксОс прОЎуЌал Ўля шаблПМПв О вектПра!
-- Ты ЎПлбаМулся, как Ќы этП парсОть буЎеЌ?
-- Да Ме ссыте, ПМ таЌ ПЎОМ в схеЌе, захаркПЎОть -- О Пк

しかし、それは「䞀般的な」TL の最初にレむアりトされた実装に関するものでした。 実際の Telegram クラむアントでの実装の怜蚎に移りたしょう。

バゞルの蚀葉

Vasily、[09.10.18/17/07 XNUMX:XNUMX] 䜕よりも、圌らが倧量の抜象抂念を台無しにしお、ボルトを打ち蟌み、コヌドゲヌガヌに束葉杖を぀けたずいう事実に、お尻が熱くなりたす。
その結果、たずドックからpilot.jpg
次に、jekichan.webp コヌドから

もちろん、アルゎリズムや数孊に粟通しおいる人なら、『Aho, Ullman』を読んでおり、数十幎にわたっお DSL コンパむラを䜜成するための事実䞊の業界暙準ツヌルに粟通しおいるず予想できたすよね?

によっお テレグラム-cli Vitaliy Valtman は、(cli) 制限倖の TLO 圢匏の出珟からわかるように、チヌムのメンバヌです。珟圚、TL を解析するためのラむブラリが割り圓おられおいたす。 別々に圌女の印象は䜕ですか TLパヌサヌ..

16.12 04:18 Vasily: 私の意芋では、lex + yacc をマスタヌしおいない人がいるず思いたす
16.12 04:18 ノァシリヌ: そうしないず説明できない
16.12 04:18 Vasily: そうですね、それずも VK の行数に察しお支払われたのですか
16.12 04:19 Vasily: その他の 3 行以䞊<censored> パヌサヌの代わりに

もしかしたら䟋倖かも 方法を芋おみたしょう Ўелает これは公匏クラむアント、Telegram デスクトップです。

    nametype = re.match(r'([a-zA-Z.0-9_]+)(#[0-9a-f]+)?([^=]*)=s*([a-zA-Z.<>0-9_]+);', line);
    if (not nametype):
      if (not re.match(r'vector#1cb5c415 {t:Type} # [ t ] = Vector t;', line)):
         print('Bad line found: ' + line);

Python の 1100 以䞊の行、いく぀かの正芏衚珟 + ベクトル型の特殊なケヌス。もちろん、これは TL 構文に埓っおスキヌム内で宣蚀されおいたすが、圌らはそれをこの構文に眮き、さらに解析したす。 ...問題は、なぜこのような奇跡をわざわざ行うのかずいうこずですОずにかく誰もドキュメントに埓っお解析しないのなら、もっずふかしおください?!

ずころで... CRC32 チェックに぀いお話したのを芚えおいたすか? したがっお、Telegram Desktop コヌド ゞェネレヌタヌには、CRC32 が蚈算されるタむプの䟋倖のリストがありたす。 䞀臎しおいたせん 図に瀺されおいるように

Vasily、[18.12 22:49] そしおここで、そのような TL が必芁かどうかを考える必芁がありたす
代替実装をいじりたい堎合は、改行を挿入し始めるず、パヌサヌの半分が耇数行の定矩で改行しおしたいたす。
ただし、tdesktopも

ワンラむナヌに぀いおのポむントを芚えおおいおください。少し埌で戻りたす。

Telegram-cli は非公匏で、Telegram Desktop は公匏ですが、他のものはどうですか? そしお誰にもわかりたせん。Android クラむアント コヌドにはスキヌマ パヌサヌがたったくありたせんでした (これはオヌプン ゜ヌスに関する疑問を匕き起こしたすが、これは XNUMX 番目の郚分です)。他にもいく぀かの面癜いコヌドがありたしたが、それらに぀いおは次のずおりです。以䞋のサブセクション。

実際にシリアル化によっお他にどのような疑問が生じたすか? たずえば、もちろん、ビット フィヌルドず条件付きフィヌルドで倱敗したした。

ノァシリヌ: flags.0? true
フィヌルドが存圚するこずを意味し、フラグが蚭定されおいる堎合は true

ノァシリヌ: flags.1? int
フィヌルドが存圚し、逆シリアル化する必芁があるこずを意味したす

ノァシリヌ: やけどしないで、䜕しおるの
Vasily: ドキュメントのどこかに、true は長されロの裞の型であるずいう蚘述がありたすが、ドキュメントから䜕かを収集するのは非珟実的です。
Vasily: オヌプン実装にもそのようなものはありたせんが、束葉杖や小道具はたくさんありたす

テレビ゜ンはどうですか MTProto のトピックを䟋に挙げるず、ドキュメントにはそのような郚分がありたすが、 % 「指定されたベアタむプに察応する」ずだけ説明されおいたす。 以䞋の䟋では、゚ラヌか文曞化されおいない䜕かが発生しおいたす。

Vasily、[22.06.18/18/38 XNUMX:XNUMX] ある堎所:

msg_container#73f1f8dc messages:vector message = MessageContainer;

別の堎合:

msg_container#73f1f8dc messages:vector<%Message> = MessageContainer;

これらは XNUMX ぀の倧きな違いですが、珟実の生掻では、ある皮の裞のベクトルが生じたす。

裞のベクトル定矩を芋たこずがなく、遭遇したこずもありたせん

電話で手曞きで曞いた分析

圌のスキヌマは定矩をコメントアりトしたした msg_container

ここでも、% に぀いお疑問が残りたす。 それは説明されおいたせん。

Vadim Goncharov、[22.06.18/19/22 XNUMX:XNUMX PM]、そしおデスクトップですか

Vasily、[22.06.18/19/23 XNUMX:XNUMX] しかし、芏制圓局の TL パヌサヌもおそらくそれを食べないだろう

// parsed manually

TL は矎しい抜象化ですが、それを完党に実装しおいる人はいたせん

そしお、圌らのバヌゞョンのスキヌムには % がありたせん

しかし、ここではドキュメント自䜓が矛盟しおいるため、xs

それは文法で芋぀かったが、意味論の説明を忘れただけかもしれない

そうですね、TLでドックを芋たしたね、XNUMXリットルがなければそれを理解するこずはできたせん

「そうですね、たずえば、あなたはすべおを批刀しおいるのですから、あるべき姿を芋せおください」ず別の読者は蚀うでしょう。

Vasily は次のように答えたす。「パヌサヌに関しおは、次のようなものが必芁です。

    args: /* empty */ { $$ = NULL; }
        | args arg { $$ = g_list_append( $1, $2 ); }
        ;

    arg: LC_ID ':' type-term { $$ = tl_arg_new( $1, $3 ); }
            | LC_ID ':' condition '?' type-term { $$ = tl_arg_new_cond( $1, $5, $3 ); free($3); }
            | UC_ID ':' type-term { $$ = tl_arg_new( $1, $3 ); }
            | type-term { $$ = tl_arg_new( "", $1 ); }
            | '[' LC_ID ']' { $$ = tl_arg_new_mult( "", tl_type_new( $2, TYPE_MOD_NONE ) ); }
            ;

どういうわけかそれよりも䌌おいたす

struct tree *parse_args4 (void) {
  PARSE_INIT (type_args4);
  struct parse so = save_parse ();
  PARSE_TRY (parse_optional_arg_def);
  if (S) {
    tree_add_child (T, S);
  } else {
    load_parse (so);
  }
  if (LEX_CHAR ('!')) {
    PARSE_ADD (type_exclam);
    EXPECT ("!");
  }
  PARSE_TRY_PES (parse_type_term);
  PARSE_OK;
}

たたは

        # Regex to match the whole line
        match = re.match(r'''
            ^                  # We want to match from the beginning to the end
            ([w.]+)           # The .tl object can contain alpha_name or namespace.alpha_name
            (?:
                #             # After the name, comes the ID of the object
                ([0-9a-f]+)    # The constructor ID is in hexadecimal form
            )?                 # If no constructor ID was given, CRC32 the 'tl' to determine it

            (?:s              # After that, we want to match its arguments (name:type)
                {?             # For handling the start of the '{X:Type}' case
                w+            # The argument name will always be an alpha-only name
                :              # Then comes the separator between name:type
                [wd<>#.?!]+  # The type is slightly more complex, since it's alphanumeric and it can
                               # also have Vector<type>, flags:# and flags.0?default, plus :!X as type
                }?             # For handling the end of the '{X:Type}' case
            )*                 # Match 0 or more arguments
            s                 # Leave a space between the arguments and the equal
            =
            s                 # Leave another space between the equal and the result
            ([wd<>#.?]+)     # The result can again be as complex as any argument type
            ;$                 # Finally, the line should always end with ;
            ''', tl, re.IGNORECASE | re.VERBOSE)

これはレクサヌ党䜓です:

    ---functions---         return FUNCTIONS;
    ---types---             return TYPES;
    [a-z][a-zA-Z0-9_]*      yylval.string = strdup(yytext); return LC_ID;
    [A-Z][a-zA-Z0-9_]*      yylval.string = strdup(yytext); return UC_ID;
    [0-9]+                  yylval.number = atoi(yytext); return NUM;
    #[0-9a-fA-F]{1,8}       yylval.number = strtol(yytext+1, NULL, 16); return ID_HASH;

    n                      /* skip new line */
    [ t]+                  /* skip spaces */
    //.*$                 /* skip comments */
    /*.**/              /* skip comments */
    .                       return (int)yytext[0];

それらの。 控えめに蚀っおも簡単です。」

䞀般に、実際に䜿甚される TL のサブセットのパヌサヌずコヌド ゞェネレヌタヌは、最終的には玄 100 行の文法ず玄 300 行のゞェネレヌタヌ (すべおを含む) に収たりたす。 printの生成されたコヌドには、型グッズ、各クラスのむントロスペクション甚の型情報が含たれたす。 各倚態性型は空の抜象基本クラスに倉換され、コンストラクタヌはそれを継承し、シリアル化および逆シリアル化のメ゜ッドを持ちたす。

タむプ蚀語に型が䞍足しおいる

匷い型付けは良いこずですよね? いいえ、これはホリバヌ (私は動的蚀語の方が奜きですが) ではなく、TL 内の仮説です。 それに基づいお、蚀語はあらゆる皮類のチェックを提䟛する必芁がありたす。 たあ、わかりたした、圌ではなく実装にしたしょう。しかし、圌は少なくずもそれらを説明する必芁がありたす。 そしお、私たちはどのような機䌚を望んでいるでしょうか

たずは制玄です。 ファむルのアップロヌドに関するドキュメントには次のようなものがありたす。

ファむルのバむナリ コンテンツは耇数の郚分に分割されたす。 すべおのパヌツは同じサむズでなければなりたせん ( パヌツサむズ )、次の条件を満たす必芁がありたす。

  • part_size % 1024 = 0 (1KBで割り切れる)
  • 524288 % part_size = 0 (512KB は、part_size で均等に割り切れる必芁がありたす)

最埌の郚分は、そのサむズがpart_size未満であれば、これらの条件を満たす必芁はありたせん。

各パヌツにはシヌケンス番号が必芁です。 ファむルパヌツ、倀の範囲は 0  2,999 です。

ファむルをパヌティション分割した埌、サヌバヌにファむルを保存する方法を遞択する必芁がありたす。 䜿甚 アップロヌド.saveBigFilePart ファむルのフルサむズが 10 MB を超える堎合、および アップロヌド.saveFilePart 小さいファむル甚。
[
]次のデヌタ入力゚ラヌのいずれかが返される堎合がありたす。

  • FILE_PARTS_INVALID - パヌツの数が無効です。 倀が次の範囲にありたせん 1..3000

これらのいずれかがスキヌマに存圚したすか? TLでなんずか衚珟できないでしょうか いいえ。 しかし、倱瀌ですが、昔ながらの Turbo Pascal でも、次の匏で䞎えられる型を蚘述するこずができたした。 範囲。 そしお圌はもう䞀぀、今ではもっずよく知られおいるこずができるはずです。 enum - 固定少数の倀の列挙で構成される型。 C のような蚀語では、数倀に぀いお泚意しおください。これたでは型に぀いおのみ説明しおきたした。 数字。 しかし、配列や文字列もありたす...たずえば、この文字列には電話番号のみを含めるこずができるず蚘述するず䟿利ですよね。

これはTLにありたせん。 しかし、たずえば JSON スキヌマにはそれがありたす。 そしお、他の誰かが 512 KB の割り算に぀いおコヌド内でチェックする必芁があるず反察できる堎合は、クラむアントが単玔に できなかった 範囲倖の番号を送信する 1..3000 (察応する゚ラヌは発生したせんでした) それは可胜ですよね? ..

ちなみに゚ラヌず戻り倀に぀いお。 TL で仕事をしたこずのある人でさえ目ががやけおいたす。私たちはすぐにはそのこずに気づきたせんでした。 それぞれ TL の関数は、実際には、説明された戻り倀の型だけでなく、゚ラヌも返すこずができたす。 しかし、これは TL 自䜓からは掚枬できたせん。 もちろん、それはいずれにしおも理解できたすし、実際には nafig は必芁ありたせん (実際には、RPC はさたざたな方法で実行できたすが、これに぀いおは埌で説明したす)。しかし、倩囜からの抜象型の数孊の抂念の玔粋さはどうでしょうか。䞖界? .. 綱匕きを぀かんだ - それで䞀臎したす。

最埌に、読みやすさに぀いおはどうでしょうか? さお、䞀般的に、私はそうしたいのですが、 説明 それをスキヌマ内に正しく配眮したす (繰り返しになりたすが、JSON スキヌマ内にありたす)。しかし、すでにそれに負担がかかっおいる堎合は、実際的な偎面はどうなるのでしょうか。少なくずも、曎新䞭に差分を確認するのはありふれたこずではないでしょうか。 で自分の目で確認しおください 実際の䟋:

- channelFull#76af5481 flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int = ChatFull;
+channelFull#1c87a71a flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_view_stats:flags.12?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int = ChatFull;

たたは

- message#44f9b43d flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long = Message;
+message#44f9b43d flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long = Message;

これを奜む人もいたすが、たずえば GitHub は、そのような長い行内の倉曎を匷調衚瀺するこずを拒吊しおいたす。 ゲヌムは「10 個の違いを芋぀ける」もので、脳がすぐに理解するのは、䞡方の䟋の始たりず終わりが同じであるずいうこずです。途䞭のどこかを退屈に読む必芁がありたす...私の意芋では、これは単なる理論䞊のこずではなく、しかし玔粋に芖芚的に芋えたす 汚くお乱雑な.

ちなみに、理論の玔床に぀いお。 なぜビットフィヌルドが必芁なのでしょうか? そうではありたせんか 匂い 型理論の芳点からは悪いですか 説明は、スキヌマの以前のバヌゞョンで参照できたす。 最初は、そうです、くしゃみごずに新しいタむプが䜜成されたした。 これらの基本は、次のような圢匏でただ残っおいたす。

storage.fileUnknown#aa963b05 = storage.FileType;
storage.filePartial#40bc6f52 = storage.FileType;
storage.fileJpeg#7efe0e = storage.FileType;
storage.fileGif#cae1aadf = storage.FileType;
storage.filePng#a4f63c0 = storage.FileType;
storage.filePdf#ae1e508d = storage.FileType;
storage.fileMp3#528a0677 = storage.FileType;
storage.fileMov#4b09ebbc = storage.FileType;
storage.fileMp4#b3cea0e4 = storage.FileType;
storage.fileWebp#1081464c = storage.FileType;

しかし、構造内に 5 ぀のオプションのフィヌルドがある堎合、考えられるすべおのオプションに察しお 32 の型が必芁になるず想像しおください。 組み合わせ爆発。 こうしお、TL 理論の玔粋さは、連茉ずいう厳しい珟実ずいう鋳鉄のお尻に再び衝突したのです。

さらに、堎所によっおは、圌ら自身がタむピングに違反しおいたす。 たずえば、MTProto (次の章) では、応答を Gzip で圧瞮できたす。レむダヌずスキヌマの違反を陀いお、すべおが適切です。 䞀床、RpcResult 自䜓を取埗するのではなく、その内容を取埗したした。 では、なぜこれを行うのでしょうか? どこでも圧瞮できるように束葉杖を䜿甚する必芁がありたした。

たたは、別の䟋ずしお、䞀床゚ラヌを芋぀けお送信したした。 InputPeerUser 代わりに InputUser。 あるいはその逆も同様です。 でも、うたくいきたした ぀たり、サヌバヌはタむプを気にしたせんでした。 どうすればいいの おそらく、その答えは、telegram-cli のコヌドの䞀郚によっお瀺されるでしょう。

  if (tgl_get_peer_type (E->id) != TGL_PEER_CHANNEL || (C && (C->flags & TGLCHF_MEGAGROUP))) {
    out_int (CODE_messages_get_history);
    out_peer_id (TLS, E->id);
  } else {    
    out_int (CODE_channels_get_important_history);

    out_int (CODE_input_channel);
    out_int (tgl_get_peer_id (E->id));
    out_long (E->id.access_hash);
  }
  out_int (E->max_id);
  out_int (E->offset);
  out_int (E->limit);
  out_int (0);
  out_int (0);

぀たり、ここでシリアル化が完了したす 手動で、生成されたコヌドではありたせん。 おそらくサヌバヌも同様の方法で実装されおいるのではないでしょうか?.原則ずしお、これは䞀床実行すれば機胜したすが、埌で曎新でどのようにサポヌトできるでしょうか? それがこの蚈画の目的ではなかったでしょうか そしお、次の質問に移りたす。

バヌゞョン管理。 レむダヌ

スキヌマ バヌゞョンがレむダヌず呌ばれる理由は、公開されたスキヌマの履歎に基づいおのみ掚枬できたす。 どうやら、最初は、基本的なこずは倉曎されおいないスキヌムで実行でき、必芁な堎合にのみ、特定の芁求に察しお別のバヌゞョンに埓っお実行されるこずを瀺すこずができるず䜜者は考えたようです。 原則ずしお、たずえ良いアむデアであっおも、新しいアむデアはいわば「混ぜ合わされお」叀いアむデアの䞊に重ねられたす。 しかし、それがどのように行われたかを芋おみたしょう。 確かに、最初から芋るこずは䞍可胜でした - それは面癜いですが、ベヌスレむダヌスキヌムは単に存圚したせん。 レむダヌは 2 から始たりたした。ドキュメントには、特別な TL 機胜に぀いお蚘茉されおいたす。

クラむアントがレむダヌ 2 をサポヌトしおいる堎合は、次のコンストラクタヌを䜿甚する必芁がありたす。

invokeWithLayer2#289dd1f6 {X:Type} query:!X = X;

実際には、これは、すべおの API 呌び出しの前に、倀を含む int が返されるこずを意味したす。 0x289dd1f6 メ゜ッド番号の前に远加する必芁がありたす。

倧䞈倫ですね。 しかし、次に䜕が起こったのでしょうか それから来たした

invokeWithLayer3#b7475268 query:!X = X;

それで、次は䜕でしょうか 掚枬しやすいので

invokeWithLayer4#dea0d430 query:!X = X;

面癜い いや、笑うのはただ早い、考えおみおください それぞれ 別のレむダヌからのリク゚ストは、そのような特別なタむプでラップする必芁がありたす。それらがすべお異なる堎合、他にどのように区別するのでしょうか? 前に 4 バむトだけを远加するのは非垞に効率的な方法です。 それで

invokeWithLayer5#417a57ae query:!X = X;

しかし、しばらくするず、それがバカナリアになるこずは明らかです。 そしお解決策は次のずおりでした。

曎新: レむダ 9 以降、ヘルパヌ メ゜ッド invokeWithLayerN ず䞀緒に䜿甚できたす initConnection

䞇歳 9 ぀のバヌゞョンを経お、぀いに 80 幎代のむンタヌネット プロトコルで行われおいたこず、぀たり接続の開始時に XNUMX 回バヌゞョン ネゎシ゚ヌションが行われるようになりたした。

それで、次は䜕ですか?

invokeWithLayer10#39620c41 query:!X = X;
...
invokeWithLayer18#1c900537 query:!X = X;

そしお今、あなたは笑うこずができたす。 さらに 9 ぀のレむダヌを経お、バヌゞョン番号を持぀ナニバヌサル コンストラクタヌが最終的に远加されたした。これは、接続の開始時に XNUMX 回だけ呌び出す必芁がありたす。レむダヌの意味は倱われおいるようです。珟圚は、次のような単なる条件付きバヌゞョンです。他のどこでも。 問題が解決したした。

右..

Vasily、[16.07.18/14/01 XNUMX:XNUMX PM] 金曜日、私はこう思いたした。
テレサヌバヌはリク゚ストなしでむベントを送信したす。 リク゚ストは InvokeWithLayer でラップする必芁がありたす。 サヌバヌは曎新をラップしたせん。応答ず曎新をラップするための構造がありたせん。

それらの。 クラむアントは曎新を垌望するレむダヌを指定できたせん

Vadim Goncharov、[16.07.18/14/02 XNUMX:XNUMX PM] InvokeWithLayer は原則ずしお束葉杖ではありたせんか?

Vasily、[16.07.18/14/02 XNUMX:XNUMX PM] これが唯䞀の方法です

Vadim Goncharov、[16.07.18/14/02 XNUMX:XNUMX PM] これは本質的に、セッションの開始時にレむダヌを䜜成するこずを意味するはずです

ちなみに、このこずから、クラむアントのダりングレヌドは提䟛されないこずがわかりたす。

アップデヌト、぀たりタむプ Updates このスキヌムでは、これはサヌバヌが API リク゚ストに応答するのではなく、むベントが発生したずきに独自にクラむアントに送信するものです。 これは耇雑なトピックであり、別の投皿で説明したすが、ここでは、クラむアントがオフラむンの堎合でもサヌバヌは曎新を蓄積するこずを知っおおくこずが重芁です。

したがっお、ラッピングを拒吊する堎合は、 それぞれの パッケヌゞにバヌゞョンを瀺す必芁があるため、論理的に次のような問題が発生する可胜性がありたす。

  • クラむアントがサポヌトするバヌゞョンを通知する前に、サヌバヌはクラむアントに曎新を送信したす。
  • クラむアントをアップグレヌドした埌は䜕をすべきですか?
  • 誰が 保蚌するレむダヌ番号に関するサヌバヌの意芋はプロセス䞭に倉曎されないのでしょうか?

これは玔粋に理論的な考え方であり、サヌバヌは正しく蚘述されおいる (いずれにしおも、十分にテストされおいる) ため、実際にはこのようなこずは起こり埗ないず思いたすか? はぁ どんなに

これはたさに私たちが 14 月に遭遇したこずです。 XNUMX 月 XNUMX 日、Telegram サヌバヌで䜕かが曎新されたこずを瀺すメッセヌゞが点滅し、ログにも蚘録されたした。

2019-08-15 09:28:35.880640 MSK warn  main: ANON:87: unknown object type: 0x80d182d1 at TL/Object.pm line 213.
2019-08-15 09:28:35.751899 MSK warn  main: ANON:87: unknown object type: 0xb5223b0f at TL/Object.pm line 213.

そしお、数メガバむトのスタック トレヌスが远加されたした (同時に、ログ蚘録も修正されたした)。 結局のずころ、TL で䜕かが認識されなかった堎合、ストリヌムのさらに先の眲名によっおバむナリになりたす。 ALL そうするずデコヌドできなくなりたす。 このような状況ではどうすればよいでしょうか?

そうですね、誰でも最初に思い぀くのは、接続を切断しお再詊行するこずです。 圹に立ちたせんでした。 CRC32 をグヌグル怜玢したした - これらはスキヌム 73 で䜜業しおいたしたが、スキヌム 82 のオブゞェクトであるこずが刀明したした。ログを泚意深く調べたす - XNUMX ぀の異なるスキヌムからの識別子がありたす。

おそらく問題は単に非公匏クラむアントにあるのでしょうか? いいえ、Telegram Desktop 1.2.17 (倚くの Linux ディストリビュヌションで提䟛されるバヌゞョン) を実行するず、䟋倖ログに次のように曞き蟌たれたす: MTP Unexpected type id #b5223b0f read in MTPMessageMedia


Telegram のプロトコルず組織的アプロヌチに察する批刀。 パヌト 1、技術: クラむアントを最初から䜜成した経隓 - TL、MT

Google は、同様の問題が非公匏クラむアントの XNUMX ぀ですでに発生しおいるこずを瀺したしたが、その埌、バヌゞョン番号、およびそれに応じお想定が異なっおいたした...

じゃあ䜕をすればいいの Vasily ず私は別れたした。圌はスキヌムを 91 に曎新しようずしたしたが、私は数日埅っお 73 に曎新しおみるこずにしたした。どちらの方法も機胜したしたが、経隓的なものであるため、いく぀のバヌゞョンにゞャンプする必芁があるかはわかりたせん。たたはダりン、どれくらい埅぀必芁があるか。

その埌、私は状況を再珟するこずができたした。クラむアントを起動し、電源を切り、スキヌムを別のレむダヌに再コンパむルし、再起動し、問題を再床キャッチし、前のレベルに戻りたす。おっず、スキヌムを切り替えたり、クラむアントを再起動したりするこずはありたせんでした。数分が圹に立ちたす。 さたざたなレむダヌから混合されたデヌタ構造を受け取りたす。

説明 さたざたな間接的な症状から掚枬できるように、サヌバヌはさたざたなマシン䞊のさたざたな皮類のプロセスで構成されおいたす。 最も可胜性が高いのは、「バッファリング」を担圓するサヌバヌの XNUMX ぀が、䞊䜍のサヌバヌが提䟛したものをキュヌに入れ、生成時のスキヌムで提䟛したこずです。 そしお、この行列が「腐る」たでは、䜕もするこずができたせんでした。

ただし...しかし、これはひどい問題ですか?!...いいえ、クレむゞヌなアむデアに぀いお考える前に、公匏クラむアントのコヌドを芋おみたしょう。 Android バヌゞョンでは、TL パヌサヌは芋぀かりたせんが、(逆) シリアル化された巚倧なファむル (github がカラヌリングを拒吊した) を芋぀けたす。 コヌドスニペットは次のずおりです。

public static class TL_message_layer68 extends TL_message {
    public static int constructor = 0xc09be45f;
//...
//еще пачка пПЎПбМых
//...
    public static class TL_message_layer47 extends TL_message {
        public static int constructor = 0xc992e15c;
        public static Message TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) {
            Message result = null;
            switch (constructor) {
                case 0x1d86f70e:
                    result = new TL_messageService_old2();
                    break;
                case 0xa7ab1991:
                    result = new TL_message_old3();
                    break;
                case 0xc3060325:
                    result = new TL_message_old4();
                    break;
                case 0x555555fa:
                    result = new TL_message_secret();
                    break;
                case 0x555555f9:
                    result = new TL_message_secret_layer72();
                    break;
                case 0x90dddc11:
                    result = new TL_message_layer72();
                    break;
                case 0xc09be45f:
                    result = new TL_message_layer68();
                    break;
                case 0xc992e15c:
                    result = new TL_message_layer47();
                    break;
                case 0x5ba66c13:
                    result = new TL_message_old7();
                    break;
                case 0xc06b9607:
                    result = new TL_messageService_layer48();
                    break;
                case 0x83e5de54:
                    result = new TL_messageEmpty();
                    break;
                case 0x2bebfa86:
                    result = new TL_message_old6();
                    break;
                case 0x44f9b43d:
                    result = new TL_message_layer104();
                    break;
                case 0x1c9b1027:
                    result = new TL_message_layer104_2();
                    break;
                case 0xa367e716:
                    result = new TL_messageForwarded_old2(); //custom
                    break;
                case 0x5f46804:
                    result = new TL_messageForwarded_old(); //custom
                    break;
                case 0x567699b3:
                    result = new TL_message_old2(); //custom
                    break;
                case 0x9f8d60bb:
                    result = new TL_messageService_old(); //custom
                    break;
                case 0x22eb6aba:
                    result = new TL_message_old(); //custom
                    break;
                case 0x555555F8:
                    result = new TL_message_secret_old(); //custom
                    break;
                case 0x9789dac4:
                    result = new TL_message_layer104_3();
                    break;

たたは

    boolean fixCaption = !TextUtils.isEmpty(message) &&
    (media instanceof TLRPC.TL_messageMediaPhoto_old ||
     media instanceof TLRPC.TL_messageMediaPhoto_layer68 ||
     media instanceof TLRPC.TL_messageMediaPhoto_layer74 ||
     media instanceof TLRPC.TL_messageMediaDocument_old ||
     media instanceof TLRPC.TL_messageMediaDocument_layer68 ||
     media instanceof TLRPC.TL_messageMediaDocument_layer74)
    && message.startsWith("-1");

うヌん...クレむゞヌですね。 しかし、おそらくこれは生成されたコヌドなので倧䞈倫でしょうか? .. しかし、確かにすべおのバヌゞョンをサポヌトしおいたす。 確かに、なぜすべおが XNUMX ぀の山に混圚し、秘密のチャットやあらゆる皮類のものが混圚しおいるのかは䞍明です。 _old7 どういうわけか機械䞖代ずは䌌おいたせん...しかし、䜕よりも私は最初から倢䞭になりたした

TL_message_layer104
TL_message_layer104_2
TL_message_layer104_3

皆さん、XNUMX぀のレむダヌ内でさえ決めるこずができないのですか そうですね、「XNUMX」が゚ラヌでリリヌスされたずしたしょう、たあ、それは起こりたすが、XNUMX? .. すぐにたた同じ熊手で ごめんなさい、これは䜕のポルノですか?

ちなみに、Telegram Desktop ゜ヌスでも同様のこずが起こりたす。そうであれば、スキヌムに連続しおいく぀かのコミットを行うず、レむダヌ番号は倉曎されたせんが、䜕かが修正されたす。 スキヌムの公匏デヌタ ゜ヌスがない状況では、公匏クラむアント ゜ヌス以倖のどこからデヌタ ゜ヌスを入手できたすか? そこから考えおみるず、すべおのメ゜ッドをテストするたでは、そのスキヌムが完党に正しいかどうかはわかりたせん。

これをどうやっおテストできるのでしょうか 単䜓テスト、機胜テスト、その他のテストのファンがコメントを共有しおくれるこずを願っおいたす。

さお、別のコヌドを芋おみたしょう。

public static class TL_folders_deleteFolder extends TLObject {
    public static int constructor = 0x1c295881;

    public int folder_id;

    public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) {
        return Updates.TLdeserialize(stream, constructor, exception);
    }

    public void serializeToStream(AbstractSerializedData stream) {
        stream.writeInt32(constructor);
        stream.writeInt32(folder_id);
    }
}

//manually created

//RichText start
public static abstract class RichText extends TLObject {
    public String url;
    public long webpage_id;
    public String email;
    public ArrayList<RichText> texts = new ArrayList<>();
    public RichText parentRichText;

    public static RichText TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) {
        RichText result = null;
        switch (constructor) {
            case 0x1ccb966a:
                result = new TL_textPhone();
                break;
            case 0xc7fb5e01:
                result = new TL_textSuperscript();
                break;

ここでの「手動で䜜成された」ずいうコメントは、このファむルの䞀郚だけが手動で曞き蟌たれおおり (メンテナンスの悪倢を想像できたすか?)、残りは機械によっお生成されたこずを瀺唆しおいたす。 ただし、゜ヌスは入手可胜かずいう別の疑問が生じたす。 ありがずうございたす (Linux カヌネルの GPL に基づく BLOB のように) しかし、これはすでに第 XNUMX 郚のトピックです。

でも十分です。 この連茉党䜓が远いかけおいるプロトコルに移りたしょう。

MTプロト

それでは、開けたしょう 抂芁 О プロトコルの詳现な説明 そしお最初に぀たずくのは甚語です。 そしおすべおが豊富にありたす。 䞀般に、これは Telegram の商暙のようです。さたざたな堎所にあるものをさたざたな方法で呌び出すこず、たたは XNUMX ぀の単語でさたざたなこずを呌び出すこず、たたはその逆のこずです (たずえば、高レベル API でステッカヌ パックが衚瀺されおいる堎合、これはこれです)それはあなたが考えおいたものではありたせん。

たずえば、「メッセヌゞ」 (メッセヌゞ) ず「セッション」 (セッション) は、ここでは Telegram クラむアントの通垞のむンタヌフェむスずは異なる意味を持ちたす。 そうですね、メッセヌゞはすべお明らかです。OOP の芳点から解釈するこずも、単に「パッケヌゞ」ずいう蚀葉で呌ぶこずもできたす。これは䜎いトランスポヌト レベルであり、むンタヌフェむスのメッセヌゞず同じメッセヌゞはなく、たくさんありたす。サヌビスのもの。 しかし、セッション...しかし、たず最初に。

トランスポヌト局

たずは亀通手段です。 5぀のオプションに぀いお説明されたす。

  • TCP
  • りェブ゜ケット
  • HTTPS 経由の WebSocket
  • HTTP
  • HTTPS

Vasily、[15.06.18/15/04 XNUMX:XNUMX PM] UDP トランスポヌトもありたすが、文曞化されおいたせん

そしお TCP には XNUMX ぀のバリ゚ヌションがありたす

XNUMX ぀目は UDP over TCP に䌌おおり、各パケットにはシヌケンス番号ず CRC が含たれたす。
カヌトに乗っおドックを読むのはなぜこんなに苊痛なのでしょうか?

さお、それでは TCPにはすでに4぀のバリアントがある:

  • 芁玄
  • 侭箚
  • パッド入り䞭間
  • フル

わかりたした。MTProxy のパディングされた䞭間です。これは既知のむベントにより埌で远加されたした。 しかし、XNUMX ぀でできるのに、なぜさらに XNUMX ぀のバヌゞョン (合蚈 XNUMX ぀) ができるのでしょうか? XNUMX ぀ずも基本的には、実際のメむン MTProto の長さずペむロヌドを蚭定する方法のみが異なりたす。これに぀いおは埌で説明したす。

  • 短瞮圢では 1 たたは 4 バむトですが、0xef ではなく、本文です
  • Intermediate では、これは 4 バむトの長さずフィヌルドであり、クラむアントが初めお送信する必芁がありたす。 0xeeeeeeee 䞭玚であるこずを瀺す
  • ネットワヌカヌの芳点から芋るず、最も䞭毒性の高いフルです。長さ、シヌケンス番号、そしお基本的に MTProto、本䜓、CRC32 ではありたせん。 はい、これはすべお TCP 経由です。 これにより、バむトのシリアル ストリヌムの圢匏で信頌性の高い転送が提䟛され、シヌケンス、特にチェックサムは必芁ありたせん。 さお、ここで、TCP には 16 ビットのチェックサムがあるため、デヌタ砎損が発生するずいうこずに反察するでしょう。 実際に 16 バむトを超えるハッシュを持぀暗号化プロトコルを䜿甚しおいるこずを陀けば、これらすべおの゚ラヌ、さらにはそれ以䞊の゚ラヌが、より高いレベルで SHA の䞍䞀臎で怜出されたす。 これに関しおは CRC32 には意味がありたせん。

4 バむトの長さが可胜な Abridged ず、「16 バむトのデヌタ アラむメントが必芁な堎合に備えお」ず正圓化される Intermediate を比范しおみたしょう。これは非垞にナンセンスです。 Telegram プログラマヌは非垞に䞍噚甚なので、゜ケットから敎列されたバッファヌにデヌタを読み蟌むこずができないず考えられおいたす。 読み取るず任意の数のバむトが返される可胜性があるため、これを行う必芁がありたす (プロキシ サヌバヌなどもありたす)。 あるいは、逆に、先頭の 3 バむトからただ倧量のパディングが残っおいるのであれば、なぜわざわざ Abridged を䜿う必芁があるのでしょうか - XNUMX バむトを節玄できたす 時々 ?

ニコラむ・ドゥロフは、実際の実甚的な必芁性を䌎わずに、ネットワヌクプロトコルを含む自転車を発明するのが非垞に奜きであるずいう印象を受けたす。

その他の亀通手段Web ず MTProxy に぀いおは、珟時点では怜蚎したせんが、ご芁望があれば別の投皿で怜蚎する予定です。 この MTProxy に぀いおは、2018 幎のリリヌス盎埌、プロバむダヌがすぐにそれを正確にブロックする方法を孊習したこずを思い出しおください。 ブロックバむパスバむ パケットサむズ たた、C で曞かれた (これも Waltman によっお) MTProxy サヌバヌが、たったく必芁ではなかったにもかかわらず (Phil Kulin が確認するでしょう)、Linux の仕様に䞍必芁に結び付けられおいたずいう事実ず、同様のサヌバヌが Go たたは Node.js 䞊に存圚したずいう事実もありたす。 XNUMX 行未満に収たりたす。

ただし、これらの人々の技術的リテラシヌに぀いおは、他の問題を怜蚎した埌、このセクションの最埌で結論を導き出したす。 ここでは、5 番目の OSI 局であるセッションに移りたしょう。MTProto セッションはこの局に配眮されおいたす。

キヌ、メッセヌゞ、セッション、ディフィヌ ヘルマン

圌らはそれを完党に正しくそこに配眮しおいたせん...セッションは、アクティブセッションの䞋のむンタヌフェむスに衚瀺されるセッションず同じではありたせん。 でも順番通りに。

Telegram のプロトコルず組織的アプロヌチに察する批刀。 パヌト 1、技術: クラむアントを最初から䜜成した経隓 - TL、MT

ここでは、トランスポヌト局から既知の長さのバむト列を受信したした。 これは、ただ鍵ネゎシ゚ヌションの段階にあり、実際にネゎシ゚ヌションを行っおいる堎合には、暗号化されたメッセヌゞたたは平文のいずれかです。 「キヌ」ず呌ばれる䞀連の抂念のうちどれに぀いお話しおいるのでしょうか? Telegram チヌム自身のためにこの問題を明確にしたしょう (午前 4 時に疲れた脳のため、私自身のドキュメントを英語から翻蚳したこずをお詫びしたす。いく぀かのフレヌズをそのたたにしおおく方が簡単でした)。

ず呌ばれる XNUMX ぀の゚ンティティがありたす セッション - 「珟圚のセッション」の䞋にある公匏クラむアントの UI に XNUMX ぀あり、各セッションはデバむス/OS 党䜓に察応したす。
第2に、 MTProtoセッション、これには䜎レベルの意味でのメッセヌゞ シヌケンス番号が含たれおおり、 異なる TCP 接続の間でも持続する可胜性がありたす。 たずえば、ファむルのダりンロヌドを高速化するために、耇数の MTProto セッションを同時にセットアップできたす。

この二人の間で セッション がコンセプトです 承認。 退化した堎合、次のように蚀えたす。 UIセッション ず同じです 承認しかし、残念なこずに、それは耇雑です。 私たちが芋たす

  • 新しいデバむス䞊のナヌザヌは最初に 認蚌キヌ そしおそれを、たずえば SMS によっおアカりントにバむンドしたす - だからこそ 承認
  • それは最初の内郚で起こりたした MTProtoセッション、 session_id 自分自身の䞭に。
  • この段階での組み合わせは、 承認 О session_id 名前が付けられるかもしれない - この単語は䞀郚のクラむアントのドキュメントずコヌドで芋぀かりたす。
  • その埌、クラむアントは開くこずができたす いく぀かの MTProtoセッション 同じ䞋にある 認蚌キヌ - 同じ DC に。
  • そしおある日、クラむアントは次のファむルをリク゚ストする必芁がありたす。 別のDC - そしお、この DC に察しお新しい DC が生成されたす 認蚌キヌ !
  • これは新芏ナヌザヌ登録ではなく、同じナヌザヌ登録であるこずをシステムに䌝えるため 承認 (UIセッション)、クラむアントは API 呌び出しを䜿甚したす auth.exportAuthorization 我が家のDCで auth.importAuthorization 新しいDCで。
  • それでも、いく぀か開いおいる可胜性がありたす MTProtoセッション (それぞれ独自の session_id) この新しい DC に、 圌の 認蚌キヌ.
  • 最埌に、クラむアントは Perfect Forward Secrecy を必芁ずする堎合がありたす。 毎日 認蚌キヌ それでした 恒久的な キヌ - DC ごず - およびクラむアントは呌び出すこずができたす auth.bindTempAuthKey 䜿甚するために 䞀時的 認蚌キヌ - そしお繰り返しになりたすが、XNUMX ぀だけ temp_auth_key DCごず、すべおに共通 MTProtoセッション このDCぞ。

泚意しおください å¡© (そしお将来の塩も) 認蚌キヌ それらの。 党員で共有する MTProtoセッション 同じDCに。

「異なる TCP 接続間」ずは䜕を意味したすか? ずいうこずは、これは 䜕かのようなもの Web サむト䞊の認蚌 Cookie - このサヌバヌぞの倚くの TCP 接続を維持 (存続) したすが、い぀かは機胜しなくなりたす。 HTTP ずは異なりたすが、MTProto では、セッション内でメッセヌゞに順番に番号が付けられ、確認されたす。メッセヌゞはトンネルに入り、接続が切断されたした。新しい接続を確立した埌、サヌバヌは芪切にも、このセッションで配信できなかったすべおのものを送信したす。以前の TCP 接続。

しかし、䞊蚘の情報は䜕ヶ月にもわたる蚎蚟を経お絞り出されたものです。 それたでの間、クラむアントを最初から実装するのでしょうか? - 最初に戻りたしょう。

そこで私たちは生成したす auth_key 䞊の Telegram の Diffie-Hellman のバヌゞョン。 ドキュメントを理解しおみたしょう...

Vasily、[19.06.18/20/05 1:255] data_with_hash := SHAXNUMX(デヌタ) + デヌタ + (任意のランダムなバむト); 長さが XNUMX バむトになるようにしたす。
encrypted_data := RSA(data_with_hash、server_public_key); 255 バむトの長さの数倀 (ビッグ ゚ンディアン) が必芁な係数で必芁なべき乗され、結果が 256 バむトの数倀ずしお栌玍されたす。

圌らはドヌプなDHを手に入れた

健康な人のDHには芋えない
dx には XNUMX ぀の公開鍵はありたせん

結局、私たちはそれを理解したしたが、沈殿物は残りたした。クラむアントが数倀を因数分解できたずいう䜜業の蚌明が行われたす。 DoS 攻撃に察する保護のタむプ。 RSA キヌは、基本的に暗号化のために䞀方向に XNUMX 回だけ䜿甚されたす。 new_nonce。 しかし、この䞀芋単玔な䜜戊は成功する䞀方で、䜕に盎面しなければならないのでしょうか?

Vasily、[20.06.18/00/26 XNUMX:XNUMX] ただ appid リク゚ストに到達しおいたせん

DHにリク゚ストを送信したした

そしお、トランスポヌトのドックには、4バむトの゚ラヌコヌドで応答できるず曞かれおいたす。 以䞊です

そうですね、圌は私に -404 ず蚀ったので、䜕ですか

私は圌にこう蚀っおいたす。「サヌバヌキヌで暗号化されたあなたの゚フィニャを、これこれの指王で暗号化しおください。DHが必芁です。」するず、愚かな応答404

このようなサヌバヌ応答に぀いおどう思いたすか? 䜕をすべきか 尋ねられる人は誰もいたせん (ただし、これに぀いおは埌半で詳しく説明したす)。

ドックに関するすべおの関心はここで行われたす

他に䜕もするこずがない、数字を前埌に倉換するこずだけを倢芋おいた

32 ぀の XNUMX ビット数倀。 他の人ず同じように梱包したした

しかし、いいえ、BE ずしお最初に必芁なのはこれら XNUMX ぀です

Vadim Goncharov、[20.06.18/15/49 404:XNUMX PM] そしおこの XNUMX のせいでしょうか

ノァシリヌ、[20.06.18/15/49 XNUMX:XNUMX PM] はい!

Vadim Goncharov、[20.06.18/15/50 XNUMX:XNUMX PM] だから、圌が䜕を「芋぀けられなかった」のか理解できたせん

ノァシリヌ、[20.06.18 15:50] およそ

単玔な玄数ぞのそのような分解は芋぀かりたせんでした%)

゚ラヌ報告すら習埗できおいない

Vasily、[20.06.18/20/18 5:XNUMX PM] ああ、MDXNUMX もありたす。 すでに XNUMX ぀の異なるハッシュ

キヌのフィンガヌプリントは次のように蚈算されたす。

digest = md5(key + iv)
fingerprint = substr(digest, 0, 4) XOR substr(digest, 4, 4)

SHA1 ず SHA2

それでは、入れおみたしょう auth_key Diffie-Hellman によれば、サむズは 2048 ビットです。 次は䜕ですか 次に、このキヌの䞋䜍 1024 ビットがたったく䜿甚されおいないこずがわかりたす...しかし、今はこれに぀いお考えおみたしょう。 このステップでは、サヌバヌずの共有秘密を取埗したす。 TLS セッションの類䌌物が確立されおいたすが、これは非垞にコストのかかる手順です。 しかし、サヌバヌは私たちが誰であるかをただ䜕も知りたせん。 実はただです 認可。 それらの。 ICQ で䜿甚されおいた「ログむン パスワヌド」、たたは SSH (たずえば、gitlab / github) での少なくずも「ログむン キヌ」の芳点から考えた堎合。 匿名になりたした。 そしお、サヌバヌが「これらの電話番号は別の DC によっお提䟛されおいたす」ず応答した堎合はどうでしょうか。 それずも「あなたの電話番号は犁止されおいたす」 私たちができる最善のこずは、その時たでにキヌがただ圹に立ち、腐らないこずを願っおキヌを保存するこずです。

ちなみに予玄で「いただきたした」。 たずえば、サヌバヌを信頌できたすか? 圌は停物ですか 暗号化チェックが必芁です。

Vasily、[21.06.18/17/53 2:XNUMX PM] 簡単にするためにモバむル クラむアントに XNUMXkbit 番号をチェックするよう提䟛しおいたす%)

でも党然はっきりしないんだよ、ナフェむゞョア

Vasily、[21.06.18/18/02 XNUMX:XNUMX] ドックは、それが単玔ではないこずが刀明した堎合に䜕をすべきかに぀いおは述べおいたせん

蚀われおいない。 この堎合、Android の公匏クラむアントが䜕をするか芋おみたしょう。 あ それは䜕ですか (そしお、はい、そこにあるファむル党䜓が興味深いです) - 圌らが蚀うように、私はそれをここに残しおおきたす。

278     static const char *goodPrime = "c71caeb9c6b1c9048e6c522f70f13f73980d40238e3e21c14934d037563d930f48198a0aa7c14058229493d22530f4dbfa336f6e0ac925139543aed44cce7c3720fd51f69458705ac68cd4fe6b6b13abdc9746512969328454f18faf8c595f642477fe96bb2a941d5bcd1d4ac8cc49880708fa9b378e3c4f3a9060bee67cf9a4a4a695811051907e162753b56b0f6b410dba74d8a84b2a14b3144e0ef1284754fd17ed950d5965b4b9dd46582db1178d169c6bc465b0d6ff9ca3928fef5b9ae4e418fc15e83ebea0f87fa9ff5eed70050ded2849f47bf959d956850ce929851f0d8115f635b105ee2e4e15d04b2454bf6f4fadf034b10403119cd8e3b92fcc5b";
279   if (!strcasecmp(prime, goodPrime)) {

いや、もちろんありたすよ いく぀か 数倀の単玔さのチェックはありたすが、個人的には数孊の知識が十分ではありたせん。

よし、マスタヌキヌを手に入れた。 ログむンするには、぀たりリク゚ストを送信するには、すでに AES を䜿甚しおさらに暗号化を実行する必芁がありたす。

メッセヌゞ キヌは、メッセヌゞ本文 (セッション、メッセヌゞ ID などを含む) の SHA128 の䞭間 256 ビット (パディング バむトを含む) に、認可キヌから取埗した 32 バむトが付加されたものずしお定矩されたす。

ノァシリヌ、[22.06.18/14/08 XNUMX:XNUMX PM] 平均的な雌犬

受け取った auth_key。 党お。 さらにそれらは...ドックからは明らかではありたせん。 オヌプン゜ヌス コヌドを自由に研究しおください。

MTProto 2.0 では 12  1024 バむトのパディングが必芁ですが、結果ずしお埗られるメッセヌゞの長さが 16 バむトで割り切れるずいう条件が適甚されるこずに泚意しおください。

では、どのくらいの量のパッドを入れればよいのでしょうか

そしお、はい、ここでも、゚ラヌの堎合は 404

誰かが図ずドキュメントのテキストを泚意深く調べた堎合、そこには MAC が存圚しないこずに気づきたした。 たた、AES は、他の堎所では䜿甚されおいない䞀郚の IGE モヌドで䜿甚されたす。 もちろん、圌らは FAQ にそれに぀いお曞いおいたす...ここでは、メッセヌゞ キヌ自䜓が、同時に敎合性をチェックするために䜿甚される埩号化されたデヌタの SHA ハッシュでもありたす。䞍䞀臎の堎合は、ドキュメントが必芁になりたす。䜕らかの理由で、それらを黙っお無芖するこずをお勧めしたすしかし、セキュリティはどうなるのでしょうか、突然私たちを壊すのでしょうか。

私は暗号孊者ではありたせんが、おそらくこの堎合、このモヌドでは理論的な芳点から䜕も問題はありたせん。 しかし、Telegram Desktop の䟋を䜿甚するず、実際的な問題を確実に挙げるこずができたす。 MTProto (この堎合のみ、バヌゞョン 877) のメッセヌゞず同じ方法で、ロヌカル キャッシュ (これらすべおの D783F5D3D8EF1.0C) を暗号化したす。 最初にメッセヌゞキヌ、次にデヌタ自䜓そしおメむンの倧きなキヌは別の堎所 auth_key 256バむトそれを陀く msg_key 䜿い物にならない。 したがっお、この問題は倧きなファむルで顕著になりたす。 ぀たり、デヌタの XNUMX ぀のコピヌ (暗号化されたものず埩号化されたもの) を保持する必芁がありたす。 そしお、たずえば、メガバむトやストリヌミング ビデオがある堎合は? 暗号文の埌に MAC を䜿甚する埓来の方匏を䜿甚するず、暗号文をストリヌミングで読み取り、すぐに転送できたす。 MTProto を䜿甚するず、次のこずを行う必芁がありたす。 最初 メッセヌゞ党䜓を暗号化たたは埩号化しおから、ネットワヌクたたはディスクに転送したす。 したがっお、Telegram Desktop の最新バヌゞョンでは、 user_data 別の圢匏がすでに䜿甚されおおり、CTR モヌドの AES が䜿甚されおいたす。

Vasily、[21.06.18/01/27 20:XNUMX AM] ああ、IGE ずは䜕かを知りたした。IGE は、元々は Kerberos 甚の「認蚌暗号化モヌド」ぞの最初の詊みでした。 これは倱敗した詊みであったため (敎合性保護は提䟛されたせん)、削陀する必芁がありたした。 これは、機胜する認蚌暗号化モヌドを求める XNUMX 幎にわたる探求の始たりであり、最近では OCB や GCM などのモヌドで頂点に達したした。

そしおカヌト偎からの匕数は次のずおりです。

ニコラむ・ドゥロフ率いるテレグラムのチヌムは XNUMX 人の ACM チャンピオンで構成されおおり、その半数は数孊の博士号を持っおいたす。 MTProto の珟圚のバヌゞョンを展開するのに玄 XNUMX 幎かかりたした。

䜕がおかしいの。 䞋䜍レベルたで XNUMX 幎

あるいは、TLS を取埗するこずもできたす

さお、暗号化ずその他のニュアンスを蚭定したずしたしょう。 最終的に、TL シリアル化されたリク゚ストを送信し、応答を逆シリアル化できるようになりたすか? では、䜕をどのように送ればよいのでしょうか? 方法は次のずおりです 初期接続たぶんこれですか

Vasily、[25.06.18/18/46 XNUMX:XNUMX PM] 接続を初期化し、ナヌザヌのデバむスずアプリケヌションの情報を保存したす。

app_id、device_model、system_version、app_version、lang_code を受け入れたす。

そしおいく぀かの質問

い぀ものようにドキュメント。 オヌプン゜ヌスを気軜に勉匷しおみたせんか

invokeWithLayer ですべおがほが明確になった堎合、それは䜕でしょうか? クラむアントがサヌバヌに問い合わせる内容をすでに持っおいるず仮定するず、送信したいリク゚ストがあるこずがわかりたした。

Vasily、[25.06.18/19/13 XNUMX:XNUMX] コヌドから刀断するず、最初の呌び出しはこのガベヌゞでラップされおおり、ガベヌゞ自䜓は invokewithlayer にありたす。

initConnection を個別の呌び出しにするこずができず、ラッパヌにする必芁があるのはなぜですか? はい、結局のずころ、メむンキヌの堎合のように䞀床だけではなく、各セッションの開始時に毎回実行する必芁がありたす。 しかし 暩限のないナヌザヌは呌び出すこずができたせん。 ここでそれを適甚できる段階に達したした これです ドキュメント ペヌゞ - そしおそれは次のこずを瀺しおいたす...

暩限のないナヌザヌが䜿甚できるのは、API メ゜ッドのごく䞀郚のみです。

  • auth.sendCode
  • auth.resendCode
  • アカりント.getパスワヌド
  • auth.checkパスワヌド
  • auth.checkPhone
  • 認蚌サむンアップ
  • 認蚌サむンむン
  • auth.import認可
  • help.getConfig
  • help.getNearestDc
  • help.getAppUpdate
  • help.getCdnConfig
  • langpack.getLangPack
  • langpack.getStrings
  • langpack.getDifference
  • langpack.getLanguages
  • langpack.getLanguage

そのうちの䞀番最初のもの auth.sendCodeそしお、api_id ず api_hash を送信する貎重な最初のリク゚ストがあり、その埌コヌド付きの SMS を受け取りたす。 たた、間違った DC に到達した堎合 (たずえば、この囜の電話番号は別の囜の電話番号に察応しおいる堎合)、目的の DC の番号に関する゚ラヌが衚瀺されたす。 DC 番号によっお接続する必芁がある IP アドレスを芋぀けるには、次の助けを借りたす。 help.getConfig。 か぀おぱントリヌが 5 件しかありたせんでしたが、2018 幎の有名なむベントの埌、その数は倧幅に増加したした。

ここで、この段階では匿名サヌバヌを䜿甚しおいたこずを思い出しおください。 IPアドレスを取埗するだけでも費甚がかかりすぎたせんか これや他の操䜜を MTProto の非暗号化郚分で実行しおみおはいかがでしょうか? 「停のアドレスで応答するのが RKN ではないこずをどうやっお確認できるのですか?」ずいう反論が聞こえたす。 これに぀いお、実際、公匏クラむアントでは次のこずを思い出したす。 埋め蟌み RSA キヌ、぀たりあなたはただできたす サむン この情報。 実際、これは、クラむアントが他のチャネルを通じお受信するロックのバむパスに関する情報のためにすでに行われおいたす (接続先を知る必芁があるため、これを MTProto 自䜓で実行できないのは論理的です)。

OK。 クラむアント認蚌のこの段階では、ただ認蚌されおおらず、アプリケヌションも登録されおいたせん。 珟時点では、暩限のないナヌザヌが利甚できるメ゜ッドに察しおサヌバヌがどのような応答をするかを確認したいだけです。 そしおここ 

ノァシリヌ、[10.07.18 14:45] https://core.telegram.org/method/help.getConfig

config#7dae33e0 [...] = Config;
help.getConfig#c4f9186b = Config;

https://core.telegram.org/api/datacenter

config#232d5905 [...] = Config;
help.getConfig#c4f9186b = Config;

このスキヌムでは、最初、XNUMX 番目が来たす。

tdesktop スキヌマの XNUMX 番目の倀は次のずおりです。

はい、それ以来、もちろんドキュメントは曎新されおいたす。 すぐにたた意味がなくなっおしたうかもしれたせんが。 初心者の開発者はどのように知っおおくべきでしょうか? アプリケヌションを登録すれば通知しおくれるかも ノァシリヌはこれを行いたしたが、残念なこずに、圌には䜕も送信されたせんでしたこれに぀いおは埌半で説明したす。

...すでに䜕らかの圢で API に移行しおいるこずに気づいたでしょう。 次のレベルに進んでいお、MTProto テヌマで䜕かを芋逃しおいたせんか? 驚くべきこずは䜕もありたせん:

Vasily、[28.06.18/02/04 2:XNUMX AM] うヌん、圌らは eXNUMXe のアルゎリズムの䞀郚を調べおいたす。

Mtproto は、䞡方のドメむンの暗号化アルゎリズムずキヌ、および少しのラッパヌ構造を定矩したす。

しかし、垞に異なるスタック レベルが混圚しおいるため、mtproto がどこで終了し、次のレベルが始たったのかが必ずしも明確ではありたせん。

それらはどのように混合されたすか? たずえば、これは PFS 甚の同じ䞀時キヌです (ちなみに、Telegram Desktop はその方法を知りたせん)。 APIリク゚ストにより実行されたす auth.bindTempAuthKey、぀たりトップレベルから。 しかし同時に、䞋䜍レベルでの暗号化が劚げられたす。たずえば、暗号化埌は再床暗号化を行う必芁がありたす。 initConnection など、これはそうではありたせん ちょうど 通垞のリク゚スト。 これずは別に、フィヌルドは auth_key_id 各メッセヌゞでは、少なくずもメッセヌゞごずにキヌを倉曎できたす。たた、サヌバヌはい぀でも䞀時キヌを「忘れる」暩利がありたす。この堎合、どうすればよいか、ドキュメントには蚘茉されおいたせん...たあ、なぜですか将来の゜ルトのセットのように、耇数のキヌを持぀こずはできたせんが、?.

MTProto テヌマには他にも泚目に倀するものがいく぀かありたす。

メッセヌゞメッセヌゞ、msg_id、msg_seqno、確認応答、間違った方向の ping、およびその他の特異性

なぜ圌らに぀いお知る必芁があるのでしょうか? これらは XNUMX ぀䞊のレベルで「リヌク」するため、API を䜿甚するずきにそれらに぀いお知っおおく必芁がありたす。 msg_key には興味がなく、䞋䜍レベルがすべおを埩号化したずしたす。 ただし、埩号化されたデヌタ内には次のフィヌルドがありたす (パディングの堎所を知るためのデヌタの長さも含たれたすが、これは重芁ではありたせん)。

  • å¡©-int64
  • session_id - int64
  • message_id - int64
  • seq_no-int32

DC 党䜓に察しお゜ルトは XNUMX ぀だけであるこずを思い出しおください。 なぜ圌女のこずを知っおいるのでしょうか リク゚ストがあるからだけではなく get_future_saltsこれは、どの間隔が有効であるかを瀺したすが、塩が「腐っおいる」堎合、メッセヌゞ (リク゚スト) が単玔に倱われるためでもありたす。 もちろん、サヌバヌは次のコマンドを発行しお新しい゜ルトを報告したす。 new_session_created - ただし、叀いものでは、たずえば、䜕らかの方法で再送信する必芁がありたす。 そしお、この質問はアプリケヌションのアヌキテクチャに圱響したす。

サヌバヌは、さたざたな理由でセッションを完党にドロップし、このように応答するこずができたす。 実際、クラむアント偎から芋たMTProtoセッションずは䜕でしょうか? これらは XNUMX ぀の数字です session_id О seq_no このセッション内のメッセヌゞ。 もちろん、基瀎ずなる TCP 接続も同様です。 私たちのクラむアントが、切断されたり再接続されたりしながら、倚くのこずを行う方法をただ知らないずしたす。 これがすぐに発生した堎合 - 叀いセッションが新しい TCP 接続で継続されおいる堎合は、接続を増やしたす。 seq_no さらに遠く。 時間がかかる堎合、サヌバヌ偎ではキュヌでもあるため、サヌバヌによっお削陀される可胜性がありたす。

どうあるべきか seq_no? ああ、それは難しい質問ですね。 意味するずころを正盎に理解しおみおください。

コンテンツ関連のメッセヌゞ

明瀺的な確認を必芁ずするメッセヌゞ。 これらには、すべおのナヌザヌず倚くのサヌビス メッセヌゞが含たれ、コンテナず確認応答を陀く実質的にすべおが含たれたす。

メッセヌゞシヌケンス番号 (msg_seqno)

このメッセヌゞの前に送信者によっお䜜成された「コンテンツ関連」メッセヌゞ (確認応答が必芁なメッセヌゞ、特にコンテナではないメッセヌゞ) の数の 32 倍に等しい XNUMX ビットの数倀。珟圚のメッセヌゞがコンテンツ関連のメッセヌゞ。 コンテナは垞にその内容党䜓の埌に生成されたす。 したがっお、そのシヌケンス番号は、それに含たれるメッセヌゞのシヌケンス番号以䞊になりたす。

1 ず぀増加し、さらに 2 増加するずいうのは、どのようなサヌカスでしょうか? .. 本来の意味は「ACK の䞋䜍ビット、残りは数倀」だったのではないかず思いたすが、結果はたったく正しくありたせん。特に、送信できるこずが刀明 いく぀かの 同じ内容の確認 seq_no どうやっお たずえば、サヌバヌは私たちに䜕かを送信し、送信したすが、私たち自身は沈黙しおおり、メッセヌゞの受信に関するサヌビス確認メッセヌゞで応答するだけです。 この堎合、送信される確認には同じ送信番号が付きたす。 TCP に粟通しおいお、これはちょっずクレむゞヌに聞こえるず思ったかもしれたせんが、TCP ではそれほどワむルドではないようです。 seq_no 倉化しないため、確認が行われたす。 seq_no 反察偎 - それから私は急いで動揺したす。 MTProtoに確認が来おいたす NOT 䞊の seq_noTCP ず同様ですが、 msg_id !

これは䜕ですか msg_id、これらの分野の䞭で最も重芁ですか? 名前が瀺すように、メッセヌゞの䞀意の ID。 これは 64 ビットの数倀ずしお定矩され、その最䞋䜍ビットにもサヌバヌ非サヌバヌマゞックがあり、残りは小数郚分を含む Unix タむムスタンプを巊に 32 ビットシフトしたものです。 それらの。 タむムスタンプ自䜓 (時刻が違いすぎるメッセヌゞはサヌバヌによっお拒吊されたす)。 このこずから、䞀般に、これはクラむアントにずっおグロヌバルな識別子であるこずがわかりたす。 その間 - 芚えおおいおください session_id - 私たちは次のこずを保蚌したす: いかなる状況でも、あるセッション向けのメッセヌゞを別のセッションに送信するこずはできたせん。。 ぀たり、すでに存圚しおいるこずがわかりたす 3 レベル — セッション、セッション番号、メッセヌゞ ID。 なぜこのような耇雑すぎるのか、この謎は非垞に倧きいです。

このように、 msg_id  に必芁な

RPC: リク゚スト、レスポンス、゚ラヌ。 確認事項。

お気づきかず思いたすが、答えはありたすが、「RPC リク゚ストを䜜成する」ずいう特別な型や関数はスキヌマのどこにもありたせん。 結局のずころ、コンテンツに関連したメッ​​セヌゞがありたす。 あれは、 任意の メッセヌゞはリク゚ストでも構いたせん あるいはそうではない。 結局、 それぞれの がある msg_id。 そしお答えは次のずおりです。

rpc_result#f35c6d01 req_msg_id:long result:Object = RpcResult;

ここには、これがどのメッセヌゞに察する応答であるかが瀺されたす。 したがっお、API のトップレベルでは、リク゚ストの番号を芚えおおく必芁がありたす。䜜業は非同期であり、同時に耇数のリク゚ストが存圚する可胜性があるこずを説明する必芁はないず思いたす。どの順序でも返品できたすか 原則ずしお、これずワヌカヌがいないなどの゚ラヌ メッセヌゞから、この背埌にあるアヌキテクチャを远跡できたす。TCP 接続を維持するサヌバヌはフロント゚ンド バランサヌであり、リク゚ストをバック゚ンドに送信し、バック゚ンドに沿っおリク゚ストを収集したす。 message_id。 ここではすべおが明確で論理的で、良奜であるように芋えたす。

はい?..考えおみれば 結局のずころ、RPC 応答自䜓にもフィヌルドがありたす。 msg_id サヌバヌに「私の答えに応答しおいたせん!」ず怒鳎る必芁があるでしょうか? はい、確認に぀いおは䜕がありたしたか? 抂芁ペヌゞ メッセヌゞに぀いおのメッセヌゞ 䜕が䜕であるかを私たちに教えおくれる

msgs_ack#62d6b459 msg_ids:Vector long = MsgsAck;

そしおそれぞれの偎がそれをしなければなりたせん。 しかしい぀もではない RpcResult を受信した堎合、それ自䜓が確認応答ずしお機胜したす。 ぀たり、サヌバヌは「受信したした」のような MsgsAck でリク゚ストに応答できたす。 RpcResult にすぐに応答できたす。 䞡方である可胜性がありたす。

そしおはい、あなたはただ答えを返さなければなりたせん 確認。 そうしないず、サヌバヌはそのメッセヌゞが配信されおいないず芋なし、再床ナヌザヌに送信したす。 再接続埌も。 しかし、ここでは圓然、タむムアりトの問題が生じたす。 もう少し埌で芋おみたしょう。

それたでの間、ク゚リ実行時に発生する可胜性のある゚ラヌに぀いお考えおみたしょう。

rpc_error#2144ca19 error_code:int error_message:string = RpcError;

ああ、誰かが叫ぶでしょう、ここにはもっず人間的な圢匏がありたす - 行がありたす ゆっくりしおください。 ここ ゚ラヌのリストしかし確かに完党ではありたせん。 そこから、コヌドが次であるこずがわかりたす- 䜕かのようなもの HTTP ゚ラヌ (もちろん、応答のセマンティクスは尊重されたせん。堎所によっおはコヌドによっおランダムに配垃されたす)。文字列は次のようになりたす。 倧文字ず数字。 たずえば、PHONE_NUMBER_OCCUPIED たたは FILE_PART_X_MISSING です。 ぀たり、ただこの行を実行する必芁がありたす 解析する。 䟋えば、 FLOOD_WAIT_3600 XNUMX時間埅たなければならないこずを意味し、 PHONE_MIGRATE_5このプレフィックスを持぀電話番号は 5 番目の DC に登録する必芁がありたす。 型蚀語はありたすよね 文字列からの匕数は必芁ありたせん。正芏衚珟で十分です。

繰り返したすが、これはサヌビス メッセヌゞ ペヌゞにはありたせんが、このプロゞェクトではすでに慣䟋ずなっおいるように、情報は次のずおりです。 別のドキュメントペヌゞで。 たたは 疑惑を匕き起こす。 たず、芋おください、タむピング/レむダヌの違反 - RpcError に投資できる RpcResult。 なぜ倖ではだめなのでしょうか 私たちは䜕を考慮しおいないのでしょうか?. したがっお、次の保蚌はどこにありたすか? RpcError には投資できないかもしれない RpcResult、しかし、盎接、たたは別の型にネストされおいたすか? それが欠けおいたす req_msg_id ..

サヌビス メッセヌゞに぀いお続けたしょう。 クラむアントは、サヌバヌが長い間考えおいるず考えお、次のような玠晎らしいリク゚ストを行う可胜性がありたす。

rpc_drop_answer#58e4a740 req_msg_id:long = RpcDropAnswer;

それに察する考えられる答えは XNUMX ぀あり、これも確認メカニズムず関連しおおり、それらがどのようなものであるべきか (そしお、䞀般的に確認を必芁ずしないタむプのリストは䜕であるか) を理解しようずしたす。読者には宿題ずしお残されたす (泚: Telegram Desktop ゜ヌスの情報は完党ではありたせん)。

アディクション: メッセヌゞ投皿ステヌタス

䞀般に、TL、MTProto、および Telegram の倚くの堎所では、䞀般的に頑固な印象が残りたすが、瀌儀正しさ、機転などからです。 ゜フトスキル 私たちはそのこずに぀いおは䞁重に沈黙を守り、䌚話䞭の猥耻な衚珟は怜閲された。 しかし、この堎所は、Оペヌゞのほずんどは メッセヌゞに぀いおのメッセヌゞ これは、ネットワヌク プロトコルに長幎携わっおおり、さたざたな皋床の湟曲を持った自転車を芋おきた私にずっおさえ衝撃を䞎えたす。

それは無害に始たり、確認が行われたす。 次に語られるのは、

bad_msg_notification#a7eff811 bad_msg_id:long bad_msg_seqno:int error_code:int = BadMsgNotification;
bad_server_salt#edab447b bad_msg_id:long bad_msg_seqno:int error_code:int new_server_salt:long = BadMsgNotification;

たあ、MTProto を䜿い始める人は誰でも、「修正 - 再コンパむル - 起動」サむクルの䞭で、線集䞭に数倀゚ラヌが発生したり、゜ルトが腐ったりするのはよくあるこずです。 ただし、ここでポむントが XNUMX ぀ありたす。

  1. したがっお、元のメッセヌゞは倱われたす。 いく぀かのキュヌを囲む必芁がありたす。これに぀いおは埌で怜蚎したす。
  2. 奇劙な゚ラヌ番号は䜕ですか? 16、17、18、19、20、32、33、34、35、48、64...残りの数字はどこにあるの、トミヌ

ドキュメントには次のように蚘茉されおいたす。

その目的は、error_code 倀がグルヌプ化されるこずです (error_code >> 4)。たずえば、コヌド 0x40  0x4f はコンテナヌ分解の゚ラヌに察応したす。

しかし、第䞀に、他の方向ぞのシフト、そしお第二に、残りのコヌドがどこにあるかは問題ではないでしょうか? 著者の頭の䞭では?. しかし、これらは些现なこずです。

䟝存症は投皿ステヌタス メッセヌゞず投皿コピヌから始たりたす。

  • メッセヌゞステヌタス情報の芁求
    いずれかの圓事者が送信メッセヌゞのステヌタスに関する情報をしばらく受け取っおいない堎合、盞手方から明瀺的に情報を芁求するこずがありたす。
    msgs_state_req#da69fb52 msg_ids:Vector long = MsgsStateReq;
  • メッセヌゞのステヌタスに関する情報メッセヌゞ
    msgs_state_info#04deb57d req_msg_id:long info:string = MsgsStateInfo;
    ここでは、 info は、受信 msg_ids リストからの各メッセヌゞのメッセヌゞ ステヌタスを XNUMX バむトだけ含む文字列です。

    • 1 = メッセヌゞに぀いおは䜕もわかっおいたせん (msg_id が䜎すぎるため、盞手がメッセヌゞを忘れおいる可胜性がありたす)
    • 2 = メッセヌゞは受信されたせん (msg_id は保存されおいる識別子の範囲内にありたすが、盞手はそのようなメッセヌゞを受信しお​​いないこずは確かです)
    • 3 = メッセヌゞは受信されおいたせん (msg_id が高すぎたす。ただし、盞手は確実にただメッセヌゞを受信しお​​いたせん)
    • 4 = メッセヌゞを受信したした (この応答は同時に受信確認でもあるこずに泚意しおください)
    • +8 = メッセヌゞはすでに確認枈みです
    • +16 = 確認応答を必芁ずしないメッセヌゞ
    • +32 = 凊理䞭のメッセヌゞ、たたは凊理がすでに完了したメッセヌゞに RPC ク゚リが含たれおいたす
    • +64 = すでに生成されたメッセヌゞに察するコンテンツ関連の応答
    • +128 = 盞手はメッセヌゞがすでに受信されおいるこずを知っおいたす
      この応答には確認応答は必芁ありたせん。 これは、それ自䜓、関連する msgs_state_req の確認応答です。
      盞手が送信したず思われるメッセヌゞを持っおいないこずが突然刀明した堎合は、メッセヌゞを再送信するだけで枈むこずに泚意しおください。 盞手がメッセヌゞの XNUMX ぀のコピヌを同時に受信した堎合でも、重耇したメッセヌゞは無芖されたす。 (時間が経過しすぎお、元の msg_id が有効でなくなった堎合、メッセヌゞは msg_copy にラップされたす)。
  • メッセヌゞ状況の自䞻的な連絡
    いずれの圓事者も、盞手方によっお送信されたメッセヌゞのステヌタスを自発的に盞手方に通知するこずができたす。
    msgs_all_info#8cc0d131 msg_ids:Vector long info:string = MsgsAllInfo
  • XNUMX ぀のメッセヌゞのステヌタスの拡匵された自䞻的な通信
    ...
    msg_detailed_info#276d3ec6 msg_id:long answer_msg_id:long bytes:int status:int = MsgDetailedInfo;
    msg_new_detailed_info#809db6df answer_msg_id:long bytes:int status:int = MsgDetailedInfo;
  • メッセヌゞの再送信の明瀺的なリク゚スト
    msg_resend_req#7d861a08 msg_ids:Vector long = MsgResendReq;
    盞手は芁求されたメッセヌゞを再送信するこずですぐに応答したす [
]
  • 回答の再送信の明瀺的なリク゚スト
    msg_resend_ans_req#8610baeb msg_ids:Vector long = MsgResendReq;
    盞手はすぐに再送信しお応答したす。 回答 リク゚ストされたメッセヌゞに [
]
  • メッセヌゞのコピヌ
    状況によっおは、無効になった msg_id を持぀叀いメッセヌゞを再送信する必芁があるこずがありたす。 次に、コピヌ コンテナヌにラップされたす。
    msg_copy#e06046b2 orig_message:Message = MessageCopy;
    メッセヌゞを受信するず、ラッパヌが存圚しないかのように凊理されたす。 ただし、メッセヌゞ orig_message.msg_id が受信されたこずが確実にわかっおいる堎合、新しいメッセヌゞは凊理されたせん (同時に、メッセヌゞず orig_message.msg_id は確認されたす)。 orig_message.msg_id の倀は、コンテナヌの msg_id よりも小さい必芁がありたす。

ずいう事実に぀いおも黙っおおこう。 msgs_state_info ここでも、未完成の TL の耳が突き出おいたす (バむトのベクトル、列挙型の䞋䜍 XNUMX ビット、および叀いビットのフラグが必芁でした)。 ポむントは別のずころにありたす。 なぜこれが実際に行われるのか理解しおいる人はいたすか 実際のクラむアントで 必芁ですか?.. 難しいこずですが、人が察話モヌドでデバッグに取り組んでいる堎合、サヌバヌに䜕をどのように質問するかによっお、ある皋床の利点があるこずは想像できたす。 ただし、リク゚ストはここに蚘茉されおいたす 埀埩.

このこずから、各偎はメッセヌゞを暗号化しお送信するだけでなく、メッセヌゞ、メッセヌゞに察する回答に関するデヌタを、未知の期間保存する必芁があるずいうこずになりたす。 ドキュメントでは、これらの機胜のタむミングや実際の適甚可胜性に぀いおは説明されおいたせん。 ない方法で。 最も驚くべきこずは、それらが実際に公匏クラむアントのコヌドで䜿甚されおいるこずです。 どうやら圌らは、公開されおいる文曞には含たれおいないこずを告げられたようです。 コヌドから理解する 理由、もはや TL の堎合ほど単玔ではありたせん。これは (比范的) 論理的に分離された郚分ではなく、アプリケヌション アヌキテクチャに関連付けられた郚分です。 アプリケヌション コヌドを理解するにはさらに倚くの時間が必芁になりたす。

Ping ずタむミング。 行列。

すべおのこずから、サヌバヌ アヌキテクチャ (バック゚ンド間でのリク゚ストの分散) に関する掚枬を思い出すず、TCP では配信が保蚌されおいるにもかかわらず (デヌタが配信されたか、デヌタが配信されたこずに぀いお通知される)、かなり退屈なこずが続きたす。ブレヌクしたすが、デヌタは問題が発生する瞬間たで配信されたす)、MTProto 自䜓でその確認が行われたす - 保蚌はありたせん。 サヌバヌはメッセヌゞを簡単に倱ったり砎棄したりする可胜性があり、それに察しおは䜕もするこずができず、さたざたな皮類の束葉杖を囲むだけです。

そしおたず第䞀に、メッセヌゞキュヌです。 たず、最初からすべおが明らかでした。未確認のメッセヌゞは保存しお再送信する必芁がありたす。 そしお䜕時以降ですか そしお道化垫は圌を知っおいたす。 おそらく、これらの䞭毒サヌビスメッセヌゞが䜕らかの圢でこの問題を束葉杖で解決したす。たずえば、Telegram Desktop には、それらに察応するキュヌが玄 4 ぀ありたす (すでに述べたように、おそらくさらに倚くのキュヌがあるため、コヌドずアヌキテクチャをより真剣に調査する必芁がありたす。珟時点では、MTProto スキヌムの特定の数の型がサンプルずしお䜿甚されおいないため、サンプルずしお取埗できないこずがわかっおいたす)。

なぜこうなった おそらく、サヌバヌ プログラマヌはクラスタヌ内の信頌性、少なくずもフロント バランサヌでのバッファリングさえも保蚌できず、この問題をクラむアントに移したのでしょう。 絶望的な気持ちから、Vasily は、TCP のアルゎリズムを䜿甚しお、キュヌを XNUMX ぀だけ䜿甚し、サヌバヌぞの RTT を枬定し、未確認のリク゚ストの数に応じお (メッセヌゞ内の) 「りィンドり」サむズを調敎する代替オプションを実装しようずしたした。 ぀たり、サヌバヌの負荷を芋積もるための倧たかなヒュヌリスティック、぀たり、同時に凊理しお倱われないリク゚ストの数です。

たあ、぀たり、わかりたすよね TCP 䞊で動䜜するプロトコルの䞊に TCP を再床実装する必芁がある堎合、これはプロトコルの蚭蚈が非垞に䞍十分であるこずを瀺しおいたす。

そうそう、なぜ耇数のキュヌが必芁なのでしょうか。䞀般に、これは高レベル API を䜿甚する人にずっお䜕を意味するのでしょうか? リク゚ストを䜜成し、シリアル化したすが、すぐに送信できないこずがよくありたす。 なぜ 答えはこうなるから msg_id、これは䞀時的なものですа私はラベルです。その予定はできるだけ遅く延期したほうがよいです。私たちずラベルの間の時間が䞀臎しないため、突然サヌバヌがそれを拒吊したす (もちろん、珟圚から時間をずらす束葉杖を䜜るこずはできたす)サヌバヌの応答から蚈算されたデルタをサヌバヌ時間に远加したす。公匏のクラむアントはこれを行いたすが、この方法は粗雑であり、バッファリングのため䞍正確です)。 したがっお、ラむブラリからロヌカル関数呌び出しを䜿甚しおリク゚ストを行うず、メッセヌゞは次の段階を経たす。

  1. 同じキュヌ内にあり、暗号化を埅機しおいたす。
  2. 任呜 msg_id そしおメッセヌゞは別のキュヌに送られたした - 転送の可胜性がありたす。 ゜ケットに送信したす。
  3. a) サヌバヌは MsgsAck に応答したした - メッセヌゞは配信されたので、「他のキュヌ」から削陀したす。
    b) たたはその逆、圌は䜕か気に入らなかったので、badmsg に答えたした - 「他のキュヌ」から再送信したす
    c) 䜕も䞍明です。別のキュヌからメッセヌゞを再送信する必芁がありたすが、正確にい぀送信されるかは䞍明です。
  4. サヌバヌが぀いに応答したした RpcResult - 実際の応答 (たたぱラヌ) - 配信されるだけでなく、凊理も行われたす。

倚分、コンテナを䜿甚するず問題を郚分的に解決できる可胜性がありたす。 これは、倚数のメッセヌゞが XNUMX ぀にパックされおおり、サヌバヌがすべおのメッセヌゞに察しお䞀床に XNUMX ぀のメッセヌゞで確認応答を返した堎合です。 msg_id。 しかし、もし䜕か問題があった堎合、圌はこのパックを拒吊し、すべおを拒吊するでしょう。

そしおこの時点で、技術的以倖の考慮事項が関係したす。 経隓から、私たちは倚くの束葉杖を芋おきたしたが、さらに今埌、悪いアドバむスやアヌキテクチャの䟋がさらに増えるでしょう。そのような状況で、信頌しおそのような決定を䞋す䟡倀があるでしょうか? この質問は修蟞的ですもちろんそうではありたせん。

私たちは䜕に぀いお話しおいたすか 「メッセヌゞに関する䞭毒メッセヌゞ」ずいうトピックに぀いおは、「あなたは愚かだ、私たちの玠晎らしいアむデアを理解しおいなかった」のような反論をしながら掚枬するこずができたす。 (通垞の人が行うべきように、最初にドキュメントを䜜成し、理論的根拠ずパケット亀換の䟋を瀺しおから話したす)。その埌、タむミング/タむムアりトは玔粋に実甚的で具䜓的な問題であり、ここではすべおが長い間知られおいたす。 しかし、ドキュメントにはタむムアりトに぀いお䜕が曞かれおいるのでしょうか?

サヌバヌは通垞、RPC 応答を䜿甚しおクラむアントからのメッセヌゞ (通垞は RPC ク゚リ) の受信を確認したす。 応答が届くたでに時間がかかる堎合、サヌバヌは最初に受信確認を送信し、少し遅れお RPC 応答自䜓を送信するこずがありたす。

クラむアントは通垞、メッセヌゞの送信が遅すぎない堎合 (受信埌 60  120 秒埌に生成された堎合)、次の RPC ク゚リに確認応答を远加するこずで、サヌバヌからのメッセヌゞ (通垞は RPC 応答) の受信を確認したす。サヌバヌからのメッセヌゞの内容。 ただし、長期間にわたっおサヌバヌにメッセヌゞを送信する理由がない堎合、たたはサヌバヌからの未確認のメッセヌゞが倚数 (たずえば 16 を超える) ある堎合、クラむアントはスタンドアロンの確認応答を送信したす。

...私は翻蚳したす私たち自身はそれがどれだけ、そしおどのように必芁なのかわかりたせん、たあ、それをこのように芋積もっおみたしょう。

そしおpingに぀いお

Ping メッセヌゞ (PING/PONG)

ping#7abe77ec ping_id:long = Pong;

通垞、応答は同じ接続に返されたす。

pong#347773c5 msg_id:long ping_id:long = Pong;

これらのメッセヌゞには確認応答は必芁ありたせん。 ポンは ping ぞの応答ずしおのみ送信されたすが、ping はどちらの偎でも開始できたす。

遅延接続終了 + PING

ping_delay_disconnect#f3427b8c ping_id:long disconnect_delay:int = Pong;

ping のように機胜したす。 さらに、これを受信した埌、サヌバヌは、以前のすべおのタむマヌを自動的にリセットする同じタむプの新しいメッセヌゞを受信しない限り、数秒埌に珟圚の接続を閉じるタむマヌを開始したす。 たずえば、クラむアントがこれらの ping を 60 秒ごずに送信する堎合、disconnect_lay を 75 秒に蚭定する可胜性がありたす。

あなたは正気ですか 60 秒以内に列車は駅に入り、乗客を降ろしお乗せたすが、トンネル内で再び通信が途絶えたす。 あなたがあちこちを芗いおいる間に 120 秒以内に圌は別の堎所に到着し、接続はおそらく切断されるでしょう。 そうですね、どこから足が生えおいるのかは明らかです。「呌び出し音は聞こえたしたが、どこにいるのかわかりたせん」ずいう堎合には、Nagle アルゎリズムず、むンタラクティブな䜜業を目的ずした TCP_NODELAY オプションがありたす。 ただし、申し蚳ありたせんが、デフォルト倀の 200 を遅らせおください。 ミリ秒。 本圓に䌌たようなこずを衚珟しお、パケットのペアを節玄したい堎合は、少なくずも 5 秒間、たたは「ナヌザヌが入力䞭です...」ずいうメッセヌゞのタむムアりトが珟圚等しい時間たで、それを延期したす。 しかし、もうだめです。

そしお最埌にpingです。 ぀たり、TCP 接続の掻性床をチェックしたす。 面癜いこずですが、玄 10 幎前、私は孊郚の寮のメッセンゞャヌに぀いお批刀的な文章を曞きたした。そこでも著者はクラむアントからサヌバヌに ping を送信したしたが、その逆は行われたせんでした。 でも、3幎生ず囜際事務所は別ですよね

たず、小さな教育プログラムです。 TCP 接続は、パケット亀換がない堎合、数週間存続する可胜性がありたす。 これは目的によっおは良いこずも悪いこずも倉わりたす。 そうですね、サヌバヌぞの SSH 接続が開いおいる堎合、コンピュヌタヌから立ち䞊がっお電源ルヌタヌを再起動し、元の堎所に戻りたした。このサヌバヌを介したセッションは䞭断されたせんでした (䜕も入力せず、パケットもありたせんでした)。䟿利。 サヌバヌ䞊に䜕千ものクラむアントがあり、それぞれがリ゜ヌスを消費し (Postgres です!)、クラむアント ホストがかなり前に再起動されおいる可胜性がありたすが、それに぀いおはわかりたせん。

チャット/IM システムは、オンラむン ステヌタスずいう別の远加の理由から 20 番目のケヌスに属したす。 ナヌザヌが「萜ちた」堎合は、察話者にそれに぀いお知らせる必芁がありたす。 そうしないず、Jabber の䜜成者が犯した間違い (そしお 18.04 幎間修正しおきた) が存圚するこずになりたす。ナヌザヌは切断されたしたが、ナヌザヌはオンラむンであるず信じおメッセヌゞを曞き続けたす (メッセヌゞも、この数分間で完党に倱われおいたした)。砎れが発芋されたした。 いいえ、TCP タむマヌの仕組みを理解しおいない倚くの人が (数十秒などのワむルドな倀を蚭定するこずで) どこでもポップする TCP_KEEPALIVE オプションは、ここでは圹に立ちたせん。OS カヌネルだけでなく、ナヌザヌのマシンは生きおいたすが、応答するこずもできるし、アプリケヌション自䜓も正垞に機胜したす (フリヌズしないず思いたすか? Ubuntu XNUMX 䞊の Telegram デスクトップが繰り返しハングアップしたした)。

だからこそpingを打぀べきなのです サヌバ クラむアントがこれを行うず、接続が切断されたずきに ping が配信されず、目的は達成されたせん。

Telegram には䜕が衚瀺されるのでしょうか? すべおが正反察です たあ、぀たり、 もちろん、圢匏的には、双方が盞互に ping を送信できたす。 実際には、クラむアントは束葉杖を䜿甚したす ping_delay_disconnect、サヌバヌ䞊でタむマヌを起動したす。 そうですね、申し蚳ありたせんが、ping なしでそこにどれくらいの期間䜏みたいかを決めるのはクラむアントの仕事ではありたせん。 サヌバヌは、その負荷に基づいお、より正確に認識したす。 しかし、もちろん、リ゜ヌスを残念に思わない堎合は、邪悪なピノキオ自䜓が原因であり、束葉杖は降りおくるでしょう...

どのように蚭蚈されるべきだったのでしょうか?

䞊蚘の事実は、コンピュヌタ ネットワヌクのトランスポヌト (および䞋䜍) レベルの分野における Telegram / VKontakte チヌムの胜力がそれほど高くなく、関連事項における資栌が䜎いこずを非垞に明確に瀺しおいるず思いたす。

なぜこれほど耇雑になったのでしょうか?Telegram アヌキテクトはどのように反察できるのでしょうか? TCP 接続が切断されおも存続するセッションを䜜成しようずしたずいう事実、぀たり、今提䟛できなかったこずは、埌で提䟛したす。 おそらく UDP トランスポヌトを䜜成しようずしたのでしょうが、困難に遭遇しお断念したした (そのため、ドキュメントは空です。自慢できるものは䜕もありたせんでした)。 しかし、ネットワヌク䞀般ず特に TCP がどのように機胜するのか、どこに䟝存できるのか、どこを自分で行う必芁があるのか​​ (そしおその方法) に぀いおの理解が䞍足しおいるため、これを暗号化ず組み合わせようずする詊みは「䞀刀䞡断」です。䞀石の鳥」 - そのような死䜓が刀明したした。

どうあるべきでしたか ずいう事実に基づいお、 msg_id は、リプレむ攻撃を防ぐために暗号的に必芁なタむムスタンプであるため、これに䞀意の識別子関数を付加するこずぱラヌです。 したがっお、珟圚のアヌキテクチャを倧幅に倉曎せずに (曎新スレッドが圢成されるずき、これはこの䞀連の投皿の別の郚分の高レベル API トピックです)、次のこずを行う必芁がありたす。

  1. クラむアントぞの TCP 接続を保持しおいるサヌバヌが責任を負いたす。゜ケットから差し匕いた堎合は、確認、凊理、たたぱラヌを返しおください。損倱はありたせん。 この堎合、確認は ID のベクトルではなく、単に「最埌に受信した seq_no」、぀たり TCP のような単なる数倀 (XNUMX ぀の数倀 - 自分自身の seq ず確認枈み) です。 私たちはい぀もセッション䞭ですよね
  2. リプレむ攻撃を防ぐためのタむムスタンプは、別個のフィヌルドになりたす。 チェックは入っおいたすが、他には䜕も圱響したせん。 十分ですし、 uint32 - ゜ルトが少なくずも半日ごずに倉曎される堎合、16 ビットを珟圚の時刻の敎数郚分の䞋䜍ビットに割り圓お、残りを秒の小数郚分に割り圓おるこずができたす (珟圚のように)。
  3. 栌玍された msg_id バック゚ンドでリク゚ストを区別するずいう芳点からは、たずクラむアント ID、次にセッション ID があり、それらを連結したす。 したがっお、リク゚スト識別子は䞀぀だけで十分です。 seq_no.

これも最良の遞択肢ではありたせんが、完党なランダムが識別子ずしお機胜する可胜性がありたす。ちなみに、これはメッセヌゞ送信時に高レベル API ですでに行われおいたす。 アヌキテクチャを盞察から絶察に完党に倉曎する方が良いでしょうが、これはこの蚘事ではなく別の郚分でのトピックです。

API

タダム そのため、痛みず束葉杖に満ちた道を通っお、最終的にサヌバヌにリク゚ストを送信し、それに察する回答を受け取るこずができ、さらにサヌバヌから曎新を受け取るこずができるようになりたしたリク゚ストぞの応答ずしおではありたせんが、より明確であれば、PUSH などのメッセヌゞ自䜓が送信されたす)。

泚意しおください。この蚘事には Perl の䟋が XNUMX ぀だけありたす。 (構文に詳しくない人のために説明するず、最初の匕数はオブゞェクトのデヌタ構造であり、XNUMX 番目の匕数はそのクラスです)。

2019.10.24 12:00:51 $1 = {
'cb' => 'TeleUpd::__ANON__',
'out' => bless( {
'filter' => bless( {}, 'Telegram::ChannelMessagesFilterEmpty' ),
'channel' => bless( {
'access_hash' => '-6698103710539760874',
'channel_id' => '1380524958'
}, 'Telegram::InputPeerChannel' ),
'pts' => '158503',
'flags' => 0,
'limit' => 0
}, 'Telegram::Updates::GetChannelDifference' ),
'req_id' => '6751291954012037292'
};
2019.10.24 12:00:51 $1 = {
'in' => bless( {
'req_msg_id' => '6751291954012037292',
'result' => bless( {
'pts' => 158508,
'flags' => 3,
'final' => 1,
'new_messages' => [],
'users' => [],
'chats' => [
bless( {
'title' => 'ХулОМПЌОка',
'username' => 'hoolinomics',
'flags' => 8288,
'id' => 1380524958,
'access_hash' => '-6698103710539760874',
'broadcast' => 1,
'version' => 0,
'photo' => bless( {
'photo_small' => bless( {
'volume_id' => 246933270,
'file_reference' => '
'secret' => '1854156056801727328',
'local_id' => 228648,
'dc_id' => 2
}, 'Telegram::FileLocation' ),
'photo_big' => bless( {
'dc_id' => 2,
'local_id' => 228650,
'file_reference' => '
'secret' => '1275570353387113110',
'volume_id' => 246933270
}, 'Telegram::FileLocation' )
}, 'Telegram::ChatPhoto' ),
'date' => 1531221081
}, 'Telegram::Channel' )
],
'timeout' => 300,
'other_updates' => [
bless( {
'pts_count' => 0,
'message' => bless( {
'post' => 1,
'id' => 852,
'flags' => 50368,
'views' => 8013,
'entities' => [
bless( {
'length' => 20,
'offset' => 0
}, 'Telegram::MessageEntityBold' ),
bless( {
'length' => 18,
'offset' => 480,
'url' => 'https://alexeymarkov.livejournal.com/[url_вырезаМ].html'
}, 'Telegram::MessageEntityTextUrl' )
],
'reply_markup' => bless( {
'rows' => [
bless( {
'buttons' => [
bless( {
'text' => '???? 165',
'data' => 'send_reaction_0'
}, 'Telegram::KeyboardButtonCallback' ),
bless( {
'data' => 'send_reaction_1',
'text' => '???? 9'
}, 'Telegram::KeyboardButtonCallback' )
]
}, 'Telegram::KeyboardButtonRow' )
]
}, 'Telegram::ReplyInlineMarkup' ),
'message' => 'А вПт О МПвая кМОга! 
// [текст сППбщеМОя вырезаМ чтПб Ме Марушать правОл Хабра П реклаЌе]
Мапечатаю.',
'to_id' => bless( {
'channel_id' => 1380524958
}, 'Telegram::PeerChannel' ),
'date' => 1571724559,
'edit_date' => 1571907562
}, 'Telegram::Message' ),
'pts' => 158508
}, 'Telegram::UpdateEditChannelMessage' ),
bless( {
'pts' => 158508,
'message' => bless( {
'edit_date' => 1571907589,
'to_id' => bless( {
'channel_id' => 1380524958
}, 'Telegram::PeerChannel' ),
'date' => 1571807301,
'message' => 'ППчеЌу Вы счОтаете Facebook плПхПй кПЌпаМОей? МПжете прПкПЌЌеМтОрПвать? ПП-ЌПеЌу, этП шОкарМая кПЌпаМОя. Без ЎПлгПв, с хПрПшей прОбылью, а еслО решат ЎОвы платОть, тП О еще ЌПгут МехОлП пПЎПрПжать.
Для ЌеМя Птвет сПвершеММП ПчевОЎеМ: пПтПЌу чтП Facebook Ўелает ужасМый пП качеству прПЎукт. Да, у МегП ЌПМПпПльМПе пПлПжеМОе О Ўа, ОЌ пПльзуется ПгрПЌМПе кПлОчествП люЎей. НП ЌОр Ме стПОт Ма Ќесте. КПгЎа-тП влаЎельцаЌ НПкОО былП сЌешМП Пт первПгП АйфПМа. ОМО ЎуЌалО, чтП лучше НПкОО МОчегП быть Ме ЌПжет О ПМа МавсегЎа ПстаМется саЌыЌ уЎПбМыЌ, красОвыЌ О твёрЎыЌ телефПМПЌ - О ЎПля рыМка этП красМПречОвП ЎеЌПМстрОрПвала. Теперь ОЌ Ме сЌешМП.
КПМечМП, рептОлПОЎы сПпрПтОвляются МапПру ЌПлПЎых геМОев: так ЊукербергПЌ был пПжраМ Whatsapp, пПтПЌ Instagram. НП всё ОЌ Ме пПжрать, Паша ДурПв Ме прПЎаётся!
Так буЎет О с ЀейсбукПЌ. Нельзя всё вреЌя Ўелать гПвМП. КтП-тП кПгЎа-тП сЎелает хПрПшОй прПЎукт, куЎа всё О уйЎут.
#сПцсетО #facebook #акцОО #рептОлПОЎы',
'reply_markup' => bless( {
'rows' => [
bless( {
'buttons' => [
bless( {
'data' => 'send_reaction_0',
'text' => '???? 452'
}, 'Telegram::KeyboardButtonCallback' ),
bless( {
'text' => '???? 21',
'data' => 'send_reaction_1'
}, 'Telegram::KeyboardButtonCallback' )
]
}, 'Telegram::KeyboardButtonRow' )
]
}, 'Telegram::ReplyInlineMarkup' ),
'entities' => [
bless( {
'length' => 199,
'offset' => 0
}, 'Telegram::MessageEntityBold' ),
bless( {
'length' => 8,
'offset' => 919
}, 'Telegram::MessageEntityHashtag' ),
bless( {
'offset' => 928,
'length' => 9
}, 'Telegram::MessageEntityHashtag' ),
bless( {
'length' => 6,
'offset' => 938
}, 'Telegram::MessageEntityHashtag' ),
bless( {
'length' => 11,
'offset' => 945
}, 'Telegram::MessageEntityHashtag' )
],
'views' => 6964,
'flags' => 50368,
'id' => 854,
'post' => 1
}, 'Telegram::Message' ),
'pts_count' => 0
}, 'Telegram::UpdateEditChannelMessage' ),
bless( {
'message' => bless( {
'reply_markup' => bless( {
'rows' => [
bless( {
'buttons' => [
bless( {
'data' => 'send_reaction_0',
'text' => '???? 213'
}, 'Telegram::KeyboardButtonCallback' ),
bless( {
'data' => 'send_reaction_1',
'text' => '???? 8'
}, 'Telegram::KeyboardButtonCallback' )
]
}, 'Telegram::KeyboardButtonRow' )
]
}, 'Telegram::ReplyInlineMarkup' ),
'views' => 2940,
'entities' => [
bless( {
'length' => 609,
'offset' => 348
}, 'Telegram::MessageEntityItalic' )
],
'flags' => 50368,
'post' => 1,
'id' => 857,
'edit_date' => 1571907636,
'date' => 1571902479,
'to_id' => bless( {
'channel_id' => 1380524958
}, 'Telegram::PeerChannel' ),
'message' => 'ППст прП 1С вызвал бурМую пПлеЌОку. ЧелПвек 10 (вОЎОЌП, 1с-прПграЌЌОстПв) еЎОМПЎушМП МапОсалО:
// [текст сППбщеМОя вырезаМ чтПб Ме Марушать правОл Хабра П реклаЌе]
Я бы ЎПбавОл, чтП блестящая у 1С ЎОстрОбуцОя, а ЌаркетОМг... Му, такПе.'
}, 'Telegram::Message' ),
'pts_count' => 0,
'pts' => 158508
}, 'Telegram::UpdateEditChannelMessage' ),
bless( {
'pts' => 158508,
'pts_count' => 0,
'message' => bless( {
'message' => 'ЗЎравствуйте, расскажОте, пПжалуйста, чеЌ вреЎОт экПМПЌОке 1С?
// [текст сППбщеМОя вырезаМ чтПб Ме Марушать правОл Хабра П реклаЌе]
#сПфт #it #экПМПЌОка',
'edit_date' => 1571907650,
'date' => 1571893707,
'to_id' => bless( {
'channel_id' => 1380524958
}, 'Telegram::PeerChannel' ),
'flags' => 50368,
'post' => 1,
'id' => 856,
'reply_markup' => bless( {
'rows' => [
bless( {
'buttons' => [
bless( {
'data' => 'send_reaction_0',
'text' => '???? 360'
}, 'Telegram::KeyboardButtonCallback' ),
bless( {
'data' => 'send_reaction_1',
'text' => '???? 32'
}, 'Telegram::KeyboardButtonCallback' )
]
}, 'Telegram::KeyboardButtonRow' )
]
}, 'Telegram::ReplyInlineMarkup' ),
'views' => 4416,
'entities' => [
bless( {
'offset' => 0,
'length' => 64
}, 'Telegram::MessageEntityBold' ),
bless( {
'offset' => 1551,
'length' => 5
}, 'Telegram::MessageEntityHashtag' ),
bless( {
'length' => 3,
'offset' => 1557
}, 'Telegram::MessageEntityHashtag' ),
bless( {
'offset' => 1561,
'length' => 10
}, 'Telegram::MessageEntityHashtag' )
]
}, 'Telegram::Message' )
}, 'Telegram::UpdateEditChannelMessage' )
]
}, 'Telegram::Updates::ChannelDifference' )
}, 'MTProto::RpcResult' )
};
2019.10.24 12:00:51 $1 = {
'in' => bless( {
'update' => bless( {
'user_id' => 2507460,
'status' => bless( {
'was_online' => 1571907651
}, 'Telegram::UserStatusOffline' )
}, 'Telegram::UpdateUserStatus' ),
'date' => 1571907650
}, 'Telegram::UpdateShort' )
};
2019.10.24 12:05:46 $1 = {
'in' => bless( {
'chats' => [],
'date' => 1571907946,
'seq' => 0,
'updates' => [
bless( {
'max_id' => 141719,
'channel_id' => 1295963795
}, 'Telegram::UpdateReadChannelInbox' )
],
'users' => []
}, 'Telegram::Updates' )
};
2019.10.24 13:01:23 $1 = {
'in' => bless( {
'server_salt' => '4914425622822907323',
'unique_id' => '5297282355827493819',
'first_msg_id' => '6751307555044380692'
}, 'MTProto::NewSessionCreated' )
};
2019.10.24 13:24:21 $1 = {
'in' => bless( {
'chats' => [
bless( {
'username' => 'freebsd_ru',
'version' => 0,
'flags' => 5440,
'title' => 'freebsd_ru',
'min' => 1,
'photo' => bless( {
'photo_small' => bless( {
'local_id' => 328733,
'volume_id' => 235140688,
'dc_id' => 2,
'file_reference' => '
'secret' => '4426006807282303416'
}, 'Telegram::FileLocation' ),
'photo_big' => bless( {
'dc_id' => 2,
'file_reference' => '
'volume_id' => 235140688,
'local_id' => 328735,
'secret' => '71251192991540083'
}, 'Telegram::FileLocation' )
}, 'Telegram::ChatPhoto' ),
'date' => 1461248502,
'id' => 1038300508,
'democracy' => 1,
'megagroup' => 1
}, 'Telegram::Channel' )
],
'users' => [
bless( {
'last_name' => 'Panov',
'flags' => 1048646,
'min' => 1,
'id' => 82234609,
'status' => bless( {}, 'Telegram::UserStatusRecently' ),
'first_name' => 'Dima'
}, 'Telegram::User' )
],
'seq' => 0,
'date' => 1571912647,
'updates' => [
bless( {
'pts' => 137596,
'message' => bless( {
'flags' => 256,
'message' => 'СПзЎать Ўжейл с ОЌеМеЌ пПкПрПче ??',
'to_id' => bless( {
'channel_id' => 1038300508
}, 'Telegram::PeerChannel' ),
'id' => 119634,
'date' => 1571912647,
'from_id' => 82234609
}, 'Telegram::Message' ),
'pts_count' => 1
}, 'Telegram::UpdateNewChannelMessage' )
]
}, 'Telegram::Updates' )
};

はい、特にネタバレは避けおください。ただ読んでいない堎合は、ぜひ読んでください。

わぁ〜〜 どんな感じですか 非垞に芋慣れたものです...おそらくこれは、クラスがオブゞェクトにアタッチされおいるこずを陀けば、JSON の兞型的な Web API のデヌタ構造です。

それで、結局のずころ...䜕ですか、同志..ずおも苊劎したした-そしお、私たちはWebプログラマヌがいる堎所で䌑憩するために立ち止たりたした 始めたばかりです?.. JSON over HTTPS のほうが簡単ではないでしょうか?! そしお、その代わりに私たちは䜕を手に入れたのでしょうか これらの努力は䟡倀がありたしたか

TL+MTProto が私たちに䜕をもたらしおくれたのか、そしおどのような代替手段が可胜なのかを評䟡しおみたしょう。 そうですね、HTTP リク゚ストずレスポンスは適合したせんが、少なくずも TLS の䞊に䜕かあるのではないでしょうか?

コンパクトな連茉。 このデヌタ構造を芋るず、JSON ず同様に、バむナリのバリアントがあるこずが思い出されたす。 MsgPack を拡匵性が䞍十分であるずマヌクしたしょう。ただし、たずえば CBOR がありたす。ちなみに、この暙準は、 RFC 7049。 を定矩しおいるずいう事実で泚目に倀したす。 タグ、拡匵メカニズムずしお、および すでに暙準化されおいる がある

  • 25 + 256 - 重耇行を行番号参照に眮き換える、このような安䟡な圧瞮方法
  • 26 - クラス名ずコンストラクタヌ匕数を持぀シリアル化された Perl オブゞェクト
  • 27 - 型名ずコンストラクタヌ匕数を持぀シリアル化された蚀語に䟝存しないオブゞェクト

さお、文字列ずオブゞェクトのパッキングを有効にしお、TL ず CBOR で同じデヌタをシリアル化しようずしたした。 結果は、メガバむトからどこかで CBOR を支持するように倉わり始めたした。

cborlen=1039673 tl_len=1095092

このように、 結論: 同期倱敗や䞍明な識別子の問題の圱響を受けず、同等の効率を備えた、実質的に単玔な圢匏がありたす。

高速接続の確立。 これは、再接続埌の RTT がれロであるこずを意味したす (キヌがすでに XNUMX 回生成されおいる堎合)。最初の MTProto メッセヌゞから適甚されたすが、いく぀かの留保事項がありたす。同じ゜ルト状態になり、セッションは腐りたせんでした。 TLS は私たちに䜕を提䟛しおくれるのでしょうか? 関連匕甚:

TLS で PFS を䜿甚する堎合、TLS セッション チケット (RFC 5077) キヌを再ネゎシ゚ヌトせず、キヌ情報をサヌバヌに保存せずに、暗号化されたセッションを再開したす。 最初の接続を開いおキヌを生成するずきに、サヌバヌは接続の状態を暗号化し、それを (セッション チケットの圢匏で) クラむアントに送信したす。 したがっお、接続が再開されるず、クラむアントはずりわけセッションキヌを含むセッションチケットをサヌバヌに送り返したす。 チケット自䜓は䞀時キヌ (セッション チケット キヌ) で暗号化され、サヌバヌに保存され、クラスタヌ化゜リュヌションで SSL を凊理するすべおのフロント゚ンド サヌバヌに配垃する必芁がありたす。[10]。 したがっお、セッション チケットの導入は、䞀時サヌバヌ キヌが長期間保存されおいる堎合などに䟵害された堎合に PFS に違反する可胜性がありたす (OpenSSL、nginx、Apache では、デフォルトでプログラムの実行䞭ずっず保存されたす。人気のあるサむト)。キヌは数時間から数日間䜿甚したす)。

ここで RTT はれロではありたせん。少なくずも ClientHello ず ServerHello を亀換する必芁がありたす。その埌、Finished ずずもに、クラむアントはすでにデヌタを送信できたす。 しかし、ここで芚えおおくべきなのは、新しく開かれた接続がたくさんある Web ではなく、メッセンゞャヌであり、その接続は倚くの堎合 XNUMX ぀で、倚かれ少なかれ存続期間が長く、Web ペヌゞに察する比范的短いリク゚ストです。すべおが内郚で倚重化されおいたす。 ぀たり、非垞にひどい地䞋鉄セクションに遭遇しなければ、これはたったく蚱容範囲です。

他に䜕か忘れたしたか コメントに曞いおください。

぀づく

この䞀連の投皿の第 XNUMX 郚では、技術的な問題ではなく、アプロヌチ、むデオロギヌ、むンタヌフェむス、ナヌザヌに察する態床など、組織的な問題に぀いお怜蚎したす。 ただし、ここで玹介されおいる技術情報に基づいおいたす。

XNUMX 番目のパヌトでは、技術コンポヌネント/開発経隓の分析を続けたす。 特に次のこずを孊びたす。

  • さたざたなTLタむプによる倧混乱の継続
  • チャンネルずスヌパヌグルヌプに぀いおの䞍明なこず
  • ダむアログよりも名簿よりも悪い
  • メッセヌゞの絶察アドレス指定ず盞察アドレス指定に぀いお
  • 写真ず画像の違いは䜕ですか
  • 絵文字が斜䜓のテキストにどのように干枉するか

そしお他の束葉杖 乞うご期埅

出所 habr.com

コメントを远加したす