информационная безопасность
без паники и всерьез
 подробно о проектеRambler's Top100
Атака на InternetSpanning Tree Protocol: недокументированное применение
BugTraq.Ru
Русский BugTraq
 Анализ криптографических сетевых... 
 Модель надежности двухузлового... 
 Специальные марковские модели надежности... 
 Google заблокировала 2 с лишним... 
 Бэкдор в xz/liblzma, предназначенный... 
 Три миллиона электронных замков... 
главная обзор RSN блог библиотека закон бред форум dnet о проекте
bugtraq.ru / форум / programming
Имя Пароль
ФОРУМ
если вы видите этот текст, отключите в настройках форума использование JavaScript
регистрация





Легенда:
  новое сообщение
  закрытая нитка
  новое сообщение
  в закрытой нитке
  старое сообщение
  • Напоминаю, что масса вопросов по функционированию форума снимается после прочтения его описания.
  • Новичкам также крайне полезно ознакомиться с данным документом.
[Win32] Не могу корректно остановить сервис NT. 23.05.04 23:43  
Автор: void <Grebnev Valery> Статус: Elderman
Отредактировано 23.05.04 23:44  Количество правок: 1
<"чистая" ссылка>
Подскажите, пожалуйста, как грамотно остановить сервис, обеспечить корректное завершение рабочего потока?
Предполагается, что сервис останавливается из mmc SCM. При завершении работы необходимо, чтобы рабочий поток освободил все используемые ресурсы.

В call-back хендлере, собственно, сделана робкая попытка только установить некий глобальный флаг g_bStopSniff = TRUE. Предполагалось (по наивности ), что рабочий поток сможет проанализировать g_bStopSniff ==TRUE ;)))Самое смешное, что некоторые гуру так и делают, блин ;))
Т.е хендлер:
DWORD WINAPI ServiceCtrlHandler( DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext ) { DWORD rc = NO_ERROR; switch (dwControl) { case SERVICE_CONTROL_STOP: g_bStopSniff = TRUE; ss.dwWin32ExitCode = 0; ss.dwCurrentState = SERVICE_STOPPED; ss.dwCheckPoint = 0; ss.dwWaitHint = 0; break; case SERVICE_CONTROL_PAUSE: <skip> default: rc = ERROR_CALL_NOT_IMPLEMENTED; break; } SetServiceStatus( hSS, &ss); return rc; }

Рабочим потоком может быть как, как собственно void WINAPI ServiceMainProc(DWORD dwArgc, LPTSTR *lpszArgv), так и вторичный поток с функцией потока SniffThread:
void WINAPI ServiceMainProc(DWORD dwArgc, LPTSTR *lpszArgv) { <skip> ss.dwCurrentState = SERVICE_RUNNING; SetServiceStatus( hSS, &ss); hThread = _beginthreadex( NULL, 0, &SniffThread, NULL, 0, &thID ); if (! hThread) err(_T("Error creating sniffer thread.")); }

а код рабочего потока примитивен:

BOOL sniff( BOOL bDebug ) { WSAData wsaData; if (WSAStartup(0x0202,(WSADATA *) &wsaData )) { err( _T("Error WSAStartup"),WSAGetLastError()); return FALSE; } <skip … > SOCKET snfSock = socket( AF_INET, SOCK_RAW, IPPROTO_IP ); if( bind(snfSock, (SOCKADDR *)&sa, sizeof(SOCKADDR)) ) { err(_T("Error bind"),WSAGetLastError()); return FALSE; } <skip … > FILE* fl = _tfopen( szPathname, _T("w")); while( ! g_bStopSniff ) { <skip … > } closesocket( snfSock ); WSACleanup(); fclose( fl ); return TRUE; }

Понятно, что я хочу в этом примере. Если bStopSniff == TRUE, то я хочу остановить цикл while, прибить сокет snfSock и закрыть файл fl. Если там были выделены ещё какие-нить ресурсы, то хочу их освободить корректно.

В общем, что видится… Когда SCM вызывает хендлер ServiceCtrlHandler (SERVICE_CONTROL_STOP), то такое ощущение, что и ServiceMainProc и его вторичные потоки (если таковые были) – всё уже прибито SCM-ом ;( Поздно пить боржоми, чтобы чего-то там освободить ;((

Как быть, научите, плиз, недопрограммера ;)))
Остановить все потоки. установить свой статус в stopped... 24.05.04 00:18  
Автор: Killer{R} <Dmitry> Статус: Elderman
<"чистая" ссылка>
> Подскажите, пожалуйста, как грамотно остановить сервис,
> обеспечить корректное завершение рабочего потока?
Остановить все потоки. Установить свой статус в STOPPED. Завершить выполнение ServiceMain.
> void WINAPI ServiceMainProc(DWORD dwArgc, LPTSTR *lpszArgv)
> {
> <skip>
> ss.dwCurrentState = SERVICE_RUNNING;
> SetServiceStatus( hSS, &ss);
>
> hThread = _beginthreadex( NULL, 0, &SniffThread,
> NULL, 0, &thID );
> if (! hThread)
> err(_T("Error creating sniffer thread."));
>
> }
мм.. а дальше* ServiceMain должен завершаться только при завершении сервиса, а так висеть и к примеру ждать какого нить Mutex'а.
Сорри, Вы наверное про это и постили - то, что в конце я там... 24.05.04 02:07  
Автор: void <Grebnev Valery> Статус: Elderman
<"чистая" ссылка>
Сорри, Вы наверное про это и постили - то, что в конце я там со Sleep пропостил.
1) Ты не понял. Рабочие потоки я могу создать, к примеру, в... 24.05.04 01:19  
Автор: void <Grebnev Valery> Статус: Elderman
<"чистая" ссылка>
> Остановить все потоки. Установить свой статус в STOPPED.

1) Ты не понял. Рабочие потоки я могу создать, к примеру, в ServiceMain. Дескрипторы этих потоков и всего, что в них создаётся ( сокетов, файлов и т.д.) я могу сделать, конечно глобальными. Но! Особождать ресурсы из другого потока (например, из которого вызывается хендлер SCM) и оттуда прибивать рабочие потоки при помощи BOOL TerminateThread( HANDLE hThread, DWORD dwExitCode );
- ИМХО bad desing.
Потоки сами должны каким-то образом получить оповещение о том, что юзверь кликнул в остнастке SCM "stop". Они сами должны освободить ресурсы, которые ранее запрашивали, а затем функция потока должна завершиться, вернув 0.

2) Когда я пытаюсь что-то установить в хендлере сервиса (например, свой флаг STOP) , то подозреваю, что поток ServiceMain уже прибит силой SCM. Другими словами, когда в ServiceCtrlHandler я получаю dwControl = SERVICE_CONTROL_STOP, то все потоки рождённые от ServiceMain выглядят совершенно мёртвыми. В этих потоках невозможно по описанному сценарию проанализировать некую глобальную переменную STOP, и затем корректно самостоятельно завершить работу.

> Завершить выполнение ServiceMain.
> > void WINAPI ServiceMainProc(DWORD dwArgc, LPTSTR
> *lpszArgv)
> > {
> > <skip>
> > ss.dwCurrentState = SERVICE_RUNNING;
> > SetServiceStatus( hSS, &ss);
> >
> > hThread = _beginthreadex( NULL, 0, &SniffThread,
> > NULL, 0, &thID );
> > if (! hThread)
> > err(_T("Error creating sniffer thread."));
> >
> > }
> мм.. а дальше* ServiceMain должен завершаться только при
> завершении сервиса, а так висеть и к примеру ждать какого
> нить Mutex'а.

Ошибаешься ;)))) В той части, что ServiceMain умеет, что-то ждать (хоть там критической секции, хоть Mutex-ов;))), если в ServiceCtrlHandler ты получил dwControl = SERVICE_CONTROL_STOP и в ответ установил статус сервиса ss.dwCurrentState = SERVICE_STOPPED, то ServiceMain и все дочерние её потоки (если таковые были), будутнещадно_прибиты SCM. ;))
Ниже, совершенно рабочий код с_while(1)_в конце. ServiceMain ни в жисть не подвиснет там. ;)) Этот поток просто будет убиенным SCM-омо при остановке сервиса.

void WINAPI ServiceMainProc(DWORD dwArgc, LPTSTR *lpszArgv) { <skip> ss.dwCurrentState = SERVICE_RUNNING; SetServiceStatus( hSS, &ss); while(1); // здесь поток не подвиснет. С ним расправится SCM ;))) }
OOO !!! Вот я идиот. Но всё равно, подскажите 24.05.04 02:04  
Автор: void <Grebnev Valery> Статус: Elderman
Отредактировано 24.05.04 02:05  Количество правок: 1
<"чистая" ссылка>
Что называется, бывает хуже, но реже, блин....Добавил Sleep(1000). Естественно заработало ;)))
Т.е. та функция хендлера добавлена одной строчкой с :
DWORD WINAPI ServiceCtrlHandler( DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext ) { DWORD rc = NO_ERROR; switch (dwControl) { case SERVICE_CONTROL_STOP: g_bStopSniff = TRUE; ss.dwWin32ExitCode = 0; ss.dwCurrentState = SERVICE_STOPPED; ss.dwCheckPoint = 0; ss.dwWaitHint = 0; // HERE ;))) OOOOOOO !!!! Sleep(1000); break; case SERVICE_CONTROL_PAUSE: <skip> default: rc = ERROR_CALL_NOT_IMPLEMENTED; break; } SetServiceStatus( hSS, &ss); return rc; }

Это работает. Но всё же. Как делают программисты более грамотно. Может перед установкой ss.dwCurrentState = SERVICE_STOPPED делать так:
case SERVICE_CONTROL_STOP: bStopSniff = TRUE; ss.dwCurrentState = SERVICE_STOP_PENDING; ss.dwWaitHint = 1000; SetServiceStatus( hSS, &ss); Sleep(1000); ss.dwWin32ExitCode = 0; ss.dwCurrentState = SERVICE_STOPPED; ss.dwCheckPoint = 0; ss.dwWaitHint = 0; break;

Как думают программисты?
тут уже был целый постинг с примерным сервисом на делфи правда 24.05.04 02:48  
Автор: Killer{R} <Dmitry> Статус: Elderman
<"чистая" ссылка>
Вот тут - http://www.bugtraq.ru/cgi-bin/forum.mcgi?type=sb&b=2&m=104683
Да, внимательно не посмотрел вначале. Думал, что и так всё... 24.05.04 03:35  
Автор: void <Grebnev Valery> Статус: Elderman
<"чистая" ссылка>
> Вот тут -
> http://www.bugtraq.ru/cgi-bin/forum.mcgi?type=sb&b=2&m=1046
> 83
Да, внимательно не посмотрел вначале. Думал, что и так всё знаю. ;))) Чего смотреть ;))))
Конечно можно и так, при получении хендлером dwControl == SERVICE_CONTROL_STOP ответить только SetState(SERVICE_STOP_PENDING).
Далее дождаться эвента в рабочем потоке ServiceMain и там уже завершиться с установкой SetState(SERVICE_STOPPED).

Кстати, да. Так чисто получается ;)))
Ща мы тот код слямзим и отрехтуем в C ;)))
1




Rambler's Top100
Рейтинг@Mail.ru


  Copyright © 2001-2024 Dmitry Leonov   Page build time: 0 s   Design: Vadim Derkach