ベースウェアが起動しているかは
shm_open('/ninix', O_RDWR, 0)
が成功するかで判定する。
OpenMutex(SYNCHRONIZE, FALSE, "/ninix_mutex")
が成功するかで判定する。
ninixではFMOはベースウェアの情報ではなくベースウェアの情報を取得できる
UNIXソケットがあるディレクトリを保持している。
末尾は
/
(Windows環境下では\
)で終わっている。例:/home/user/.ninix/sock/
、C:\ninix-kagari\.ninix\sock\
2024/10/15 追記
ninix-kagariではパスの区切り文字はOSに依らず/
で固定で末尾もそれで終わる。
ただしベースウェアはWindowsでは追記前の\
を使用しても良い。
とにかく、後述のUNIXソケットを開く際にユーザーがパスの区切り文字を意識しなくて済むようにすること。
例:/home/user/.ninix/sock/
、C:/ninix-kagari/.ninix/sock/
UTF-8な文字列なので非ASCII文字を含む場合は注意!
POSIX環境とWindowsで内部構造が違うので以下に記載する。 ただし、エラーハンドリングはほとんどしていないので各自で実装すること。
CでFMOの取得を行う場合を以下に記す。 なお、32/64bit間ではやり取りできないので注意すること。
#include <fcntl.h>
#include <limits.h>
#include <semaphore.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
struct shm_t {
uint32_t size;
sem_t sem;
char buf[PATH_MAX];
};
char *getFMO() {
struct shm_t *shm;
int fd = shm_open("/ninix", O_RDWR, 0);
shm = mmap(NULL, sizeof(struct shm_t), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
close(fd);
sem_wait(&shm->sem);
char *ptr = strndup(shm->buf, shm->size);
sem_post(&shm->sem);
return ptr;
}
int main() {
char *fmo = getFMO();
puts(fmo);
free(fmo);
return 0;
}
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
struct shm_t {
uint32_t size;
char buf[MAX_PATH];
};
char *strndup_(char *s, size_t n) {
char *p = malloc(sizeof(char) * (n + 1));
if (p == NULL) {
return NULL;
}
memcpy(p, s, n);
p[n] = '\0';
return p;
}
char *getFMO() {
char *ptr = NULL;
HANDLE mutex = OpenMutex(SYNCHRONIZE, FALSE, "/ninix_mutex");
if (WaitForSingleObject(mutex, INFINITE) != WAIT_OBJECT_0) {
goto error_wait_for_single_object;
}
HANDLE fmo = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, "/ninix");
struct shm_t *shm = (struct shm_t *) MapViewOfFile(fmo, FILE_MAP_ALL_ACCESS, 0, 0, 0);
ptr = strndup_(shm->buf, shm->size);
UnmapViewOfFile(shm);
CloseHandle(fmo);
ReleaseMutex(mutex);
error_wait_for_single_object:
CloseHandle(mutex);
return ptr;
}
int main() {
char *fmo = getFMO();
puts(fmo);
free(fmo);
return 0;
}
ninix-kagariはPOSIX環境のデフォルトでは
【FMOで取得できるパス】ninix_kagari
なるUNIXソケットをlistenしている。
(例:/home/user/.ninix/sock/ninix_kagari
)
2024/10/16 追記
【FMOで取得できるパス】ninix
をlistenするようにした。
(例:/home/user/.ninix/sock/ninix
)
クライアントは受信専用。送信しても無視される。 ソケットにconnectすると、以下のようなデータが流れた後、closeされる。
uint32_t
id1.key1\x01value1\x0d\x0a
id1.key2\x01value2\x0d\x0a
...
idn.keym\x01valuem\x0d\x0a
null-terminated
見やすいように改行を行っているが、実際は改行は\x0d\x0a
の部分だけ。
SSPのFMO相当のデータが含まれるが、hwnd系は存在しない。
uint32_t
は符号なし32bit整数型で、null-terminatedを含まないサイズ。
idはUUIDを使う。
各ゴーストは【FMOで取得できるパス】#{id}
なるUNIXソケットをlistenしている。
#{id}
は前述のUUID。
(例:/home/user/.ninix/sock/01234567-89ab-cdef-0123-456789abcdef
)
このソケットに対しSSTPを送るとSSPのDirectSSTP相当の動作をする。
Q. FMOにninix-kagari本体のUNIXソケットの情報も含めれば良くね?
A. そうすると共有メモリが固定長じゃなくなって面倒くさい。
Q. WindowsでUNIXソケット対応してるのWindows 10以降なんだけど?
A. クロスプラットフォームでプロセス間通信出来るのこれくらいしかない気がする。
Q. UNIXソケットの方の実装例は無いの?
A. 固有の処理はないので、一般的なUNIXソケットの通信方法を使えば大丈夫。