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