Desde hace mucho tiempo que quiero armar un pequeño y simple programa para gestionar las descargas desde canales de IRC.
En IRC las descargas son po DCC (Direct Client-to-client), segun wikipedia, la definicion seria:
Es un protocolo de IRC que permite interconectar dos peers (puntos) usando un servidor IRC como saludo (handshaking) para permitir intercambiar archivos o llevar acabo tareas no relacionadas con el chat. Una vez conectados, una típica sesión de DCC corre independiente del servidor IRC. Originalmente diseñado para ser usado con IrcII es ahora soportado por varios clientes IRC.
Mediante este protolo y la utilizacion del comando SEND, se puede hacer transferencias de archivos.
DCC SEND
El servicio de envío (SEND) permite a los usuarios enviarse archivo entre ellos. La especificación original para el saludo (handshake) no permitía al receptor conocer el tamaño total del archivo, pausar y reanudar (resume) la transferencia. Esto hizo que los clientes introdujeran sus propias extensiones para el saludo (handshake), muchas de las cuales lograron un amplio soporte.
El saludo (handshake) original consistía que el emisor enviaba el siguiente CTCP al destinatario:
DCC SEND <filename><ip><port>
Como en el DCC Chat, <ip> y <port> son la dirección ip y el puerto de la máquina emisora donde escuchara la conversación entrante. Esta es una practica común el agregar el tamaño del archivo como último argumento.
DCC SEND <filename><ip><port><file size>
En este punto, la especificación original tenía al receptor conectado a la dirección dada y el puerto esperando los datos, o ignorar el pedido, pero para clientes que soportan la extensión DCC RESUME, una tercer alternativa es preguntar al remitente saltarse una parte del archivo enviando un CTCP reply:
DCC RESUME <filename><port><position>
Si el cliente soporta DCC RESUME, este responderá con un
DCC ACCEPT <filename><port><position>
y el receptor puede conectarse a la dirección y al puerto dato y escuchar los datos para añadirlo en el archivo.
Los datos se envían en bloques, a los que el cliente debe corresponder enviando los tamaños de los bloques de datos entrantes como enteros de 32 bits (network byte order). Esto ralentiza las conexiones, y es redundante porque tal comportamiento ya está implementado por TCP. La extensión send-ahead solventa este problema no esperando las respuestas, pero ya que el receptor aún debe enviarlas por cada bloque que recibe, en el caso de que el emisor las espere, no está completamente solucionado.
En algunos canales de IRC, hay pequeños scripts que van publicando archivos, y mediante algunas reglas se los puede ir solicitando.
Hasta aca muy clara la informacion, pero al momento de empezar a hacer algunas pruebas sobre Ruby, me encontre con el primero problema.
¿Como nos conectamos con el servidor irc mediante un script ruby?
Para esto vamos a usar la clase TCPSocket y mediante las simples lineas a continuacion, ya estamos conectados.
@socket = TCPSocket.new(servidor, puerto)
Una vez conectados, segun el RFC1459 que describe la arquitectura de IRC, tenemos que hacer el paso de registrarnos con el servidor, es decir, enviar la informacion necesaria para que sepa quienes semos, tanto ese servidor, como el resto.
Esto se logra mandando 3 datos: PASSWORD, NICK, USER. Cualquier operacion que se desee hacer antes de tener una registracion valida, nos va a dar un error.
Para esto usamos el siguiente codigo:
password = "passwordsecreta"
nick = "NickEnElServer"
@socket.puts "PASSWORD #{password}"
@socket.puts "NICK #{nick}"
@socket.pust "USER #{nick} #{nick} #{nick} :#{nick}"
No es mayor problema esta parte de conexion y resgitracion, pero despues de un rato importante, y revisar algunos codigos, vi que en algunos casos, enviaban un sleep despues de la accion USER. Esto es para no enviar nada antes que el servidor nos registre, algo tan simple como esto:
Una vez que estamos registrados, podemos seguir enviando comandos varios al server.