Windows'ta Winpcap (Packet Capture Library) Kullanımı

11:19 , ,

Winpcap kütüphanesi windows ve Linux/Unix platformlar için yazılmış bir "packet capture library" sidir. Ünlü wireshark programı bu kütüphanenin üzerine bina edilmiştir. Bu kütüphaneyi windows'ta kullanarak uygulamalar geliştirmek için önce yapılması gerekenler sırasıyla aşağıdaki gibidir:


  • ilk önce http://www.winpcap.org/devel.htm adresinden developer paketinin indirilmesi gerekmektedir. 


  • Ardından Visual Studio'da include library klasörünü ve linker için lib klasörlerinin yerinin gösterilmesi ve preprocessor'e bununla ayar girilmesi gerekmektedir.


Additional Include Directories:  (Başlık Dosyalarının eklenmesi)


Additional Library Directories: (Kütüphanelerin eklenmesi)



Additional Dependencies: (Ön işlemci kütüphanesinin eklenmesi)


Preprocessor Definitions


C'de extern anahtar sözcüğü

11:21

Bir kaynak dosya içinde tanımlanan bir değişkene ya da işleve, yalnızca tanımlandığı kaynak dosya içinde değil, projeyi oluşturan diğer kaynak dosyalarda da erişilebiliyorsa, nesne ya da işlevin dış bağlantısı “external linkage” vardır denir.

Bir kaynak dosya içinde tanımlanan bir değişkene ya da işleve, yalnızca tanımlandığı kaynak dosya içinde erişilebiliyorsa, projeyi oluşturan diğer kaynak dosyalarda erişilemiyorsa, nesne ya da işlevin iç bağlantısı “internal linkage” vardır denir.

extern anahtar kelimesi derleyiciye değişkenin dışarıda tanımlandığını bildirmek için kullanılan bir keyword'tür. Compiler extern keyword'unu gördüğünde değişken için alan tahsisinde bulunmaz. 





Yukarıdaki a.c | b.c | c.c şeklinde üç c dosyası bulunmaktadır. b.c dosyası içinde g_x değişkeni bildirilmiş a.c ile c.c dosyalarında extern keyword'u ile dış bağlantıya ait g_x değişkeni kullanılmıştır.



eğer b.c dosyasında da int g_x bildirimi olmasaydı veya orada da extern g_x bildirilimi yapılsaydı compile aşamasında olmasada link aşamasında hata verecekti.



scanf fonksiyonunun türevleri [ scanf, sscanf, fscanf ]

10:58


scanf, sscanf, fscanf fonksiyonları okuma amaçlı kullanılan fonksiyonlardır. Kısaca her birine değinmek gerekirse:

scanf:

scanf stdin dosyasından formatlı okuma yapmak için kullanılan bir fonksiyondur.  

int scanf(const char *format, ...);




sscanf:

sscanf ise bir veri yapısından formatlı okuma yapmak için kullanılan bir fonksiyondur.

int sscanf(const char *str, const char *format, ...);



fscanf:

fscanf ise dosyadan formatlı okuma yapmak için kullanılan bir fonksiyondur.

int fscanf(FILE *stream, const char *format, ...);


ÖZET: scanf format bilgisini ve bu formata göre aldığı değerleri yazacağı adresi ister. fscanf ise dosyadan formatlı okuma yapmak için kullanılır. scanf'e ek olarak dosya handle değerini ister. sscanf ise dosya yerine string gibi bir veri yapısından formatlı okuma yapar.


C'de Operatörler

11:15

ATAMA OPERATÖRLERİ

C' de bir den fazla atama operatörü vardır. Diğer dillerde atama operatörünün değer üretmesi gibi bir durum yoktur. C’de bu operatörde değer üretir.
image
C dilinde atama operatörü bir değer üretir.
  • Atama operatörünün ürettiği değer nesneye atanan değerdir.
  • Atama operatörünün öncelik yönü sağdan sola doğrudur.
x=y=z=t=func();
image

  • Well Formed : Çalışma Anında ne olacağı belli olan bunun garantisi verilen programlardır. Bazı kodlar çalışma anında ne olacağı kesin değildir. Kod legal ama çalışma anında ne olacağı, nasıl cevap vereceği belli değildir. Run time ‘da her şey olabilir. (ill formed)
  • Undefined Behaviour : Syntax hatası olmamasına karşın run time’de nasıl çalışacağına ilişkin bir garanti olmamasıdır.
image

image

  • Sequence point : yaptığınız işlemin etkisini gösterdiği noktaya denir.

image

image

Noktalı virgülden sonra ve yukarıda ki 4 operatörden sonra ve ( ) ‘den sonra yan etki noktası vardır.
Bir yan etki noktasından önce yan etkiye maruz kalan bir değişkeni tekrardan kullanmayın.
  • Tanımsız davranış demek hatalı kod demektir.
C’de bazı durumlarda nasıl davranacağı belirtilmemiştir. Bu durumlara ise Undefined Behavior denir. Yani ne sonuc vereceği belirsizdir.

image

Mesela 15%-2 işleminin sonucu +1 de olabilir -1 ‘de Derleyiciden derleyiciye değişen davranışlardır. Standartlar bu durumun uclarını açık bırakmışlardır. Bu sebeple genel olarak derleyiciler öğretmen olarak kullanmak yanlış bir yargıya ulaşmamıza sebep olabilir.

VİRGÜL OPERATÖRÜ

Diğer programlama dillerinde virgül operatörü yoktur. C’de virgül hem operatör hem de syntax’ın bir parçasıdır.
image

  • for (i=3,k=5;k<x;k++) :ifade virgül operatörü sayesinde yapılmıştır. Virgül operatörünün de geri dönüş değeri vardır. Virgül operatörünün sağındaki operand
x=10, y=20;                 
z=(y,x); z 10’a eşit olur.

  • C’de yapılan en büyük hatalardan biri "." konulması gereken yere "," konulmasıdır.


image

LOGIC OPERATÖRLER


  • !          :logical DEĞİL
  • ||          :logical OR 
  • &&     :logical AND
  • |           :bitwise OR
  • &        :bitwise AND

Bazı aynı anlamlı ifadeler:


  • x<y      :    y>x
  • x>y      :    y<x
  • x>=y    :    !(x<y)
  • x<=y    :    !(y<x)
  • x==y    :    [!(x>y)&&!(x<y)]
  • x!=y     :    ((x<y)||(y<x))


C’de kısa devre kuralı
 :


  if(x>0 && y<-5) if’in içinde bulunan koşullardan biri yanlışsa ve operatöründe sola bakmak anlamsızdır bu nedenle C’de bu duruma kısa devre kuralı denir. Kısa devre kuralında bir Ve için bir yanlış yeterli iken veya için bir doğru yeterlidir.



C'de Bilinirlik Alanı ve Ömür Kavramı

10:55

Bilinirlikte dar kapsamlı değişken geniş kapsamlı değişkeni maskeleyecektir. C ‘de İsim gizlemesi diye bir kavram vardır.
Fonksiyon tanımlaması yaparken (int x,int y) benzeri parantez içi ifadelerin fonksiyonun kapanış parantezine kadar aktif olduğu bilinmesi gerekmektedir.

image

Bir alanda hem üst bir kapsama sahip hem de yerel bir değişken varsa üstü kullanmanın bir yolu yoktur. Örnek vermek gerekirse

image

C’de ömür kavramı 3’e ayrılır;
  1.   Statik
  2.   Otomatik
  3.   Dinamik
  • Statik Ömür : Hayatını programın başından sonuna kadar sürdürmektedir.
  • Otomatik Ömür : Bir kodun yürütülmesi sırasında bellekte kalan kodun çalışması sonlandığında bellekten silinen bir ömür çeşitidir.
  • Dinamik Ömür : Programın çalışıp bitmesiyle ilgili bir ömür anlayışı olmayan ne zaman istersek hayata geçen ne zaman istersek hayatı sonlanacaktır.

Atama (ingilizce overwrite ) hayatta olan bir nesneye yapılır. ilk değer verme hayata gelirken aldığı değer olacaktır.
  • Global değişkenler Static Ömürlüdür.
  • Fonksiyon içinde ve parametre olarak tanımlananlar Otomatik Ömürlüdür.
  • Static Ömürlü olan değişkenler ilk değer verilmezse 0 değeri otomatik olarak verilir.

ÖNEMLİ: Stringler yani iki tırnak içinde olan ifadeler C'de static ömürlüdür. Mesela printf(“Hello World”) ifadesi içinde “Hello World” ifadesi static ömürlüdür ve program sonlanana kadar ömrünü sürdürür.
  • Program main ile başlar ve main bittiğinde program sonlanır. main içine yazılan değişken program sonuna kadar ömrünü sürdürse de bu o değişkenin static değişken olduğu anlamına GELMEZ.
  • Static ömürlü değişkenler hayata main fonksiyonu çağrılmadan gelirler.
  • Static ömürlü bir değişkenle static ömürlü olan global değişken birbirinden farklıdır. Static ömürlü değişkenler tanımlandığı alanda kullanılır ve program sonlana kadar saklanır ve o alanda kullanılır fakat global değişkenlerde static’tir ve her yerden erişme imkanı vardır.

Çöp değer (garbage value) bellekte var olan silinmiş yani üzerine yazılabilir (eski değerlerdir). Otomatik ömürlü değişkenler çöp değerle başlar ve set edilmezse yanlış sonuçlar doğurur. Sonuç olarak otomatik ömürlü değişkenlere değer atamadan kullanmak hatalı olacaktır.

Kısaca otomatik ömürlü değişkenler garbage value ile başlar. Bu yüzden kullanmadan önce set etmek gerekir.

Geçici Nesne:
Çağrılan bir fonksiyon geri dönüş değerini geçici bir değişkene atar. Fonksiyonu çağrında bu değeri bu geçici değişkenden alarak işlem yapar. Ve orada geçici değişken sonlanmaktadır. Fakat fonksiyon çağrıldığında fonksiyon geçici değişkene bir şey göndermez ( bu C ‘de olası bir durumdur ) ise  (Programcının hatalı kod yazımından dolayı) bu durumda geçici değişken dinamik ömürlü olduğundan dolayı garbage value değeri üzerinden işlem yapılır ve hatalı sonuçlar oluşabilir.

C'de Tamponlama Mekanizmasının Degistirilmesi ( setvbuf - setbuf Fonksiyonları )

10:39

“fopen” ile bir dosyayı açtığımızda fopen açılan her dosya için bir tampon oluşturur. Tampon <stdio.h> da bildirilen BUFSIZ sembolik sabitinin belirttiği uzunluktadır. C'de tamponlama mekanizması ( Tampon  stratejisi ve tamponlama boyutu ) iki ayrı fonksiyonla değiştirilebilmektedir . Bunlar setbuf ve setvbuf fonksiyonlarıdır. Standartlara göre setbuf ve setvbuf fonksiyonları dosya fopen'la açıldıktan ve hiçbir işlem yapmadan önce çağrılmalıdır.


Tamponun default boyutu stdio.h içinde bildirilmiş olup BUFSIZE ile belirtilmiştir. Bizim bu sembolik sabit değerini değiştirmemiz tamponlama mekanizmasının boyutunu değiştirmez. Tamponlama boyutunu ve stratejisini değiştirmek için setbuf veya setvbuf fonksiyonlarını kullanmamız gerekir. 

Tamponlama stratejisi;

  • _IOFBF :Full Buffered
  • _IOLBF :Line Buffered
  • _IONBF :No Buffered

setbuf:

setbuf aşağıda belirtilen örnekte olduğu gibi sadece tamponlama yerini değiştirir. Fonksiyon çağrısından sonra tamponlama olarak tmp isimli alanı kullanmaya başlar.


setvbuf:

setvbuf fonksiyonu ise hem tamponlama yerini hem tamponlama boyutunu hem de stratejisini değiştirir.


iki örneğinde çıktısı aşağıdaki gibidir. 

C' de fork ve exec Kavramı


fork()

fork fonksiyonu bir process'in bire bir kopyasını oluşturmak için kullanılır. fork işlevi işletim sisteminde thread kavramı olmadan önce işletim sisteminin çalışma zamanından daha fazla kazanmak için kullanılmaktaydı. Fork işlemi ile aynı process'ten birden fazla oluşturularak işlemler daha kısa zamanda yapılması sağlanmaktaydı.


 fork fonksiyonu çağrıldığı zaman child process id'si sıfır ile parent process id'si sıfır dışı değerle yukarıdaki gibi kontrol edilerek istenilen kodların çalıştırılması sağlanır.


 fork fonksiyonun hala kullanıldığı ikinci kısım ise bir proces çalışma anında başka bir process'i daha çalıştırmak isterse bu durumda yapması gereken şey process'in bir kopyasını oluşturmak ve child veya parent process'i çalıştırılmak istenen process haline getirmek.bu işlevin ikinci kısmı içinde exec fonksiyonu kullanılmaktadır.

execl()

execl fonksiyonunun çalışma mantığı fonksiyon çağrıldığı anda fonsiyonun parametre ifadesinde girilen fonksiyon çalışmaya başlayacak ve o process artık çağrılan process olarak yaşamına devam edecek. Kısaca artık execl fonksiyonunun altında olan kodların o process için çalışması mümkün olmayacak.


kısaca fork fonksiyonun process'in bir klonunun oluştururken exec process'i mutasyona uğratıp başka bir process olarak çalışmasını sağlayacaktır.


Yukarıda hem fork hem de exec işlemi gerçekleştirilmiştir. önce fork ie iki tane process oluşturulmuş ardından child process exec ile main process'ine dönüşmüş parent process ise çalışmasına devam etmiştir.





stdin,stdout,stderr dosyaları

00:57


Windows, Unix/Linux işletim sistemlerinde STDIN, STDOUT ve STDERR birer dosya gibi ele alınmaktadır. Biz bu dosya üzerinde işlem yaparken  bu dosyalar nerelere yönlendirilmiş ise davranış biçimi o yönde olacaktır. Genel olarak stdin dosyası klavyeye yönlendirilmiştir. stdout ve stderr ise ekrana yönlendirilmiştir. Yani biz stderr veya stdout'a yazdığımız zaman bu yazılanlar ekrana çıkacak eğer stdout veya stderr yazıcıya yönlendirilmiş olsaydı o zaman yazıcıdan çıkış olacaktı. stdin dosyası genelde klavyeye yönlendirilmiştir. Dolayısıyla biz klavyeden doğrudan okuma yapmıyoruz stdin dosyasından okuma yapıyoruz ve klavye stdin dosyasına yazma yaptığı için doğrudan klavyeden okuma yaptığımızı farzederiz.Aslında işletim sisteminin stdin dosyasından okuma yapmaktayız.

Kısaca ekran sanki bir dosyadır, biz bu dosyaya yazma yaptığımızda ekrana yazmış oluruz. Klavye de bir dosya gibidir, biz bu dosyadan okuma yaptığımızda klavyeden okuma yapmış oluruz.

getchar, gets ve scanf gibi giriş fonksiyonları aslında birer dosya fonksiyonudur ve stdin dosyasından okuma yapmaktadır. printf, puts, putchar gibi fonksiyonlar da birer dosya fonksiyonudur. Default olarak stdout dosyasına yazma yapmaktadırlar.

İşletim sistemlerinde aygıtların birer dosya gibi işlem görülmesinin nedeni aygıtların kullanımı daha basite indirgemektir. Biz sadece bu dosyalarla işlem yaparken işletim sisteminin dosya alt sistemi bu dosyaların birer aygıta ilişkin olduğunu anlar ve aygıtlara yönelir. Ve bu noktada işin önemli bir kısmını işletim sistemi üzerine almış olur. UNIX türevi işletim sistemlerinde bu tasarıma Sanal Dosya Sistemi (Virtual File System) denilmektedir.

C programlama dilinde STDIN, STDOUT ve STDERR dosyaları işletim sisteminin  STDIN, STDOUT ve STDERR dosyalarıyla çalışmaktadır ama C programlama dilinde bu dosyalara erişimde tamponlama mekanizmasının kullanıldığı bilgisi akıldan çıkarılmamalıdır.

Linux shell komutlarından örnek vermek gerekirse:

komut1  >  file.txt     : komut1'in stdout'u file yönlendirilmiştir. Dolayısıyla mesela komut1 bir c programı olsaydı printf ile ekrana basmak istediğimiz karakterler dosyaya yazılacaktı.

komut1  |   komut2   : komut1'in stdout'u komut2'ye stdin olarak yönlendirilmiştir.Dolayısıyla mesela komut1 bir c programı olsaydı printf ile ekrana basmak istediğimiz karakterler ikinci c programında stdin dosyasından okuma yapılan mesela gets fonksiyonu ile alınabilecekti.

Bir C Kodunun Çalıstırılabilir Dosya Haline Gelme Süreci

10:36


Yazdığımız bir C kodunun çalıştırılabilir dosya haline gelirken arka planda hangi aşamalardan geçtiğini öğrenmek hem bakış açımızı hem de programlama bilgisini genişletecektir. gcc derleyicileri önce preprocessor'ü devreye sokar ardından compiler devreye girer ve ardından linker devreye girer ve çalıştırılabilir dosyamız elde edilmiş olur. Bu arada yazdığımız programın assembly karşılığını gcc bize üretmektedir.



 Yazdığımız program basit bir "Hello World" programı ve şimdi bu hello.c programının üzerinden çalışmaya başlayalım;





  • .c dosyaları kaynak kod dosyaları
  • .i dosyaları ön işlemci çıktısının ardından oluşturulan dosya
  • .o dosyaları compiler ardından oluşan object file dosyası
  • main ise linkerin ardından oluşan çalıştırılabilir dosya


Pre-processing

Kısaca ön işlemci # (diyez) ile başlayan ifadeler üzerinde değişiklik yapan programdır. Ön işlemci kaynak kod üzerinde değişiklik yapan bir süreçtir. 


gcc -E main.c dediğimizde ön işlemci çalışır ve çıktıyı ekrana basar. Ben bu çıktıyı prepro.c' ye yönlendirdim. Şimdi vim ile bu dosyanın içeriğine bakalım;


Yukarıda ve aşağıda görüleceği üzere kaynak kodda linker için gerekli düzenlemeler yapılmış include' ların tam yol adresleri girilmiştir.


Compilation


Compilation yada compiler aşaması ise derleyici kaynak kodu link işlemleri dışında object dosyaya dönüştürme işlemlerine gerçekleştirdiği aşamadır. Derleme işlemi bittikten sonra linker' a gönderilir ve linker'dan sonra çalıştırılabilir makine koduna tamamiyle dönüştürülmüş olur.


Linking
Linker işleminin artından artık çalıştırılabilir kodlar üretilmiş olmaktadır.




Ext: Assembly

.s isimli dosya assembly dosyası ve assembly üzerinde inceleme yapmak dosya açılıp incelenebilir.




gcc assembly çıktısı intel veya AT&T veya INTEL syntax'ına göre çıkartılabilir. Örnek kullanım aşağıdaki gibidir:

gcc main.c -S -masm=att -o asm.s
gcc main.c -S -masm=intel -o asm.s

C'de Dinamik Hafıza Yönetimi

07:33


C' de dinamik memory yönetiminde kullanılabilir 4 tane fonksiyon vardır. Bunlar:
  1. malloc
  2. calloc
  3. realloc
  4. free 

    fonksiyonlarıdır. Aşağıdaki örnekte tüm bu fonsiyonların kullanıldığı bir örnek program yazılmış, şimdi bu örnek üzerinden sırasıyla fonksiyonları incelemeye başlayalım.



malloc:

malloc fonksiyonu dinamik olan alan tahsis edilmesi için kullanılır. Prototipi aşağıdaki gibidir:

void *malloc(size_t size)

Fonksiyona parametre olarak verilen boyut kadar alan oluşturur ve alanın başlangıç adresini void * türünden bir adres olarak geri döndürür. 

calloc:

calloc fonksiyonu da dinamik olan alan tahsis edilmesi için kullanılır. malloc ile farkı ise calloc’un ayırdığı hafıza bloğunun içeriğini sıfırlaması olmaktadır. Prototipi aşağıdaki gibidir:


void *calloc(size_t nitems, size_t size)


realloc:

realloc fonksiyonu ise daha önce malloc veya calloc fonksiyonu ile tahsis edilmiş olan alanı büyütmek için kullanılır.
void *realloc(void *ptr, size_t size)
birinci parametre malloc,calloc veya realloc ile tahsis edilmiş olan alanın başlagıç adresi ikinci parametre ise yeni boyut olarak bildirilmektedir.

Free:

Free fonksiyonu parametre olarak aldığı başlangıç adresinde tahsis edilmiş olan alanın boşaltılmasını sağlar.
En başta yazılan programın çıktısı da aşağıdaki gibidir.