Каков путь к сокету для пользовательского приложения FCGI, созданного локальным http-сервером? (например, apache/mod_fcgid, lighttpd/mod_fastcgi и т. д.)

Я работаю над комплектом разработчика fastcgi, написанным на target-c/cocoa, который имитирует поведение и структуру AppKit/UIKit (делегаты приложений, циклы выполнения, очереди событий и т. д.). Я сделал свою домашнюю работу по fastcgi, libfcgi, реализациям fastcgi Objective c с использованием libfcgi, и я пришел к печальному осознанию того, что для того, чтобы сделать его на 100% «Какао», мне придется реализовать протокол самостоятельно, из нуля (способ, которым libfcgi предназначен для «зацикливания», не очень хорошо сочетается с CoreFoundation RunLoops и очередями событий).

При этом существуют следующие случаи для приложения fastcgi-responder в соответствии с документацией (Технический документ FCGI) на fastcgi.com:

  1. Приложение является локальным для веб-сервера и порождается последним по мере необходимости для выполнения входящих запросов.
  2. Приложение является локальным или удаленным по отношению к веб-серверу, но веб-сервер предполагает, что оно уже запущено, и взаимодействует с ним через сокет домена или сокет tcp/ip.

Меня устраивает второй случай, потому что я контролирую путь к сокету/IP-адрес и порт, где я хочу, чтобы мое приложение прослушивало: я знаю, где находится мой канал связи.

У меня проблема с первым сценарием. Я просеивал fci_stdio.c и fcgiapp.c, смотрел на FCGX_Accept_r, FCGX_InitRequest, FCGX_Stream и тому подобное, и я не могу найти, из какого сокета он пытается читать.

Нет, это не stdin, так как он перехватывается и "заворачивается" в структуру FCGI_FILE в fcgi_stdio.h, как указано в документации на fastcgi.com. Я признаю, что мои дни программирования posix далеко позади, и я немного заржавел. Я определенно что-то упускаю.

Я пытался прослушать stdin в своем приложении, и он выдал ошибку posix 57 (неопределенная ошибка) и никаких данных. Вот пример вывода, который я получаю в журнале примера приложения:

2013-05-01 11:40:01.486 Test-FCGIKit[2477:707] /Users/catalin/Sites/fcgi/Test-FCGIKit-CocoaBundle.bundle/Contents/MacOS/Test-FCGIKit
2013-05-01 11:40:01.495 Test-FCGIKit[2477:707] applicationWillFinishLaunching:
2013-05-01 11:40:01.497 Test-FCGIKit[2477:707] startRunLoop
2013-05-01 11:40:01.498 Test-FCGIKit[2477:707] applicationDidFinishLaunching:
2013-05-01 11:40:01.500 Test-FCGIKit[2477:707] * Waiting for events 
2013-05-01 11:40:01.501 Test-FCGIKit[2477:707] didReadToEndOfStdIn:
2013-05-01 11:40:01.502 Test-FCGIKit[2477:707] NSConcreteNotification 0x7fb3d9806670 {name = NSFileHandleReadToEndOfFileCompletionNotification; object = <NSConcreteFileHandle: 0x7fb3d8c15030>; userInfo = {
    NSFileHandleError = 57;
    NSFileHandleNotificationDataItem = <>;
}}
2013-05-01 11:40:01.504 Test-FCGIKit[2477:707] * Waiting for events 
2013-05-01 11:40:01.508 Test-FCGIKit[2477:707] * Processed event 
2013-05-01 11:40:01.510 Test-FCGIKit[2477:707] * Waiting for events 
[Wed May 01 11:40:41 2013] [warn] [client 127.0.0.1] mod_fcgid: read data timeout in 40 seconds
[Wed May 01 11:40:41 2013] [error] [client 127.0.0.1] Premature end of script headers: Test-FCGIKit
2013-05-01 11:40:43.337 Test-FCGIKit[2477:707] Caught SIGTERM. Terminating.
2013-05-01 11:40:43.338 Test-FCGIKit[2477:707] terminate:
2013-05-01 11:40:43.339 Test-FCGIKit[2477:707] applicationShouldTerminate:
2013-05-01 11:40:43.343 Test-FCGIKit[2477:707] quit
2013-05-01 11:40:43.345 Test-FCGIKit[2477:707] applicationWillTerminate:
  • Пожалуйста, не вводите в заблуждение имена сообщений: они должны быть точно такими же, как AppKit/UIKit, но они не от NSApplication. ** Это нормально для тайм-аута, поскольку я ничего не делаю в коде, чтобы ответить на запрос или отправить какие-либо данные обратно на сервер (я довольно далек от этого).

Как приложение узнает, какой путь к сокету прослушивать (читать/записывать), если сервер создает сокет динамически по запросу?


person Cătălin Stan    schedule 01.05.2013    source источник


Ответы (1)


Наконец, после еще немного копания, проб и ошибок, большого количества кофе и свежего воздуха, я наткнулся на абзац в спецификации FastCGI по адресу http://www.fastcgi.com/devkit/doc/fcgi.-spec.html

2.2 Дескрипторы файлов

Веб-сервер оставляет один файловый дескриптор FCGI_LISTENSOCK_FILENO открытым, когда приложение начинает выполнение. Этот дескриптор относится к прослушивающему сокету, созданному веб-сервером.

FCGI_LISTENSOCK_FILENO равно STDIN_FILENO. Стандартные дескрипторы STDOUT_FILENO и STDERR_FILENO закрываются, когда приложение начинает выполняться. Надежный метод для приложения определить, было ли оно вызвано с помощью CGI или FastCGI, — это вызвать getpeername(FCGI_LISTENSOCK_FILENO), который возвращает -1 с errno, установленным в ENOTCONN для приложения FastCGI.

Выбор веб-сервером надежного транспорта, потоковых каналов Unix (AF_UNIX) или TCP/IP (AF_INET), подразумевается во внутреннем состоянии сокета FCGI_LISTENSOCK_FILENO.

Таким образом, мне действительно не следует заботиться о фактическом физическом пути сокета, поскольку он передается моему приложению через поток STDIN. Все, что мне нужно сделать, это слушать. Не все ли мы?!

Поскольку я знаю, к чему прислушиваться, я могу использовать [NSFileHandle acceptConnectionInBackgroundAndNotify] (см. документацию Apple здесь), чтобы прослушивать сокет и отвечать на запросы.

Вау!

person Cătălin Stan    schedule 02.05.2013