{"action":"created","comment":{"url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/pulls/comments/194226834","pull_request_review_id":127365943,"id":194226834,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDE5NDIyNjgzNA==","diff_hunk":"@@ -82,3 +82,15 @@\n   after = Time.now\n   assert_true (after - before) < (timeout + 1)\n end\n+\n+assert(\"FastRemoteCheck::ICMP#ping? for wait packet reply\") do\n+  ret = []\n+  th = []\n+  th << Thread.new { FastRemoteCheck::ICMP.new(\"1.1.1.1\", 3).ping? }\n+  th << Thread.new { FastRemoteCheck::ICMP.new(\"1.1.1.2\", 3).ping? }\n+  th << Thread.new { FastRemoteCheck::ICMP.new(\"1.1.1.3\", 3).ping? }\n+  th << Thread.new { FastRemoteCheck::ICMP.new(\"1.1.1.4\", 3).ping? }\n+  th << Thread.new { FastRemoteCheck::ICMP.new(\"1.1.1.5\", 3).ping? }","path":"test/mrb_fastremotecheck.rb","position":null,"original_position":12,"commit_id":"dd75c18bec3448e350af40e23014e203cd4807b4","original_commit_id":"eb5def336fd5c358981220b9947607fc2fc6b8bc","user":{"login":"matsumotory","id":648437,"node_id":"MDQ6VXNlcjY0ODQzNw==","avatar_url":"https://avatars0.githubusercontent.com/u/648437?v=4","gravatar_id":"","url":"https://api.github.com/users/matsumotory","html_url":"https://github.com/matsumotory","followers_url":"https://api.github.com/users/matsumotory/followers","following_url":"https://api.github.com/users/matsumotory/following{/other_user}","gists_url":"https://api.github.com/users/matsumotory/gists{/gist_id}","starred_url":"https://api.github.com/users/matsumotory/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/matsumotory/subscriptions","organizations_url":"https://api.github.com/users/matsumotory/orgs","repos_url":"https://api.github.com/users/matsumotory/repos","events_url":"https://api.github.com/users/matsumotory/events{/privacy}","received_events_url":"https://api.github.com/users/matsumotory/received_events","type":"User","site_admin":false},"body":"2.と3.だけじゃだめな理由はなんですか？","created_at":"2018-06-09T13:09:15Z","updated_at":"2018-06-09T13:09:15Z","html_url":"https://github.com/matsumotory/mruby-fast-remote-check/pull/8#discussion_r194226834","pull_request_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/pulls/8","author_association":"OWNER","_links":{"self":{"href":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/pulls/comments/194226834"},"html":{"href":"https://github.com/matsumotory/mruby-fast-remote-check/pull/8#discussion_r194226834"},"pull_request":{"href":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/pulls/8"}},"in_reply_to_id":194223267},"pull_request":{"url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/pulls/8","id":193656686,"node_id":"MDExOlB1bGxSZXF1ZXN0MTkzNjU2Njg2","html_url":"https://github.com/matsumotory/mruby-fast-remote-check/pull/8","diff_url":"https://github.com/matsumotory/mruby-fast-remote-check/pull/8.diff","patch_url":"https://github.com/matsumotory/mruby-fast-remote-check/pull/8.patch","issue_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/issues/8","number":8,"state":"open","locked":false,"title":"Wait for ICMP_ECHOREPLY packet alive","user":{"login":"takumakume","id":10905048,"node_id":"MDQ6VXNlcjEwOTA1MDQ4","avatar_url":"https://avatars2.githubusercontent.com/u/10905048?v=4","gravatar_id":"","url":"https://api.github.com/users/takumakume","html_url":"https://github.com/takumakume","followers_url":"https://api.github.com/users/takumakume/followers","following_url":"https://api.github.com/users/takumakume/following{/other_user}","gists_url":"https://api.github.com/users/takumakume/gists{/gist_id}","starred_url":"https://api.github.com/users/takumakume/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/takumakume/subscriptions","organizations_url":"https://api.github.com/users/takumakume/orgs","repos_url":"https://api.github.com/users/takumakume/repos","events_url":"https://api.github.com/users/takumakume/events{/privacy}","received_events_url":"https://api.github.com/users/takumakume/received_events","type":"User","site_admin":false},"body":"https://github.com/matsumotory/mruby-fast-remote-check/pull/7 のPRの修正版として、以下のように問題の特定と修正を行いました。\r\n\r\n### 発生した問題\r\n\r\n同時に単一のsocket上で複数のIPアドレスに ICMP Echo Reqest を送信した場合に最初の ICMP Echo Reply の到着によって、本来別のIPアドレスからの Reply を待つプロセスもrecv後、リトライすることなく `false` を返してしまう。\r\n\r\n### 再現テスト手順と結果の説明\r\n\r\n#### 再現手順\r\n\r\n今回は分かりやすいように以下のようなコードを挿入してPrintデバッグを実施しました。\r\nhttps://github.com/takumakume/mruby-fast-remote-check/commit/a146830368c0ad604e6208765af13e3d97e7e013\r\n\r\n1. テストコード (test.rb)\r\n\r\n  ```ruby\r\n  ip = ARGV[0]\r\n  puts \" ==> #{ip} #{FastRemoteCheck::ICMP.new(ip, 3).ping?}\"\r\n  ```\r\n\r\n2. tcpdumpによりICMPパケットの収集\r\n\r\n  ```\r\n  tcpdump -s0 -nn -w tcpdump_$(date +%Y%m%d%H%M%S).cap icmp\r\n  ```\r\n\r\n3. テストコードを並行で実行\r\n\r\n  ```sh\r\n  echo \"8.8.8.8\r\n  1.1.1.1\" | xargs -P 2 -L 1 strace -Ttt -ff -s 1500000 -o strace_$(date +%Y%m%d%H%M%S) mruby/bin/mruby ~/test.rb\r\n  ```\r\n\r\n#### 結果\r\n\r\n以下にtcpdumpの結果と、straceの結果を時系列に並べて説明する。\r\n\r\n```sh\r\n# ソケットを(4)で作成\r\n15:31:18.865712 [8.8.8.8] socket(AF_INET, SOCK_RAW, IPPROTO_ICMP) = 4 <0.000033>\r\n15:31:18.865771 [8.8.8.8] setsockopt(4, SOL_SOCKET, SO_RCVTIMEO, \"\\3\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\", 16) = 0 <0.000009>\r\n15:31:18.865802 [8.8.8.8] setsockopt(4, SOL_SOCKET, SO_SNDTIMEO, \"\\3\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\", 16) = 0 <0.000008>\r\n# 8.8.8.8へICMPを送付\r\n15:31:18.865831 [8.8.8.8] sendto(4, \"\\10\\0\\367\\377\\0\\0\\0\\0\", 8, 0, {sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr(\"8.8.8.8\")}, 16) = 8 <0.000120>\r\n# 8.8.8.8へのICMP echoが送信される\r\n15:31:18.865912 [tcpdump] IP server > 8.8.8.8: ICMP echo request, id 0, seq 0, length 8\r\n# recvを開始 (ブロッキング)\r\n15:31:18.866035 [8.8.8.8] recvfrom(4, \"E\\0\\0\\34\\342\\244@\\0?\\1=\\36\\10\\10\\10\\10\\n\\0\\2\\17\\0\\0\\377\\377\\0\\0\\0\\0\", 1500, 0, NULL, NULL) = 28 <0.022840>\r\n\r\n# 別プロセスでソケットを(4)で作成\r\n15:31:18.868766 [1.1.1.1] socket(AF_INET, SOCK_RAW, IPPROTO_ICMP) = 4 <0.000035>\r\n15:31:18.868824 [1.1.1.1] setsockopt(4, SOL_SOCKET, SO_RCVTIMEO, \"\\3\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\", 16) = 0 <0.000009>\r\n15:31:18.868855 [1.1.1.1] setsockopt(4, SOL_SOCKET, SO_SNDTIMEO, \"\\3\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\", 16) = 0 <0.000008>\r\n# 1.1.1.1へICMPを送付\r\n15:31:18.868882 [1.1.1.1] sendto(4, \"\\10\\0\\367\\377\\0\\0\\0\\0\", 8, 0, {sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr(\"1.1.1.1\")}, 16) = 8 <0.000106>\r\n# 1.1.1.1へのICMP echoが送信される\r\n15:31:18.868916 [tcpdump] IP server > 1.1.1.1: ICMP echo request, id 0, seq 0, length 8\r\n# recvを開始 (ブロッキング)\r\n15:31:18.869023 [1.1.1.1] recvfrom(4, \"E\\0\\0\\34\\342\\244@\\0?\\1=\\36\\10\\10\\10\\10\\n\\0\\2\\17\\0\\0\\377\\377\\0\\0\\0\\0\", 1500, 0, NULL, NULL) = 28 <0.019892>\r\n\r\n# 8.8.8.8からのICMP echo replyが到着\r\n# ここで2つの recvfrom が受け取る\r\n15:31:18.888700 [tcpdump] IP 8.8.8.8 > server: ICMP echo reply, id 0, seq 0, length 8\r\n\r\n15:31:18.888953 [8.8.8.8] fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0 <0.000014>\r\n15:31:18.889005 [1.1.1.1] fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0 <0.000189>\r\n15:31:18.889065 [8.8.8.8] mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fcc6e79c000 <0.000018>\r\n\r\n# 8.8.8.8からのICMP echo replyが到着\r\n# socketには入るが、recvはもう起きない\r\n15:31:18.889147 [tcpdump] IP 1.1.1.1 > server: ICMP echo reply, id 0, seq 0, length 8\r\n15:31:18.889194 [8.8.8.8] close(4)                = 0 <0.000023>\r\n\r\n15:31:18.889249 [1.1.1.1] mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fe205c47000 <0.000014>\r\n\r\n# 8.8.8.8からのreplyをrecvしているので True\r\n15:31:18.889270 [8.8.8.8] write(1, \"data->dst_ip, recv_iphdr->saddr : 134744072, 134744072 ==> 8.8.8.8 true\", 71) = 71 <0.000269>\r\n\r\n15:31:18.889308 [1.1.1.1] close(4)                = 0 <0.000017>\r\n\r\n# 8.8.8.8からのreplyをrecvしているので False\r\n15:31:18.889367 [1.1.1.1] write(1, \"data->dst_ip, recv_iphdr->saddr : 16843009, 134744072 ==> 1.1.1.1 false\", 71) = 71 <0.000017>\r\n```\r\n\r\n### 本PRの解決手法\r\n\r\n- これまで通りにrecv後に、ICMPパケットのチェック処理を行う。そこで、チェックが通らない場合は再度recv待機する。\r\n- epollを使って、socketを監視してrecvをリトライする。タイムアウトもepollで行う。\r\n\r\n### 同様のテスト手順の確認結果\r\n\r\n`本PRの解決手法` で示した意図通りに動作している。\r\n\r\n```sh\r\n23:41:17.395409 [8.8.8.8] socket(AF_INET, SOCK_RAW, IPPROTO_ICMP) = 4 <0.000039>\r\n23:41:17.395472 [8.8.8.8] setsockopt(4, SOL_SOCKET, SO_RCVTIMEO, \"\\3\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\", 16) = 0 <0.000011>\r\n23:41:17.395508 [8.8.8.8] setsockopt(4, SOL_SOCKET, SO_SNDTIMEO, \"\\3\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\", 16) = 0 <0.000007>\r\n23:41:17.395536 [8.8.8.8] sendto(4, \"\\10\\0\\367\\377\\0\\0\\0\\0\", 8, 0, {sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr(\"8.8.8.8\")}, 16) = 8 <0.000277>\r\n23:41:17.395573 [tcpdump] IP server > 8.8.8.8: ICMP echo request, id 0, seq 0, length 8\r\n23:41:17.395862 [8.8.8.8] epoll_create(1)         = 5 <0.000014>\r\n23:41:17.395906 [8.8.8.8] epoll_ctl(5, EPOLL_CTL_ADD, 4, {EPOLLIN, {u32=4, u64=4642859646980}}) = 0 <0.000009>\r\n23:41:17.395943 [8.8.8.8] epoll_wait(5, [{EPOLLIN, {u32=4, u64=4642859646980}}], 1, 3000) = 1 <0.035051>\r\n23:41:17.396938 [1.1.1.1] socket(AF_INET, SOCK_RAW, IPPROTO_ICMP) = 4 <0.000040>\r\n23:41:17.397017 [1.1.1.1] setsockopt(4, SOL_SOCKET, SO_RCVTIMEO, \"\\3\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\", 16) = 0 <0.000009>\r\n23:41:17.397045 [1.1.1.1] setsockopt(4, SOL_SOCKET, SO_SNDTIMEO, \"\\3\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\", 16) = 0 <0.000007>\r\n23:41:17.397070 [1.1.1.1] sendto(4, \"\\10\\0\\367\\377\\0\\0\\0\\0\", 8, 0, {sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr(\"1.1.1.1\")}, 16) = 8 <0.000154>\r\n23:41:17.397106 [tcpdump] IP server > 1.1.1.1: ICMP echo request, id 0, seq 0, length 8\r\n23:41:17.397268 [1.1.1.1] epoll_create(1)         = 5 <0.000013>\r\n23:41:17.397308 [1.1.1.1] epoll_ctl(5, EPOLL_CTL_ADD, 4, {EPOLLIN, {u32=4, u64=9266893077904097284}}) = 0 <0.000008>\r\n23:41:17.397338 [1.1.1.1] epoll_wait(5, [{EPOLLIN, {u32=4, u64=9266893077904097284}}], 1, 3000) = 1 <0.033591>\r\n23:41:17.430764 [tcpdump] IP 8.8.8.8 > server: ICMP echo reply, id 0, seq 0, length 8\r\n23:41:17.431053 [1.1.1.1] recvfrom(4, \"E\\0\\0\\34V~@\\0?\\1\\311D\\10\\10\\10\\10\\n\\0\\2\\17\\0\\0\\377\\377\\0\\0\\0\\0\", 1500, MSG_DONTWAIT, NULL, NULL) = 28 <0.000012>\r\n23:41:17.431053 [8.8.8.8] recvfrom(4, \"E\\0\\0\\34V~@\\0?\\1\\311D\\10\\10\\10\\10\\n\\0\\2\\17\\0\\0\\377\\377\\0\\0\\0\\0\", 1500, MSG_DONTWAIT, NULL, NULL) = 28 <0.000012>\r\n# ここで、別のIPアドレスからのリプライのため再度epollで待つ\r\n23:41:17.431110 [1.1.1.1] epoll_wait(5, [{EPOLLIN, {u32=4, u64=9266893077904097284}}], 1, 3000) = 1 <0.013761>\r\n23:41:17.431118 [8.8.8.8] close(5)                = 0 <0.000015>\r\n23:41:17.431154 [8.8.8.8] close(4)                = 0 <0.000062>\r\n23:41:17.431312 [8.8.8.8] fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0 <0.000009>\r\n23:41:17.431356 [8.8.8.8] mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f05bec9a000 <0.000012>\r\n23:41:17.431394 [8.8.8.8] write(1, \" ==> 8.8.8.8 true\", 17) = 17 <0.000226>\r\n23:41:17.431764 [8.8.8.8] write(1, \"\\n\", 1)       = 1 <0.000207>\r\n23:41:17.432026 [8.8.8.8] close(3)                = 0 <0.000012>\r\n23:41:17.432060 [8.8.8.8] munmap(0x7f05bec9b000, 4096) = 0 <0.000019>\r\n23:41:17.432215 [8.8.8.8] exit_group(0)           = ?\r\n23:41:17.432334 [8.8.8.8] +++ exited with 0 +++\r\n23:41:17.444778 [tcpdump] IP 1.1.1.1 > server: ICMP echo reply, id 0, seq 0, length 8\r\n23:41:17.444939 [1.1.1.1] recvfrom(4, \"E\\0\\0\\34V\\201@\\0?\\1\\327O\\1\\1\\1\\1\\n\\0\\2\\17\\0\\0\\377\\377\\0\\0\\0\\0\", 1500, MSG_DONTWAIT, NULL, NULL) = 28 <0.000014>\r\n23:41:17.445033 [1.1.1.1] close(5)                = 0 <0.000014>\r\n23:41:17.445070 [1.1.1.1] close(4)                = 0 <0.000019>\r\n23:41:17.445137 [1.1.1.1] fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0 <0.000010>\r\n23:41:17.445177 [1.1.1.1] mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f7d830ed000 <0.000016>\r\n23:41:17.445228 [1.1.1.1] write(1, \" ==> 1.1.1.1 true\", 17) = 17 <0.000032>\r\n23:41:17.445300 [1.1.1.1] write(1, \"\\n\", 1)       = 1 <0.000078>\r\n23:41:17.445422 [1.1.1.1] close(3)                = 0 <0.000012>\r\n23:41:17.445456 [1.1.1.1] munmap(0x7f7d830ee000, 4096) = 0 <0.000022>\r\n23:41:17.445669 [1.1.1.1] exit_group(0)           = ?\r\n23:41:17.445904 [1.1.1.1] +++ exited with 0 +++\r\n```\r\n\r\nなお、epollで待つ動作のためCPU専有はしない。\r\n\r\n```sh\r\n# time mruby/bin/mruby -e 'p FastRemoteCheck::ICMP.new(\"1.255.255.255\", 3).ping?'\r\ntrace (most recent call last):\r\n\t[0] -e:1\r\n-e:1: sys failed. errno: 0 message: Success mrbgem message: epoll_wait timeout (RuntimeError)\r\n\r\nreal\t0m3.007s\r\nuser\t0m0.002s\r\nsys\t0m0.002s\r\n```\r\n\r\nテストコードまで落とし込むことはできなかったが、テスト手順を明確に示し、再現可能な状態にした上で原因の特定をすることはできました。\r\n","created_at":"2018-06-08T15:56:11Z","updated_at":"2018-06-09T13:09:15Z","closed_at":null,"merged_at":null,"merge_commit_sha":"f6fe1dcd2dc5eeb3d558862a5095627fe7f9701c","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/pulls/8/commits","review_comments_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/pulls/8/comments","review_comment_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/pulls/comments{/number}","comments_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/issues/8/comments","statuses_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/statuses/dd75c18bec3448e350af40e23014e203cd4807b4","head":{"label":"takumakume:wait_for_packet","ref":"wait_for_packet","sha":"dd75c18bec3448e350af40e23014e203cd4807b4","user":{"login":"takumakume","id":10905048,"node_id":"MDQ6VXNlcjEwOTA1MDQ4","avatar_url":"https://avatars2.githubusercontent.com/u/10905048?v=4","gravatar_id":"","url":"https://api.github.com/users/takumakume","html_url":"https://github.com/takumakume","followers_url":"https://api.github.com/users/takumakume/followers","following_url":"https://api.github.com/users/takumakume/following{/other_user}","gists_url":"https://api.github.com/users/takumakume/gists{/gist_id}","starred_url":"https://api.github.com/users/takumakume/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/takumakume/subscriptions","organizations_url":"https://api.github.com/users/takumakume/orgs","repos_url":"https://api.github.com/users/takumakume/repos","events_url":"https://api.github.com/users/takumakume/events{/privacy}","received_events_url":"https://api.github.com/users/takumakume/received_events","type":"User","site_admin":false},"repo":{"id":136434410,"node_id":"MDEwOlJlcG9zaXRvcnkxMzY0MzQ0MTA=","name":"mruby-fast-remote-check","full_name":"takumakume/mruby-fast-remote-check","owner":{"login":"takumakume","id":10905048,"node_id":"MDQ6VXNlcjEwOTA1MDQ4","avatar_url":"https://avatars2.githubusercontent.com/u/10905048?v=4","gravatar_id":"","url":"https://api.github.com/users/takumakume","html_url":"https://github.com/takumakume","followers_url":"https://api.github.com/users/takumakume/followers","following_url":"https://api.github.com/users/takumakume/following{/other_user}","gists_url":"https://api.github.com/users/takumakume/gists{/gist_id}","starred_url":"https://api.github.com/users/takumakume/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/takumakume/subscriptions","organizations_url":"https://api.github.com/users/takumakume/orgs","repos_url":"https://api.github.com/users/takumakume/repos","events_url":"https://api.github.com/users/takumakume/events{/privacy}","received_events_url":"https://api.github.com/users/takumakume/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/takumakume/mruby-fast-remote-check","description":"FastRemoteCheck can perform port listening check at high speed using raw socket","fork":true,"url":"https://api.github.com/repos/takumakume/mruby-fast-remote-check","forks_url":"https://api.github.com/repos/takumakume/mruby-fast-remote-check/forks","keys_url":"https://api.github.com/repos/takumakume/mruby-fast-remote-check/keys{/key_id}","collaborators_url":"https://api.github.com/repos/takumakume/mruby-fast-remote-check/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/takumakume/mruby-fast-remote-check/teams","hooks_url":"https://api.github.com/repos/takumakume/mruby-fast-remote-check/hooks","issue_events_url":"https://api.github.com/repos/takumakume/mruby-fast-remote-check/issues/events{/number}","events_url":"https://api.github.com/repos/takumakume/mruby-fast-remote-check/events","assignees_url":"https://api.github.com/repos/takumakume/mruby-fast-remote-check/assignees{/user}","branches_url":"https://api.github.com/repos/takumakume/mruby-fast-remote-check/branches{/branch}","tags_url":"https://api.github.com/repos/takumakume/mruby-fast-remote-check/tags","blobs_url":"https://api.github.com/repos/takumakume/mruby-fast-remote-check/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/takumakume/mruby-fast-remote-check/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/takumakume/mruby-fast-remote-check/git/refs{/sha}","trees_url":"https://api.github.com/repos/takumakume/mruby-fast-remote-check/git/trees{/sha}","statuses_url":"https://api.github.com/repos/takumakume/mruby-fast-remote-check/statuses/{sha}","languages_url":"https://api.github.com/repos/takumakume/mruby-fast-remote-check/languages","stargazers_url":"https://api.github.com/repos/takumakume/mruby-fast-remote-check/stargazers","contributors_url":"https://api.github.com/repos/takumakume/mruby-fast-remote-check/contributors","subscribers_url":"https://api.github.com/repos/takumakume/mruby-fast-remote-check/subscribers","subscription_url":"https://api.github.com/repos/takumakume/mruby-fast-remote-check/subscription","commits_url":"https://api.github.com/repos/takumakume/mruby-fast-remote-check/commits{/sha}","git_commits_url":"https://api.github.com/repos/takumakume/mruby-fast-remote-check/git/commits{/sha}","comments_url":"https://api.github.com/repos/takumakume/mruby-fast-remote-check/comments{/number}","issue_comment_url":"https://api.github.com/repos/takumakume/mruby-fast-remote-check/issues/comments{/number}","contents_url":"https://api.github.com/repos/takumakume/mruby-fast-remote-check/contents/{+path}","compare_url":"https://api.github.com/repos/takumakume/mruby-fast-remote-check/compare/{base}...{head}","merges_url":"https://api.github.com/repos/takumakume/mruby-fast-remote-check/merges","archive_url":"https://api.github.com/repos/takumakume/mruby-fast-remote-check/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/takumakume/mruby-fast-remote-check/downloads","issues_url":"https://api.github.com/repos/takumakume/mruby-fast-remote-check/issues{/number}","pulls_url":"https://api.github.com/repos/takumakume/mruby-fast-remote-check/pulls{/number}","milestones_url":"https://api.github.com/repos/takumakume/mruby-fast-remote-check/milestones{/number}","notifications_url":"https://api.github.com/repos/takumakume/mruby-fast-remote-check/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/takumakume/mruby-fast-remote-check/labels{/name}","releases_url":"https://api.github.com/repos/takumakume/mruby-fast-remote-check/releases{/id}","deployments_url":"https://api.github.com/repos/takumakume/mruby-fast-remote-check/deployments","created_at":"2018-06-07T06:49:07Z","updated_at":"2018-06-07T06:49:09Z","pushed_at":"2018-06-09T13:02:37Z","git_url":"git://github.com/takumakume/mruby-fast-remote-check.git","ssh_url":"git@github.com:takumakume/mruby-fast-remote-check.git","clone_url":"https://github.com/takumakume/mruby-fast-remote-check.git","svn_url":"https://github.com/takumakume/mruby-fast-remote-check","homepage":"","size":31,"stargazers_count":0,"watchers_count":0,"language":"C","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"other","name":"Other","spdx_id":null,"url":null,"node_id":"MDc6TGljZW5zZTA="},"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"matsumotory:master","ref":"master","sha":"309350e1d90737a0b979e73ea008d44780d210f6","user":{"login":"matsumotory","id":648437,"node_id":"MDQ6VXNlcjY0ODQzNw==","avatar_url":"https://avatars0.githubusercontent.com/u/648437?v=4","gravatar_id":"","url":"https://api.github.com/users/matsumotory","html_url":"https://github.com/matsumotory","followers_url":"https://api.github.com/users/matsumotory/followers","following_url":"https://api.github.com/users/matsumotory/following{/other_user}","gists_url":"https://api.github.com/users/matsumotory/gists{/gist_id}","starred_url":"https://api.github.com/users/matsumotory/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/matsumotory/subscriptions","organizations_url":"https://api.github.com/users/matsumotory/orgs","repos_url":"https://api.github.com/users/matsumotory/repos","events_url":"https://api.github.com/users/matsumotory/events{/privacy}","received_events_url":"https://api.github.com/users/matsumotory/received_events","type":"User","site_admin":false},"repo":{"id":82250290,"node_id":"MDEwOlJlcG9zaXRvcnk4MjI1MDI5MA==","name":"mruby-fast-remote-check","full_name":"matsumotory/mruby-fast-remote-check","owner":{"login":"matsumotory","id":648437,"node_id":"MDQ6VXNlcjY0ODQzNw==","avatar_url":"https://avatars0.githubusercontent.com/u/648437?v=4","gravatar_id":"","url":"https://api.github.com/users/matsumotory","html_url":"https://github.com/matsumotory","followers_url":"https://api.github.com/users/matsumotory/followers","following_url":"https://api.github.com/users/matsumotory/following{/other_user}","gists_url":"https://api.github.com/users/matsumotory/gists{/gist_id}","starred_url":"https://api.github.com/users/matsumotory/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/matsumotory/subscriptions","organizations_url":"https://api.github.com/users/matsumotory/orgs","repos_url":"https://api.github.com/users/matsumotory/repos","events_url":"https://api.github.com/users/matsumotory/events{/privacy}","received_events_url":"https://api.github.com/users/matsumotory/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/matsumotory/mruby-fast-remote-check","description":"FastRemoteCheck can perform port listening check at high speed using raw socket","fork":false,"url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check","forks_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/forks","keys_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/keys{/key_id}","collaborators_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/teams","hooks_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/hooks","issue_events_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/issues/events{/number}","events_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/events","assignees_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/assignees{/user}","branches_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/branches{/branch}","tags_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/tags","blobs_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/git/refs{/sha}","trees_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/git/trees{/sha}","statuses_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/statuses/{sha}","languages_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/languages","stargazers_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/stargazers","contributors_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/contributors","subscribers_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/subscribers","subscription_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/subscription","commits_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/commits{/sha}","git_commits_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/git/commits{/sha}","comments_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/comments{/number}","issue_comment_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/issues/comments{/number}","contents_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/contents/{+path}","compare_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/compare/{base}...{head}","merges_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/merges","archive_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/downloads","issues_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/issues{/number}","pulls_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/pulls{/number}","milestones_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/milestones{/number}","notifications_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/labels{/name}","releases_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/releases{/id}","deployments_url":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/deployments","created_at":"2017-02-17T02:53:12Z","updated_at":"2018-06-07T14:20:24Z","pushed_at":"2018-06-09T13:02:39Z","git_url":"git://github.com/matsumotory/mruby-fast-remote-check.git","ssh_url":"git@github.com:matsumotory/mruby-fast-remote-check.git","clone_url":"https://github.com/matsumotory/mruby-fast-remote-check.git","svn_url":"https://github.com/matsumotory/mruby-fast-remote-check","homepage":"","size":25,"stargazers_count":3,"watchers_count":3,"language":"C","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":3,"mirror_url":null,"archived":false,"open_issues_count":2,"license":{"key":"other","name":"Other","spdx_id":null,"url":null,"node_id":"MDc6TGljZW5zZTA="},"forks":3,"open_issues":2,"watchers":3,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/pulls/8"},"html":{"href":"https://github.com/matsumotory/mruby-fast-remote-check/pull/8"},"issue":{"href":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/issues/8"},"comments":{"href":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/issues/8/comments"},"review_comments":{"href":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/pulls/8/comments"},"review_comment":{"href":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/pulls/8/commits"},"statuses":{"href":"https://api.github.com/repos/matsumotory/mruby-fast-remote-check/statuses/dd75c18bec3448e350af40e23014e203cd4807b4"}},"author_association":"NONE"}}
{"actor":{"display_login":"matsumotory"}}