#!/usr/bin/python
# -*- coding: iso-8859-15 -*-
"""
Sistema de procedimientos remotos del CdC. Superdemonio.
Autor  : Silvio Fernández Marín
Archivo: rpcdaemon.py
Resumen: Metaservidor que inicia los procedimientos de cdcrpc
Uso: Intentar usar el script de inicio rpcdaemon editanto cdcrpc.conf
Admite órdenes en línea de comandos, invocar sin parámetros para ver
MEJORAS A IMPLEMENTAR (por orden de prioridad?)
201- crear servidor para ejecutar script bash (no importante)(HECHO)
11- Transporte sobre ssl (https) (no importante)
2- restricición de conexciones entrantes por ip CIDR (HECHO)
3- revisar consistencia multihilo servidores rpc  (HECHO)
4- hacer funcion logs multiplataforma  (HECHO)
41 - demonizaqr metaservidor (HECHO)
42 - script inicio metaserver (HECHO)
5- comentar   (HECHO)
6- codificacion (HECHO)
7- implementacion multiproceso (en proceso de estudio)
8- configuracion fichero(s) xml (en proceso de estudio)
"""

#Modulos a importar ------------------------------------------------------------
import thread
import os
import sys
import time
import getopt        # opciones linea de comandos

#Anade al path el direcotorio donde estan las funciones comunes
sys.path.insert(0, '/home/centro/scripts/cdcrpc')
#funciones comunes que se usan en varias partes
import commonfunc
import comprueba_pid

# configure these paths:
PIDFILE = '/var/run/cdcrpc.pid'

#GESTION DE ARCHIVOS DE CONFIGURACION Y DE PARAMETROS LINEA DE COMANDO
def lee_info():
    """
    lee_info: funcion que comprueba opciones de linea de comandos
    (si hay) y obtiene la informacion necesaria para el monitoreo
    del archivo de configuracion, el archivo se le ha pasado como parámetro
    La sintaxis del archivo de configuracion debe ser la siguiente:
    #RUTA PARA LOS MODULOS PROPIOS
    MODULEPATH = /ruta/a/mis/modulos
    
    #FICHERO DE LOGS
    LOGS = /var/log/rpcdaemon
    #CODIFICACION EN EL ENVIO XMLRPC
    ENCODING = iso-8859-15
    #ENCODING = utf-8


    #MI IP, PARA CASO CON VARIOS INTERFACES, ELEGIR SOLO UNA
    MYIP = 127.0.0.1
    #MYIP = 172.16.3.10
    #MYIP = localhost

    #IPS PERMITIDAS
    ALLOWIP = 127.0.0.1
    ALLOWIP = 172.16.3.247
    ALLOWIP = 172.16.3.9
    ALLOWIP = 172.16.3.141
    ALLOWIP = 172.16.3.10
    ALLOWIP = 193.147.160.146
    #ALLOWIP = 172.16.0.0/24

    #SERVICE = PUERTO MODULO [UID]
    #SERVICE = 10222 modulo 1253
    #SERVICE = 7777    serverrpc
    SERVICE = 8888    makedoc
    SERVICE = 9999 creacorreo
    """
    
    # Inicializar mensajes de ayuda
    options = 'Opciones:\n'
    options = options + ' -m <modupath> ruta donde se encuentran nuestros módulos/servicios.\n'
    options = options + ' -e <enconding> codificación que se usa en el intercambio.\n'
    options = options + ' -s <server> ip, que usará mi servidor.\n'
    options = options + ' -a <allowips> ips que podrán acceder a los servicios, separarados por un espacio.\n'
    options = options + ' -p <ports> puertos donde se lanzarán los servicios, separados por un espacio.\n'
    options = options + ' -c <configuration file> Fichero de configuracion. Por defecto /etc/cdcrpc/cdcrpc.conf.\n'
    options = options + ' -k <servicios> servicios que se quiere iniciar, deben estar en el path adecuado.\n'
    options = options + ' -l <fichero de logs> ruta del fichero de logs del metaservidor.\n'
    options = options + ' Opciones -k -p deben usarse consecutivamente para cada servicio, deben coincidir en numero, ejemplo:\n'
    options = options + ' BIEN: xmlmultiserver.py -p 7777 -k servicio7777 -p 8888 - k servicio2\n'
    options = options + ' BIEN: xmlmultiserver.py -p 7777 -p 8888 -k servicio7777 -k servicio2\n'
    options = options + ' MAL:  xmlmultiserver.py -p 7777 -p 8888 -k servicio2 -k servicio7777\n'
    options = options + ' MAL:  xmlmultiserver.py -p 7777 -k servicio2 -p 8888 -k servicio7777\n'
    options = options + ' MAL:  xmlmultiserver.py -p 7777 -p 8888 -k serviciounico\n'
    options = options + ' BIEN: xmlmultiserver.py -p 7777 -p 8888 -k serviciounico -k serviciounico\n'
    

    usage = ' Uso: monitoreo.py [opciones] \n\n'
    usage = usage + options

    # Inicializar valores por defecto, cambiar si se desea
    global ports
    global modupath
    global encoding
    global allowips
    global host
    global configfile
    global servicios
    global server
    global ficherologs
    global debug
    
    ports = []
    modupath = '/root/cdcrpc'  
    encoding = 'iso-8859-1'
    server = 'localhost'
    allowips= []
    configfile ='/etc/cdcrpc/cdcrpc.conf'
    servicios = []
    ficherologs = '/var/log/metaserver.log'

    # Analizar posibles opciones
    try:
        (opts, args) = getopt.getopt(sys.argv[1:], 'h:p:m:e:s:a:c:k',['help', 'ports=', 'modupath=', 'encoding=', 'server=','allowips=', 'config=', 'servicios='])

    except getopt.error, why:
        commonfunc.log('getopt error: %s\n%s' % (why, usage), True, 'LOG_WARNING', ficherologs)
        
    try:
        for opt in opts:
            if opt[0] == '-h' or opt[0] == '--help':
                print usage
                sys.exit(0)
            #ojo  puede ser multiple
            if opt[0] == '-p' or opt[0] == '--ports':
                ports.append(opt[1:][0])
            if opt[0] == '-m' or opt[0] == '--modupath':
                modupath = opt[1:][0]
            if opt[0] == '-e' or opt[0] == '--encoding':
                encoding = opt[1:][0]
            if opt[0] == '-s' or opt[0] == '--server':
                server = opt[1:][0]
            #ojo puede ser multiple
            if opt[0] == '-a' or opt[0] == '--allowips':
                allowips.append(opt[1:][0])
            if opt[0] == '-c' or opt[0] == '--configfile':
                configfile = opt[1:][0]
            #ojo puede ser multiple
            if opt[0] == '-k' or opt[0] == '--servicios':
                servicios.append(opt[1:][0])
            if opt[0] == '-l' or opt[0] == '-logs':
                ficherologs = opt[1:][0]

    # Si opcion no valida, logeamos error y salimos
    except ValueError, why:
        commonfunc.log('Parámetro inválido \'%s\' para la opcion %s: %s\n%s' % (opt[1], opt[0], why, usage), True, 'LOG_ERR', ficherologs)
        #print 'Parametro invalido \'%s\' para la opcion %s: %s\n%s' % (opt[1], opt[0], why, usage)
     
    #Inicializamos variables múltiples no inicializadas
    if len(ports) == 0:
        ports = [8888]
    if len(allowips) == 0:
        allowips = ['']
    if len(servicios) == 0:
        servicios = ['server8888']
    if len(ports) != len(servicios):
        commonfunc.log('Debe haber el mismo numero de servicios que de puertos\n%s' % (usage), True, 'LOG_ERR', ficherologs)

    # si no exixte ficher0 de configuracion, logeamos error
    if os.path.exists(configfile)==False:
        commonfunc.log(' El archivo '+configfile+' no existe\n', False, 'LOG_ERR', ficherologs)
    else:
    # analizamos fichero de configuracion
        fileconf=open(configfile)

        #reiniciamos/ borramos valores por defecto,
        #listas las vaciamos, ponemos error en el resto
        ports = []
        encoding = 'error'
        server = 'error'
        modupath = 'error'
        ficherologs = 'error'  
        allowips= []
        servicios = []
        debug = 'error'
        
        # obtenemos la ip denuestro metaservidor del archivo de configuracion:
        for linea in fileconf:
            allowips = commonfunc.leeconf(linea,'ALLOWIP',allowips,2)
            server = commonfunc.leeconf(linea, 'MYIP', server,2)    
            modupath = commonfunc.leeconf(linea, 'MODULEPATH', modupath,2)
            encoding = commonfunc.leeconf(linea,'ENCODING', encoding,2)
            ports = commonfunc.leeconf(linea, 'SERVICE', ports, 2)
            servicios = commonfunc.leeconf(linea, 'SERVICE', servicios, 3)
            ficherologs = commonfunc.leeconf(linea, 'LOGS', ficherologs, 2)
            debug = commonfunc.leeconf(linea, 'VERBOSE', debug, 2)
            #print debug
            #a implementar
            #uids = commonfunc.leeconf(linea, 'SERVICE', uids, 4)
     
        #Errores de archivo de configuracion mal formado
        if server == 'error':
            commonfunc.log('No dirección metaservidor en el archivo de configuración\n', True, 'LOG_ERR', ficherologs)
        if ficherologs == 'error':
            commonfunc.log('No se encuentra la ruta del archivo de logs en el archivo de configuración\n', True, 'LOG_ERR', ficherologs)
        if len(allowips) == 0:
            commonfunc.log('Ninguna dirección permitida en el archivo de configuración\n', True, 'LOG_ERR', ficherologs)
        if modupath == 'error':
            commonfunc.log('No se encuentra la ruta de los módulos en el archivo de configuración\n', True, 'LOG_ERR', ficherologs)
        if encoding == 'error':
            commonfunc.log('No se encuentra que codificación usar en el archivo de configuración\n', True, 'LOG_ERR', ficherologs)
        if len(ports) == 0 or len(servicios) == 0:
            commonfunc.log('No se encuentra ningún par puerto-servicio en el archivo de configuración\n', True, 'LOG_ERR', ficherologs)
        if len(ports) != len(servicios):
            commonfunc.log('Archivo de configuración malformado, revise la configuración de los servicios\n', True, 'LOG_ERR', ficherolos)
 

def inicioServidor(host, ports, cerrojo, indice, allowips):
    """
    Invoca a la última línea de cada servicio que será la que inicie el servidor
    xml-rpc, asegura la integridad de los hilos y permite iniciar múltiples
    servicios concurrentemente, recibe la dirección del servidor, el puerto en
    el que el servicio escuchará, un cerrojo a efectos de sincronización de 
    hilos y una lista con las ips que tienes autorizado el acceso a ese 
    servicio.
    """
    #cerrojo que asegura que cada servidor se inicie en el puerto que debe
    # se libera en el error o en cada servidor, flag = para debug
    flag = cerrojo.acquire()
    port = int(ports)
    modules[indice].initServer(host, port, cerrojo, encoding, allowips)
  

def demoniza():
    """
    Demonizamos el programa, lo separamos de su tty y redirigimos las salidas,   
    tambien podemos fijar el usuario como el que se ejecutara (deshabilitado por 
    defecto). Tambien puede cambiar el directorio de ejecucion (recomendable,    
    deshabilitado por defecto) (hay que descomentar lineas para habilitar) 
    """
    # Redirigemos las salida y entrada estándar a /dev/null
    #if (hasattr(os, "devnull")):
    #    REDIRECT_TO = os.devnull
    #else:
    #    REDIRECT_TO = "/dev/null"
    if (debug != 'ON'):
        devnull = open('/dev/null', 'w')
        #COMENTAR LA LINEA INFERIOR PARA MOSTRAR DEBUG POR PANTALLA
        sys.stderr = sys.stdout = devnull
        
    #print 'DEBUG MODE ON'
    #definimos grupo y usuario
    #os.setegid(1000)
    #os.seteuid(1000)

    #hacemos el doble fork
    try: 
        pid = os.fork()
        if pid > 0:
            # exit first parent
            sys.exit(0)
    except OSError, e:
        commonfunc.logs('Ha fallado el primer fork: %d (%s)' % (e.errno, e.strerror), True, 'LOG_ERR', ficherologs)
      
    # fijamos permisos y directorio inicial
    #os.chdir("/")
    #os.setsid() 
    #os.umask(0)

    # segundo fork
    try:
        pid = os.fork()
        if pid > 0:
        # salimos del segundo padre, guardeamos pid
            open(PIDFILE,'w').write("%d"%pid)
            sys.exit(0)
    except OSError, e:
        commonfunc.logs('Ha fallado el segundo fork: %d (%s)' % (e.errno, e.strerror), True, 'LOG_ERR', ficherologs)
#COMIENZA LA EJECUCIÓN DEL SCRIPT  



#comprobamos si el proceso no se esta ejecutando ya
comprueba_pid.comprueba_pid('/var/run/cdcrpc.pid')

#gestionamos archivo de configuracion y parametros linea de comando
lee_info()

#demonizamos el programa
demoniza()

#print 'DEBUG MODE ON'
#print debug
#Modulo propios a importar, segun configuracion --------------------------------
#Anade al path el directorio donde estan nuestros modulos
sys.path.insert(0, str(modupath))


#los importamos asi porque estamos usando una string, no un modulo para llamarlos
#nos devuelve el identificador del modulo que usaremos aqui
modules = map(__import__, servicios)

i=-1
for puerto in ports:
    global cerrojo
    cerrojo = thread.allocate_lock()
    i = int(i+1)
    thread.start_new(inicioServidor,(server, puerto, cerrojo,i, allowips,))


while True:
    time.sleep(3600)
    #pass  
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="es">
	<head>
            <title>e-REdING. Biblioteca de la Escuela Superior de Ingenieros de Sevilla.</title>

                <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta name="description" content="Buscador de proyectos ETSI" />
<meta name="author" content="Daniel Callejo"/>
<meta name="author" content="Federico L&oacute;pez"/>
<meta name="author" content="Juli&aacute;n P&eacute;rez"/>
<meta name="author" content="Jos&eacute; Mar&iacute;a Vidal Vidal"/>
<base href="/bibing/proyectos/" /><link rel="shortcut icon" href="./favicon.ico" />
<link rel="stylesheet" href="./publico/css/estructura.css" type="text/css" />
<link rel="stylesheet" href="./publico/css/bootstrap.css" type="text/css" media="screen"/>
<link rel="stylesheet" href="./publico/css/enlaces-capas.css" type="text/css"  />
<link rel="stylesheet" href="./publico/css/pestanas.css" type="text/css"  /> 
<link rel="stylesheet" href="./publico/css/formularios.css" type="text/css" />
<link rel="stylesheet" href="./publico/css/lightbox.css" type="text/css"  />
<link rel="stylesheet" href="./publico/css/autocompleter.css" type="text/css"  />
<link rel="stylesheet" href="./publico/css/resultados.css" type="text/css"  />
<link rel="stylesheet" href="./publico/css/milista.css" type="text/css"  />
<link rel="stylesheet" href="./publico/css/explorador.css" type="text/css"  />
<link rel="stylesheet" href="./publico/css/ultimos.css" type="text/css"  />
<link rel="stylesheet" href="./publico/css/contactar.css" type="text/css"  />
<!-- <link rel="stylesheet" href="./css/print.css" type="text/css" media="print" /> -->
<script src="./publico/javascript/jquery-1.9.1.min.js" type="text/javascript"></script>
<script src="./publico/javascript/bootstrap.js" type="text/javascript"></script>

<script src="./publico/javascript/mootools-1.2.4-core.js" type="text/javascript"></script>
<script src="./publico/javascript/mootools-1-1.2.4.2-more.js" type="text/javascript"></script>
<script src="./publico/javascript/targetbl.js" type="text/javascript"></script>
<script src="./publico/javascript/mensajes.js" type="text/javascript"></script>
<script src="./publico/javascript/form.js" type="text/javascript"></script>
<script src="./publico/javascript/autocompleter/Observer.js" type="text/javascript"></script>
<script src="./publico/javascript/autocompleter/Autocompleter.js" type="text/javascript"></script>
<script src="./publico/javascript/autocompleter/Autocompleter.Request.js" type="text/javascript"></script>
<script src="./publico/javascript/domready.js" type="text/javascript"></script>

<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-8T1TSNC1QY"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());

  gtag('config', 'G-8T1TSNC1QY');
</script>



<script type="text/javascript">
function seleccionar_todo(){
   for (i=0;i<document.formulario_marcados.elements.length;i++)
      if(document.formulario_marcados.elements[i].type == "checkbox")
         document.formulario_marcados.elements[i].checked=1
}
function deseleccionar_todo(){
   for (i=0;i<document.formulario_marcados.elements.length;i++)
      if(document.formulario_marcados.elements[i].type == "checkbox")
         document.formulario_marcados.elements[i].checked=0
} 
</script>
	</head>
    <body style="min-width: 960px; background-color: #e2e2e2; height: 100%">	
		<a name="arriba"></a>
<div>
<div id="header">
    <table id="Tabla_01" height="105" border="0" cellpadding="0" cellspacing="0">
    <tr>
        <td>
            <img src="./publico/imagenes/cabecera/banner_new2_01.jpg" width="3" height="105" alt="">
        </td>
        <td>
            <img src="./publico/imagenes/cabecera/banner_new2_02.jpg" width="100" height="105" alt="">
        </td>
        <td width="100%" align="right"  style="min-width: 613px; background-repeat: no-repeat; background-position: top right; font-size: medium; font-weight: bold; color: white;">
            <table width="100%" height="105" border="0">
                <tr>
                    <td style=" vertical-align: top; width: 547px">
                        <!-- <a style="text-decoration: none" href="./"><img src="./publico/imagenes/cabecera/banner_new2_03.jpg"alt=""></a> -->
                        <a style="text-decoration: none" href="/bibing/proyectos/"><img src="./publico/imagenes/cabecera/banner_new2_03.jpg"alt=""></a>
                     </td>
                     <td  background="./publico/imagenes/cabecera/banner_new2_04.jpg" style="background-repeat: no-repeat; background-color: #c6d4e8;"><br><br><br>
                         &nbsp;
                        </td>
                    </tr>
             </table>
        </td>
    </tr>
    <tr style="border-top: 1px solid #ffffff;">
        <td colspan="3" id="menu_sup" style="font-size: small; text-align: right; background-color: #9c1f2f; vertical-align: bottom">
             
					<a href="/bibing/proyectos/" class="enlace " style=" color: #ffffff">Inicio&nbsp;&nbsp;|</a>
					<a href="/bibing/proyectos/acerca/" style=" color: #ffffff" class="enlace ">&nbsp;&nbsp;Acerca de&nbsp;&nbsp;|</a>
					
					<a href="/bibing/proyectos/contactar/" style=" color: #ffffff" class="enlace ">&nbsp;&nbsp;Contactar&nbsp;&nbsp;</a>
			 <!--       <a href="/bibing/proyectos/ayuda/" style=" color: #ffffff" class="enlace  ">&nbsp;&nbsp;Ayuda&nbsp;&nbsp;|</a> -->
					<!-- <form id="idioma" class=""  method="post" action="">
					<div class="inline" style="color: white">
					<input type="submit" class="tipo_letra " style=" color: #ffffff"name="idioma" value="Castellanossss" />&nbsp;&nbsp;
					</div>	
					</form> -->
			        </td>

    </tr>
    </table>
</div>
<br><br>
<div class="colmask rightmenu">
<div class="panel panel-default" style="margin:20px">
            <div class="panel-heading"><h4>DESARROLLO DE UN ENTORNO DE PRÃ�CTICAS PARA REDES MULTISERVICIO</h4><h5 style="color:grey"><span class="glyphicon glyphicon-user""></span> : <b>MARTÃ�N REDONDO, ALBERTO JESÃšS</b><br><span class="glyphicon glyphicon-book""></span>  :<b> Ingenier&iacute;a TelecomunicaciÃ³n</b></h5></div><div class="panel-body"><div class="contenido_proyecto"><div class="titulo2_explorador">Contenido del proyecto:</div><div class="ruta"><a href="use/abreproy/12106">Directorio ra&iacute;z</a>&nbsp;&nbsp;>&nbsp;&nbsp;<a href="use/abreproy/12106/direccion/ARCHIVOS%252F">ARCHIVOS</a>&nbsp;&nbsp;>&nbsp;&nbsp;<a href="use/abreproy/12106/direccion/ARCHIVOS%252Fservidor_xmlrpc%252F">servidor_xmlrpc</a>&nbsp;&nbsp;>&nbsp;&nbsp;<a href="use/abreproy/12106/direccion/ARCHIVOS%252Fservidor_xmlrpc%252Fcdcrpc.py%252F">cdcrpc.py</a></div><div class="listing"></div></div></div></div>
</div>
</div>

        
	</body>
 
 
<!-- Inicio Google Analytics -->
<!--
	<script type="text/javascript">
		var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
		document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
	</script>
	
	<script type="text/javascript">
		try {
		var pageTracker = _gat._getTracker("UA-7789620-1");
		pageTracker._trackPageview();
	} 
		catch(err) {}
	</script>
-->
<!-- Fin Google Analytics -->

</html>

