Out Of Bounds Exception!

Mi lugar de irreflexión y algo de programación

Los códigos WTF: Reloaded

Sabíamos que este día llegaría: el día en que volvería a tener material para tratar este interesante tema de los códigos sangraojos, quemaneuronas, matagatitos…

El caso es que vuelvo a tener trabajo y dado que en todas las empresas siempre hay algún proyecto marrón/con-código-hecho-hasta-por-el-de-recursos-humanos, he decidido dedicar otra entrada a estas pequeñas perlas que algunos programadores nos dejan preparadas para nuestro regocijo y deleite personal.

Algo que me dió la primera sensación de deja vu con mi otro trabajo fue las comprobaciones-null sin sentido, y dado que a simple vista ya vi unas cuantas, hice una búsqueda del texto “==null” en el proyecto…

Quitando las copias del repositorio, se nos quedan en la mitad: 135 comprobaciones. Ahora vamos a quitar las que realmente son útiles: a ojo de buen cubero he descartado unas (vamos a ser generosos) 50, por lo que nos quedan 85. ¿Os parecen pocas?

Tengamos ahora en cuenta, obviando su utilidad, que la comentaré luego, cuántas veces se llama a las funciones que las tienen: onDraw, onAccuracyChanged, onSensorChanged… por mencionar sólo algunas. Y ¿qué tienen de especial estas funciones? Que se llaman bastante a menudo (de hecho onDraw se llamará MUCHAS veces por segundo: cada vez que repintemos la pantalla)

En lo referente a la utilidad, espero que este par de fragmentos lo aclaren totalmente:

protected void onDraw(Canvas canvas) {
    	if (canvas==null) return;

public Matrix(Matrix m) {
        if (m==null) throw new NullPointerException();

        set(m.a1,m. a2, m.a3, m.b1, m.b2, m.b3, m.c1, m.c2, m.c3);
}

¿Hace falta decir más? Por si acaso, lo aclaro: en el primer caso tenemos el modo paranoico-on donde comprobamos hasta lo más básico; en el segundo caso es mucho más divertido, en vez de dejar ejecutar y que pegue el NullPointerException el método solito, mejor vamos a forzarlo, ¡que es más diver! 😀 (SERIOUSLY).

Vale, quizá yo sea un poco maniático y hacer alguna que otra comprobación inútil (en este caso, bastantes) en un if no sea para tanto… ¿no? Vamos a comprobarlo:

Cada if tarda una media de 40ns (en un iMac con un procesador i5 a 2.5 GHz), lo cual hace que tengamos que ejecutar 25000 ifs (sí, son muchos) para tener un delay de un milisegudo.

Ahora tengamos en cuenta que estamos en un sistema operativo móvil, donde aparentemente (yo soy el primer sorprendido) un if tarda una media de 600ns en un tablet Asus Transformer TF101 (procesador Dual-core 1 GHz Cortex-A9) y unos bonitos 1200ns de media en un “anticuado” Nexus One (procesador 1 GHz Qualcomm Scorpion).

Con lo cual la cosa cambia bastante, concretamente a 1ms cada 1666 ifs para el Asus y a 1ms cada ¡833 ifs! Esos ya no son tantos, ¿eh?

Vale, ahora calculemos cuántas veces se puede llamar al método onDraw en una aplicación normalita: pongamos unos 60 cómodos fps, lo cual implica que el método se va a llamar 60 veces cada segundo, habiendo unos 50 ifs que se llaman en este o en otros métodos (llamados por el onDraw), hace que cada segundo, haya 3.6ms de delay en inútiles comprobaciones.

Siendo realistas no es mucho, pero los datos son aproximados, quizá de igual teniendo 50 comprobaciones inútiles, pero hay que tener en cuenta también otros terminales menos potentes, métodos que ya se tomen su tiempo para dibujar la interfaz, muchas más comprobaciones (se han dado casos, si), etc.

Con lo cual, no hace falta que empeceis a quitar ifs de vuestras aplicaciones, pero sí que es bueno tener en cuenta el coste de cada llamada en funciones de dibujado.

Dejando a un lado las cuentas de la abuela, sigo con algunos ejemplos más divertidos:

public abstract class PaintableObject {
    private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);

    public PaintableObject() {
        if (this.paint==null) {
            this.paint = new Paint();
            this.paint.setTextSize(16);
            this.paint.setAntiAlias(true);
            this.paint.setColor(Color.BLUE);
            this.paint.setStyle(Paint.Style.STROKE);
        }
    }

Pos mu’ bien

——-

Este es que es “por si acaso”, no vaya a ser que los arguments vayan con retaso, ¡oiga!

@Override
public void onActivityCreated(Bundle savedInstanceState) {
	super.onActivityCreated(savedInstanceState);
	if(getArguments()!=null){
		whatever=(Whatever) getArguments().get(Constants.KEY_Whatever);
		updateWhatever(whatever);
	}
	
}

public void updateWhatever(Whatever whatever){
	whatever=(Whatever) getArguments().get(Constants.KEY_Whatever);
	if(whatever!=null && whatever.getId()!=null)
	(...)
}

———–

Este es de un linear layout en un xml sin el atributo orientation (por defecto es horizontal). Entonces cada vez que se pinta, ¡pues le cambiamos la orientación! Así de simple.

    
<LinearLayout
        android:id="@+id/apartado_row_llContent"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="26dp"
        android:layout_marginRight="26dp"
        android:paddingTop="5dp"/>
(...)

parent.setOrientation(LinearLayout.VERTICAL);

————–

Por si acaso explico que isChecked() y setChecked(boolean) son un “getter” y “setter” de la misma variable.

new OnClickListener() {

	@Override

	public void onClick(View v) {

		if (twitter.isChecked()) {
	
			if (!loggedTwitter) {
	
				ShareUtils.showTwitterAuthDialog(...)
	
			} else {
	
				twitter.setChecked(true);
	
			}
	
		} else {
			twitter.setChecked(false);
	
		}
	}
}

wat?

————

Este último es mi favorito, aunque es una chorrada como una casa xD

moverAguja((loc.getSpeed() * 3600) / 1000);

Es que las fracciones no se le daban bien en el cole.

Codeando un servidor web en python para administrar programas remotamente (y III)

Bueno, últimamente he andado algo liado con trabajos, terminar la carrera, PFC y demás, así que no he podido dedicar nada de tiempo a mi querido servidor en python.

No obstante he subido el proyecto a Google Code para manejarlo desde ahí, así que ya que estoy pongo la url para los interesados. También lo añado a la sección de descargas

http://code.google.com/p/remote-process-management/

Si alguien está interesado en participar que me envíe un mail y tan ricamente le doy permisos.

PD: Perdón por las chapucillas, un día de estos lo estructuro todo bien y todo 😀

Un saludo.

Codeando un servidor web en python para administrar programas remotamente (II)

Por si te perdiste la parte 1.

Bueno, voy a continuar con el programa que empezamos en el post pasado. Lo que habría que hacer a continuación es crear una clase para el manejo de procesos y añadir diversos métodos a nuestra clase principal para controlarlos. Empecemos con la nueva clase:

En mi caso se va a llamar ProcessManager (muy original, ¿eh?) y va a tener una clase interna para manejar la entrada/salida del processo con un thread:

class ProcessManager:
    class ProcessReaderThread ( threading.Thread ):
    
        def __init__ ( self, subprocess):
            self.proc = subprocess
            self.alive = True
            self.buffer = list()
            threading.Thread.__init__ ( self )
    
        def run ( self ):
            while self.alive:
                output = self.proc.stdout.readline().strip()                
                self.buffer.append(output)
                
        def stop (self):
            self.alive = False
            
        def tell (self, cmd):
            self.proc.stdin.write('%s\n' % cmd)
            self.buffer.append(cmd)            

El constructor acepta un objeto subprocess (que veremos a continuación), inicializa el buffer de salida y crea la variable alive que determinará cuándo un proceso está o no en ejecución.
El método run se ejecuta para arrancar nuestro thread y lee la salida estándar del proceso mientras que alive sea true.
El método stop hace que alive sea false por lo que ya no se leerá más de la salida del proceso.
El método tell pasa un comando a la entrada estándar del proceso.

Además de esta clase interna, ProcessManager tendrá los siguientes métodos:

    def __init__ (self, name, path, processName):
        self.name = name
        self.path = path
        self.processName = processName
        self.process = None
        self.thread = None

Método constructor de la clase que toma como parámetros el nombre, ruta y proceso que sacamos de nuestro fichero de programas. Las variables process y thread se (auto)explican ahora.

El método startProcess iniciará el proceso en cuestión:

    def startProcess(self):
        self.process = subprocess.Popen(self.path,
                                stdin=subprocess.PIPE,
                                stdout=subprocess.PIPE,
                                )
        
        #Start a different thread to read process's output
        self.thread = self.ProcessReaderThread(self.process, self.log)
        self.thread.start()

Básicamente utilizamos la clase subprocess para abrir el proceso indicándole que tanto la entrada como la salida estándar las administraremos nosotros. Posteriormente creamos un nuevo thread y le pasamos este descriptor de proceso para que se encargue de él. Por tanto las variables process y thread servirán para controlar tanto el thread “lector/escritor” como el proceso en sí.

Obviamente, como “todo lo que tiene un principio, tiene un final Neo“:

    def killProcess(self):
        self.thread.stop()
        try:
            self.process.terminate()
        except:
            pass

Este método símplemente dirá al thread que deje de leer/escribir en el proceso y después terminará éste.

Nuestro método tell servirá para que la clase principal del programa lance los comandos que quiera que reciba el proceso

    def tellProcess(self, cmd):
        try:            
            self.thread.tell(cmd)
        except:
            pass

Básicamente llamará a la función ya vista de la clase interna. Nota: aquí hay un pequeño bug (solucionado en la versión que pondré para descarga) por el cual, si el proceso es cerrado sin llamar al método de esta clase (por ej: haciendo un exit si el programa es un terminal) al intentar ejecutar un comando, saltará una excepción, por lo tanto habría que comprobar si el proceso de verdad está corriendo y, si no, terminarlo.

Finalmente nos quedan un par de métodos básicos:

    def isRunning(self):
        if self.thread:
            return self.thread.alive
        
        return False
    
    def getOutputBuffer(self):
            return self.thread.buffer

Y con esto ya tendríamos nuestro manejador de procesos. A continuación pongo los nuevos métodos que tendrá nuestra clase principal para lidiar con todo esto y también haremos que nuestro servidor acepte peticiones POST para que se pueda manejar desde fuera.

Empezamos con las peticiones POST en la clase ServerHandler

    def do_POST(self):
        try:            
            form = cgi.FieldStorage(
            fp = self.rfile, 
            headers = self.headers,
            environ = {'REQUEST_METHOD':'POST',
                       'CONTENT_TYPE':self.headers['Content-Type'],
                      })
                    
            if len(form.keys()) > 0:
                field = form.keys()[0]
                action = field.split("_")[0]
                name = field.split("_")[1]
                        
                if action == 'cmd':
                    if len(form[field].value) > MAX_CMD_LENGTH:
                        self.log_alert("%s" % OVERFLOW_ATTEMPT, len(form[field].value))
                    executeCommand(name, form[field].value[:MAX_CMD_LENGTH], self.client_address[0])
                elif action == 'switch':
                    switchProgram(name)
                            
                self.send_response(200)
                self.send_header('Content-type', 'text/html')
                self.end_headers()
                self.wfile.write(makeHtml())
                return
            
        except Exception, err :
            if DEBUG: print 'Exception in POST: ' + str(err)
            self.send_error(500)        
            return 

Dado que nuestro html es muy listo y en el valor de los botones se incluye el nombre del proceso, nos bastará con coger los parámetros POST suministrados (con el cgi.FieldStorage) y hacer un split para tener la acción a realizar y el nombre del proceso sobre el cual hacerlo.
Una vez tengamos esto diferenciaremos las dos opciones actuales (switch* para cambiar de ON a OFF y viceversa; cmd para ejecutar un comando) y llamaremos a uno u otro método.
*Nótese que cometí el error de poner dos botones y hacer un switch, lo cual no tiene sentido, pero lo arreglaré en la siguiente versión.

Vamos ahora con el método de switch (que más tarde tendrá que aceptar un parámetro para ver si queremos encenderlo o apagarlo):

def switchProgram(name):
    
    global programs
    for program in programs:
        if program['name'] == name:
            #Create a new manager if there's noone
            if not program['manager']:
                program['manager'] = ProcessManager(program['name'], program['path'], program['process'])
                
            if not program['manager'].isRunning():
                if DEBUG: print "Turning ON " + name 
                program['manager'].startProcess()
            else:
                if DEBUG: print "Turning OFF " + name 
                program['manager'].killProcess()
                
            break

Básicamente cogemos nuestra lista de programas y buscamos el que nos piden por parámetro (quizá se podría agilizar esto usando un diccionario, así que lo apuntaré para futuras revisiones). Una vez encontrado miraremos a ver si alguna vez durante la ejecución hemos creado un manager para él (si no, lo creamos), y llamaremos a startProcess o killProcess dependiendo de si está apagado o encendido respectivamente.

Finalmente nuestro método executeCommand hará lo siguiente:

def executeCommand(name, command):
    
    global programs
    
    for program in programs:
        if program['name'] == name and program['manager']:
            program['manager'].tellProcess(command)

Buscamos el programa que nos piden y, si tiene un manager, le pasamos el comando.

Y ya está, más o menos por encima he explicado como crear un programa de unas 400 loc para administrar nuestros procesos. He obviado algunas partes porque se meten más con html que con el programa en sí, pero realmente son muy sencillas (quizá tediosas) de hacer.

Esto sería una versión alpha si acaso, aún necesitaríamos añadir logs, autenticación, protección contra XSS, lista de baneados, un nombre decente y algunas mejoras más que ya iré viendo y posteando según las vaya incluyendo. El programa lo pondré para descarga cuando considere que está medianamente presentable (está hecho en dos tardes, así que imaginad).

Un saludo.

Codeando un servidor web en python para administrar programas remotamente (I)

Tras una temporadilla considerable sin pasarme por estos lares a actualizar con alguna aventura de las mías, hoy, por fin, vuelvo a las andadas.

Y lo hago nada más y nada menos que con un programa que se me ocurrió en una de esas tardes ociosas típicas: un proceso que actúe como servidor web, mostrando una página html pseudodinámica (luego explico por qué el ‘pseudo’) que permita a un usuario administrar (iniciar, detener y comunicarse) una serie de programas configurables.

La idea me vino debido a que mis compañeros de clase y yo solemos jugar a diversos juegos según la temporada, y muchas veces a uno le toca hacer de servidor para alguno en concreto, por lo que se hace algo pesado estar pendiente de cuando los otros quieren jugar y tú no quieres o no estás. Por lo tanto, creé este programa para evitarme eso, símplemente me basta con tener el pc encendido conectado a internet y el servidorcillo web corriendo.

Tras esta pequeña introducción, vamos al lío. Primero hay que elegir el lenguaje de programación, el cual tiene que cumplir, al menos, dos requisitos: mínimo consumo de memoria y facilidad para lo que queremos hacer. Expongo a continuación mis 3 lenguajes preferidos y vamos descartando:

C++ no es precisamente trivial para abrir sockets ni en el manejo de procesos sobre Windows, por no hablar de que la programación sobre esta plataforma, para mí, es horrible, así que ni me lo planteo.
Java y su consumo de memoria no es precisamente óptimo y, aunque probablemente se pueda configurar la máquina virtual para que no ocupe esos odiosos 50 MB de ram para hacer una suma, quiero algo simple y lo quiero ya, así que descartado.
Python… qué puedo decir de mi amado Python, es más simple que el mecanismo de un chupete, consume poco más que un programa en C y además es posible que el resultado sea portable a Linux y todo. No se hable más.

¡Y empieza el codeo! Empecemos con la clase principal, que incluye el sevidor (nótese que soy algo nuevo en Python, así que es probable que muchas cosas se puedan hacer mejor o más rápido; si es así decídmelo y lo actualizo con mucho gusto).

Función main que es la que arranca todo el tema (llamada cuando se arranca el script):

def main():
    try:
        print 'Programs loaded...'
        loadProgramList()
        server = HTTPServer(('', 8080), ServerHandler)
        print 'Started httpserver...'
        server.serve_forever()
    except KeyboardInterrupt:
        print '^C received, shutting down server'
        server.socket.close()

if __name__ == '__main__':
    main()

Carga la lista de programas y arranca el servidor, simple, ¿no?

La función loadProgramList símplemente va a abrir un archivo de programas que tiene el siguiente formato (nótese que cada campo está separado por una tabulación, no por un espacio):

#NOMBRE RUTA PROCESO DESC
TaskManager V:\Window$\System23\taskmgr.exe taskmgr Programa bonito

La función es la que sigue:

def loadProgramList():
    file = open('programs')
    
    global programs
    programs = list()
        
    for line in file:
        if line.find('#') != 0 and line != '':
            line = line.replace('\n','').split("\t")
            programs.append({'name':line[0], 'path':line[1], 'process':line[2], 'manager':None})
            
    return programs

Programs es una variable global en la que guardamos una lista donde cada programa es un diccionario clave-valor con las propiedades extraídas del fichero y un extra, manager, que luego explicaré.

Vamos a la clase del ServerHandler:

class ServerHandler(BaseHTTPRequestHandler):
    
    def do_GET(self):
        try:
            if not self.path.endswith('favicon.ico'):                
                                   
                self.send_response(200)
                self.send_header('Content-type', 'text/html')
                self.end_headers()
                self.wfile.write(makeHtml())                    
                return
                
        except IOError:
            self.send_error(404,'File Not Found: %s' % self.path)
            return     

Algo simplificado, pero igualmente válido para explicar las bases. Cuando nos soliciten una página por get, contestamos con el resultado de la función makeHtml

Para terminar con la primera parte, veamos cómo es esta función:

def makeHtml():
    html = ''
    
    file = open('index.html')
    
    #load the html
    for line in file:
        html += line
            
    #find server's tags
    regex = re.compile(r' .*? ')
    tags = regex.findall(html)
    
    #replace server's tags
    for tag in tags:
        keyword = tag.replace('', '').replace('', '').strip()
        if keyword == ...
            content = ...
            html = html.replace(tag, content)
    return html

Vamos por partes, primero abrimos la página en html que hemos creado (con su css, javascript y demás ya hecho) y buscamos nuestras etiquetas personalizadas, que tendrán la forma <py>tag</py> donde ‘tag’ estará definido en el código (o, en caso de que en un futuro se quiera expandir esto, en un fichero). Ahora se sustituye cada una de las etiquetas por un contenido concreto, en mi caso haré que por cada programa se cree una etiqueta <li> para mostrar una serie de pestañas hechas con JQuery. Por otro lado debajo de esto añadiré, también para cada programa, un contenido concreto (varios botones, una caja de texto, etc) para el manejo de cada programa. En resumen, queda algo así:

El estilo ya es cosa de cada uno, yo como soy algo cutre lo he hecho lo más simple posible =P

En la parte 2 añadiré algunas mejoras y veremos cómo arrancar procesos y comunicarnos con ellos.

¡Un saludo!

El lío con Java y Bash

Me considero un Windowsero (no confundir con fanboy) de toda la vida, de hecho hasta hace apenas uno o dos años no sabía ni que existía Linux (qué le vamos a hacer) y cuando me lo presentaron obviamente no me gustaba: una interfaz “cutrilla”, mucho que teclear en la consola, dificultad para instalar/desinstalar cosas, pocos juegos (xD) y todas esas cosillas que un usuario de Windows dice (que no tienen por qué ser ciertas).

No obstante, una vez que le fui cogiendo el truco, me ha llegado a gustar y, a pesar de que no lo uso como SO principal, sí lo hago para trabajar, hacer el PFC o para trastear con temas de seguridad, scripting, etc. Es cuestión de gustos, para unas cosas me es más útil Windows y para otras Linux =) (no me voy a meter en para qué cosas es mejor uno u otro, cada cual que les saque el partido que quiera/pueda).

El caso es que últimamente estoy trasteando en un servidor Ubuntu con Tomcat (a.k.a. Servlets en Java) al que accedo mediante Kitty (un fork del famoso Putty), desde donde me dedico principalmente a toquetear una base de datos Mysql y a mirar algunos logs, nada del otro mundo.

Hace poco sacamos una nueva tarea en el scrum del proyecto que consistía en, dado un fichero multimedia (audio o vídeo), sacar la duración del mismo en el servidor. Como ya se usa ffmpeg en otra parte del servidor, decidí ver qué tal se haría así en vez de mediante Java (ya que para ello tengo entendido que se requieren librerías externas). Por tanto mi primera tarea era ver cómo me daba este valor el programa, lo cual es bastante simple (lo voy a mostrar paso a paso de cómo lo he ido haciendo, por lo que es normal que algún comando del principio no funcione xD):

ffmpeg -i video.3gp

Lo cual nos devuelve este tochaco:

ffmpeg version 0.8.git, Copyright (c) 2000-2011 the FFmpeg developers
  built on Jul 21 2011 08:29:21 with gcc 4.3.2
  configuration: --disable-yasm
  libavutil    51. 11. 0 / 51. 11. 0
  libavcodec   53.  8. 0 / 53.  8. 0
  libavformat  53.  6. 0 / 53.  6. 0
  libavdevice  53.  2. 0 / 53.  2. 0
  libavfilter   2. 27. 0 /  2. 27. 0
  libswscale    2.  0. 0 /  2.  0. 0
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x9ec4380] max_analyze_duration 5000000 reached at 5046000
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'ruta/video.3gp':
  Metadata:
    major_brand     : 3gp4
    minor_version   : 768
    compatible_brands: 3gp4mp413gp6
    copyright       :
    copyright-eng   :
  Duration: 00:00:05.28, start: 0.000000, bitrate: 91 kb/s
    Stream #0.0(eng): Video: mpeg4, yuv420p, 176x144 [PAR 1:1 DAR 11:9], 74 kb/s, 19.10 fps, 30 tbr, 1k tbn, 30 tbc
    Stream #0.1(eng): Audio: amrnb, 8000 Hz, 1 channels, flt, 12 kb/s
    Stream #0.2(eng): Data: mp4s / 0x7334706D, 0 kb/s
    Stream #0.3(eng): Data: mp4s / 0x7334706D, 0 kb/s
At least one output file must be specified

Donde se puede observar también que nos da un pequeño error en la última línea, dado que no le hemos especificado el archivo de salida ya que no nos interesa al querer extraer su información (si no, nos sobrescribiría el fichero o crearía un archivo igual que luego tendríamos que borrar). Pero bueno, al menos tenemos la duración, así que sólo falta extraerla del tochaco ese, por lo que vamos probando con algo simple:

ffmpeg -i video.3gp | grep Duration

Pero la sorpresa está en que no ocurre nada, vuelve a salir todo el chorrazo otra vez… Después de un rato devanándome los sesos descubro que el problema está en que la salida la hace por stderr, por lo que el pipe no lo coge como entrada, así que Googleando un poco encuentro un arreglo:

ffmpeg -i video.3gp 2>&1 | grep Duration

Que básicamente redirige la salida de error (2>) a la salida estándar (&1). Y, ahora sí, nos devuelve la línea en cuestión:

  Duration: 00:00:05.28, start: 0.000000, bitrate: 91 kb/s

Continuando un poco y encadenando algún comando más nos sale algo como esto:

ffmpeg -i video.3gp 2>&1 | grep Duration | awk '{print $2}' | sed 's/.\{4\}$//'

Que básicamente lo que hace es coger el segundo campo con awk y quitar los 4 últimos caracteres correspondientes al punto, los centisegundos y la coma separadora.

Si se prefiere no usar tantos pipes, con awk se llega a la misma solución (aunque se podría mejorar la expresión regular a algo como esto (\d\d:){2}\d\d, suponiendo que soporte el \d para dígitos y el {N} para repeticiones):

ffmpeg -i $1 2>&1 | awk '/Duration: [0-9][0-9]:[0-9][0-9]:[0-9[0-9]/ {print substr($2,1,8)}'

Pues qué bonito todo, la vida nos sonríe y esto ya está (o no ;)), sólo falta metérselo a Java para que obre su magia, básicamente algo así:

String command = "ffmpeg -i " + file.getAbsolutePath() + " 2>&1 | grep Duration | awk '{print $2}' | sed 's/.\\{4\\}$//'";
Process pr = Runtime.getRuntime().exec(command);

Posteriormente habría que coger el InputStream de nuestro objeto pr y leer de ahí (sí, es InputStream y no OutputStream, es que son unos cachondos =])

El problema (porque obviamente iba a haber más de uno) es que esto no funciona y el por qué, ahora obvio para mí después de pelearme con ello, es el siguiente: al llamar al método exec(comando) estamos ejecutando el programa del comando en cuestión (ffmpeg en este caso) y, dado que los pipes son propios de Linux y no de este programa, obviamente esto no puede funcionar. Por tanto una aproximación más válida sería algo como esto:

"bash -c \"ffmpeg -i " + file.getAbsolutePath() + " 2>&1 | grep Duration | awk '{print $2}' | sed 's/.\\{4\\}$//'\"";

Que básicamente ejecuta una shell con esos comandos donde los pipes si estarían permitidos. Aún así, nos suelta un error más:

-i: -c: line 0: unexpected EOF while looking for matching `"'
-i: -c: line 1: syntax error: unexpected end of file

Que probablemente se deba al lío de comillas, barras normales e invertidas y demás que tenemos ahí… Con lo cual aquí se me iluminó la bombilla y decidí que iba a optar por algo mejor: un script. Me parece una solución mucho mejor por varios motivos:

  • Es optimizable: si nuestro ejecutable (ffmpeg) se actualiza y hay que cambiar los comandos, encontramos otro mejor o símplemente vemos una solución más óptima basta con modificar el script sin modificar la entrada o salida de datos.
  • Es reutilizable: Puede que nos sirva para un uso particular o para otros proyectos más adelante.
  • Es cómodo: no tendremos que estar cogiendo el código del servidor y ejecutándolo para probar cosas, ya que basta con ejecutar el script y voilá. Asimismo por cada modificación no hay que estar haciendo deploy del servidor y demás…

La “desventaja” que veo sería la portabilidad, ya que habría que mover el script con el servidor en caso de que se despliegue en otro sitio. Además habría que vigilar la posibilidad de que fuese eliminado, de modo que se volviese a generar o al menos que no causase alguna excepción graciosa.

Y bueno, hasta aquí mi experiencia de estos días con Linux y Java, al final lo hice funcionar (a pesar de subestimar la tarea) y me he quedado a gusto =P

Agur!

Los robots(txt) hackeados

Y es que la curiosidad, cuando se junta con el aburrimiento, es muy mala compañera. Estando en un seminario sobre seguridad en aplicaciones web (el título real era “Hacking Web”, pero me suena un poco lamer, la verdad) andaba yo trasteando un poco con google y los parámetros en las búsquedas y en cómo podría encontrar sitios web que hubieran sido hackeados o defaceados por el típico “just 4 fun and curiosity”, el problema es que hay que ser bastante hábil juntando los comandos para que salgan resultados “limpios” ya que cualquier post que hable sobre el tema muy probablemente saldrá en los resultados…

Búsqueda en del término "hacked"

Es por esto que se me ocurrió ponerme en el lado de alguien que ha comprometido una web y está pensando cómo dejar su “huella” de una forma sutil. A la cabeza me vino un fichero que comparten bastantes sitios web:

Búsqueda en los archivos Robots.txt

Más de medio millón de resultados, así que “why not?”, por lo que probé con algunas combinaciones de términos para ver qué salía y he aquí algunos resultados, cuanto menos, curiosos:

Son pocos resultados, sí, veamos qué pasa si cambiamos la palabra clave:

Como es lógico y normal, toda esta búsqueda siguió por las típicas palabras clave de “password”, “passwd”, “admin”, etc. Donde se puede ver la práctica bastante común de intentar ocultar directorios con información sensible a los crawlers y bots de la red, dejando así información para los asaltantes que se molesten en comprobar este fichero. Una buena lectura al respecto la podemos encontrar en esta entrada del blog de Chema Alonso, al que, por cierto, le he cogido prestado el estilo de post por un día, espero que no le importe =P

En definitiva, una tarde entretenida buscando sitios que funcionan perfectamente sin saber que su fichero robots.txt ha sido vulnerado 🙂

El “exposed” de la consulta médica

Es curioso ver en las películas el típico asalto a una compañía o algún tipo de organización mediante una mezcla de ingeniería social, habilidades de James Bond, algo de suerte y un simple pendrive USB: el espía en cuestión se cuela en la organización, probablemente fingiendo ser un magnate interesado en los productos que allí se ofrecen y consigue ser atendido por, si no el jefe de la compañía, algún otro jefecillo no mucho menos importante que, naturalmente, dispone de un PC en su despacho que, estoy seguro, tiene acceso a todos y cada uno de los datos de la compañía, sin escatimar en pijadas de seguridad.

Por supuesto el espía conseguirá, de algún modo, hacer que este “inocente” jefecillo se levante de su trono para ir a atender algún asunto que requiera su atención, probablemente simulando algún tipo de fallo de seguridad en el edificio o distrayendo la atención con alguna visita preparada. En cualquier caso dicho jefecillo saldrá de su despacho no sin antes dejar su ordenador y pantalla encendidos y, evidentemente, sin bloquearlo o, en caso de hacerlo, probablemente cualquier pintas con un “transcodificador con 17 GHz y 200 mil millones de chips” (o chipotes como diría mi profesor de Arquitectura de Computadores) podrá crackear la contraseña en menos de 5 segundos…

En cualquier caso, nuestro espía habrá accedido a la información que contiene ese PC y que, como ya dije, le permitirá acceder a TODA la información de la empresa y hasta controlar el termostato del despacho de Jose Antonio, que no le gusta el calor y pone el aire a tope cada mañana.

Bueno, yo no soy ningún espía, no suelo llevar pendrives USB encima todo el día (sólo el 40% del tiempo), tampoco voy colándome en organizaciones o empresas para intentar asaltar ningún sistema, aunque sí que se kárate, mira qué bien. El caso es que hace unas semanas tuve que ir a la consulta médica (más concretamente a la enfermería, pero no os preocupéis que estoy como un roble) y la verdad es que la situación que se me planteo no podía ser más… peliculera y cutre a la vez.

Resulta que la enfermería estaba ocupada, así que pasamos al despacho del enfermero/doctor en cuestión. Me senté en la típica camilla mientras él miraba sus cosas en el ordenador, que casualmente tenía perfectamente visible casi en frente de mí, por lo que podía ver fácilmente lo que estaba haciendo. No obstante no me gusta mirar a la gente mientras hace cosas en su ordenador, así que me distraje viendo la cantidad de documentos y papeles que tenía en su estantería (y no pude evitar preguntarme cuántos contendrían información sensible; qué le voy a hacer si soy curioso). El caso es que cuando terminó empezó a preparar el material oportuno y se dio cuenta de que le faltaban un par de cosas, así que con un “ahora vengo” salió de la consulta y subió unas escaleras… y allí me quedé yo: con una pila de documentos de vete tú a saber quién o qué en frente y un ordenador sin bloquear y con la pantalla encendida a mi derecha…

Obviamente no hice nada malo (y aunque hubiera tenido un USB con alguna “utilidad chula” tampoco, para qué mentir), pero sí que, en los 3 minutos y pico que estuvo fuera, se me ocurrieron infinidad de “trastadas” que podría haber hecho, ainss. Lo peor de todo es que, tras volver, tuvo que irse otros 2 minutos más a por otra cosa, dejándome con el pensamiento en la cabeza de que $deity definitivamente me estaba poniendo a prueba.

Los códigos WTF

En la vida de todo programador (ya sea Informático, Teleco, de FP o mi abuela dándole a la tecla) llega un momento en el que uno se embarca (o le embarcan) en algún tipo de proyecto más o menos grande en el que, inevitablemente, va a tener que reutilizar código ajeno y/o trabajar con otros compañeros. También existe la posibilidad de encontrarte esta situación en códigos ajenos que encuentras por ahí, ya sean tutoriales, ejemplos, PoCs (pruebas de concepto), como porno escrito en C… Aunque con estos últimos (los publicados en Internet, no el porno) es bastante menos común, ya que normalmente uno se lo piensa un par de veces antes de publicar algo, ¿no? =P

Se cumpla una, otra o las circunstancias que sean, el caso es que aparece cerca ese momento en el que te va a tocar modificar el código de otro (o no) y, muy probablemente, comprender qué hace (esto normalmente sí), y es en este momento en el que la tensión crece, la piel se te pone de gallina y rezas a los dioses que conoces para que no te toque a ti…

A mí me tocó hace poco, así que decidí recopilar unos cuantos más que fuese viendo y hacer una entrada sobre ello, que para algo el blog es mío 😀

  • El primero es un código en C que encontré en un ejemplo de inyección de código en procesos:
    BOOL st=TRUE;
    do
    {
        if(strcmp(pInfo.szExeFile, "test.exe")==0)
        {
            myPid=pInfo.th32ProcessID;
            break;
        }
        Process32Next(processList, &amp;pInfo);
    }
    while(st!=FALSE);

    Obviando el hecho de que se le colaron algunos códigos HTML (incluido algún “&lt;” y “&gt;” en los include), el problema de este código es evidente: ¿para qué declarar un booleano que no usas?. Eso sin entrar a si es más o menos “elegante” el uso del break.

  • Este siguiente está en Java y es algo curioso:
    File f = new File (filename);
    if (f =! null){
        //...
    }

    Según mi parecer algunos programadores nos solemos poner algo paranoicos cuando llevamos muchas líneas de código escritas en un proyecto que no termina de funcionar, por lo que acabamos comprobando hasta lo más obvio, ¿cierto?

  • Más Java, este es de un tutorial de una librería con la que me he estado peleando últimamente:
    if(true) {
        //...
    }
    else {
        //...
    }

    Realmente no tengo nada que decir… podría entender que alguien escriba un código así si programa sobre algún IDE muy cutre o incluso con un simple editor de textos y, además, el proyecto en cuestión ha ido creciendo y esto lo ha implementado en varias fases. No obstante las risas te las echas igualmente cuando lo ves 🙂

  • Este es una aportación de mi amigo ccdg:
    public boolean containsStation(String station) {
        return stations == null ? null : stations.containsKey(station);
    }

    Este sí que es un verdadero código para decir “WTF??” ya que técnicamente no es posible convertir un null a un tipo de dato (ya sea boolean, int, float, o cualquiera, aunque sí a los objetos que los representan, como Boolean, Integer, etc.), no obstante parece ser que este programador se las ha apañado para “engañar” al compilador de Java y hacer que no detecte esta incompatibilidad de equipos, por lo que un código como el siguiente compilaría perfectamente, solo que tiraría un NullPointerException al ejecutarse:

    boolean a = true ? null : false;

    De hecho es curioso ver cómo un IDE como Eclipse nos señalará que “false” es código muerto, ya que siempre se va a cumplir que “true” es true, pero no se percatará de la asignación a no ser que sea demasiado obvia:

    boolean a = true ? null : null;

Y esto es todo amigos, espero que les hayan gustado y que no repitan ninguno en su trabajo =P

HelloBlog

Hola a tod@s!

Si has llegado hasta este blog probablemente me conozcas, así que no tendré que decir mucho de mí. No obstante, para los que no me conozcáis me llamo Alberto (a.k.a. Shyish), estudio Informática en la Carlos 3º de Leganés y he trabajado de programador en Deimos Space sobre la plataforma Android hasta septiembre de 2011. Me encanta la informática, las series, algo de manga y la música (clásica para concentrarme y rock para la fiesta :D).

El motivo de este blog no es otro que el de compartir algunas experiencias (más bien pocas) sobre temas de programación e informática en general que considere interesantes. Así mismo también aprovecharé para publicar algunos programas que haga en mi tiempo libre para que los uséis como bien os parezca.

Así que, sin más dilación, al lío!