成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

通過 JNI 移植一個 tracepath 追蹤路由數據鏈給你的應用

商務辦公
Linux 的 tracepath 指令可以追蹤數據到達目標主機的路由信息,同時還能夠發現 MTU 值。它跟蹤路徑到目的地,沿著這條路徑發現 MTU。它使用 UDP 端口或一些隨機端口。

[[356805]]

背景

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

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

最近剛好在調研網絡診斷覆蓋能力,所以順手移植了下它,大致效果如下。

demo 效果

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

開始移植

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

定義 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.  //業務方調用開始 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 回調狀態 
  41.     public interface StateListener { 
  42.         void onStart(); 
  43.         void onUpdate(String update); 
  44.         void onEnd(); 
  45.     } 

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

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

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

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

  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 

手機連著 ipv4 的網絡一運行,臥槽,跪了,定位代碼發現tracepath6.c里面是寫死模式的,需要動態適配,改造點如下:

  1. ...... 
  2. sa_family_t family = AF_UNSPEC; //把這里初值AF_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 變量類型來維護的,默認改為 AF_UNSPEC 后就會自動探測類型,匹配到 AF_INET6 或者 AF_INET 則走自己對應邏輯,這樣就能完美兼容 IPV6 和 IPV4 了。

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

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

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

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

 

責任編輯:武曉燕 來源: 碼農每日一題
相關推薦

2018-08-26 05:38:44

路由器調制解調器網絡設備

2021-04-14 15:59:50

博睿數據金融科技APM

2021-05-12 14:44:28

大數據數據鏈博睿數據

2020-09-06 22:59:35

Linux文件命令

2023-01-30 16:21:24

Linux外觀

2021-04-20 20:10:15

博睿數據數據鏈DNA

2022-07-06 19:00:00

微服務框架鏈路

2018-08-22 17:32:45

2022-12-22 08:22:17

Python圖像圖像處理

2021-09-29 10:35:02

數據鏈DNA博睿數據

2018-01-30 05:04:02

2021-08-04 17:55:38

keysRedis數據庫

2022-05-23 08:23:24

鏈路追蹤SleuthSpring

2018-07-03 15:20:36

Promise函數借錢

2012-03-05 19:43:00

lumia

2012-12-12 09:47:56

JavaScript

2019-09-30 09:26:29

Java編程語言國旗

2020-09-15 13:56:08

公眾號機器人圖靈機器人

2014-11-19 13:06:59

2021-05-12 14:48:12

大數據博睿數據數據鏈DNA
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩欧美在线观看视频 | 久久婷婷麻豆国产91天堂 | 日韩在线一区二区三区 | 精品美女视频在线观看免费软件 | 国产特一级黄色片 | 久久久精品一区二区三区四季av | 在线免费视频一区 | 日韩在线免费看 | 日韩一及片 | 国产精品99久久久久久久久久久久 | 美女三区 | 欧美区在线| 国产一区二区免费电影 | 久久69精品久久久久久国产越南 | 日本免费黄色一级片 | 爱操影视 | 欧美视频三区 | 超碰日韩 | 色婷婷综合在线观看 | 亚洲精品在线观 | 精久久久 | 国产二区视频 | 91影院在线观看 | 欧美成人性生活 | 亚洲精品久久久久国产 | 久久久久1 | 色视频在线免费观看 | 精品免费国产视频 | 日韩在线观看一区 | 成人在线免费电影 | 国产精品久久久久永久免费观看 | 日本一区二区高清不卡 | 日韩电影免费在线观看中文字幕 | 一区二区三区亚洲视频 | 日本免费一区二区三区 | a级片www| 久久久91| 久久久久久久一区二区 | 天天操天天干天天曰 | 成人精品视频在线 | 亚洲国产一区二区在线 |