Root > Documents > Web Güvenlik Açıkları > Pipe Communication and FIFO
Cyber-Warrior.Org \ Doküman \ Web Güvenlik Açıkları > Pipe Communication and FIFO
Madde
  Yazar : spaNKy
  Date : 05.08.2005 12:07:45
 
# Pipe Communication and FIFO
 

PIPE Nedir?

Linux ve diger tüm UNIX türevi isletim sistemlerinin çok hos bir özelligi de küçük komut zincirlerini bir araya getirerek büyük programlardan daha kabiliyetli küçük programlar yazmaktir. Bahsettigim, süreçler arasi haberlesme teknigi mekanizmasi olan pipe’tir. Pipe ilk olarak UNIX’in gelistirildigi Bell labaratuarlarinda gelistirilmistir. Pipe islemlerini "|" simgesi ile gösteririz. Hemen hemen bütün kabuklar bunu destekler. Borulama kisaca bir programin standart çikisini baska bir programa standart giris olarak verme diye tanimlanabilir. Örnegin:

cclub:~> ls -l | grep cpp

Yukaridaki komut dizinde, içerisinde cpp geçen dosyalarin ismi ekrana basar. Söyleki: "ls -l" dizindeki dosyalari çikti olarak üretir. Bu çiktilar girdi olarak grep komutuna verilir. grep ise girdide arama yapan bir komuttur. Dolaysiyla dizindeki dosyalardan ismi cpp içerenlerin adini yazar. Burada dikkat ederseniz "ls -l" komutunun çiktisi ekrana basilmadi. Ayni sekilde grep’e üçüncü parametre olarak verilmesi gereken dosya isimleri verilmedi.

FIFO, pipe ile transfer edilecek veriler için bir yoldur. Ilk giren, ilk çikar mantigi ile çalisir. Gerçek bir boru düsünün. Boruya kirmizi bir top, sonra mavi bir top, sonra yesil bir top sokalim. Borunun diger tarafindan sirasiyla kirmizi, mavi ve yesil top çikar. Bu bir veri yapisidir. Bundan baska ters çalisan yigin denilen LIFO vardir. Burada son giren ilk çikar. Bunu da su sekilde hayal edin: Bir çuvala üst üste sirasiyla kirmizi, yesil, mavi paketler koyalim ve kargoya verelim. Kargoyu teslim alan paketleri mavi, yesil, kirmizi sirasiyla çikarir.

Pipe ile çalisan programlar yazabilmek için bilmemiz gereken bazi seyler var. Bunlardan ilki pipe fonksiyonudur. Tahmin edebileceginiz fonksiyon ayni isme sahiptir ve unistd.h içerisinde prototipi su sekilde tanimlanmistir:

int pipe( int filedes[2] ) ;

Bu fonksiyon iki adet dosya tanimlayicisi olusturur: okumak için filedes[0] ve yazmak için filedes[1]. Fonksiyon sorunsuz çalistiginda 0 degerini geri döndürür.

<DIV align=left>
<DIV align=center>

// pipe.c - Pipe ile süreç haberlestirme
// Versiyon: 011231
// Baris Simsek, <[email protected]>
// http://www.acikkod.org

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main()
{
    pid_t pid;
  int mypipe[2];
  char buffer[100];

  /* Pipe olustur. */
  if (pipe(mypipe))
  {
    fprintf(stderr, "Pipe olustururken hata olustu. ");
    return 1;
  }

  /* Çocuk süreç olustur. */
  pid = fork();
  if(pid == (pid_t) 0)
  {
    /* Çocuk süreç. */
    read(mypipe[0], buffer, 100);
    printf("%s ", buffer);
    return 1;
  }
  else if (pid < (pid_t) 0)
  {
    fprintf(stderr, "Fork yaparken hata olustu. ");
    return 1;
  }
  else
  {
    /* Ana süreç. */
    write(mypipe[1], "hello world!", 13);
    return 1;
  }

  return 0;
}

Yukaridaki örnekte fork() ile ikinci bir süreç olusturduk. Ve sonra bu süreç ile pipe’in okunan kismindan (mypipe[0]) 100 byte’lik buffer okuduk. Ana süreç içerisinden de pipe’in yazilacak kismina (mypipe[1]) "hello world!" mesajini yazdik.

Fork yaptiginiz zaman çocuk süreç ana sürecin bütün durumuna aynen sahip olur. Açik dosya tanimlayicilarini da kopyalar. Bu nedenle pipe olusturduktan sonra fork ederseniz, olusturdugunuz pipe’i iki process’in haberlesmesi için kullanabilirsiniz. Yukaridaki kod buna bir örnektir. Ekrana yazilan "hello world!" mesaji, ana sürecin çiktisi olsa da ekrana basan çocuk süreçtir. Ana sürec bu mesaji pipe’a yazmis, çocuk süreç te pipe’dan okumustur.

Eger pipe’a yazilandan çok veri okumaya çalisirsaniz, ancak yazilan kadar veri alabilirsiniz. Eger pipe’dan son okumanizdan sonra pipe’a hiçbir sey yazilmamis ise ve siz pipe’dan okumaya çalisiyorsaniz programiniz bloke edilecektir. Ta ki yeni veri yazilana kadar veya pipe’in yazilan ucu kapatilana kadar. Bunu göz önünde tutarak programlarinizi istenmeyen sonuclardan koruyunuz. UNIX isletim sistemlerinde disardan veri bekleyen süreçlerin "zamanlayici" (scheduler) tarafindan bloke edildigini hatirlayin.

Linux pipe’lari yazilirken 4096 byte sinirina sahiptir. 4k’dan daha büyük veri pipe’a yazacagi zaman süreç bloke olur ve pipe’dan okuma yapilmasini bekler.

FIFO Dosyalar

Eger iki süreç bir pipe üzerinden haberlesmek istiyor ve ayni süreç altinda calismiyorsa pipe() fonksiyonu islerini görmeyecektir. Ancak üzülmeyin, bu durumda FIFO dosyalari (named pipe) kullanabilirsiniz.

FIFO dosyasi, dosya sisteminizdeki siradan bir dosya gibidir, ancak tipki pipe gibi özellikleri vardir. Iki süreçten birisi FIFO dosyasini okumak, digeri yazmak için açabilir. Bu iki süreç FIFO araciligi ile haberlesebilir. Birinin yazdigini digeri okur. Yukaridaki gibi blok olma olayi burada da söz konusu. Sözleri bir yana birakip gösteri yapmaya ne dersiniz?

cclub:~> mkfifo myfifo
cclub:~> ls -l myfifo
prw-r--r-- 1 root root 0 Dec 23 20:04 myfifo|

Yukarda yaptiklarima bir göz atalim: "mkfifo" komutu ile myfifo adinda özel dosyamizi olusturdum. "ls -l" komutu ile dosyamiza baktiginizda, dosya isminin sonuna "|" karakterinin eklendigini göreceksiniz. Bu karakter ile dosya sistemimiz onun bir FIFO dosyasi oldugunu isaretliyor. Biraz man sayfasi okuyalim:

DESCRIPTION
mkfifo creates FIFOs (also called "named pipes") with the
specified filenames.

A "FIFO" is a special file type that permits independent
processes to communicate. One process opens the FIFO file
for writing, and another for reading, after which data can
flow as with the usual anonymous pipe in shells or else-
where.

By default, the mode of created FIFOs is 0666 (`a+rw’)
minus the bits set in the umask.

Simdi gösteriye devam edelim.

cclub:~> cat myfifo

Bu komut sonucunda kabuk program (shell) bekleyecektir. Çünkü sürecimiz bloklanmistir. myfifo’ya henüz bir ses yazilmadigi halde biz ondan okumak istiyoruz. Simdi baska bir terminal açin.

cclub:~> cat > myfifo

Bu komutun anlami klavyeden alinacak girdileri "myfifo" dosyasina yaz. ">" sembolu standart çiktiyi yönlendirmek için kullanilir. "cat" fonksiyonu normalde parametre olarak verilen dosyayi görüntüler. Eger parametre vermezseniz girdi olarak standart girisi (burada klavye) kullanir. Simdi en son açtigimiz terminalde bir seyler yazalim. Örnegin "hello world!" yazin. Diger terminale geçtiginizde ne göreceksiniz, izleyelim:

2. terminal

cclub:~> cat > myfifo
hello world!

1. terminal

cclub:~> cat myfifo
hello world!

Harika degil mi! Ikinci açtigimiz terminalde klavyeden girdiklerimizi FIFO dosyamiza yazdik. Ilk açtigimiz terminalde bloke olmus sürecimiz pipe üzerine veri yazildigini gördü ve okuyup "cat" komutu ile ekrana basti. Gördügünüz gibi iki süreç arasinda haberlesmeyi sagladik.

Bu gösteriyi kabuk programi (shell) kullanarak yaptik. "cat" komutu sayesinde dosyadan okumayi ve yine "cat" komutu ile kabuk programin bir özelligi olan yönlendirmeyi (>) kullanarak ta yazmayi sagladik. FIFO dosyalarini kendi yazacaginiz programlarda da kullanabilirsiniz. C içinde FIFO dosyasi olusturmak için mkfifo() fonksiyonunu kullanabilirsiniz. Yine man sayfalarimiza göz atalim:

NAME
mkfifo - make a FIFO special file (a named pipe)

SYNOPSIS
#include <sys/types.h>
#include <sys/stat.h>

int mkfifo ( const char *pathname, mode_t mode );

Prototipi yukarda gördügünüz gibi. Kullanabilmek için sys/types.h ve sys/stat.h baslik dosyalarini yüklemeniz gerekir. Yazacaginiz iki süreçten birisi FIFO dosyasindan okumaya, digeri de FIFO dosyasina yazmaya calissin. Yukaridaki iki örnegi bu sekilde simule edebilirsiniz. 
<DIV align=center>
// fifo-reader.c - FIFO’dan okuyan program
// Versiyon: 011231
// Baris Simsek, <[email protected]>
// http://www.acikkod.org

#include <sys/types.h>
#include <sys/stat.h>

int main()
{
  int fd;
  char buffer[100];

  fd=fopen("myfifo","r");

  fgets(buffer,100,fd);
  printf("Buffer: %s ",buffer);

  return 0;
}

   
   
Cyber-Warrior TIM All Legal and illegal Rights Reserved.\CWDoktoray 2001©