Hệ thống VoIP sử dụng tổng đài chuyển mạch mềm hỗ trợ ENUM

Một phần của tài liệu Phương vị từ tiếng Hán hiện đại và những biểu hiện từ vựng, ngữ pháp tương đương trong tiếng Việt (Trang 67)

Hệ thống thử nghiệm sử dụng máy chủ IBM PC chạy hệ điều hành Redhat Linux. Phần mềm PBX được sử dụng là phần mềm mã nguồn mở Asterisk, sử dụng cùng module hỗ trợ ENUM.

Để kết nối với PSTN, 1 router Cisco 3725 có sử dụng giao tiếp FXO và phần mềm voice được kết nối thông qua tổng đài nội bộ PSTN PBX.

Phần mềm Asterisk là phần mềm tổng đài chạy trên hệ điều hành Linux. Asterisk có đầy đủ tính năng của một tổng đài cho hệ thống thoại VOIP. Tổng đài Asterisk hỗ trợ truyền tín hiệu thoại qua mạng IP theo các giao thức H323, SIP… Ngoài ra tổng đài Asterisk cho phép ghép kênh theo thời gian TDM để truyền tín hiệu thoại từ mạng VOIP sang mạng PSTN. Các thành phần hệ thống được mô tả trong sơ đồ thử nghiệm sau:

Hình 24. Sơ đồ thử nghiệm tổng đài chuyển mạch mềm Asterisk

* Cấu hình của hệ thống tổng đài Asterisk

+ Cấu hình các User đăng ký cho dịch vụ SIP

; SIP Configuration for Asterisk ;

[general]

port = 5060 ; Port to bind to bindaddr = 203.162.57.157 ; Address to bind to localnet = 203.162.57.144 ; Internal NETWORK address localmask = 255.255.255.240 ; Internal netmask

context = default ; Default for incoming calls

srvlookup = yes ; Enable SRV lookups on outbound calls [100]

type=friend username=100 secret=100

host=dynamic

qualify=200 ; Qualify peer is no more than 200ms away defaultip=203.162.57.189 [101] type=friend username=101 callerid secret=101 host=dynamic nat=yes defaultip=203.162.57.179 [102] type=friend username=102 callerid secret=102 nat=yes host=dynamic ;defaultip=203.162.57.158

+ Cấu hình để thực hiện các cuộc gọi

exten => _847Xxx,1,EnumLookup(${EXTEN}) exten => _847Xxx,2,Dial(${ENUM},90) exten => _849XXxxxxxx,1,EnumLookup(${EXTEN}) exten => _849XXxxxxxx,2,Dial(SIP/909${ENUM:4},30) exten => _844XXxxxxx,1,EnumLookup(${EXTEN}) exten => _844XXxxxxx,2,Dial(SIP/9${ENUM:4},30) exten => _841XXX,1,EnumLookup(${EXTEN}) exten => _841XXX,2,Dial(${ENUM},30)

+ Hoạt động của tổng đài Asterisk

Theo cấu hình trên, các điện thoại VOIP (softphone) có số điện thoại 1xx sẽ được kết nối với tổng đài Asterisk.

Khi tổng đài nhận được các tín hiệu về số điện thoại bị gọi có dạng 844xxxxxxxxx, 849xxxxxxxxx, 844xxx tổng đài sẽ thực hiện truy vấn ENUM tại hệ thống DNS. Kết quả thu được sẽ là số điện thoại theo dịch vụ SIP.

Tổng đài sẽ thực hiện kết nối theo giao thức Sip với địa chỉ có được khi truy vấn hệ thống ENUM.

+ Cấu hình và hoạt động của Router gateway

Cấu hình của Router gateway

Using 1834 out of 57336 bytes ! version 12.3 ! hostname Router ! boot-start-marker

boot system flash c3725-ipvoice-mz.123-6.bin boot-end-marker ! ! interface FastEthernet0/0 ip address 203.162.57.148 255.255.255.240 duplex auto speed auto ! ip classless ip route 0.0.0.0 0.0.0.0 203.162.57.145 ip http server ! voice-port 1/0/0 ! voice-port 1/0/1 ! voice-port 1/1/0 ! voice-port 1/1/1 ! !

dial-peer voice 1 pots application session destination-pattern 3.. no digit-strip port 1/1/0 ! retry bye 2 retry cancel 2

dial-peer voice 2 voip application session

destination-pattern 847... session protocol sipv2

session target ipv4:203.162.57.157 codec g711ulaw

!

dial-peer voice 3 pots application session

port 1/1/0 !

dial-peer voice 4 pots

destination-pattern 844... no digit-strip

port 1/1/0 !

dial-peer voice 5 pots application session destination-pattern 606 port 1/0/0

!

dial-peer voice 6 voip application session

destination-pattern 841... session protocol sipv2

session target ipv4:203.162.57.157 codec g711ulaw ! sip-ua retry invite 4 retry response 3 ! end

Hoạt động của Router gateway:

Khi nhận được các số điện thoại có dạng 847xxx, router sẽ kết nối với tổng đài Asterisk voip1.vnnic.net.vn (203.162.57.157).

Khi nhận được cuộc gọi tới số điện thoại 841xxx, router sẽ kết nối với tổng đài Asterisk voip2.vnnic.net.vn (203.162.57.156).

Khi nhận được cuộc gọi tới số điện thoại có 849xxxxxx hoặc 844xxxxxxx, router sẽ kết nối với mạng PSTN qua cổng 1/1/0.

+ Log hệ thống khi hoạt động

Apr 12 10:06:50 DEBUG[1125329600]: chan_sip.c:4200 check_user: Setting NAT on RTP to 0

Apr 12 10:06:50 DEBUG[1125329600]: chan_sip.c:598 __sip_ack: Stopping retransmission on 'A51A8019-717C- 4FA7-B703-1C33A72E75ED@203.162.57.189' of Response 8591: Found

Apr 12 10:06:50 DEBUG[1125329600]: chan_sip.c:4200 check_user: Setting NAT on RTP to 0 Apr 12 10:06:50 DEBUG[1125329600]: chan_sip.c:5291 handle_request: Check for res for 104

Apr 12 10:06:50 DEBUG[1125329600]: chan_sip.c:1140 find_user: Call from user '104' is 1 out of 0 Apr 12 10:06:50 DEBUG[1125329600]: chan_sip.c:3586 build_route: build_route: Contact hop:

<sip:104@203.162.57.189:5060>

Apr 12 10:06:50 DEBUG[1217602880]: enum.c:114 parse_naptr: input='+84913091440', flags='u', services='E2U+sip', regexp='!^\+849(.*)$!sip:\1@203.162.57.148!', repl=''

ENUM got '1'

-- Executing Dial("SIP/104-e9e5", "SIP/90913091440@203.162.57.148|30") in new stack Apr 12 10:06:51 DEBUG[1217602880]: chan_sip.c:1013 sip_call: Outgoing Call for 90913091440 Apr 12 10:06:51 DEBUG[1217602880]: chan_sip.c:1112 find_user: 90913091440 is not a local user -- Called 90913091440@203.162.57.148

Apr 12 10:06:51 DEBUG[1125329600]: chan_sip.c:618 __sip_semi_ack: (Provisional) Stopping retransmission (but retaining packet) on '4e1d276513b52d404133907326379121@203.162.57.157' Request 102: Found

Apr 12 10:06:54 DEBUG[1125329600]: chan_sip.c:618 __sip_semi_ack: (Provisional) Stopping retransmission (but retaining packet) on '4e1d276513b52d404133907326379121@203.162.57.157' Request 102: Found

-- SIP/203.162.57.148-d02a is making progress passing it to SIP/104-e9e5

Apr 12 10:06:54 DEBUG[1125329600]: chan_sip.c:580 __sip_ack: Acked pending invite 102 Apr 12 10:06:54 DEBUG[1125329600]: chan_sip.c:598 __sip_ack: Stopping retransmission on '4e1d276513b52d404133907326379121@203.162.57.157' of Request 102: Found

Apr 12 10:06:54 DEBUG[1125329600]: chan_sip.c:3586 build_route: build_route: Contact hop: <sip:90913091440@203.162.57.148:5060>

-- SIP/203.162.57.148-d02a answered SIP/104-e9e5

-- Attempting native bridge of SIP/104-e9e5 and SIP/203.162.57.148-d02a

Apr 12 10:06:54 DEBUG[1125329600]: chan_sip.c:598 __sip_ack: Stopping retransmission on 'A51A8019-717C- 4FA7-B703-1C33A72E75ED@203.162.57.189' of Response 8592: Found

Apr 12 10:06:55 DEBUG[1217602880]: rtp.c:1008 ast_rtp_write: Ooh, format changed from UNKN to ULAW Apr 12 10:06:55 DEBUG[1217602880]: rtp.c:1008 ast_rtp_write: Ooh, format changed from UNKN to ULAW Apr 12 10:06:55 DEBUG[1125329600]: chan_sip.c:580 __sip_ack: Acked pending invite 103

Apr 12 10:06:55 DEBUG[1125329600]: chan_sip.c:598 __sip_ack: Stopping retransmission on '4e1d276513b52d404133907326379121@203.162.57.157' of Request 103: Found

Apr 12 10:06:55 DEBUG[1125329600]: chan_sip.c:3586 build_route: build_route: Contact hop: <sip:90913091440@203.162.57.148:5060>

Apr 12 10:06:55 DEBUG[1125329600]: chan_sip.c:618 __sip_semi_ack: (Provisional) Stopping retransmission (but retaining packet) on 'A51A8019-717C-4FA7-B703-1C33A72E75ED@203.162.57.189' Request 102: Found Apr 12 10:06:55 DEBUG[1125329600]: chan_sip.c:580 __sip_ack: Acked pending invite 102

Apr 12 10:06:55 DEBUG[1125329600]: chan_sip.c:598 __sip_ack: Stopping retransmission on 'A51A8019-717C- 4FA7-B703-1C33A72E75ED@203.162.57.189' of Request 102: Found

Apr 12 10:06:55 DEBUG[1125329600]: chan_sip.c:3586 build_route: build_route: Contact hop: <sip:104@203.162.57.189:5060>

Apr 12 10:07:02 DEBUG[1217602880]: rtp.c:1282 ast_rtp_bridge: Oooh, got a hangup

Apr 12 10:07:02 DEBUG[1217602880]: channel.c:2239 ast_channel_bridge: Returning from native bridge, channels: SIP/104-e9e5, SIP/203.162.57.148-d02a

Apr 12 10:07:02 DEBUG[1217602880]: chan_sip.c:1216 sip_hangup: find_user(90913091440) - decrement outUse counter

Apr 12 10:07:02 DEBUG[1217602880]: chan_sip.c:1112 find_user: 90913091440 is not a local user == Spawn extension (default, 84913091440, 2) exited non-zero on 'SIP/104-e9e5'

3.2.3. Chƣơng trình thƣờng trú trong trình duyệt Web để hỗ trợ truy nhập Website thông qua số ENUM

Như đã trình bày trong các kiến trúc của hệ thống, đối với các ứng dụng ENUM ở chế độ trong suốt một chương trình thường trú (Plugin) có thể được thiết kế chạy ngầm trên hệ thống. Như vậy với bất kỳ truy vấn nào có địa chỉ định dạng theo dạng quy ước của ENUM (chẳng hạn như +8445564951) sẽ được chương trình plugin bắt giữ và xử lý trước. Truy vấn ENUM vào hệ thống DNS sẽ được chương trình thực hiện và tùy theo ứng dụng đang sử dụng, chương trình sẽ trả về địa chỉ tài nguyên của người bị gọi, các ứng dụng truyền thống sẽ thực hiện tiếp với địa chỉ hợp lệ này.

Theo như đã phân tích, chế độ này là thân thiện nhất đối với người dùng tuy nhiên khó khăn trong thực hiện do phải được tương thích với từng chương trình ứng dụng khác nhau. Do vậy, trong khuôn khổ thời gian có hạn của một đề tài, luận văn tập trung đi vào xây dựng một chương trình Plugin gắn với trình duyệt Mozilla Firefox. Với chương trình này, bằng một trình duyệt thông thường người sử dụng có thể truy cập Website qua số ENUM của chủ Website đã được khai báo trong cơ sở dữ liệu.

Đây là chương trình để giới thiệu và chứng minh về khả năng đáp ứng của ENUM nên chưa thể tập trung vào hoàn thiện các tính năng thân thiện với người dùng cũng như chưa xét đến các yếu tố hiệu năng (performance) và an ninh (security). Với việc chạy kèm chương trình Plugin, trình duyệt Firefox sẽ cho phép người sử dụng nhập địa chỉ Web bằng cả 2 dạng: dạng URL thông thường cho Web (http://www.vnnic.net.vn) và dạng số điện thoại ENUM (+8445564951) sử dụng thủ tục "http+E2U".

Nhập địa chỉ đích Bắt đầu Nhận dạng Lớp ứng dụng thông thường Kết thúc

Chuyển đổi ENUM sang DNS

Truy vấn bản ghi NAPTR

Tìm thấy RR phù hợp ? ENUM number URL thông thường Tìm thấy Lỗi Lỗi

Hình 25. Lƣu đồ thuật giải chƣơng trình Plugin xử lý địa chỉ Web nhập vào dạng ENUM

Chương trình được hoàn thiện từ các phần mềm mã nguồn mở có sẵn trên Internet tại các địa chỉ http://www.w3.org và http://www.mozilla.org.

Các khai báo cơ sở dữ liệu ENUM, bản ghi NAPTR được thực hiện trên hệ thống máy chủ tên miền quốc gia của Việt Nam tại địa chỉ DNS1.VNNIC.NET.VN - 203.162.57.105 và DNS2.VNNIC.NET.VN -

203.119.8.108, DNS3.VNNIC.NET.VN - 203.119.36.107 và DNS-

HCM01.VNNIC.NET.VN 203.162.87.66.

Sau đây là các đoạn mã Java được sử dụng trong chương trình:

//Register our function to event BEFORE PAGE LOAD const NOTIFY_STATE_DOCUMENT =

Components.interfaces.nsIWebProgress.NOTIFY_STATE_DOCUMENT; const STATE_IS_DOCUMENT =

const STATE_START = Components.interfaces.nsIWebProgressListener.STATE_START; function registerMyListener() { window.getBrowser().addProgressListener(myListener , NOTIFY_STATE_DOCUMENT); } function unregisterMyListener() { window.getBrowser().removeProgressListener(myListener); } window.addEventListener("load",registerMyListener,false); window.addEventListener("unload",unregisterMyListener,false); var myListener = { onStateChange:function(aProgress,aRequest,aFlag,aStatus) { if((aFlag & (STATE_IS_DOCUMENT|STATE_START))&(gURLBar.value.substring(0,1)=="+") ) { aRequest.QueryInterface(Components.interfaces.nsIChannel); enumquery(); BrowserStop(); if(gURLBar.value.substring(0,1)=="+") {gURLBar.value=""; BrowserStop();

alert("Cannot find HTTP resources for this enum.\nKhông tìm thấy tài nguyên http:// cho số enum này.")}

else loadURI(gURLBar.value,null,null); } }, onLocationChange:function(a,b,c){}, onProgressChange:function(a,b,c,d,e,f){}, onStatusChange:function(a,b,c,d){}, onSecurityChange:function(a,b,c){}, /*XXX

This is not nsIWebProgressListenr method, just killing a error in tabbrowser.xml Maybe a bug. */ onLinkIconAvailable:function(a){} } //---Main function--- function enumquery() {

// get profile directory var dir =

Components.classes["@mozilla.org/file/directory_service;1"] .getService(Components.interfaces.nsIProperties)

.get("ProfD", Components.interfaces.nsIFile); dir.append("extensions");

dir.append("{248e4192-266b-47a3-9dd2-787215f96a28}"); dir.append("enumquery.exe");

//Open file exe

var fileexe = Components.classes["@mozilla.org/file/local;1"] .createInstance(Components.interfaces.nsILocalFile);

fileexe.initWithPath(dir.path); //create an nsIProcess

var process = Components.classes["@mozilla.org/process/util;1"] .createInstance(Components.interfaces.nsIProcess);

process.init(fileexe); //Read PREFERENCEs

var prefs = Components.classes["@mozilla.org/preferences- service;1"]. getService(Components.interfaces.nsIPrefBranch); var tempDNSServer = prefs.getCharPref("property.enumquery.prefs.dnsserver"); var tempSuffix = prefs.getCharPref("property.enumquery.prefs.suffix"); //Execute exe with 4 params

var args = [gURLBar.value,"http",tempSuffix,tempDNSServer]; process.run(true, args, args.length);

//Read file dat - result

var filedat = Components.classes["@mozilla.org/file/local;1"]

.createInstance(Components.interfaces.nsILocalFile);

filedat.initWithPath("C:\\temp_enum_query_extension.dat"); //open an input stream from file

var istream = Components.classes["@mozilla.org/network/file-input- stream;1"]

.createInstance(Components.interfaces.nsIFileInputStream); istream.init(filedat, 0x01, 0444, 0);

istream.QueryInterface(Components.interfaces.nsILineInputStream); //read lines into array

var line = {}, lines = [], hasmore; do { hasmore = istream.readLine(line); if (line.value!="") { gURLBar.value=line.value; var enumstr=line.value; if(enumstr.substring(0,4).toLowerCase()!="http") enumstr="http://" + enumstr; } lines.push(line.value); } while(hasmore); istream.close();

// do something with read data }

//--- function ENUMQUERY_PREFS(){

this.prefBranch = null; // pref values

this.DNS_SERVER_ADDRESS =

"property.enumquery.prefs.dnsserver"; // oops, sidebar?

this.ENUM_SUFFIX = "property.enumquery.prefs.suffix"; } ENUMQUERY_PREFS.prototype.getPrefBranch = function(){ if (!this.prefBranch){ this.prefBranch = Components.classes['@mozilla.org/preferences- service;1']; this.prefBranch = this.prefBranch.getService(); this.prefBranch = this.prefBranch.QueryInterface(Components.interfaces.nsIPrefBranch); } return this.prefBranch; }

ENUMQUERY_PREFS.prototype.setCharPref = function(aName, aValue){ var myPrefs = this.getPrefBranch();

myPrefs.setCharPref(aName, aValue); }

ENUMQUERY_PREFS.prototype.getCharPref = function(aName){ var myPrefs = this.getPrefBranch();

var rv = null; try{ rv = myPrefs.getCharPref(aName); } catch (e){ } return rv; } //--- var ENUMQUERY_PREFS; function pg_prefs_load() {

ENUMQUERY_PREFS = new ENUMQUERY_PREFS();

document.getElementById("enumquery.prefs.dnsserver").value= ENUMQUERY_PREFS.getCharPref(ENUMQUERY_PREFS.DNS_SERVER_ADDRESS); document.getElementById("enumquery.prefs.suffix").value = ENUMQUERY_PREFS.getCharPref(ENUMQUERY_PREFS.ENUM_SUFFIX); } function pg_prefs_accept() { ENUMQUERY_PREFS.setCharPref(ENUMQUERY_PREFS.DNS_SERVER_ADDRESS, document.getElementById ("enumquery.prefs.dnsserver").value) ENUMQUERY_PREFS.setCharPref(ENUMQUERY_PREFS.ENUM_SUFFIX, document.getElementById("enumquery.prefs.suffix").value); }

3.3. Kết quả hoạt động của các hệ thống thử nghiệm

3.3.1. Hệ thống VoIP sử dụng tổng đài chuyển mạch mềm hỗ trợ ENUM

Hệ thống cho phép:

- Gọi điện giữa softphone được kết nối cùng 1 tổng đài.

- Gọi điện giữa các softphone kết nối với 2 tổng đài khác nhau. Người sử

dụng kết nối với tổng đài Asterisk 1 ( số điện thoại 1xx) có thể gọi điện tới người sử dụng kết nối với tổng đài Asterisk 2 (số điện thoại 7xx).

- Gọi điện từ softphone thuộc mạng IP đến 1 số điện thoại bất kỳ (cố định,

di động) thuộc mạng PSTN tại Việt Nam.

- Gọi điện từ mạng PSTN đến softphone.

Softphone sử dụng phần mềm X-Lite của X-ten (http://www.xten.com) với các cấu hình đặt như sau:

Hoạt động giữa các softphone kết nối cùng với một tổng đài Asterisk

Người sử dụng A có số điện thoại (100) gọi điện đến người sử dụng B có số điện thoại (101).

Người sử dụng A quay số 101.

Do 2 số điện thoại 100 và 101 được kết nối với tổng đài Asterisk nên tổng đài xác định được địa chỉ của số điện thoại 101.

Thông qua thủ tục SIP, tổng đài sẽ báo hiệu với người sử dụng B.

Người sử dụng A và B được báo hiệu sẽ kết nối để thiết lập kênh thoại với nhau. Tín hiệu thoại sẽ được truyền qua mạng IP theo giao thức RTP.

Hình 27. Cuộc gọi giữa 2 softphone

Nguyên tắc hoạt động khi gọi điện giữa các softphone kết nối với hai tổng đài Asterisk

Người sử dụng A kết nối với tổng đài Asterisk 1 ( số điện thoại 100) gọi điện tới người sử dụng B kết nối với tổng đài Asterisk 2 (số điện thoại 700).

Người sử dụng A quay số 847700.

Tổng đài Asterisk 1 nhận được số bị gọi là 847700.

Tổng đài sẽ kết nối với máy chủ DNS để thực hiện truy vấn ENUM tìm ra địa chỉ SIP của người bị gọi. Sau khi truy vấn sẽ thu được địa chỉ

700@voip2.vnnic.net.vn .

Tổng đài Asterisk 1 sẽ kết nối với tổng đài Asterisk 2 để kết nối báo hiệu với người sử dụng 2.

Tổng đài Asterisk 2 nhận được tín hiệu báo hiệu thiết lập cuộc gọi với người sử dụng 700 (đã đăng ký với tổng đài). Tổng đài Asterisk 2 báo hiệu với người sử dụng 700 để thiết lập kênh thoại.

Người sử dụng A và B được báo hiệu sẽ kết nối để thiết lập kênh thoại với nhau. Tín hiệu thoại sẽ được truyền qua mạng IP theo giao thức RTP.

Hoạt động của hệ thống khi gọi từ softphone ra mạng PSTN

Người sử dụng A ( số điện thoại 100 ) gọi điện cho người sử dụng B ở mạng PSTN có số điện thoại 8445564952.

Người sử dụng A quay số điện thoại 8445564952. Tổng đài Asterisk 1 nhận được số bị gọi 8445564952.

Tổng đài Asterisk 1 kết nối tới hệ thống DNS để truy vấn ENUM. Tổng đài

Asterisk 1 sẽ thu được địa chỉ SIP là 8445564952@sipgateway.vnnic.net.vn.

Tổng đài Asterisk 1 kết nối với router gateway qua thủ tục SIP để gọi điện đến

địa chỉ 8445564952@sipgateway.vnnic.net.vn.

Router gateway nhận được địa chỉ 8445564952@sipgateway.vnnic.net.vn

Router gateway gọi điện tới mạng PSTN tại số điện thoại 8445564952 theo phương thức gọi điện thông thường của mạng PSTN.

Kênh thoại sẽ được thiết lập theo hướng:

User A -> tổng đài Asterisk1 -> Router gateway -> mạng PSTN -> User B.

Hình 28. Gọi từ softphone ra PSTN (cố định và di động)

Hoạt động của hệ thống khi gọi từ mạng PSTN tới số điện thoại Softphone

Để gọi điện tới mạng VOIP, người sử dụng cần gọi điện tới số điện thoại 5564944 để kết nối với Router gateway.

Sau khi kết nối với router gateway, người sử dụng sẽ nhận được âm mời quay số. Người sử dụng A quay tiếp số 841100 để gọi điện tới số điện thoại 100.

Router gateway nhận được số điện thoại 841100.

Router kết nối với tổng đài Asterisk 2 để thiết lập kết nối theo địa chỉ 844100@voip2.vnnic.net.vn.

Tổng đài Asterisk 2 thực hiện truy vấn ENUM để tìm ra địa chỉ Sip

100@voip1.vnnic.net.vn.

Tổng đài Asterisk 1 kết nối với người sử dụng tại địa chỉ 100 để thiết lập kênh thoại.

Kênh thoại sẽ được thiết lập như sau:

Người sử dụng PSTN -> Router gateway -> tổng đài Asterisk 2 -> tổng đài Asterisk 1 -> User B ( số điện thoại 100).

3.3.2. Trình duyệt Web (Firefox) hỗ trợ truy nhập Website qua số ENUM

Chương trình Plugin được cài đặt vào Mozilla Firefox và chèn thêm một chức

năng Enum Query trong thực đơn Tool của trình duyệt.

Nhờ chương trình Plugin này, người dùng có thể nhập trực tiếp số ENUM vào trình duyệt Firefox để truy nhập vào Website của chủ nhân số ENUM đã có đăng

Một phần của tài liệu Phương vị từ tiếng Hán hiện đại và những biểu hiện từ vựng, ngữ pháp tương đương trong tiếng Việt (Trang 67)

Tải bản đầy đủ (PDF)

(89 trang)