SSTP/1.x

SSTP/1.x

参考:SSTP(外部サイト)

現在のところDirectSSTPについてはWindowsの仕様に大きく依存しており、他OSでの実装を想定していません。
IPCの仕組み自体は他OSにも存在するため、別途仕様を規定することが望ましいと思われます。
もし仕様が決定した場合は別途掲載を考えておりますので、Ukadoc Projectまでご連絡ください。

概要

SSTPはゴースト間の汎用通信仕様です。単純なSakuraScriptの再生や、外部からのイベント通知等に使えます。
通信は基本的にはTCP/IPで行われます。ポート9801または9821(SSPのみ)をリスニングしており、SSTPプロトコルに従ってリクエストを投げると、処理結果が返ってきます。
セキュリティ上の都合で、現在は設定を変更しない限りlocalhost限定でのリスニングとなり、端末外部からは通信できません。また、昔はポート11000番もリスニングしていましたが、マルウェアによる通信と誤認されたことから現在では廃止されています。
IANAのPort number registryには7743と9801番が登録されていますが、実運用されているのは9801番のみです。
同じ略称のプロトコルにMicrosoftが策定したVPN通信のためのSecure Socket Tunneling Protocolがありますが、技術上の関連性はありません。
パフォーマンスの必要な頻繁な通信を考慮しておらず、HTTPのようなkeep-aliveの仕組みはありません。毎回通信終了時に切断されます。

Direct SSTP

Direct SSTPはOSに強く依存したIPCの仕組みを利用した通信仕様です。プロトコル仕様は(Socket) SSTPと同じですが、比較的処理が重いTCP/IPを使用せず、直接ゴーストを指定して軽量な通信を行うことを目的としています。
現在のところWindows上のみ仕様が決まっており、下記の通りとなります。

WM_COPYDATAをSendMessage系関数で送信(Postは不可)
SendMessageのhWnd = 通信先ゴーストのHWND FMOから取得
wParam = 返信先の「自身の」HWND レスポンスはWM_COPYDATAを指定したHWND(ウインドウ)で受ける。
lParam = COPYDATASTRUCTへのポインタ
copydatastruct.lpData = SSTPプロトコルに従った文字列
copydatastruct.cbData = 文字列の長さ
copydatastruct.dwData = 9801
備考:
送信側は安全のためlpDataにゼロ終端の文字列を用意し、cbDataにはゼロ終端を含むことが望ましい。
受信側は安全のためゼロ終端を期待せず、必ずcbDataを考慮して処理を行うこと。
受信側は通信先として指定されたHWNDを、受信すべきゴーストがSSTPプロトコル内で指定されたものと同等として取り扱い、できる限りそのゴーストを優先する。
受信側・送信側共にウインドウを1つ以上持つGUIアプリのみを想定しており、コンソールアプリでは使用できない。

SSTP over HTTP

SSTP over HTTPは、SSP 2.6.32で実装された、HTTPリクエストメッセージボディにSSTPリクエストをそのまま突っ込み、HTTPレスポンスボディにSSTPレスポンスがそのまま返ってくるきわめて単純な仕組みです。
ElectronなどJavaScriptを使ってアプリを作った時に、より簡単にSSTP通信をやりとりするために使うのを想定しています。
localhost:9801(または別途指定されたSSTPポート) に対して、 /api/sstp/v1 に Content-Type: text/plainでHTTP/1.1でPOSTしてください。
レスポンスもそのまま、HTTP/1.1 200 OKのContent-Type: text/plainで返ってきます。
SSTPがエラーでもHTTPは200 OKな点に注意してください。
なお、Content-Lengthヘッダは必須で、無ければエラーになります。

お試し

既存のjsライブラリは、jsでSSTP over HTTPを行うために使用できます。

注意:Originヘッダがlocalhostを指していない場合は、強制的にリモートアドレスからのSSTPリクエストとして扱われ、SakuraScriptタグや実行できるSSTPメソッドに強い制約がかかり、かつSecurityLevelヘッダも無視されます。
この制約は、HTTPのOriginがlocalhost、かつSSTPのSecurityLevelがlocalの場合のみ緩和されます。

request/response

SHIORIなど他のプロトコルと同じく、HTTPに似せた独自プロトコルです。
リクエストのCharset指定は必須で、指定が無い場合はエラーとなるか、OS標準指定の文字コードとして解釈されます。

request

requestサンプル

SEND SSTP/1.0
Charset: UTF-8
Sender: SSTPクライアント
Script: \h\s0テストー。\u\s[10]テストやな。
Option: notranslate

requestの各メソッドに共通するヘッダ

メソッド固有のものについては、後ろのメソッド別の説明を確認すること。

Charset
リクエストの文字コード。一番最初の行に現れるのが望ましい。
特に理由がなければUTF-8を推奨する。
Sender
送信者を示す文字列。「SSTP送信ツール」など。COMMUNICATEメソッドの場合は、送信元のゴースト\0名。
SecurityLevel
SHIORIやSakuraScriptで処理する際のセキュリティレベルの指定。local/externalのいずれか。
DirectSSTP、または127.0.0.1等明らかにローカルから来たリクエストのみ有効。
SSTP over HTTPは、localhostから配信されたhtml等から送られた場合を除き、常にexternalとみなされる。
SecurityOrigin [SSP 2.6.59]
送信元サーバを示すURL風の文字列。以下の形式となる。HTTPヘッダのOriginと考え方は同じ。
SecurityOrigin: null
SecurityOrigin: <scheme>://<hostname>
SecurityOrigin: <scheme>://<hostname>:<port>
scheme は通常、http,https,sstpのいずれか。hostnameは送信元サーバ名かIP。portは返信受付可能なポート。
特に指定がない場合は、nullが指定されたものとみなされる。
SSTP over HTTPは、HTTPのOriginヘッダの中身が常に設定され、SSTPの中のSecurityOriginは無視される。
Option
SSTPで実行されるSakuraScriptがどのように扱われるかのオプションを指定する。
カンマ区切りで複数指定可能。指定する文字列は以下の通り。
nodescript : バルーンのSSTP表示を無効にする(リモートからのSSTPは無効)
notranslate : OnTranslateやMAKOTOでのトランスレート処理を行わない
nobreak : 現在実行中のスクリプトを中断せず、終わるまで待つ
ID
"Owned SSTP"と呼ばれるもの。SHIORI uniqueidで送られてきたIDか、FMOの識別ID(SSPのみ)を指定すると、各種セキュリティチェックやロック等を無視して、本SSTPをゴースト内部での処理と同じ優先度で扱う。
SecurityLevel指定がlocalになり、さらに\tなどの割り込み禁止状態でも強制的に割り込み再生を可能とする。
X-SSTP-PassThru-(任意の文字列)
NOTIFYなどゴースト側との通信の際に、SHIORIに直接渡されるヘッダ。
文字コード変換等最低限の処理が行われるだけで、(任意の文字列)の部分や中身はそのまま中継される。
HWnd
DirectSSTP限定で、responseを返信すべきウインドウハンドルを示す。
ウインドウハンドル(ポインタ相当)のデータを符号なし10進整数として扱い、それを文字列化したもの。
省略時はWM_COMMUNICATEのwParam。
ReceiverGhostHWnd [SSP 2.5.57]
(Socket)SSTP限定で、requestを送るべきゴーストの\0のウインドウハンドルを示す。
これを指定すると、処理すべきゴーストが固定され、Socket経由でもDirectSSTPと同じ処理が可能になる。
見つからなかった場合は、404 Not Foundで即時エラー終了する。
ReceiverGhostName [SSP 2.5.57]
(Socket)SSTP限定で、requestを送るべきゴーストの\0名を示す。
これを指定すると、処理すべきゴーストが固定され、Socket経由でもDirectSSTPと同じ処理が可能になる。HWndの名前版。
見つからなかった場合は、404 Not Foundで即時エラー終了する。

response

responseサンプル(データなし)

SSTP/1.4 200 OK
Charset: UTF-8
Script: \h\s0テストー。\u\s[10]テストやな。

responseサンプル(データあり)

SSTP/1.4 200 OK
Charset: UTF-8
Script: \h\s0テストー。\u\s[10]テストやな。

追加データはここ

responseの各メソッドに共通するヘッダ

Charset
リクエストの文字コード。一番最初の行に現れるのが望ましい。
特に理由がなければUTF-8を推奨する。
互換性の問題解消のため、わざと省略される場合がある。その場合はrequestと同じ文字コードと仮定すること。
X-SSTP-PassThru-(任意の文字列)
NOTIFYなどゴースト側との通信の際に、SHIORIから直接返されてきたヘッダ。
文字コード変換等最低限の処理が行われるだけで、(任意の文字列)の部分や中身はそのまま中継される。

responseのステータスコード

HTTPと同じく、200番台は正常受理、その他はエラー。

200 OK
正常終了(返り値つき)
204 No Content
正常終了(返り値なし)
210 Break
実行はされたがスクリプト実行中にブレークされた
※EntryつきのSEND/1.xなど極めて限られた状況に限り、通常は即時200か204リターン。
400 Bad Request
リクエストに何かしらカバーしきれない不備がある
404 Not Found ※SSPのみ
ゴースト指定のSSTPで該当ゴーストがインストールや起動がされていない
408 Request Timeout
タイムアウト:ゴースト/SHIORI側と通信できない時など(普段はほぼ起こらない)
409 Conflict
\tタグなどの割り込み禁止状態か、他のリクエストの処理中
413 Payload Too Large ※SSPのみ
SSTPリクエストが長すぎて処理を拒否した
420 Refuse
ゴースト側の設定の都合で受信拒否された
500 Internal Server Error ※SSPのみ
処理系内部で検出されたなにかしらの問題で処理しきれなかった
501 Not Implemented
未実装のコマンドなどが含まれて処理できなかった
503 Service Unavailable
処理系内部の都合でSSTPを受け付けられない状態
505 Version Not Supported ※SSPのみ
SSTPのバージョンがおかしい(1.0未満、3.0以上など)
512 Invisible
最小化などでゴーストが表示されておらず、何も処理できない状態

メソッド:NOTIFY

ゴーストにイベントを通知するためのメソッドです。
Eventヘッダ=SHIORI/3.0 IDに対応し、Reference*はそのままです。

イベント通知のみサンプル(NOTIFY/1.0)

NOTIFY SSTP/1.0
Charset: UTF-8
Sender: Media Player
Event: OnMusicPlay
Reference0: 自由の翼
Reference1: Linked Horizon

ゴースト側で指定したイベントIDに反応しない場合に、「保険用の」スクリプトを指定して再生させることができます。
その際に、IfGhostヘッダを指定すると、直後にあるScriptヘッダは指定したゴースト専用のスクリプトとして扱います。

保険反応つきサンプル(NOTIFY/1.1)

NOTIFY SSTP/1.1
Charset: UTF-8
Sender: Media Player
Event: OnMusicPlay
Reference0: 紅蓮の弓矢
Reference1: Linked Horizon
IfGhost: Emily,Teddy
Script: \0\s[6]その日、エミリは思い出した…\n\s[7]まだ今日は芋食べてない!\1\s[11]わざわざ今思い出したの?
IfGhost: ラーシェ,ティセ
Script: \0\s[3]巨人っていっても、身長は列車数両分しかないよね。\1\s[14]それが縦に立ち上がるとさすがに大きいと思うけどね。

request固有ヘッダ

Event
イベントID。SHIORI/3.0ではIDヘッダの指定として取り扱われる。
Reference*
イベントのReferenceヘッダ。SHIORIには文字コード変換等最低限の処理を行い、そのまま引き渡される。
Script
イベントに反応しなかった場合に再生されるSakuraScript。
IfGhost
\0側名,\1側名 の書式でゴーストの名前を指定すると、直後に来たScriptヘッダを特定のゴースト専用として取り扱う。
IfGhostの直後ではないScriptヘッダが存在した場合は、IfGhostに該当しない場合のデフォルト処理用Scriptとなる。
省略した場合はどのゴーストに対しても同じScriptヘッダが再生される。
SSTPのゴースト起動オプションを有効にしていた場合は、ここで指定したゴーストが一時的に起動される。
Option
SSTPで実行されるSakuraScriptや指定されたイベントがどのように扱われるかのオプションを指定する。
カンマ区切りで複数指定可能。指定する文字列のうち、NOTIFY特有分は以下の通り。
notify : イベントを強制的にNOTIFYで送る。また、保険用スクリプトはValueNotifyヘッダで返された場合と同じように強制的に扱われる。 [SSP 2.6.76]

response固有ヘッダ

Script
イベント通知の結果再生されたスクリプト。現在SSPのみ対応。

メソッド:SEND

(執筆中)

request固有ヘッダ

Option
SSTPで実行されるSakuraScriptがどのように扱われるかのオプションを指定する。
カンマ区切りで複数指定可能。指定する文字列のうち、SEND特有分は以下の通り。
notify : スクリプトがValueNotifyヘッダで返された場合と同じように強制的に扱われる。 [SSP 2.6.76]

メソッド:COMMUNICATE

COMMUNICATEメソッドで、ゴーストに外部から任意の文字列を与えて、反応させることができます。
基本的にゴースト内部でのコミュニケートボックスを使った反応と同じになりますが、SSTPなのでゴースト側で受理されない場合があります。

単純なCOMMUNICATE(COMMUNICATE/1.1)

COMMUNICATE SSTP/1.1
Charset: UTF-8
Sender: User
Sentence: おはよう。

コミュニケートはSSTPサーバ同士(≒ゴースト同士)で送受信を繰り返すことができます。
SHIORI/3.0のレスポンスReference0での送信の場合は、SSTP送信タイミングはSakuraScriptを再生し終わった時となります。
これを用いて、同時起動しているゴースト同士が会話しているような処理を組むことが可能となります。

ゴースト間コミュニケート(COMMUNICATE/1.2)

COMMUNICATE SSTP/1.2
Charset: UTF-8
Sender: Emily
HWnd: 28236
Sentence: \0\s[5]ちゃっらーん!エミリでーす!\nボクのお腹にはまだ若干の余裕が…?\1\s[11]そんなこと言ってたらまた太るよ?
Surface: 5,11
Reference0: 芋ちょうだい
Reference1: たくさんちょうだい
Reference2: 今すぐちょうだい

request固有ヘッダ

Reference*
コミュニケートの拡張情報。SHIORI/3.0ではReference2以降に格納される。SSTP Reference0 = SHIORI Reference2。
Surface
送信元ゴーストのコミュニケート送信時点(≒スクリプト実行終了時点)での\0と\1のサーフィス番号。
OnCommunicateイベントでSurfaceヘッダとして渡される。
Option
[旧仕様]substituteを指定すると、Sentenceの内容を\1が喋る。 ※SSP未実装

メソッド:EXECUTE

EXECUTEメソッドで、ゴーストの各種情報取得や、SakuraScriptによらない各種コマンド実行などを行うことができます。
このメソッドの実行では、ゴーストは喋りませんが、内部状態が書き換わる可能性があります。

EXECUTEサンプル

EXECUTE SSTP/1.1
Charset: UTF-8
Sender: SSTPクライアント
Command: GetName

request固有ヘッダ

Command または Command[param1,param2...]
実行すべきコマンド。実行する内容と返ってくる情報は後述。
大かっこ以降は実行すべきコマンドに渡すパラメータを指定する。
Reference* [SSP]
大かっこ指定の代わりにReference0~のヘッダでパラメータを指定することもできる。

Commandヘッダに指定できる文字列と、responseの「追加データ」で返ってくる結果については、下記を参照してください。

Commandヘッダに指定できるコマンドと、返ってくる追加データ

GetName
起動中のゴーストの (\0名),(\1名) カンマ区切り
GetNames [SSP]
現在インストールされている\0名のリスト。改行区切り。空行で終端。
GetFMO [SSP 2.5.57] [リモート制限あり]
FMOの中身と同等の情報を取得する。
ただしSSTPで通信したアプリケーション内部での管理分に限り、同時実行中のアプリケーション群共用である本来のFMOとは異なる。
主にウインドウを持たずDirect SSTPを送信できないコンソールアプリなどで、Socket SSTPのみでReceiverGhostHWndヘッダを活用しDirect SSTP相当の機能を実現するために用いられる。
改行区切り、空行で終端。
リモートからの要求の場合は、各パス情報が抜け、ヘッダとhwndがダミーに置き換わる。
GetGhostName [SSP]
起動中のゴースト本体の名前(descript.txtのname)
GetShellName [SSP]
起動中のゴーストの現在使用中のシェルの名前
GetBalloonName [SSP]
起動中のゴーストの現在使用中のバルーンの名前
GetVersion
ベースウェア(実行中のソフト)のバージョン
GetGhostNameList [SSP 2.6.53]
SSPで認識している全ゴーストの名前(descript.txtのname)の改行区切りリスト
GetShellNameList [SSP 2.6.53]
起動中のゴーストで認識している全シェルの名前(descript.txtのname)の改行区切りリスト
GetBalloonNameList [SSP 2.6.53]
SSPで認識している全バルーンの名前(descript.txtのname)の改行区切りリスト
GetHeadlineNameList [SSP 2.6.53]
SSPで認識している全ヘッドラインの名前(descript.txtのname)の改行区切りリスト
GetPluginNameList [SSP 2.6.53]
SSPで認識している全プラグインの名前(descript.txtのname)の改行区切りリスト
GetShortVersion [SSP 2.6.53]
ベースウェア(実行中のソフト)のバージョン(ピリオド区切りのバージョン番号のみ)
version.jsonのssp.full.versionなどと単純比較すると最新版かどうかチェックできる
Quiet [リモート不可]
Restoreを実行するか、16秒間が経過するまで黙る。追加データなし(ステータスコード200番台で成功)
Restore
Quietを解除。追加データなし(ステータスコード200番台で成功)
CompressArchive [SSP] [リモート不可]
指定したフォルダ内のファイル群を圧縮ファイルに圧縮する。
処理が終わるまでレスポンスが返らないので注意。
パラメータ0:圧縮ファイル名
パラメータ1:圧縮すべきフォルダのフルパス
追加データなし(ステータスコード200番台で成功)
ExtractArchive [SSP] [リモート不可]
指定した圧縮ファイルを解凍する。
処理が終わるまでレスポンスが返らないので注意。
パラメータ0:圧縮ファイル名
パラメータ1:解凍先のフォルダのフルパス
追加データなし(ステータスコード200番台で成功)
DumpSurface [SSP 2.5.98] [リモート不可]
合成済みのサーフェス画像を指定したディレクトリに出力する。パラメータは\![execute,dumpsurface]と同じ。
処理が終わるまでレスポンスが返らないので注意。
追加データなし(ステータスコード200番台で成功)
MoveAsync [SSP] [リモート不可]
\![moveasync]と同じことをSakuraScriptを介さずに実行する。パラメータ指定方法はSakuraScript版と同じ。
SSTPのタイムアウトまでにresponseを返せないのとデッドロックの原因になるため、asyncなしのmoveは実行できない。
追加データなし(ステータスコード200番台で成功)
SetTrayIcon [SSP] [リモート不可]
\![set,tasktrayicon]と同じことをSakuraScriptを介さずに実行する。パラメータ指定方法はSakuraScript版と同じ。
追加データなし(ステータスコード200番台で成功)
SetTrayBalloon [SSP] [リモート不可]
\![set,trayballoon]と同じことをSakuraScriptを介さずに実行する。パラメータ指定方法はSakuraScript版と同じ。
追加データなし(ステータスコード200番台で成功)
SetProperty [SSP] [リモート不可]
プロパティシステムに値を書き込む。
パラメータ0:プロパティの名前
パラメータ1:設定すべき値
追加データなし(ステータスコード200番台で成功)
GetProperty [SSP]
プロパティシステムから値を読み出す。
パラメータ0:プロパティの名前
追加データは取得したプロパティの値。
SetCookie
Senderで指定したクライアント名ごとに保存される、汎用データ保存領域に書き込む。
ブラウザの「クッキー」と同様の使い方を想定している。
パラメータ0:クッキーの名前
パラメータ1:設定すべき値
追加データなし(ステータスコード200番台で成功)
GetCookie
Senderで指定したクライアント名ごとに保存される、汎用データ保存領域から読み出す。
パラメータ0:クッキーの名前
追加データは取得したクッキーの値。

メソッド:GIVE

[旧仕様] ゴーストに各種データを与え、処理したり反応させたりするためのメソッドです。
相当昔の仕様であり、現在これを使用する意味はありません。NOTIFYやCOMMUNICATEを使用してください。

requestサンプル

GIVE SSTP/1.1
Charset: UTF-8
Sender: SSTPクライアント
Document: まず水や。それから粉やな。

GIVE SSTP/1.1
Charset: UTF-8
Sender: SSTPクライアント
Song: 佐世保の時雨

request固有ヘッダ

Document
文書(汎用的な文字列)
SHIORI/3.0ではユーザーコミュニケートと同じ扱いとなり、OnCommunicateイベントが発生する。
Song
歌の名前。
SHIORI/3.0ではOnMusicPlayイベントが発生し、Reference0がSongヘッダに指定された文字列となる。