自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

通過 JNI 移植一個 tracepath 追蹤路由數(shù)據(jù)鏈給你的應(yīng)用

商務(wù)辦公
Linux 的 tracepath 指令可以追蹤數(shù)據(jù)到達(dá)目標(biāo)主機(jī)的路由信息,同時還能夠發(fā)現(xiàn) MTU 值。它跟蹤路徑到目的地,沿著這條路徑發(fā)現(xiàn) MTU。它使用 UDP 端口或一些隨機(jī)端口。

[[356805]]

背景

Linux 的 tracepath 指令可以追蹤數(shù)據(jù)到達(dá)目標(biāo)主機(jī)的路由信息,同時還能夠發(fā)現(xiàn) MTU 值。它跟蹤路徑到目的地,沿著這條路徑發(fā)現(xiàn) MTU。它使用 UDP 端口或一些隨機(jī)端口。它類似于 Traceroute,只是不需要超級用戶權(quán)限,并且沒有花哨的選項(xiàng)。

Android 也是移植的它,其源碼放置位置在platform/external/iputils/tracepath6.c。我們之所以直接移植tracepath6.c而不是tracepath.c的原因是 tracepath6 支持 IPV6 和 IPV4 兩種模式,而tracepath.c僅僅支持 IPV4,所以一把梭后我們直接完美兼容了兩種。

最近剛好在調(diào)研網(wǎng)絡(luò)診斷覆蓋能力,所以順手移植了下它,大致效果如下。

demo 效果

移植后開箱即用地址https://github.com/yanbober/android-tracepath,喜歡就給個小星星唄,一閃一閃亮晶晶。

開始移植

本想撿個現(xiàn)成,去看了platform/external/iputils/tracepath6.c源碼發(fā)現(xiàn)這貨直接是寫死默認(rèn)假定 IPV6 模式的,需要不同模式的話需要自己執(zhí)行命令時傳遞模式參數(shù),不支持自己動態(tài)識別模式,所以需要移植改造。

定義 Java 接口約定

為了方便給 app 使用,需要通過 JNI 包裝到 Java 層接口,約定如下:

  1. package cn.yan.android.tracepath; 
  2.  
  3. public final class AndroidTracePath { 
  4.     static { 
  5.         System.loadLibrary("tracepath-compat"); 
  6.     } 
  7.  
  8.     private StateListener mStateListener; 
  9.  
  10.     public AndroidTracePath(StateListener stateListener) { 
  11.         this.mStateListener = stateListener; 
  12.     } 
  13.  //業(yè)務(wù)方調(diào)用開始 tracepath 的方法,hostName 是你的域名或者 ip 
  14.     public void startTrace(String hostName) { 
  15.         nativeInit(); 
  16.         nativeStartTrace(hostName); 
  17.     } 
  18.  
  19.     public native void nativeInit(); 
  20.  
  21.     public native void nativeStartTrace(String hostName); 
  22.  
  23.     public void nativeOnStart() { 
  24.         if (null != mStateListener) { 
  25.             mStateListener.onStart(); 
  26.         } 
  27.     } 
  28.  
  29.     public void nativeOnUpdate(String update) { 
  30.         if (null != mStateListener) { 
  31.             mStateListener.onUpdate(update); 
  32.         } 
  33.     } 
  34.  
  35.     public void nativeOnEnd() { 
  36.         if (null != mStateListener) { 
  37.             mStateListener.onEnd(); 
  38.         } 
  39.     } 
  40.  //tracepath 回調(diào)狀態(tài) 
  41.     public interface StateListener { 
  42.         void onStart(); 
  43.         void onUpdate(String update); 
  44.         void onEnd(); 
  45.     } 

接著就是對應(yīng) JNI 層的接口了,這里沒啥說的,都是老套路,一鍵生成也罷,動態(tài)映射也罷,隨意擺弄,反正最終能調(diào)用到tracepath6.c源碼就行。

我們重點(diǎn)是改造tracepath6.c,由于這玩意默認(rèn)編譯后是一個可執(zhí)行文件,我們通過 cmake 需要當(dāng)作依賴編譯,所以他的 main 方法入口就不再適合我們了,我們需要進(jìn)行改造(換個方法名即可),如下:

  1. //int main(int argc, char **argv) 替換為 tracepath 函數(shù) 
  2. int tracepath(int argc, char **argv) 

這玩意需要給我們的 JNI 包裝接口(apicompat.c)調(diào)用,所以我們給他新建一個頭文件把這個方法報漏一下,如下:

  1. //tracepath6.h 
  2.  
  3. #ifndef ANDROIDTRACEPATH_TRACEPATH6_H 
  4. #define ANDROIDTRACEPATH_TRACEPATH6_H 
  5.  
  6. int tracepath(int argc, char** arg); 
  7.  
  8. #endif //ANDROIDTRACEPATH_TRACEPATH6_H 

手機(jī)連著 ipv4 的網(wǎng)絡(luò)一運(yùn)行,臥槽,跪了,定位代碼發(fā)現(xiàn)tracepath6.c里面是寫死模式的,需要動態(tài)適配,改造點(diǎn)如下:

  1. ...... 
  2. sa_family_t family = AF_UNSPEC; //把這里初值A(chǔ)F_INET6換成AF_UNSPEC 
  3. ...... 
  4. int tracepath(int argc, char **argv) 
  5.  ...... 
  6.  memset(&hints, 0, sizeof(hints)); 
  7.  hints.ai_family = AF_UNSPEC; //把這里family變量換成AF_UNSPEC 
  8.  hints.ai_socktype = SOCK_DGRAM; 
  9.  hints.ai_protocol = IPPROTO_UDP; 
  10. #ifdef USE_IDN 
  11.  hints.ai_flags = AI_IDN; 
  12. #endif 
  13.  gai = getaddrinfo(argv[0], pbuf, &hints, &ai0); 
  14.  if (gai) { 
  15.   fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(gai)); 
  16.         return 1; 
  17.  } 
  18.  
  19.  fd = -1; 
  20.  for (ai = ai0; ai; ai = ai->ai_next) { 
  21.   //這里一段判斷family的邏輯刪掉 
  22.   if (ai->ai_family != AF_INET6 && 
  23.       ai->ai_family != AF_INET) 
  24.    continue
  25.   family = ai->ai_family; 
  26.   fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); 
  27.   if (fd < 0) 
  28.    continue
  29.   memcpy(&target, ai->ai_addr, sizeof(target)); 
  30.   targetlen = ai->ai_addrlen; 
  31.   break; 
  32.  } 
  33.  ...... 

可以看到,貫穿全流程的模式是通過一個全局的 family 變量類型來維護(hù)的,默認(rèn)改為 AF_UNSPEC 后就會自動探測類型,匹配到 AF_INET6 或者 AF_INET 則走自己對應(yīng)邏輯,這樣就能完美兼容 IPV6 和 IPV4 了。

到此運(yùn)行能出結(jié)果了,但是 tracepath 的打印結(jié)果沒法輸出到 Java 層回調(diào)中,我們需要繼續(xù)改造。常規(guī)想法就是一個一個換掉tracepath6.c里面的 printf 函數(shù)為 JNI 回調(diào) Java 方法實(shí)現(xiàn),這樣比較麻煩。我們還是采用了一把梭的模式,如下:

  1. //tracepath6.c 
  2.  
  3. #include "./../apicompat.h" 
  4.  
  5. #define printf(...) callbackOnUpdate(__VA_ARGS__) 

如上通過一個宏直接替換 printf 為我們 JNI 接口層的 callbackOnUpdate 函數(shù),這個函數(shù)的作用就是調(diào)用 Java 方法,這樣就能把數(shù)據(jù)傳遞回去了。

到此基本 ok 了,還差最后的優(yōu)化,你也看到了,tracepath6.c編寫初衷是一個可執(zhí)行程序,現(xiàn)在把它移植成 so,所以我們不能在直接 exit 了,相關(guān)地方都需要一把梭的替換為 return 解決問題,到此完美解決所有。

 

責(zé)任編輯:武曉燕 來源: 碼農(nóng)每日一題
相關(guān)推薦

2018-08-26 05:38:44

路由器調(diào)制解調(diào)器網(wǎng)絡(luò)設(shè)備

2021-04-14 15:59:50

博睿數(shù)據(jù)金融科技APM

2021-05-12 14:44:28

大數(shù)據(jù)數(shù)據(jù)鏈博睿數(shù)據(jù)

2020-09-06 22:59:35

Linux文件命令

2023-01-30 16:21:24

Linux外觀

2021-04-20 20:10:15

博睿數(shù)據(jù)數(shù)據(jù)鏈DNA

2022-07-06 19:00:00

微服務(wù)框架鏈路

2018-08-22 17:32:45

2022-12-22 08:22:17

Python圖像圖像處理

2021-09-29 10:35:02

數(shù)據(jù)鏈DNA博睿數(shù)據(jù)

2021-08-04 17:55:38

keysRedis數(shù)據(jù)庫

2018-01-30 05:04:02

2012-12-12 09:47:56

JavaScript

2018-07-03 15:20:36

Promise函數(shù)借錢

2012-03-05 19:43:00

lumia

2022-05-23 08:23:24

鏈路追蹤SleuthSpring

2019-09-30 09:26:29

Java編程語言國旗

2020-09-15 13:56:08

公眾號機(jī)器人圖靈機(jī)器人

2014-11-19 13:06:59

2009-06-22 13:50:00

java連接mysql
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號