A mIRC scriptnyelve – IV. rész: Sockets

Most, hogy a mIRC programozó felületének fő részeit már ismerjük, ideje mélyebb vizekre evezni. Az újabb mIRC-ek képesek a socket kezelésre, azaz TCP és UDP kommunikációra - ez a lehetőség hatalmas kapukat nyit meg a programozó számára: FTP és telnet klienst, vagy akár IRC servert is lehet írni a mIRC-en belül.

A programozás megkezdéséhez szükség van egy kis elméleti háttérre – az érthetőség kedvéért ezt itt most megpróbálom minimálisra csökkenteni. Egy-egy gépet az IP címe segítségével tudunk azonosítani - mivel ez egy rendkívül hosszú szám, amit senki sem tud megjegyezni, pontozott decimális alakban használjuk (pl. 145.236.224.248 - a Matávnet elsődleges DNS-e), ill. domain nevekkel is hivatkozhatunk rájuk, amit a DNS-ekben, táblázat formában tárolnak. A gyakorta használatos "DNS kiszolgáló", ill. "DNS server" kifejezések redundánsak, hiszen a DNS a Domain Name Server rövidítése, így a szerver (kiszolgáló) szó már a DNS alakban is szerepel (A rövídítést jelentheti a Domain Names Service fogalmat is, ami magyarul domain név szolgáltatást jelent. Ilyen jelentés mellett használható a DNS után a szerver szó is. A szerk!). Egy-egy IRC-s felhasználó IP-jét a "/DNS" parancs segítségével tudjuk megkérdezni a szervertől, ill. domain neves formáját az illető whois-ában is láthatjuk (de megkapjuk sok más esetben is - ezt azonban a mIRC alapesetben elrejti előlünk).

A TCP összeköttetés-alapú, míg az UDP összeköttetés-mentes protokoll - ez a valóságban annyit jelent majd számunkra, hogy a TCP kommunikációhoz először kapcsolódni fogunk a célponthoz, míg ha nincs szükség hosszabb kommunikációra, akkor UDP-t is küldhetünk, "bele a semmibe", kapcsolódás nélkül. Fontos észben tartani, hogy az UDP célba érkezéséről semmiféle visszaigazolást nem kapunk (hacsak nem hibaüzenetet, ill. szerencsés esetben a kívánt választ).

Használni fogunk bizonyos "portokat" is - ezek olyanok mintha kis kapuk lennének, s mi választhatjuk meg, hogy a 65536 közül melyiken "megyünk be" - fontos azonban az is, hogy a kapu nyitva legyen, s a mögötte állók értelmezni tudják, hogy mit akarunk tőlük. Egyes portokat a hozzájuk tartozó legismertebb szolgáltatások alapján el is neveztek - a 80-as pl. a http, a 6667-es pedig az IRC szerver portja.

Ahhoz, hogy valamilyen érdemleges kommunikációt tudjunk véghezvinni egy-egy kiszolgálóval, tudnunk kell, hogy azok miként működnek. Ezt az információt az RFC-kben találjuk meg (Request For Comments). Egyes RFC-kre a számukkal hivatkozhatunk, így pl. FTP - 959, WWW - 1630, ill. a Remote-nál már említett IRC-szabványról az 1459-es RFC-ben olvashatunk. Nem minden RFC vált szabvánnyá (erről az 1011-es RFC-ben tudhatunk meg többet). Az RFC-k teljesebb listáját az 1012-es RFC-ben találjuk.

Az alapok után nézzünk pár szót a TCP kommunikáció mIRC-ben történő megvalósításáról! Amennyiben mi akarunk figyelni egy portot, és az azon bejövő adatokat (pl. hogy lássuk, ha valaki megnézi, hogy fenn van-e nekünk egy trójai program), a socklisten [név] [port] parancsot kell használnunk. Az elkövetkezendőkben a megadott névvel fogunk tudni hivatkozni az adott portra - így kell tennünk majd az "on [felh. szint]:socklisten: [név]: { [parancs] }"-nál is, mely akkor futtatja le a parancsot, ha az előzőleg már figyelt portra valaki csatlakozni akar. Ha kommunikálni akarunk a porton, akkor kötelező a sockaccept [név] parancs segítségével elfogadnunk a csatlakozást.

A másik variáció, hogy mi akarunk valakire csatlakozni - ez esetben a sockopen [név] [ip] [port] parancsot kell használnunk. A kapcsolat sikeres létrejöttét az "on [felh. szint]:sockopen: [név]:{ [parancs] } " segítségével észlelhetjük.

Miután megtörtént a kapcsolódás, a kommunikáció a sockwrite és a sockread parancsok segítségével lehetséges. A sockwrite szintaxisa "sockwrite [név] [elküldendő adatok]". Amennyiben nem szöveget akarunk küldeni, a &binvar-t kell használnunk - ezzel itt most nem fogunk foglalkozni, bővebb információ a mIRC súgójában található róla. Mivel az enter-t jelző "soremelés-kocsivissza" karaktereket a változókban nem tároljuk, a sockwrite parancsot "-n" opcióval kell meghívni, ha a sor végén "enter"-t is szeretnénk küldeni (ezt a legtöbb esetben használni kell). A sockread szintaxisa "sockread [méret] [változó]", ahol a méret a megtekinteni kívánt adatok mérete bájtban, a változó pedig az, ahova az adatokat "menteni" akarjuk. A sockread parancsnak az "on [felh.szint]:sockread:[név]: { [parancs] }"-nál, a parancsoknál kell lennie - ezek akkor futnak le, ha adatot kaptunk az adott néven. Ha itt a sockread-et sockwrite-ra cseréljük, akkor a parancs abban az esetben érvényesül, ha befejeztük az adatok küldését (erre kevesebb szükség szokott lenni).

A kommunikáció után a kapcsolat megszakítása a sockclose [név] parancs segítségével lehetséges. Némely esetekben szükséges a hivatkozási nevek megmásítása, ezt a sockrename [régi név] [új név] segítségével tehetjük meg.

Hogy bizonyos információkat tudjunk meg az éppen aktuális kapcsolatról, a függvényeket kell segítségül hívnunk. A legfontosabb a $sock([név]).[tulajdonság], ahol tulajdonságként többek között a következőket írhatjuk:

name - a nevet adja vissza (a zárójelben lévő név tartalmazhat *-ot, így a $sock([név csillaggal],[szám]).name a [szám]. nevet adja vissza, amire áll a csillagos kifejezés.)

ip - a kapcsolatban szereplő másik fél IP címe

port - a használt port száma

sent & rcvd - elküldött ill. kapott adatok mérete

ls & lr - utolsó küldés ill. fogadás óta eltelt idő

Fontos függvény a $sockname is - ez az aktuális kapcsolat nevét adja vissza, a $sockerr, amely akkor ad igazat, ha hiba történt (rögtön az adott socket parancs után kell állnia a vizsgálatnak), és a $portfree([port száma]), mellyel megnézhetjük, hogy egy adott portot használunk-e már.

Most, hogy az alapokkal tisztában vagyunk, nézzünk egy példát használatukra: lépjünk fel még egy példányban IRC-re, anélkül, de ne a mIRC szolgáltatásait, hanem a socketkezelést használva!

Ahhoz, hogy ezt megtegyük, tudnunk kell, mit vár el tőlünk az IRC server, miután a kapcsolat létrejött. Az IRC-RFC-ben leírtak szerint először a nick-ünket kell megadni - azaz ki kell küldeni egy NICK [becenevünk] parancsot -, majd egy USER parancs segítségével néhány alap-információt kell megadnunk (ezek fognak a whois-ban látszani). A USER parancs szintaxisa: USER [becenevünk] [host] [server neve] [igazi nevünk], ahol csak e legutolsó beállítás a fontos, mivel az előzőeken hiába akarunk, a valóságon nem tudunk változtatni.

alias kapcs sockopen newuser 127.0.0.1 6667 [ENTER]

; létrehoztunk egy "kapcs" parancsot - ezzel visszük majd fel a későbbiekben a klónt. A 127.0.0.1 arra az esetre van, ha a már régebben említett saját IRC servert használjuk tesztelésre - helyette bármely másik IRC server IP-je írható, vagy akár változóban is tárolhatjuk a használandó szerver címét.[ENTER]

on *:sockopen:newuser: { [ENTER]

; ha a kapcsolat létrejött...[ENTER]

sockwrite -n newuser NICK alma [ENTER]

; elküldjük a nick-ünket (jelen esetben ez "alma")[ENTER]

sockwrite -n newuser USER alma 127.0.0.1 video.fw.hu :ezittazigazinevem [ENTER]

; ...majd a USER parancsot használjuk.[ENTER]

} [ENTER]

A "kapcs" parancs kiadása után /whois alma-val megnézhetjük az eredményt: az általunk beállított adatokkal megtaláljuk a klónunkat.

A script ezzel még nem készült el - mindenekelőtt érdemes tájékoztatni a felhasználót a klón sikeres (vagy sikertelen) csatlakozásáról, továbbá ha nem akarjuk, hogy klónunk rövidesen a Ping Timeout istenének martalékul essen, a szerver PING parancsára PONG-al kell válaszolnunk.

on *:sockread:newuser: { [ENTER]

;figyeljük a bejövő adatokat [ENTER]

if ($sockerr ] 0) { echo 4 $active *** Socket hiba } [ENTER]

;ha hiba van, kiírjuk [ENTER]

sockread 4096 %temp [ENTER]

;beolvassuk a bejövő adatokat egy változóba [ENTER]

if ($sockbr == 0) || ( %temp == $null ) { return } [ENTER]

if ($gettok(%temp,1,32) == PING) { .sockwrite -n $sockname PONG : $+

"pong" } [ENTER]

;ha PING-et küldött a server, PONG-al válaszolunk (A $gettok-al a %temp egy adott részét vizsgáljuk - hogy melyikre van szükségünk, azt az IRC RFC-ből tudhatjuk meg.) [ENTER]

if ($gettok(%temp,2,32) == 001) { echo 4 $active *** Sikeres kapcsolódás. }[ENTER]

;001-et (köszöntő szöveget) akkor kapunk, amikor a serverre sikerült csatlakozni - így ez alkalmas ennek vizsgálatára. [ENTER]

if ($gettok(%temp,1,32) == ERROR) { echo 4 $active *** HIBA:

$gettok(%temp,2,32) }[ENTER]

;Ha hibaüzenetet kapunk, kiírjuk. [ENTER]

}[ENTER]

Utasítás küldéséhez a sockwrite parancsot kell használnunk - egy köszönést például az alábbiakkal hajtathatunk végre vele: sockwrite -n newuser privmsg #csatinev :Hello!. A parancsok legtöbb esetben megegyeznek az általunk eddig ismertekkel - ha valami mégsem sikerül, az RFC-t kell segítségül hívni.

Úgy tudom, RFC-fordítással nagyon kevesen foglalkoznak - olyannyira, hogy egyetlen sem érhető el közülük magyar nyelven -, aki tehát komolyabban akar foglalkozni a socket-ekkel, mindenképpen szüksége lesz az angol nyelvre is.

Varga Gábor