SlideShare a Scribd company logo
1 of 37
Servicios
                 y
                        demonios
   Código residente de ejecución con
     frecuencia programada para
       procesamiento de eventos
Programas residentes

• Procesos que se arrancan y cuando finalizan
  dejan parte de su código instalado en
  memoria.
• El código residente queda protegido por el
  sistema de administración de memoria del
  S.O.
• El código resiente no se ejecuta por
  intervención directa del usuario.
Programas residentes

• El código residente se ejecuta mediante
  señales de software o interrupciones de
  hardware.
• Los programas AGENTES son rutinas
  residentes, diseñadas para Windows, tienen
  una interfaz GUI oculta y se registran en la
  barra de tareas del sistema.
Servicios

• Programas residentes, sin interfaz gráfica, que son
  iniciados al arrancar el sistema.
• No requieren que un usuario se registre para entrar
  en ejecución, siempre están activos.
• Pueden ser configurados para arrancar en forma
  automática, manual o para ser deshabilitados.
Interfaz con el “Service Control
               Manager”
• Se administran mediante la aplicación de
  servicios (“services”) dentro del Panel de
  Control/Herramienta.
Servicios
• Los servicios pueden añadirse dinámicamente.
• Los estados de un proceso son:
   –   Habilitado
   –   Deshabilitado
   –   Iniciado
   –   Iniciando
   –   Detenido
   –   Deteniéndose
• Su inicio puede ser:
   – Manual
   – Automático
Servicios
• Los servicios pueden activarse o desactivarse
  según se requiera, sin necesidad de reinicializar el
  sistema.
Para instalar un proceso se requiere ...

Programa instalador.
   Da de alta el programa del proceso dentro de la
   base de servicios (procesos) de Windows.


Programa del proceso.
   Contiene el código funcional del servicio
   (proceso).
Funciones relacionadas con servicios

•   CreateService
•   DeleteService
•   EnumServicesStatus
•   RegisterServiceCtrlHandler
•   SetServiceStatus
•   ServiceMain
Eventos que puede
          recibir/enviar un servicio
•   SERVICE_STOPPED
•   SERVICE_START_PENDING
•   SERVICE_STOP_PENDING
•   SERVICE_RUNNING
•   SERVICE_CONTINUE_PENDING
•   SERVICE_PAUSE_PENDING
•   SERVICE_PAUSED

            • SERVICE_ACCEPT_STOP
            • SERVICE_ACCEPT_PAUSE_CONTINUE
            • SERVICE_ACCEPT_SHUTDOWN
Ejemplo de un servicio
SERVICE_STATUS_HANDLE manejador;
SERVICE_STATUS serviceStatus;
SERVICE_TABLE_ENTRY tabla;
char nombreServicio[]="Srv_ProgAva";

VOID WINAPI ServiceMain(DWORD dwArgc,LPTSTR *lpszArgv);
VOID WINAPI mainHandle(DWORD fdwControl);

void main(void)
{
        tabla.lpServiceName=nombreServicio;
        tabla.lpServiceProc=&ServiceMain;

       StartServiceCtrlDispatcher(&tabla);
}
                          Declaración de las rutinas que servirán para las

                          operaciones principales del servicio.

                          Estas hay que indicarlas ya que sus nombres no

                          son estándares de Windows, sino un capricho del

                          programador.
Ejemplo de un servicio
SERVICE_STATUS_HANDLE manejador;
SERVICE_STATUS serviceStatus;
SERVICE_TABLE_ENTRY tabla;
char nombreServicio[]=“Srv_ProgAva";

VOID WINAPI ServiceMain(DWORD dwArgc,LPTSTR *lpszArgv);
VOID WINAPI mainHandle(DWORD fdwControl);

void main(void)
{
        tabla.lpServiceName=nombreServicio;
        tabla.lpServiceProc=&ServiceMain;

       StartServiceCtrlDispatcher(&tabla);
}



                                       Declaración de la estructura de datos

                                       SERVICE_TABLE_ENTRY.

                                       Inicialización de la estructura.
Estructura SERVICE_TABLE_ENTRY
“The SERVICE_TABLE_ENTRY structure is used by the
StartServiceCtrlDispatcher function to specify the ServiceMain
function for a Win32 service that can run in the calling process.”


           typedef struct _SERVICE_TABLE_ENTRY {
               LPTSTR lpServiceName;
               LPSERVICE_MAIN_FUNCTION lpServiceProc;
           } SERVICE_TABLE_ENTRY, *LPSERVICE_TABLE_ENTRY;


          “Members
                      lpServiceName  Pointer to a null-terminated string that names a
                      service that can run in this service process. This string is ignored if
                      the service is installed in the service control manager database as a
                      SERVICE_WIN32_OWN_PROCESS service type. For a
                      SERVICE_WIN32_SHARE_PROCESS service process, this string
                      names the service that uses the ServiceMain function pointed to by
                      the lpServiceProc member.”
Ejemplo de un servicio
SERVICE_STATUS_HANDLE manejador;
SERVICE_STATUS serviceStatus;
SERVICE_TABLE_ENTRY tabla;
char nombreServicio[]="Srv_ProgAva";

VOID WINAPI ServiceMain(DWORD dwArgc,LPTSTR *lpszArgv);
VOID WINAPI mainHandle(DWORD fdwControl);

void main(void)
{
        tabla.lpServiceName=nombreServicio;
        tabla.lpServiceProc=&ServiceMain;

       StartServiceCtrlDispatcher(&tabla);
}
                          Declaración de las rutinas que servirán para las

                          operaciones principales del servicio.

                          Estas hay que indicarlas ya que sus nombres no

                          son estándares de Windows, sino un capricho del

                          programador.
Función StartServiceCtrlDispatcher
The StartServiceCtrlDispatcher function connects the main thread of a service process to the service
control manager, which causes the thread to be the service control dispatcher thread for the calling
process.

BOOL StartServiceCtrlDispatcher(
  LPSERVICE_TABLE_ENTRY lpServiceStartTable                                                  // address of service
                                                                                             // table
);
     Parameters
                    lpServiceStartTable
                    Pointer to an array of SERVICE_TABLE_ENTRY structures containing one entry for each service
                    that can execute in the calling process. The members of the last entry in the table must have NULL
                    values to designate the end of the table.

     Return Values
                  If the function succeeds, the return value is nonzero.
                  If the function fails, the return value is zero. To get extended error information, call GetLastError.

     Errors
                    The following error code can be set by the service control manager. Other error codes can be set by
                    the registry functions that are called by the service control manager.

     Value Meaning
                 ERROR_INVALID_DATA The specified dispatch table contains entries that are not in the proper
                 format.
                 ERROR_SERVICE_ALREADY_RUNNING Windows NT 5.0 and later: The process has already
                 called StartServiceCtrlDispatcher. Each process can call StartServiceCtrlDispatcher only one time.
Rutina ServiceMain
VOID WINAPI ServiceMain(DWORD dwArgc,LPTSTR *lpszArgv)

{

    serviceStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS;

    serviceStatus.dwCurrentState=SERVICE_START_PENDING;          //Avisar que ...

                                                                             // ESTAMOS INICIANDO

    serviceStatus.dwControlsAccepted=SERVICE_CONTROL_INTERROGATE// ...EL ARRANQUE!

                               |SERVICE_ACCEPT_STOP

                               |SERVICE_ACCEPT_PAUSE_CONTINUE

                               |SERVICE_ACCEPT_SHUTDOWN;

    serviceStatus.dwWin32ExitCode=NO_ERROR;

    serviceStatus.dwServiceSpecificExitCode=0;

    serviceStatus.dwCheckPoint=estado++;

    serviceStatus.dwWaitHint=100;

                                           Inicialización de la estructura serviceStatus para

    interfaz_al_SCM=RegisterServiceCtrlHandler(nombreServicio,mainHandle);
                                          preparar el arranque del servicio.
    SetServiceStatus(interfaz_al_SCM,&serviceStatus);     //Avisar que estamos
Rutina ServiceMain
VOID WINAPI ServiceMain(DWORD dwArgc,LPTSTR *lpszArgv)

{

    serviceStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS;

    serviceStatus.dwCurrentState=SERVICE_START_PENDING;              //Avisar que ...

                                                                                  // ESTAMOS INICIANDO

    serviceStatus.dwControlsAccepted=SERVICE_CONTROL_INTERROGATE// ...EL ARRANQUE!

                               |SERVICE_ACCEPT_STOP

                               |SERVICE_ACCEPT_PAUSE_CONTINUE

                               |SERVICE_ACCEPT_SHUTDOWN;

    serviceStatus.dwWin32ExitCode=NO_ERROR;

    serviceStatus.dwServiceSpecificExitCode=0;

    serviceStatus.dwCheckPoint=estado++;

    serviceStatus.dwWaitHint=100;

                                                 Registrar la rutina que de ahora en adelante servirá
    interfaz_al_SCM=RegisterServiceCtrlHandler(nombreServicio,mainHandle);
                                                 para recibir mensajes del sistema operativo.
    SetServiceStatus(interfaz_al_SCM,&serviceStatus);       //Avisar que estamos
Rutina ServiceMain
VOID WINAPI ServiceMain(DWORD dwArgc,LPTSTR *lpszArgv)

{

    serviceStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS;

    serviceStatus.dwCurrentState=SERVICE_START_PENDING;           //Avisar que ...

                                                                               // ESTAMOS INICIANDO

    serviceStatus.dwControlsAccepted=SERVICE_CONTROL_INTERROGATE// ...EL ARRANQUE!

                               |SERVICE_ACCEPT_STOP

                               |SERVICE_ACCEPT_PAUSE_CONTINUE

                               |SERVICE_ACCEPT_SHUTDOWN;

    serviceStatus.dwWin32ExitCode=NO_ERROR;

    serviceStatus.dwServiceSpecificExitCode=0;

    serviceStatus.dwCheckPoint=estado++;

    serviceStatus.dwWaitHint=100;

                                                 Mandar la ServiceManager la indicación de que
    interfaz_al_SCM=RegisterServiceCtrlHandler(nombreServicio,mainHandle);
                                                 nuestro servicio ya está activo.
    SetServiceStatus(interfaz_al_SCM,&serviceStatus); //Avisar que estamos
Rutina ServiceMain
VOID WINAPI ServiceMain(DWORD dwArgc,LPTSTR *lpszArgv)

{

    serviceStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS;

    serviceStatus.dwCurrentState=SERVICE_START_PENDING;           //Avisar que ...

                                                                               // ESTAMOS INICIANDO

    serviceStatus.dwControlsAccepted=SERVICE_CONTROL_INTERROGATE// ...EL ARRANQUE!

                               |SERVICE_ACCEPT_STOP

                               |SERVICE_ACCEPT_PAUSE_CONTINUE

                               |SERVICE_ACCEPT_SHUTDOWN;

    serviceStatus.dwWin32ExitCode=NO_ERROR;

    serviceStatus.dwServiceSpecificExitCode=0;

    serviceStatus.dwCheckPoint=estado++;

    serviceStatus.dwWaitHint=100;
                                      Llamar a nuestra rutina de inicialización ... mmmh, aunque

                                      esto debió haberse hecho antes del SetServiceStatus,
    interfaz_al_SCM=RegisterServiceCtrlHandler(nombreServicio,mainHandle);

                                       no? ... ¿por qué?
    SetServiceStatus(interfaz_al_SCM,&serviceStatus); //Avisar que estamos
Rutina mainHandle
VOID WINAPI mainHandle(DWORD fdwControl)
{
    switch(fdwControl) {

        case SERVICE_CONTROL_STOP:
            serviceStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS;
            serviceStatus.dwCurrentState=SERVICE_STOP_PENDING;
            serviceStatus.dwControlsAccepted=SERVICE_CONTROL_INTERROGATE
                                                |SERVICE_ACCEPT_STOP
                                                |SERVICE_ACCEPT_PAUSE_CONTINUE
                                                |SERVICE_ACCEPT_SHUTDOWN;
...
            break;
        case SERVICE_CONTROL_PAUSE:
            serviceStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS;
            serviceStatus.dwCurrentState=SERVICE_PAUSE_PENDING;
            serviceStatus.dwControlsAccepted=SERVICE_CONTROL_INTERROGATE
                                                |SERVICE_ACCEPT_STOP
                                                |SERVICE_ACCEPT_PAUSE_CONTINUE
                                                |SERVICE_ACCEPT_SHUTDOWN;
...
            break;
        case SERVICE_CONTROL_CONTINUE:
            serviceStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS;
            serviceStatus.dwCurrentState=SERVICE_CONTINUE_PENDING;
...
          }
}                                          El servicio debe tener capacidad para responder

                                           a cada tipo de petición que pueda generar el
Rutina mainHandle
....
case SERVICE_CONTROL_CONTINUE:
          serviceStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS;
          serviceStatus.dwCurrentState=SERVICE_CONTINUE_PENDING;
          serviceStatus.dwControlsAccepted=SERVICE_CONTROL_INTERROGATE
                                                  |SERVICE_ACCEPT_STOP
                                                  |SERVICE_ACCEPT_PAUSE_CONTINUE
                                                  |SERVICE_ACCEPT_SHUTDOWN;
          serviceStatus.dwWin32ExitCode=NO_ERROR;
          serviceStatus.dwServiceSpecificExitCode=0;
          serviceStatus.dwCheckPoint=estado++;
          serviceStatus.dwWaitHint=100;
          SetServiceStatus(interfaz_al_SCM,&serviceStatus);

         reactivarProceso();

         serviceStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS;
         serviceStatus.dwCurrentState=SERVICE_RUNNING;
         serviceStatus.dwControlsAccepted=SERVICE_CONTROL_INTERROGATE
                                                 |SERVICE_ACCEPT_STOP
                                                 |SERVICE_ACCEPT_PAUSE_CONTINUE
                                                 |SERVICE_ACCEPT_SHUTDOWN;
         serviceStatus.dwWin32ExitCode=NO_ERROR;
         serviceStatus.dwServiceSpecificExitCode=0;
         serviceStatus.dwCheckPoint=estado++;
         serviceStatus.dwWaitHint=100;
         SetServiceStatus(interfaz_al_SCM,serviceStatus);
         break;
}                                                   Cada caso puede tener llamadas a diversas
...
                                                    rutinas, según corresponda para realizar
Instalador de un servicio
char nombreServicio[]=“Srv_ProgAva";    //Así lo reconocerá el S.O.

char nombreDisplay[]=“Servicio_ProgAva";   //Así lo veremos en pantalla.

char pathServicio[]=“C:ProgAvaservicio.exe";   //Aquí está el .exe

SC_HANDLE manejadorServicios; //Descriptor del manejador de servicios
SC_HANDLE nuevoServicio;      //Apuntador a nuestro nuevo servicio

ENUM_SERVICE_STATUS datos[200];
int resume,bytesFaltantes,serviciosFaltantes,i;

void main(void) {
    manejadorServicios=OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
    resume=0;
    for (i=0;i<20;i++) {
        resume=i;
        if (EnumServicesStatus(manejadorServicios,SERVICE_WIN32,
              SERVICE_STATE_ALL,&datos[0],sizeof(datos),
               &bytesFaltantes,&serviciosFaltantes,&resume)==NULL) {
            printf("(%d) Error!n",GetLastError());
        else {
            printf("%d Servicio (Nombre) --> %sn",i,datos[i].lpServiceName);
            printf("%d Servicio (Display) -> %sn",i,datos[i].lpDisplayName);
        }
    }
Instalador de un servicio
char nombreServicio[]=“Srv_ProgAva";    //Así lo reconocerá el S.O.

char nombreDisplay[]=“Servicio_ProgAva";   //Así lo veremos en pantalla.

char pathServicio[]=“C:ProgAvaservicio.exe";   //Aquí está el .exe

SC_HANDLE manejadorServicios; //Descriptor del manejador de servicios
SC_HANDLE nuevoServicio;      //Apuntador a nuestro nuevo servicio

ENUM_SERVICE_STATUS datos[200];
int resume,bytesFaltantes,serviciosFaltantes,i;

void main(void) {
    manejadorServicios=OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
    resume=0;
    for (i=0;i<20;i++) {
        resume=i;
        if (EnumServicesStatus(manejadorServicios,SERVICE_WIN32,
              SERVICE_STATE_ALL,&datos[0],sizeof(datos),
               &bytesFaltantes,&serviciosFaltantes,&resume)==NULL) {
            printf("(%d) Error!n",GetLastError());
        else {
            printf("%d Servicio (Nombre) --> %sn",i,datos[i].lpServiceName);
            printf("%d Servicio (Display) -> %sn",i,datos[i].lpDisplayName);
        }
    }
Instalador de un servicio
char nombreServicio[]=“Srv_ProgAva";    //Así lo reconocerá el S.O.

char nombreDisplay[]=“Servicio_ProgAva";   //Así lo veremos en pantalla.

char pathServicio[]=“C:ProgAvaservicio.exe";   //Aquí está el .exe

SC_HANDLE manejadorServicios; //Descriptor del manejador de servicios
SC_HANDLE nuevoServicio;      //Apuntador a nuestro nuevo servicio

ENUM_SERVICE_STATUS datos[200];
int resume,bytesFaltantes,serviciosFaltantes,i;

void main(void) {
    manejadorServicios=OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
    resume=0;
    for (i=0;i<20;i++) {
        resume=i;
        if (EnumServicesStatus(manejadorServicios,SERVICE_WIN32,
              SERVICE_STATE_ALL,&datos[0],sizeof(datos),
               &bytesFaltantes,&serviciosFaltantes,&resume)==NULL) {
            printf("(%d) Error!n",GetLastError());
        else {
            printf("%d Servicio (Nombre) --> %sn",i,datos[i].lpServiceName);
            printf("%d Servicio (Display) -> %sn",i,datos[i].lpDisplayName);
        }
    }
Ejemplo del instalador de un servicio
char nombreServicio[]=“Srv_ProgAva";
char nombreDisplay[]=“Servicio_ProgAva";
char pathServicio[]="E:ProgAvaservicio.exe";

SC_HANDLE manejadorServicios; //Descriptor del manejador de servicios
SC_HANDLE nuevoServicio;      //Apuntador a nuestro nuevo servicio

ENUM_SERVICE_STATUS datos[200];
int resume,bytesFaltantes,serviciosFaltantes,i;

void main(void) {
    manejadorServicios=OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
    resume=0;
    for (i=0;i<20;i++) {
        resume=i;
        if (EnumServicesStatus(manejadorServicios,SERVICE_WIN32,
              SERVICE_STATE_ALL,&datos[0],sizeof(datos),
               &bytesFaltantes,&serviciosFaltantes,&resume)==NULL) {
            printf("(%d) Error!n",GetLastError());
        else {
            printf("%d Servicio (Nombre) --> %sn",i,datos[i].lpServiceName);
            printf("%d Servicio (Display) -> %sn",i,datos[i].lpDisplayName);
        }
    }
Ejemplo del instalador de un servicio
char nombreServicio[]=“Srv_ProgAva";
char nombreDisplay[]=“Servicio_ProgAva";
char pathServicio[]="E:ProgAvaservicio.exe";

SC_HANDLE manejadorServicios; //Descriptor del manejador de servicios
SC_HANDLE nuevoServicio;      //Apuntador a nuestro nuevo servicio

ENUM_SERVICE_STATUS datos[200];
int resume,bytesFaltantes,serviciosFaltantes,i;

void main(void) {
    manejadorServicios=OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
    resume=0;
    for (i=0;i<20;i++) {
        resume=i;
        if (EnumServicesStatus(manejadorServicios,SERVICE_WIN32,
              SERVICE_STATE_ALL,&datos[0],sizeof(datos),
               &bytesFaltantes,&serviciosFaltantes,&resume)==NULL) {
            printf("(%d) Error!n",GetLastError());
        else {
            printf("%d Servicio (Nombre) --> %sn",i,datos[i].lpServiceName);
            printf("%d Servicio (Display) -> %sn",i,datos[i].lpDisplayName);
        }
    }
Ejemplo del instalador de un servicio
char nombreServicio[]=“Srv_ProgAva";
char nombreDisplay[]=“Servicio_ProgAva";
char pathServicio[]="E:ProgAvaservicio.exe";

SC_HANDLE manejadorServicios; //Descriptor del manejador de servicios
SC_HANDLE nuevoServicio;      //Apuntador a nuestro nuevo servicio

ENUM_SERVICE_STATUS datos[200];
int resume,bytesFaltantes,serviciosFaltantes,i;

void main(void) {
    manejadorServicios=OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
    resume=0;
    for (i=0;i<20;i++) {
        resume=i;
        if (EnumServicesStatus(manejadorServicios,SERVICE_WIN32,
              SERVICE_STATE_ALL,&datos[0],sizeof(datos),
               &bytesFaltantes,&serviciosFaltantes,&resume)==NULL) {
            printf("(%d) Error!n",GetLastError());
        else {
            printf("%d Servicio (Nombre) --> %sn",i,datos[i].lpServiceName);
            printf("%d Servicio (Display) -> %sn",i,datos[i].lpDisplayName);
        }
    }
Ejemplo del instalador de un servicio


    if((nuevoServicio=CreateService(manejadorServicios,
            nombreServicio,nombreDisplay,SERVICE_ALL_ACCESS,
            SERVICE_WIN32_OWN_PROCESS,SERVICE_AUTO_START,
            SERVICE_ERROR_NORMAL,pathServicio,
            NULL,NULL,NULL,NULL,NULL))==NULL)
         printf("(%d) Error al crear el servicio %sn",
                             GetLastError(),nombreServicio);
    else
         printf("Servicio %s creado!!!n",nombreServicio);
    getchar();
} //main
‘¡¡¡Demonios!!!’ … “Linux Daemons”
• Son procesos que se activan al iniciar la operación
  del “kernel” y finalizan cuando se apaga el
  sistema.
• No requieren interacción con el usuario, por lo
  tanto son procesos que no tienen terminal de
  control y por eso se dice que se ejecutan en
  “background”.
• Debido a lo anterior, el flujo de salida y de errores
  debe tratarse de manera particular.
Señales y demonios
• Los procesos tipo “daemon” siguen un protocolo
  específico para interactuar con el “kernel” y con
  las aplicaciones que los requieren.
• Las interfaces hacia un “daemon” pueden ser
  (entre otros):
   –   Archivos.
   –   “Pipes”.
   –   “Sockets”.
   –   Señales.
• Su funcionamiento es similar al de un servicio en
  Windows, pero tienen una codificación distinta.
Señales de demonios
• Las señales son eventos (interrupciones) de “software”.

• Son útiles para procesar eventos asincrónicos (teclado, red,
  archivos, etc).

• La definición de señales es particular de la implementación
  del sistema operativo, pero en el archivo <signal.h> se
  pueden encontrar las definiciones estándares.

• Un programa define rutinas específicas para capturar
  señales, en él establece sus reglas de procesamiento; para
  esto se utiliza la directiva:
     void (*signal(int signo, void (*func)(int)))(int);
Señales
•   Al recibir una señal, un proceso puede hacer tres cosas:
     –    Ignorar la señal.
     –    Atrapar la señal y procesarla mediante su rutina de atención
          (“handler”); aunque se debe saber que hay señales que no se puede
          interceptar, tal como SIGKILL y SIGSTOP.
     –    Pasar el evento al sistema operativo para que se realice su
          procesamiento de facto.


•   Para enviar una señal a un proceso se pueden utilizar un par de rutinas:
                   int kill(pid_t pid, int signo);
                        int raise(int signo);


•   Igualmente se puede enviar una señal desde una terminal utilizando el
    comando kill y conociendo en número de proceso.
“Signal handler”
#include <stdio.h>

#include <stdlib.h>

#include <signal.h>



static void signalHandler(int signo) {     //El argumento es el número de la señal

    if (signo == SIGUSR1)

           printf("received SIGUSR1n");

    else if (signo == SIGUSR2)

           printf("received SIGUSR2n");

    else if (signo == SIGINT)

           printf("CTRL-C!!!n");

    else if (signo == SIGQUIT) {

           printf("Bye, bye.n");

                exit(0);

    } else if (signo == SIGKILL)

           printf("It will be not so easy to get rid of me!!!n");

    else

           printf("received signal %dn", signo);

}



int main(void) {
Catálogo de señales
   Señal    Acción de facto                                Descripción

SIGABRT    “Terminate+core”     Esta señal se genera al invocar la rutina abort(…) {<stdlib.h>}

SIGALRM    “Terminate”          Es invocada cuando expira el tiempo establecido por la rutina
                                alarm(…) {<unistd.h>. También está relacionada con la rutina
                                setitimer(…).
SIGCHLD    “Ignore”             Se genera en el proceso padre cuando un proceso hijo termina o
                                se detiene.
SIGCONT    “Continue/ignore”    Esta señal es útil para reactivar un proceso que ha sido detenido
                                previamente
SIGHUP     “Terminate”          Esta señal se envía a un proceso en caso de detectarse que su
                                terminar controladora se ha desconectado o cerrado.
SIGINT     “Terminate”          Esta señal se genera al detectarse la pulsación de la combinación
                                de teclas <Control-C>.
SIGIO      “Terminate/ignore”   Se activa para indicar la detección de un evento asincrónico de E/
                                S.
SIGKILL    “Terminate”          Es una de las que no es interceptable, siempre útil para brindar
                                una forma segura para finalizar un proceso.
SIGPIPE    “Terminate”          Esta señal marca un error en el mecanismo de comunicación entre
                                procesos a través de “pipes”.
Catálogo de señales
   Señal     Acción de facto                              Descripción

SIGQUIT     “Terminate+core”   Es similar a SIGINT, pero adicionalmente genera un archivo de
                               depuración de errores (“core dump file”).
SIGSTOP     “Stop process”     No puede ser interceptada ni ignorada, es la forma correcta de
                               finalizar un proceso.
SIGTERM     “Terminate”        Esta señal es generada por el comando “kill” de facto, sin
                               parámetros adicionales.
SIGURG      “Ignore”           Notificación de un evento urgente, como la llegada de datos a
                               través de una interfaz de red.
SIGUSR1     “Terminate”        Su aplicación está definida por el programador/usuario.

SIGUSR2     “Terminate”        Su aplicación está definida por el programador/usuario.

SIGVTALRM   “Terminate”        Esta señal se genera por la finalización de un contador virtual
                               asociado con la función setitimer(…).
SIGXCPU     “Terminate+core”   Esta señal se canaliza al proceso cuando él excede el uso de CPU
                               que le ha sido establecido en el sistema.
Estructura de un demonio
#include <stdio.h>

#include <fcntl.h>

#include <signal.h>
                                              Tres rutinas son esenciales:
#include <unistd.h>
                                              • La rutina principal de inicialización
                                                general.
rutina1 (…) {                                 • Una rutina para inicializar el
…                                               funcionamiento del “daemon”
}                                             • La rutina para recibir señales y
                                                procesarlas en forma conveniente.
rutina2 (…) {

…
                                              Se pueden tener rutinas adicionales de
}

…
                                                soporte e invocaciones a
void signalHandler(int sigNum) {
                                                bibliotecas sin restricciones.
         switch(sigNum) {

                     case SIGHUP:

                                     …

                                     break;

                     case SIGTERM:

                                     …

                                     break;
daemonize()
•   Modificar la máscara de creación de archivos invocando a la rutina umask
    para evitar heredar dicha característica del proceso principal.
•   Clonar el proceso mediante un fork y hacer que el proceso padre finalice.
    Esto es útil para hacer simular al “shell” que el proceso ya terminó,
    desasociarlo de su terminal, de su usuario/grupo y renunciar a ser el proceso
    interactivo (“group leader”).
•   Invocar setsid para crear una nueva sesión de trabajo logrando tres cosas:
    convertirse en el proceso líder de la sesión, convertirse en el proceso líder de
    grupo y renunciar a tener una terminal controladora.
•   Cambiar el directorio de facto de trabajo al raíz, evitando así recibirlo
    heredado del padre.
•   Cerrar todos los descriptores de archivo que pudo haber heredado del
    proceso padre.
•   Asignar los descriptores de archivo 0, 1 y 2 a /dev/null (stdin, stdout, stderr).
•   Asegurarse de ser la única instancia del demonio activo.
•   Interceptar señales relevantes y canalizarlas a una rutina de atención.

More Related Content

Viewers also liked

Young target 확보를_위한_애니콜_브랜드_커뮤니케이션_전략(대상)
Young target 확보를_위한_애니콜_브랜드_커뮤니케이션_전략(대상)Young target 확보를_위한_애니콜_브랜드_커뮤니케이션_전략(대상)
Young target 확보를_위한_애니콜_브랜드_커뮤니케이션_전략(대상)Sun-Hyung Kim
 
Formas basicas con sombra
Formas basicas con sombraFormas basicas con sombra
Formas basicas con sombraVero81
 
José Andréu _ Mitigation Program Across Multiple Sectors - GHG Mitigation in ...
José Andréu _ Mitigation Program Across Multiple Sectors - GHG Mitigation in ...José Andréu _ Mitigation Program Across Multiple Sectors - GHG Mitigation in ...
José Andréu _ Mitigation Program Across Multiple Sectors - GHG Mitigation in ...smartcityexpo
 
كنا فكرة كتيب تعريفي
كنا فكرة   كتيب تعريفيكنا فكرة   كتيب تعريفي
كنا فكرة كتيب تعريفيdangermind
 
Aliran sesat dan cara menghindarinya
Aliran sesat dan cara menghindarinyaAliran sesat dan cara menghindarinya
Aliran sesat dan cara menghindarinyakalenderbijak
 
Case Management
Case ManagementCase Management
Case ManagementPCHALAWA
 

Viewers also liked (13)

Nirvana
NirvanaNirvana
Nirvana
 
Young target 확보를_위한_애니콜_브랜드_커뮤니케이션_전략(대상)
Young target 확보를_위한_애니콜_브랜드_커뮤니케이션_전략(대상)Young target 확보를_위한_애니콜_브랜드_커뮤니케이션_전략(대상)
Young target 확보를_위한_애니콜_브랜드_커뮤니케이션_전략(대상)
 
Formas basicas con sombra
Formas basicas con sombraFormas basicas con sombra
Formas basicas con sombra
 
Foto 1 C
Foto 1 CFoto 1 C
Foto 1 C
 
Economia empresa "Dany sport"
Economia empresa "Dany sport"Economia empresa "Dany sport"
Economia empresa "Dany sport"
 
José Andréu _ Mitigation Program Across Multiple Sectors - GHG Mitigation in ...
José Andréu _ Mitigation Program Across Multiple Sectors - GHG Mitigation in ...José Andréu _ Mitigation Program Across Multiple Sectors - GHG Mitigation in ...
José Andréu _ Mitigation Program Across Multiple Sectors - GHG Mitigation in ...
 
Ecuador
EcuadorEcuador
Ecuador
 
Semina zucchine in classe
Semina zucchine in classeSemina zucchine in classe
Semina zucchine in classe
 
Tutorial
TutorialTutorial
Tutorial
 
1.2 terbitan berseri
1.2 terbitan berseri1.2 terbitan berseri
1.2 terbitan berseri
 
كنا فكرة كتيب تعريفي
كنا فكرة   كتيب تعريفيكنا فكرة   كتيب تعريفي
كنا فكرة كتيب تعريفي
 
Aliran sesat dan cara menghindarinya
Aliran sesat dan cara menghindarinyaAliran sesat dan cara menghindarinya
Aliran sesat dan cara menghindarinya
 
Case Management
Case ManagementCase Management
Case Management
 

Similar to Roger2

Similar to Roger2 (20)

Procedimientos almacenados
Procedimientos almacenadosProcedimientos almacenados
Procedimientos almacenados
 
procedimientos almacenados
procedimientos almacenadosprocedimientos almacenados
procedimientos almacenados
 
. procedimientos almacenados
.  procedimientos almacenados.  procedimientos almacenados
. procedimientos almacenados
 
TRANSACCIONES, TRIGGERS, PROCEDIMIENTOS ALMACENADOS: DB2/IBM
TRANSACCIONES, TRIGGERS, PROCEDIMIENTOS ALMACENADOS: DB2/IBM   TRANSACCIONES, TRIGGERS, PROCEDIMIENTOS ALMACENADOS: DB2/IBM
TRANSACCIONES, TRIGGERS, PROCEDIMIENTOS ALMACENADOS: DB2/IBM
 
Procedimientos almacenados en MySQL
Procedimientos almacenados en MySQLProcedimientos almacenados en MySQL
Procedimientos almacenados en MySQL
 
Procedimientos almacenadoss
Procedimientos almacenadossProcedimientos almacenadoss
Procedimientos almacenadoss
 
Disparadores - base de datos
Disparadores - base de datosDisparadores - base de datos
Disparadores - base de datos
 
Disparadores
DisparadoresDisparadores
Disparadores
 
Ms SQL Server
Ms SQL ServerMs SQL Server
Ms SQL Server
 
Procedimientos almacenados
Procedimientos almacenadosProcedimientos almacenados
Procedimientos almacenados
 
Disparadores 1213820550525607-9
Disparadores 1213820550525607-9Disparadores 1213820550525607-9
Disparadores 1213820550525607-9
 
Funciones store proc_triggers
Funciones store proc_triggersFunciones store proc_triggers
Funciones store proc_triggers
 
Pa
PaPa
Pa
 
Tarea
TareaTarea
Tarea
 
High Level Services of Athento Platform
High Level Services of Athento PlatformHigh Level Services of Athento Platform
High Level Services of Athento Platform
 
Tipos De Comportamiento
Tipos De ComportamientoTipos De Comportamiento
Tipos De Comportamiento
 
Taller de Base de Datos - Unidad 6 SQL procedural
Taller de Base de Datos - Unidad 6 SQL proceduralTaller de Base de Datos - Unidad 6 SQL procedural
Taller de Base de Datos - Unidad 6 SQL procedural
 
Pseint.
Pseint.Pseint.
Pseint.
 
Pseint
PseintPseint
Pseint
 
About debuggers.help
About debuggers.helpAbout debuggers.help
About debuggers.help
 

Roger2

  • 1. Servicios y demonios Código residente de ejecución con frecuencia programada para procesamiento de eventos
  • 2. Programas residentes • Procesos que se arrancan y cuando finalizan dejan parte de su código instalado en memoria. • El código residente queda protegido por el sistema de administración de memoria del S.O. • El código resiente no se ejecuta por intervención directa del usuario.
  • 3. Programas residentes • El código residente se ejecuta mediante señales de software o interrupciones de hardware. • Los programas AGENTES son rutinas residentes, diseñadas para Windows, tienen una interfaz GUI oculta y se registran en la barra de tareas del sistema.
  • 4. Servicios • Programas residentes, sin interfaz gráfica, que son iniciados al arrancar el sistema. • No requieren que un usuario se registre para entrar en ejecución, siempre están activos. • Pueden ser configurados para arrancar en forma automática, manual o para ser deshabilitados.
  • 5. Interfaz con el “Service Control Manager” • Se administran mediante la aplicación de servicios (“services”) dentro del Panel de Control/Herramienta.
  • 6. Servicios • Los servicios pueden añadirse dinámicamente. • Los estados de un proceso son: – Habilitado – Deshabilitado – Iniciado – Iniciando – Detenido – Deteniéndose • Su inicio puede ser: – Manual – Automático
  • 7. Servicios • Los servicios pueden activarse o desactivarse según se requiera, sin necesidad de reinicializar el sistema.
  • 8. Para instalar un proceso se requiere ... Programa instalador. Da de alta el programa del proceso dentro de la base de servicios (procesos) de Windows. Programa del proceso. Contiene el código funcional del servicio (proceso).
  • 9. Funciones relacionadas con servicios • CreateService • DeleteService • EnumServicesStatus • RegisterServiceCtrlHandler • SetServiceStatus • ServiceMain
  • 10. Eventos que puede recibir/enviar un servicio • SERVICE_STOPPED • SERVICE_START_PENDING • SERVICE_STOP_PENDING • SERVICE_RUNNING • SERVICE_CONTINUE_PENDING • SERVICE_PAUSE_PENDING • SERVICE_PAUSED • SERVICE_ACCEPT_STOP • SERVICE_ACCEPT_PAUSE_CONTINUE • SERVICE_ACCEPT_SHUTDOWN
  • 11. Ejemplo de un servicio SERVICE_STATUS_HANDLE manejador; SERVICE_STATUS serviceStatus; SERVICE_TABLE_ENTRY tabla; char nombreServicio[]="Srv_ProgAva"; VOID WINAPI ServiceMain(DWORD dwArgc,LPTSTR *lpszArgv); VOID WINAPI mainHandle(DWORD fdwControl); void main(void) { tabla.lpServiceName=nombreServicio; tabla.lpServiceProc=&ServiceMain; StartServiceCtrlDispatcher(&tabla); } Declaración de las rutinas que servirán para las operaciones principales del servicio. Estas hay que indicarlas ya que sus nombres no son estándares de Windows, sino un capricho del programador.
  • 12. Ejemplo de un servicio SERVICE_STATUS_HANDLE manejador; SERVICE_STATUS serviceStatus; SERVICE_TABLE_ENTRY tabla; char nombreServicio[]=“Srv_ProgAva"; VOID WINAPI ServiceMain(DWORD dwArgc,LPTSTR *lpszArgv); VOID WINAPI mainHandle(DWORD fdwControl); void main(void) { tabla.lpServiceName=nombreServicio; tabla.lpServiceProc=&ServiceMain; StartServiceCtrlDispatcher(&tabla); } Declaración de la estructura de datos SERVICE_TABLE_ENTRY. Inicialización de la estructura.
  • 13. Estructura SERVICE_TABLE_ENTRY “The SERVICE_TABLE_ENTRY structure is used by the StartServiceCtrlDispatcher function to specify the ServiceMain function for a Win32 service that can run in the calling process.” typedef struct _SERVICE_TABLE_ENTRY { LPTSTR lpServiceName; LPSERVICE_MAIN_FUNCTION lpServiceProc; } SERVICE_TABLE_ENTRY, *LPSERVICE_TABLE_ENTRY; “Members lpServiceName  Pointer to a null-terminated string that names a service that can run in this service process. This string is ignored if the service is installed in the service control manager database as a SERVICE_WIN32_OWN_PROCESS service type. For a SERVICE_WIN32_SHARE_PROCESS service process, this string names the service that uses the ServiceMain function pointed to by the lpServiceProc member.”
  • 14. Ejemplo de un servicio SERVICE_STATUS_HANDLE manejador; SERVICE_STATUS serviceStatus; SERVICE_TABLE_ENTRY tabla; char nombreServicio[]="Srv_ProgAva"; VOID WINAPI ServiceMain(DWORD dwArgc,LPTSTR *lpszArgv); VOID WINAPI mainHandle(DWORD fdwControl); void main(void) { tabla.lpServiceName=nombreServicio; tabla.lpServiceProc=&ServiceMain; StartServiceCtrlDispatcher(&tabla); } Declaración de las rutinas que servirán para las operaciones principales del servicio. Estas hay que indicarlas ya que sus nombres no son estándares de Windows, sino un capricho del programador.
  • 15. Función StartServiceCtrlDispatcher The StartServiceCtrlDispatcher function connects the main thread of a service process to the service control manager, which causes the thread to be the service control dispatcher thread for the calling process. BOOL StartServiceCtrlDispatcher( LPSERVICE_TABLE_ENTRY lpServiceStartTable // address of service // table ); Parameters lpServiceStartTable Pointer to an array of SERVICE_TABLE_ENTRY structures containing one entry for each service that can execute in the calling process. The members of the last entry in the table must have NULL values to designate the end of the table. Return Values If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To get extended error information, call GetLastError. Errors The following error code can be set by the service control manager. Other error codes can be set by the registry functions that are called by the service control manager. Value Meaning ERROR_INVALID_DATA The specified dispatch table contains entries that are not in the proper format. ERROR_SERVICE_ALREADY_RUNNING Windows NT 5.0 and later: The process has already called StartServiceCtrlDispatcher. Each process can call StartServiceCtrlDispatcher only one time.
  • 16. Rutina ServiceMain VOID WINAPI ServiceMain(DWORD dwArgc,LPTSTR *lpszArgv) { serviceStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS; serviceStatus.dwCurrentState=SERVICE_START_PENDING; //Avisar que ... // ESTAMOS INICIANDO serviceStatus.dwControlsAccepted=SERVICE_CONTROL_INTERROGATE// ...EL ARRANQUE! |SERVICE_ACCEPT_STOP |SERVICE_ACCEPT_PAUSE_CONTINUE |SERVICE_ACCEPT_SHUTDOWN; serviceStatus.dwWin32ExitCode=NO_ERROR; serviceStatus.dwServiceSpecificExitCode=0; serviceStatus.dwCheckPoint=estado++; serviceStatus.dwWaitHint=100; Inicialización de la estructura serviceStatus para interfaz_al_SCM=RegisterServiceCtrlHandler(nombreServicio,mainHandle); preparar el arranque del servicio. SetServiceStatus(interfaz_al_SCM,&serviceStatus); //Avisar que estamos
  • 17. Rutina ServiceMain VOID WINAPI ServiceMain(DWORD dwArgc,LPTSTR *lpszArgv) { serviceStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS; serviceStatus.dwCurrentState=SERVICE_START_PENDING; //Avisar que ... // ESTAMOS INICIANDO serviceStatus.dwControlsAccepted=SERVICE_CONTROL_INTERROGATE// ...EL ARRANQUE! |SERVICE_ACCEPT_STOP |SERVICE_ACCEPT_PAUSE_CONTINUE |SERVICE_ACCEPT_SHUTDOWN; serviceStatus.dwWin32ExitCode=NO_ERROR; serviceStatus.dwServiceSpecificExitCode=0; serviceStatus.dwCheckPoint=estado++; serviceStatus.dwWaitHint=100; Registrar la rutina que de ahora en adelante servirá interfaz_al_SCM=RegisterServiceCtrlHandler(nombreServicio,mainHandle); para recibir mensajes del sistema operativo. SetServiceStatus(interfaz_al_SCM,&serviceStatus); //Avisar que estamos
  • 18. Rutina ServiceMain VOID WINAPI ServiceMain(DWORD dwArgc,LPTSTR *lpszArgv) { serviceStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS; serviceStatus.dwCurrentState=SERVICE_START_PENDING; //Avisar que ... // ESTAMOS INICIANDO serviceStatus.dwControlsAccepted=SERVICE_CONTROL_INTERROGATE// ...EL ARRANQUE! |SERVICE_ACCEPT_STOP |SERVICE_ACCEPT_PAUSE_CONTINUE |SERVICE_ACCEPT_SHUTDOWN; serviceStatus.dwWin32ExitCode=NO_ERROR; serviceStatus.dwServiceSpecificExitCode=0; serviceStatus.dwCheckPoint=estado++; serviceStatus.dwWaitHint=100; Mandar la ServiceManager la indicación de que interfaz_al_SCM=RegisterServiceCtrlHandler(nombreServicio,mainHandle); nuestro servicio ya está activo. SetServiceStatus(interfaz_al_SCM,&serviceStatus); //Avisar que estamos
  • 19. Rutina ServiceMain VOID WINAPI ServiceMain(DWORD dwArgc,LPTSTR *lpszArgv) { serviceStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS; serviceStatus.dwCurrentState=SERVICE_START_PENDING; //Avisar que ... // ESTAMOS INICIANDO serviceStatus.dwControlsAccepted=SERVICE_CONTROL_INTERROGATE// ...EL ARRANQUE! |SERVICE_ACCEPT_STOP |SERVICE_ACCEPT_PAUSE_CONTINUE |SERVICE_ACCEPT_SHUTDOWN; serviceStatus.dwWin32ExitCode=NO_ERROR; serviceStatus.dwServiceSpecificExitCode=0; serviceStatus.dwCheckPoint=estado++; serviceStatus.dwWaitHint=100; Llamar a nuestra rutina de inicialización ... mmmh, aunque esto debió haberse hecho antes del SetServiceStatus, interfaz_al_SCM=RegisterServiceCtrlHandler(nombreServicio,mainHandle); no? ... ¿por qué? SetServiceStatus(interfaz_al_SCM,&serviceStatus); //Avisar que estamos
  • 20. Rutina mainHandle VOID WINAPI mainHandle(DWORD fdwControl) { switch(fdwControl) { case SERVICE_CONTROL_STOP: serviceStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS; serviceStatus.dwCurrentState=SERVICE_STOP_PENDING; serviceStatus.dwControlsAccepted=SERVICE_CONTROL_INTERROGATE |SERVICE_ACCEPT_STOP |SERVICE_ACCEPT_PAUSE_CONTINUE |SERVICE_ACCEPT_SHUTDOWN; ... break; case SERVICE_CONTROL_PAUSE: serviceStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS; serviceStatus.dwCurrentState=SERVICE_PAUSE_PENDING; serviceStatus.dwControlsAccepted=SERVICE_CONTROL_INTERROGATE |SERVICE_ACCEPT_STOP |SERVICE_ACCEPT_PAUSE_CONTINUE |SERVICE_ACCEPT_SHUTDOWN; ... break; case SERVICE_CONTROL_CONTINUE: serviceStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS; serviceStatus.dwCurrentState=SERVICE_CONTINUE_PENDING; ... } } El servicio debe tener capacidad para responder a cada tipo de petición que pueda generar el
  • 21. Rutina mainHandle .... case SERVICE_CONTROL_CONTINUE: serviceStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS; serviceStatus.dwCurrentState=SERVICE_CONTINUE_PENDING; serviceStatus.dwControlsAccepted=SERVICE_CONTROL_INTERROGATE |SERVICE_ACCEPT_STOP |SERVICE_ACCEPT_PAUSE_CONTINUE |SERVICE_ACCEPT_SHUTDOWN; serviceStatus.dwWin32ExitCode=NO_ERROR; serviceStatus.dwServiceSpecificExitCode=0; serviceStatus.dwCheckPoint=estado++; serviceStatus.dwWaitHint=100; SetServiceStatus(interfaz_al_SCM,&serviceStatus); reactivarProceso(); serviceStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS; serviceStatus.dwCurrentState=SERVICE_RUNNING; serviceStatus.dwControlsAccepted=SERVICE_CONTROL_INTERROGATE |SERVICE_ACCEPT_STOP |SERVICE_ACCEPT_PAUSE_CONTINUE |SERVICE_ACCEPT_SHUTDOWN; serviceStatus.dwWin32ExitCode=NO_ERROR; serviceStatus.dwServiceSpecificExitCode=0; serviceStatus.dwCheckPoint=estado++; serviceStatus.dwWaitHint=100; SetServiceStatus(interfaz_al_SCM,serviceStatus); break; } Cada caso puede tener llamadas a diversas ... rutinas, según corresponda para realizar
  • 22. Instalador de un servicio char nombreServicio[]=“Srv_ProgAva"; //Así lo reconocerá el S.O. char nombreDisplay[]=“Servicio_ProgAva"; //Así lo veremos en pantalla. char pathServicio[]=“C:ProgAvaservicio.exe"; //Aquí está el .exe SC_HANDLE manejadorServicios; //Descriptor del manejador de servicios SC_HANDLE nuevoServicio; //Apuntador a nuestro nuevo servicio ENUM_SERVICE_STATUS datos[200]; int resume,bytesFaltantes,serviciosFaltantes,i; void main(void) { manejadorServicios=OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS); resume=0; for (i=0;i<20;i++) { resume=i; if (EnumServicesStatus(manejadorServicios,SERVICE_WIN32, SERVICE_STATE_ALL,&datos[0],sizeof(datos), &bytesFaltantes,&serviciosFaltantes,&resume)==NULL) { printf("(%d) Error!n",GetLastError()); else { printf("%d Servicio (Nombre) --> %sn",i,datos[i].lpServiceName); printf("%d Servicio (Display) -> %sn",i,datos[i].lpDisplayName); } }
  • 23. Instalador de un servicio char nombreServicio[]=“Srv_ProgAva"; //Así lo reconocerá el S.O. char nombreDisplay[]=“Servicio_ProgAva"; //Así lo veremos en pantalla. char pathServicio[]=“C:ProgAvaservicio.exe"; //Aquí está el .exe SC_HANDLE manejadorServicios; //Descriptor del manejador de servicios SC_HANDLE nuevoServicio; //Apuntador a nuestro nuevo servicio ENUM_SERVICE_STATUS datos[200]; int resume,bytesFaltantes,serviciosFaltantes,i; void main(void) { manejadorServicios=OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS); resume=0; for (i=0;i<20;i++) { resume=i; if (EnumServicesStatus(manejadorServicios,SERVICE_WIN32, SERVICE_STATE_ALL,&datos[0],sizeof(datos), &bytesFaltantes,&serviciosFaltantes,&resume)==NULL) { printf("(%d) Error!n",GetLastError()); else { printf("%d Servicio (Nombre) --> %sn",i,datos[i].lpServiceName); printf("%d Servicio (Display) -> %sn",i,datos[i].lpDisplayName); } }
  • 24. Instalador de un servicio char nombreServicio[]=“Srv_ProgAva"; //Así lo reconocerá el S.O. char nombreDisplay[]=“Servicio_ProgAva"; //Así lo veremos en pantalla. char pathServicio[]=“C:ProgAvaservicio.exe"; //Aquí está el .exe SC_HANDLE manejadorServicios; //Descriptor del manejador de servicios SC_HANDLE nuevoServicio; //Apuntador a nuestro nuevo servicio ENUM_SERVICE_STATUS datos[200]; int resume,bytesFaltantes,serviciosFaltantes,i; void main(void) { manejadorServicios=OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS); resume=0; for (i=0;i<20;i++) { resume=i; if (EnumServicesStatus(manejadorServicios,SERVICE_WIN32, SERVICE_STATE_ALL,&datos[0],sizeof(datos), &bytesFaltantes,&serviciosFaltantes,&resume)==NULL) { printf("(%d) Error!n",GetLastError()); else { printf("%d Servicio (Nombre) --> %sn",i,datos[i].lpServiceName); printf("%d Servicio (Display) -> %sn",i,datos[i].lpDisplayName); } }
  • 25. Ejemplo del instalador de un servicio char nombreServicio[]=“Srv_ProgAva"; char nombreDisplay[]=“Servicio_ProgAva"; char pathServicio[]="E:ProgAvaservicio.exe"; SC_HANDLE manejadorServicios; //Descriptor del manejador de servicios SC_HANDLE nuevoServicio; //Apuntador a nuestro nuevo servicio ENUM_SERVICE_STATUS datos[200]; int resume,bytesFaltantes,serviciosFaltantes,i; void main(void) { manejadorServicios=OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS); resume=0; for (i=0;i<20;i++) { resume=i; if (EnumServicesStatus(manejadorServicios,SERVICE_WIN32, SERVICE_STATE_ALL,&datos[0],sizeof(datos), &bytesFaltantes,&serviciosFaltantes,&resume)==NULL) { printf("(%d) Error!n",GetLastError()); else { printf("%d Servicio (Nombre) --> %sn",i,datos[i].lpServiceName); printf("%d Servicio (Display) -> %sn",i,datos[i].lpDisplayName); } }
  • 26. Ejemplo del instalador de un servicio char nombreServicio[]=“Srv_ProgAva"; char nombreDisplay[]=“Servicio_ProgAva"; char pathServicio[]="E:ProgAvaservicio.exe"; SC_HANDLE manejadorServicios; //Descriptor del manejador de servicios SC_HANDLE nuevoServicio; //Apuntador a nuestro nuevo servicio ENUM_SERVICE_STATUS datos[200]; int resume,bytesFaltantes,serviciosFaltantes,i; void main(void) { manejadorServicios=OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS); resume=0; for (i=0;i<20;i++) { resume=i; if (EnumServicesStatus(manejadorServicios,SERVICE_WIN32, SERVICE_STATE_ALL,&datos[0],sizeof(datos), &bytesFaltantes,&serviciosFaltantes,&resume)==NULL) { printf("(%d) Error!n",GetLastError()); else { printf("%d Servicio (Nombre) --> %sn",i,datos[i].lpServiceName); printf("%d Servicio (Display) -> %sn",i,datos[i].lpDisplayName); } }
  • 27. Ejemplo del instalador de un servicio char nombreServicio[]=“Srv_ProgAva"; char nombreDisplay[]=“Servicio_ProgAva"; char pathServicio[]="E:ProgAvaservicio.exe"; SC_HANDLE manejadorServicios; //Descriptor del manejador de servicios SC_HANDLE nuevoServicio; //Apuntador a nuestro nuevo servicio ENUM_SERVICE_STATUS datos[200]; int resume,bytesFaltantes,serviciosFaltantes,i; void main(void) { manejadorServicios=OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS); resume=0; for (i=0;i<20;i++) { resume=i; if (EnumServicesStatus(manejadorServicios,SERVICE_WIN32, SERVICE_STATE_ALL,&datos[0],sizeof(datos), &bytesFaltantes,&serviciosFaltantes,&resume)==NULL) { printf("(%d) Error!n",GetLastError()); else { printf("%d Servicio (Nombre) --> %sn",i,datos[i].lpServiceName); printf("%d Servicio (Display) -> %sn",i,datos[i].lpDisplayName); } }
  • 28. Ejemplo del instalador de un servicio if((nuevoServicio=CreateService(manejadorServicios, nombreServicio,nombreDisplay,SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,pathServicio, NULL,NULL,NULL,NULL,NULL))==NULL) printf("(%d) Error al crear el servicio %sn", GetLastError(),nombreServicio); else printf("Servicio %s creado!!!n",nombreServicio); getchar(); } //main
  • 29. ‘¡¡¡Demonios!!!’ … “Linux Daemons” • Son procesos que se activan al iniciar la operación del “kernel” y finalizan cuando se apaga el sistema. • No requieren interacción con el usuario, por lo tanto son procesos que no tienen terminal de control y por eso se dice que se ejecutan en “background”. • Debido a lo anterior, el flujo de salida y de errores debe tratarse de manera particular.
  • 30. Señales y demonios • Los procesos tipo “daemon” siguen un protocolo específico para interactuar con el “kernel” y con las aplicaciones que los requieren. • Las interfaces hacia un “daemon” pueden ser (entre otros): – Archivos. – “Pipes”. – “Sockets”. – Señales. • Su funcionamiento es similar al de un servicio en Windows, pero tienen una codificación distinta.
  • 31. Señales de demonios • Las señales son eventos (interrupciones) de “software”. • Son útiles para procesar eventos asincrónicos (teclado, red, archivos, etc). • La definición de señales es particular de la implementación del sistema operativo, pero en el archivo <signal.h> se pueden encontrar las definiciones estándares. • Un programa define rutinas específicas para capturar señales, en él establece sus reglas de procesamiento; para esto se utiliza la directiva: void (*signal(int signo, void (*func)(int)))(int);
  • 32. Señales • Al recibir una señal, un proceso puede hacer tres cosas: – Ignorar la señal. – Atrapar la señal y procesarla mediante su rutina de atención (“handler”); aunque se debe saber que hay señales que no se puede interceptar, tal como SIGKILL y SIGSTOP. – Pasar el evento al sistema operativo para que se realice su procesamiento de facto. • Para enviar una señal a un proceso se pueden utilizar un par de rutinas: int kill(pid_t pid, int signo); int raise(int signo); • Igualmente se puede enviar una señal desde una terminal utilizando el comando kill y conociendo en número de proceso.
  • 33. “Signal handler” #include <stdio.h> #include <stdlib.h> #include <signal.h> static void signalHandler(int signo) { //El argumento es el número de la señal if (signo == SIGUSR1) printf("received SIGUSR1n"); else if (signo == SIGUSR2) printf("received SIGUSR2n"); else if (signo == SIGINT) printf("CTRL-C!!!n"); else if (signo == SIGQUIT) { printf("Bye, bye.n"); exit(0); } else if (signo == SIGKILL) printf("It will be not so easy to get rid of me!!!n"); else printf("received signal %dn", signo); } int main(void) {
  • 34. Catálogo de señales Señal Acción de facto Descripción SIGABRT “Terminate+core” Esta señal se genera al invocar la rutina abort(…) {<stdlib.h>} SIGALRM “Terminate” Es invocada cuando expira el tiempo establecido por la rutina alarm(…) {<unistd.h>. También está relacionada con la rutina setitimer(…). SIGCHLD “Ignore” Se genera en el proceso padre cuando un proceso hijo termina o se detiene. SIGCONT “Continue/ignore” Esta señal es útil para reactivar un proceso que ha sido detenido previamente SIGHUP “Terminate” Esta señal se envía a un proceso en caso de detectarse que su terminar controladora se ha desconectado o cerrado. SIGINT “Terminate” Esta señal se genera al detectarse la pulsación de la combinación de teclas <Control-C>. SIGIO “Terminate/ignore” Se activa para indicar la detección de un evento asincrónico de E/ S. SIGKILL “Terminate” Es una de las que no es interceptable, siempre útil para brindar una forma segura para finalizar un proceso. SIGPIPE “Terminate” Esta señal marca un error en el mecanismo de comunicación entre procesos a través de “pipes”.
  • 35. Catálogo de señales Señal Acción de facto Descripción SIGQUIT “Terminate+core” Es similar a SIGINT, pero adicionalmente genera un archivo de depuración de errores (“core dump file”). SIGSTOP “Stop process” No puede ser interceptada ni ignorada, es la forma correcta de finalizar un proceso. SIGTERM “Terminate” Esta señal es generada por el comando “kill” de facto, sin parámetros adicionales. SIGURG “Ignore” Notificación de un evento urgente, como la llegada de datos a través de una interfaz de red. SIGUSR1 “Terminate” Su aplicación está definida por el programador/usuario. SIGUSR2 “Terminate” Su aplicación está definida por el programador/usuario. SIGVTALRM “Terminate” Esta señal se genera por la finalización de un contador virtual asociado con la función setitimer(…). SIGXCPU “Terminate+core” Esta señal se canaliza al proceso cuando él excede el uso de CPU que le ha sido establecido en el sistema.
  • 36. Estructura de un demonio #include <stdio.h> #include <fcntl.h> #include <signal.h> Tres rutinas son esenciales: #include <unistd.h> • La rutina principal de inicialización general. rutina1 (…) { • Una rutina para inicializar el … funcionamiento del “daemon” } • La rutina para recibir señales y procesarlas en forma conveniente. rutina2 (…) { … Se pueden tener rutinas adicionales de } … soporte e invocaciones a void signalHandler(int sigNum) { bibliotecas sin restricciones. switch(sigNum) { case SIGHUP: … break; case SIGTERM: … break;
  • 37. daemonize() • Modificar la máscara de creación de archivos invocando a la rutina umask para evitar heredar dicha característica del proceso principal. • Clonar el proceso mediante un fork y hacer que el proceso padre finalice. Esto es útil para hacer simular al “shell” que el proceso ya terminó, desasociarlo de su terminal, de su usuario/grupo y renunciar a ser el proceso interactivo (“group leader”). • Invocar setsid para crear una nueva sesión de trabajo logrando tres cosas: convertirse en el proceso líder de la sesión, convertirse en el proceso líder de grupo y renunciar a tener una terminal controladora. • Cambiar el directorio de facto de trabajo al raíz, evitando así recibirlo heredado del padre. • Cerrar todos los descriptores de archivo que pudo haber heredado del proceso padre. • Asignar los descriptores de archivo 0, 1 y 2 a /dev/null (stdin, stdout, stderr). • Asegurarse de ser la única instancia del demonio activo. • Interceptar señales relevantes y canalizarlas a una rutina de atención.