一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

DBUS基礎(chǔ)知識

 orion360doc 2011-12-08

DBUS基礎(chǔ)知識

1.  進程間使用D-Bus通信

D-Bus是一種高級的進程間通信機制,它由項目提供,使用GPL許可證發(fā)行。D-Bus最主要的用途是在Linux桌面環(huán)境為進程提供通信,同時能將Linux桌面環(huán)境和Linux內(nèi)核事件作為消息傳遞到進程。D-Bus的主要概率為總線,注冊后的進程可通過總線接收或傳遞消息,進程也可注冊后等待內(nèi)核事件響應(yīng),例如等待網(wǎng)絡(luò)狀態(tài)的轉(zhuǎn)變或者計算機發(fā)出關(guān)機指令。目前,D-Bus已被大多數(shù)Linux發(fā)行版所采用,開發(fā)者可使用D-Bus實現(xiàn)各種復(fù)雜的進程間通信任務(wù)。

2.  D-Bus的基本概念

D-Bus是一個消息總線系統(tǒng),其功能已涵蓋進程間通信的所有需求,并具備一些特殊的用途。D-Bus是三層架構(gòu)的進程間通信系統(tǒng),其中包括:

接口層:接口層由函數(shù)庫libdbus提供,進程可通過該庫使用D-Bus的能力。

總線層:總線層實際上是由D-Bus總線守護進程提供的。它在Linux系統(tǒng)啟動時運行,負責進程間的消息路由和傳遞,其中包括Linux內(nèi)核和Linux桌面環(huán)境的消息傳遞。

包裝層:包裝層一系列基于特定應(yīng)用程序框架的Wrapper庫。

D-Bus具備自身的協(xié)議,協(xié)議基于二進制數(shù)據(jù)設(shè)計,與數(shù)據(jù)結(jié)構(gòu)和編碼方式無關(guān)。該協(xié)議無需對數(shù)據(jù)進行序列化,保證了信息傳遞的高效性。無論是libdbus,還是D-Bus總線守護進程,均不需要太大的系統(tǒng)開銷。

總線是D-Bus的進程間通信機制,一個系統(tǒng)中通常存在多條總線,這些總線由D-Bus總線守護進程管理。最重要的總線為系統(tǒng)總線(System Bus),Linux內(nèi)核引導(dǎo)時,該總線就已被裝入內(nèi)存。只有Linux內(nèi)核、Linux桌面環(huán)境和權(quán)限較高的程序才能向該總線寫入消息,以此保障系統(tǒng)安全性,防止有惡意進程假冒Linux發(fā)送消息。

會話總線(Session Buses)由普通進程創(chuàng)建,可同時存在多條。會話總線屬于某個進程私有,它用于進程間傳遞消息。

進程必須注冊后才能收到總線中的消息,并且可同時連接到多條總線中。D-Bus提供了匹配器(Matchers)使進程可以有選擇性的接收消息,另外運行進程注冊回調(diào)函數(shù),在收到指定消息時進行處理。匹配器的功能等同與路由,用于避免處理無關(guān)消息造成進程的性能下降。除此以外,D-Bus機制的重要概念有以下幾個。

對象:對象是封裝后的匹配器與回調(diào)函數(shù),它以對等(peer-to-peer)協(xié)議使每個消息都有一個源地址和一個目的地址。這些地址又稱為對象路徑,或者稱之為總線名稱。對象的接口是回調(diào)函數(shù),它以類似C++的虛擬函數(shù)實現(xiàn)。當一個進程注冊到某個總線時,都要創(chuàng)建相應(yīng)的消息對象。

消息:D-Bus的消息分為信號(signals)、方法調(diào)用(method calls)、方法返回(method returns)和錯誤(errors)。信號是最基本的消息,注冊的進程可簡單地發(fā)送信號到總線上,其他進程通過總線讀取消息。方法調(diào)用是通過總線傳遞參數(shù),執(zhí)行另一個進程接口函數(shù)的機制,用于某個進程控制另一個進程。方法返回是注冊的進程在收到相關(guān)信息后,自動做出反應(yīng)的機制,由回調(diào)函數(shù)實現(xiàn)。錯誤是信號的一種,是注冊進程錯誤處理機制之一。

服務(wù):服務(wù)(Services)是進程注冊的抽象。進程注冊某個地址后,即可獲得對應(yīng)總線的服務(wù)。D-Bus提供了服務(wù)查詢接口,進程可通過該接口查詢某個服務(wù)是否存在。或者在服務(wù)結(jié)束時自動收到來自系統(tǒng)的消息。

建立服務(wù)的流程:
----------------------------------
    建立一個dbus連接之后 -- dbus_bus_get(),為這個dbus連接(DbusConnection)起名 -- dbus_bus_request_name(),這個名字將會成為我們在后續(xù)進行遠程調(diào)用的時候的服務(wù)名,然后我們進入監(jiān)聽循環(huán) -- dbus_connection_read_write()。在循環(huán)中,我們從總線上取出消息 -- dbus_connection_pop_message(),并通過比對消息中的方法接口名和方法名 -- dbus_message_is_method_call(),如果一致,那么我們跳轉(zhuǎn)到相應(yīng)的處理中去。在相應(yīng)的處理中,我們會從消息中取出遠程調(diào)用的參數(shù)。并且建立起回傳結(jié)果的通路 -- reply_to_method_call()。回傳動作本身等同于一次不需要等待結(jié)果的遠程調(diào)用。
發(fā)送信號的流程:
----------------------------------
    建立一個dbus連接之后,為這個dbus連接起名,建立一個發(fā)送信號的通道,注意,在建立通道的函數(shù)中,需要我們填寫該信號的接口名和信號名 -- dbus_message_new_signal()。然后我們把信號對應(yīng)的相關(guān)參數(shù)壓進去 -- dbus_message_iter_init_append(); dbus_message_iter_append_basic()。然后就可以啟動發(fā)送了 -- dbus_connection_send(); dbus_connection_flush。
進行一次遠程調(diào)用的流程:
----------------------------------
    建立好dbus連接之后,為這dbus連接命名,申請一個遠程調(diào)用通道 -- dbus_message_new_method_call(),注意,在申請遠程調(diào)用通道的時候,需要填寫服務(wù)器名,本次調(diào)用的接口名,和本次調(diào)用名(方法名)。壓入本次調(diào)用的參數(shù) -- dbus_message_iter_init_append(); dbus_message_iter_append_basic(),實際上是申請了一個首地址,我們就是把我們真正要傳的參數(shù),往這個首地址里面送(送完之后一般都會判斷是否內(nèi)存越界了)。然后就是啟動發(fā)送調(diào)用并釋放發(fā)送相關(guān)的消息結(jié)構(gòu) -- dbus_connection_send_with_reply()。這個啟動函數(shù)中帶有一個句柄。我們馬上會阻塞等待這個句柄給我們帶回總線上回傳的消息。當這個句柄回傳消息之后,我們從消息結(jié)構(gòu)中分離出參數(shù)。用dbus提供的函數(shù)提取參數(shù)的類型和參數(shù) -- dbus_message_iter_init(); dbus_message_iter_next(); dbus_message_iter_get_arg_type(); dbus_message_iter_get_basic()。也就達成了我們進行本次遠程調(diào)用的目的了。
信號接收流程:
----------------------------------
    建立一個dbus連接之后,為這個dbus連接起名,為我們將要進行的消息循環(huán)添加匹配條件(就是通過信號名和信號接口名來進行匹配控制的) -- dbus_bus_add_match()。我們進入等待循環(huán)后,只需要對信號名,信號接口名進行判斷就可以分別處理各種信號了。在各個處理分支上。我們可以分離出消息中的參數(shù)。對參數(shù)類型進行判斷和其他的處理。
dbus_connection_read_write()
--------------------------------------
    As long as the connection is open, this function will block until it can read or write, then read or write, then return #TRUE.
    If the connection is closed, the function returns #FALSE.
dbus_connection_pop_message()
--------------------------------------
    Returns the first-received message from the incoming message queue, removing it from the queue. The caller owns a reference to the returned message. If the queue is empty, returns #NULL.
dbus_connection_send()
--------------------------------------
    Adds a message to the outgoing message queue. Does not block to write the message to the network; that happens asynchronously. To force the message to be written, call dbus_connection_flush(). Because this only queues the message, the only reason it can
fail is lack of memory. Even if the connection is disconnected, no error will be returned.
    @param connection the connection.
    @param message the message to write.
    @param serial return location for message serial, or #NULL if you don't care
    @returns #TRUE on success.
dbus_connection_send_with_reply()
--------------------------------------
    Queues a message to send, as with dbus_connection_send(), but also returns a #DBusPendingCall used to receive a reply to the message. If no reply is received in the given timeout_milliseconds, this function expires the pending reply and generates a synthetic error reply (generated in-process, not by the remote application) indicating that a timeout occurred.
    A #DBusPendingCall will see a reply message before any filters or registered object path handlers. See dbus_connection_dispatch() for details on when handlers are run.
    A #DBusPendingCall will always see exactly one reply message, unless it's cancelled with dbus_pending_call_cancel().
    If #NULL is passed for the pending_return, the #DBusPendingCall will still be generated internally, and used to track the message reply timeout. This means a timeout error will occur if no reply arrives, unlike with dbus_connection_send().
    If -1 is passed for the timeout, a sane default timeout is used. -1 is typically the best value for the timeout for this reason, unless you want a very short or very long timeout. There is no way to avoid a timeout entirely, other than passing INT_MAX for the
timeout to mean "very long timeout." libdbus clamps an INT_MAX timeout down to a few hours timeout though.
    @warning if the connection is disconnected, the #DBusPendingCall will be set to #NULL, so be careful with this.
    @param connection the connection
    @param message the message to send
    @param pending_return return location for a #DBusPendingCall object, or #NULL if connection is disconnected
    @param timeout_milliseconds timeout in milliseconds or -1 for default
    @returns #FALSE if no memory, #TRUE otherwise.
dbus_message_is_signal()
--------------------------------------
    Checks whether the message is a signal with the given interface and member fields. If the message is not #DBUS_MESSAGE_TYPE_SIGNAL, or has a different interface or member field, returns #FALSE.
dbus_message_iter_init()
--------------------------------------
    Initializes a #DBusMessageIter for reading the arguments of the message passed in.
dbus_message_iter_next()
--------------------------------------
    Moves the iterator to the next field, if any. If there's no next field, returns #FALSE. If the iterator moves forward, returns #TRUE.
dbus_message_iter_get_arg_type()
--------------------------------------
    Returns the argument type of the argument that the message iterator points to. If the iterator is at the end of the message, returns #DBUS_TYPE_INVALID.
dbus_message_iter_get_basic()
--------------------------------------
    Reads a basic-typed value from the message iterator. Basic types are the non-containers such as integer and string.
dbus_message_new_signal()
--------------------------------------
    Constructs a new message representing a signal emission. Returns #NULL if memory can't be allocated for the message. A signal is identified by its originating object path, interface, and the name of the signal.
    Path, interface, and signal name must all be valid (the D-Bus specification defines the syntax of these fields).
    @param path the path to the object emitting the signal
    @param interface the interface the signal is emitted from
    @param name name of the signal
    @returns a new DBusMessage, free with dbus_message_unref()
dbus_message_iter_init_append()
--------------------------------------
    Initializes a #DBusMessageIter for appending arguments to the end of a message.
    @param message the message
    @param iter pointer to an iterator to initialize
dbus_message_iter_append_basic()
--------------------------------------
    Appends a basic-typed value to the message. The basic types are the non-container types such as integer and string.
    @param iter the append iterator
    @param type the type of the value
    @param value the address of the value
    @returns #FALSE if not enough memory
dbus_message_new_method_call()
--------------------------------------
    Constructs a new message to invoke a method on a remote object. Returns #NULL if memory can't be allocated for the message. The destination may be #NULL in which case no destination is set; this is appropriate when using D-Bus in a peer-to-peer context (no message bus). The interface may be #NULL, which means that if multiple methods with the given name exist it is undefined which one will be invoked.
    The path and method names may not be #NULL.
    Destination, path, interface, and method name can't contain any invalid characters (see the D-Bus specification).
    @param destination name that the message should be sent to or #NULL
    @param path object path the message should be sent to
    @param interface interface to invoke method on, or #NULL
    @param method method to invoke
    @returns a new DBusMessage, free with dbus_message_unref()
dbus_bus_get()
--------------------------------------
    Connects to a bus daemon and registers the client with it. If a connection to the bus already exists, then that connection is returned. The caller of this function owns a reference to the bus.
    @param type bus type
    @param error address where an error can be returned.
    @returns a #DBusConnection with new ref
dbus_bus_request_name()
--------------------------------------
    Asks the bus to assign the given name to this connection by invoking the RequestName method on the bus.
    First you should know that for each bus name, the bus stores a queue of connections that would like to own it. Only one owns it at a time - called the primary owner. If the primary owner releases the name or disconnects, then the next owner in the queue atomically takes over.
    So for example if you have an application org.freedesktop.TextEditor and multiple instances of it can be run, you can have all of them sitting in the queue. The first one to start up will receive messages sent to org.freedesktop.TextEditor, but if that one exits another will become the primary owner and receive messages.
    The queue means you don't need to manually watch for the current owner to disappear and then request the name again.
    @param connection the connection
    @param name the name to request
    @param flags flags
    @param error location to store the error
    @returns a result code, -1 if error is set
    給DBusConnection起名字(命名) -- 兩個相互通信的連接(connection)不能同名
    命名規(guī)則: xxx.xxx (zeng.xiaolong)
dbus_bus_add_match()
--------------------------------------
    Adds a match rule to match messages going through the message bus. The "rule" argument is the string form of a match rule.
    @param connection connection to the message bus
    @param rule textual form of match rule
    @param error location to store any errors
dbus_pending_call_block()
--------------------------------------
    Block until the pending call is completed. The blocking is as with dbus_connection_send_with_reply_and_block(); it does not enter the main loop or process other messages, it simply waits for the reply in question.
    If the pending call is already completed, this function returns immediately.
    @todo when you start blocking, the timeout is reset, but it should really only use time remaining since the pending call was created. This requires storing timestamps instead of intervals in the timeout
    @param pending the pending call
dbus_pending_call_steal_reply()
--------------------------------------
    Gets the reply, or returns #NULL if none has been received yet. Ownership of the reply message passes to the caller. This function can only be called once per pending call, since the reply message is tranferred to the caller.
    @param pending the pending call
    @returns the reply message or #NULL.

安裝D-Bus可在其官方網(wǎng)站下載源碼編譯,地址為http://dbus.?;蛘咴诮K端上輸入下列指令:

    1. yum install dbus dbus-devel dbus-doc

安裝后,頭文件位于"/usr/include/dbus-<版本號>/dbus"目錄中,編譯使用D-Bus的程序時需加入編譯指令"`pkg-config --cflags --libs dbus-1`"。

3.  D-Bus的用例

在使用GNOME桌面環(huán)境的Linux系統(tǒng)中,通常用GLib庫提供的函數(shù)來管理總線。在測試下列用例前,首先需要安裝GTK+開發(fā)包(見22.3節(jié))并配置編譯環(huán)境。該用例一共包含兩個程序文件,每個程序文件需單獨編譯成為可執(zhí)行文件。

1.消息發(fā)送程序

"dbus-ding-send.c"程序每秒通過會話總線發(fā)送一個參數(shù)為字符串Ding!的信號。該程序的源代碼如下:

  1. #include <glib.h>                               // 包含glib庫  
  2. #include <dbus/dbus-glib.h>                     // 包含
    glib庫中D-Bus管理庫  
  3. #include <stdio.h> 
  4. static gboolean send_ding(DBusConnection *bus);// 定義發(fā)送消息函數(shù)的原型  
  5. int main ()  
  6. {  
  7.    GMainLoop *loop;                             // 定義一個事件循環(huán)對象的指針  
  8.    DBusConnection *bus;                         // 定義總線連接對象的指針  
  9.    DBusError error;                             // 定義D-Bus錯誤消息對象  
  10.    loop = g_main_loop_new(NULL, FALSE);         // 創(chuàng)建新事件循環(huán)對象  
  11.    dbus_error_init (&error);                    // 將錯誤消息對象連接到D-Bus  
  12.                                                 // 錯誤消息對象  
  13.    bus = dbus_bus_get(DBUS_BUS_SESSION, &error);// 連接到總線  
  14.    if (!bus) {                              // 判斷是否連接錯誤  
  15. g_warning("連接到D-Bus失敗: %s", error.message);  
  16.                                         // 使用GLib輸出錯誤警告信息  
  17.       dbus_error_free(&error);              // 清除錯誤消息  
  18.       return 1;  
  19.    }  
  20.    dbus_connection_setup_with_g_main(bus, NULL);  
  21.                                             // 將總線設(shè)為接收GLib事件循環(huán)  
  22.    g_timeout_add(1000, (GSourceFunc)send_ding, bus);  
  23.                                     // 每隔1000ms調(diào)用一次send_ding()函數(shù)  
  24.                                             // 將總線指針作為參數(shù)  
  25.    g_main_loop_run(loop);                   // 啟動事件循環(huán)  
  26.    return 0;  
  27. }  
  28. static gboolean send_ding(DBusConnection *bus)  // 定義發(fā)
    送消息函數(shù)的細節(jié)  
  29. {  
  30.    DBusMessage *message;                        // 創(chuàng)建消息對象指針  
  31.    message = dbus_message_new_signal("/com/burtonini/dbus/ding",   
  32.                                        "com.burtonini.dbus.Signal",  
  33.                                        "ding");     // 創(chuàng)建消息對象并標識路徑  
  34.    dbus_message_append_args(message,  
  35.                             DBUS_TYPE_STRING, "ding!",  
  36.                             DBUS_TYPE_INVALID);     //將字符串Ding!定義為消息  
  37.    dbus_connection_send(bus, message, NULL);    // 發(fā)送該消息  
  38.    dbus_message_unref(message);                 // 釋放消息對象  
  39.    g_print("ding!\n");                          // 該函數(shù)等同與標準輸入輸出                                    
  40.    return TRUE;  
  41. }

main()函數(shù)創(chuàng)建一個GLib事件循環(huán),獲得會話總線的一個連接,并將D-Bus事件處理集成到GLib事件循環(huán)之中。然后它創(chuàng)建了一個名為send_ding()函數(shù)作為間隔為一秒的計時器,并啟動事件循環(huán)。send_ding()函數(shù)構(gòu)造一個來自于對象路徑"/com/burtonini/dbus/ding"和接口"com.burtonini.dbus.Signal"的新的Ding信號。然后,字符串Ding!作為參數(shù)添加到信號中并通過總線發(fā)送。在標準輸出中會打印一條消息以讓用戶知道發(fā)送了一個信號。

2.消息接收程序

dbus-ding-listen.c程序通過會話總線接收dbus-ding-send.c程序發(fā)送到消息。該程序的源代碼如下:

  1. #include <glib.h>                               // 包含glib庫  
  2. #include <dbus/dbus-glib.h>                     // 包含glib庫中D-Bus管理庫  
  3. static DBusHandlerResult signal_filter      // 定義接收消息函數(shù)的原型  
  4.       (DBusConnection *connection, DBusMessage *message, void *user_data);  
  5. int main()  
  6. {  
  7.    GMainLoop *loop;                             // 定義一個事件循環(huán)對象的指針  
  8.    DBusConnection *bus;                         // 定義總線連接對象的指針  
  9.    DBusError error;                             // 定義D-Bus錯誤消息對象  
  10.    loop = g_main_loop_new(NULL, FALSE);         // 創(chuàng)建新事件循環(huán)對象  
  11.    dbus_error_init(&error);                     // 將錯誤消息對象連接到D-Bus  
  12.                                                 // 錯誤消息對象  
  13.    bus = dbus_bus_get(DBUS_BUS_SESSION, &error);    // 連接到總線  
  14.    if (!bus) {                              // 判斷是否連接錯誤  
  15. g_warning("連接到D-Bus失敗: %s", error.message);  
  16.                                         // 使用GLib輸出錯誤警告信息  
  17.       dbus_error_free(&error);              // 清除錯誤消息  
  18.       return 1;  
  19.   }  
  20.    dbus_connection_setup_with_g_main(bus, NULL);      
  21.                                             // 將總線設(shè)為接收GLib事件循環(huán)  
  22.    dbus_bus_add_match(bus, "type='signal',interface
    ='com.burtonini.dbus.Signal'");  // 定義匹配器  
  23.    dbus_connection_add_filter(bus, signal_filter, loop, NULL);  
  24.                                             // 調(diào)用函數(shù)接收消息  
  25.    g_main_loop_run(loop);                   // 啟動事件循環(huán)  
  26.    return 0;  
  27. }  
  28. static DBusHandlerResult                    // 定義接收消息函數(shù)的細節(jié)  
  29. signal_filter (DBusConnection *connection,
    DBusMessage *message, void *user_data)  
  30. {  
  31.    GMainLoop *loop = user_data;             // 定義事件循環(huán)對象的指針,并與主函數(shù)中的同步  
  32.    if (dbus_message_is_signal               // 接收連接成功消息,判斷是否連接失敗  
  33.         (message, DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL,
    "Disconnected")) {  
  34.       g_main_loop_quit (loop);              // 退出主循環(huán)  
  35.       return DBUS_HANDLER_RESULT_HANDLED;  
  36.    }  
  37.    if (dbus_message_is_signal(message, "com.burtonini.dbus.Signal",   
  38.    "Ping")) {  
  39.                                             // 指定消息對象路徑,判斷是否成功  
  40.       DBusError error;                      // 定義錯誤對象  
  41.       char *s;  
  42. dbus_error_init(&error);                // 將錯誤消息對象連接到D-Bus錯誤  
  43.                                         // 消息對象  
  44.       if (dbus_message_get_args                 // 接收消息,并判斷是否有錯誤  
  45.          (message, &error, DBUS_TYPE_STRING, &s,
    DBUS_TYPE_INVALID)) {  
  46.          g_print("接收到的消息是: %s\n", s);   // 輸出接收到的消息  
  47.          dbus_free (s);                     // 清除該消息  
  48.       }   
  49.       else {                                    // 有錯誤時執(zhí)行下列語句  
  50.          g_print("消息已收到,但有錯誤提示: %s\n", error.message);  
  51.          dbus_error_free (&error);  
  52.       }  
  53.       return DBUS_HANDLER_RESULT_HANDLED;  
  54.    }  
  55.    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;  
  56. }

該程序偵聽dbus-ping-send.c程序正在發(fā)出的信號。main()函數(shù)和前面一樣啟動,創(chuàng)建一個到總線的連接。然后它聲明愿意在使用com.burtonini.dbus.Signal接口的信號被發(fā)送時得到通知,將signal_filter()函數(shù)設(shè)置為通知函數(shù),然后進入事件循環(huán)。當滿足匹配的消息被發(fā)送時,signal_func()函數(shù)會被調(diào)用。

如果需要確定在接收消息時如何處理,可通過檢測消息頭實現(xiàn)。若收到的消息為總線斷開信號,則主事件循環(huán)將被終止,因為監(jiān)聽的總線已經(jīng)不存在了。若收到其他的消息,首先將收到的消息與期待的消息進行比較,兩者相同則輸出其中參數(shù),并退出程序。兩者不相同則告知總線并沒有處理該消息,這樣消息會繼續(xù)保留在總線中供別的程序處理。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    国产精品99一区二区三区| 亚洲一区二区精品久久av| 日韩黄色一级片免费收看| 视频一区二区三区自拍偷| 字幕日本欧美一区二区| 欧美日韩国产福利在线观看| 日韩三级黄色大片免费观看| 亚洲国产丝袜一区二区三区四| 国产乱淫av一区二区三区| 国语对白刺激高潮在线视频| 国产在线一区二区三区不卡| 日韩人妻中文字幕精品| 婷婷开心五月亚洲综合| 欧美日韩精品一区二区三区不卡| 亚洲国产精品久久综合网| 激情五月激情婷婷丁香| 98精品永久免费视频| 久久精品国产第一区二区三区| 日韩国产中文在线视频| av中文字幕一区二区三区在线| 欧美日韩国产欧美日韩| 中文字幕不卡欧美在线| 日韩成人动作片在线观看| 国产传媒一区二区三区| 久久天堂夜夜一本婷婷| 亚洲视频一级二级三级| 日韩欧美中文字幕av| 国产一区二区三区午夜精品| 国产成人国产精品国产三级| 亚洲午夜精品视频观看| 国产精品一区二区丝袜| 国产精品亚洲综合色区韩国| 精品偷拍一区二区三区| 亚洲伦理中文字幕在线观看| 亚洲国产av精品一区二区| 中文字幕中文字幕一区二区| 婷婷色香五月综合激激情| 亚洲国产成人爱av在线播放下载| 国产一区二区三区不卡| 久久精品福利在线观看| 国产精品免费不卡视频|