diff --git a/omvs_main.c b/omvs_main.c index 6ae03c5..5565c99 100644 --- a/omvs_main.c +++ b/omvs_main.c @@ -17,6 +17,7 @@ static gint _omvs_jobs = 1; static gint _omvs_sleep = 1000; static gint _omvs_timeout = 10000; static gboolean _omvs_quiet; +static gboolean _omvs_wait; static gchar **_omvs_net_dev_names; static gchar **_omvs_net_dev_descs; @@ -38,6 +39,8 @@ static GOptionEntry _omvs_entries[] = "Timeout time(milliseconds) in each scan", "ms" }, { "quiet", 'q', 0, G_OPTION_ARG_NONE, &_omvs_quiet, "Print no log except for errors", NULL }, + { "wait", 'w', 0, G_OPTION_ARG_NONE, &_omvs_wait, + "Wait for multicast packet", NULL }, { NULL } }; @@ -84,6 +87,7 @@ static gint _omvs_print_net_devs_info(void); static gint _omvs_deinit_net_devs_info(void); static gint _omvs_start_scan(OMVSScanner *scanner); static gpointer _omvs_start_scan_job(gpointer data); +static gint _omvs_wait_for_multicast_packet(void); static gint _omvs_init_net_devs_info(void) { gchar errbuf[PCAP_ERRBUF_SIZE]; @@ -198,7 +202,7 @@ static gpointer _omvs_start_scan_job(gpointer data) { addr[3] = (guint8)((o_ipaddr->addr >> 0) & 0xff); addr_str = - g_strdup_printf("%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]); + g_strdup_printf("%u.%u.%u.%u", addr[0], addr[1], addr[2], addr[3]); if (!_omvs_quiet) { g_print("[%p] start scanning %s\n", (void *)g_thread_self(), addr_str); @@ -392,6 +396,153 @@ static gint _omvs_start_scan(OMVSScanner *scanner) { return 0; } +static gint _omvs_wait_for_multicast_packet(void) { + pcap_t *pcap; + gchar errbuf[PCAP_ERRBUF_SIZE]; + const guint8 *packet; + struct pcap_pkthdr *header; + GHashTable *urihashtable; + gint64 time1, time2; + OMVSGst gst; + gchar *cur_uri; + + pcap = pcap_open_live(_omvs_net_dev_names[_omvs_net_dev_idx], + sizeof(OMVSEthHdr) + sizeof(OMVSIPHdr) + sizeof(OMVSUDPHdr), + TRUE, 500, errbuf); + if (pcap == NULL) { + g_printerr("[%p] can't open pcap: %s\n", (void *)g_thread_self(), errbuf); + goto finish_return2; + } + if (pcap_datalink(pcap) != DLT_EN10MB) { + g_printerr("[%p] %s is not ethernet\n", (void *)g_thread_self(), + _omvs_net_dev_names[_omvs_net_dev_idx]); + goto finish_return3; + } + + gst = NULL; + urihashtable = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); + time1 = g_get_monotonic_time(); + + for (;;) { + gint ret; + guint caplen; + OMVSIPHdr *ip; + OMVSUDPHdr *udp; + guint ip_hdr_len; + gint udp_port; + GInetAddress *addr; + gchar *addr_str; + guint32 haddr; + gchar *uri; + gchar *filename; + + ret = pcap_next_ex(pcap, &header, &packet); + + if (ret < 0) { + break; + } + + if (gst) { + time2 = g_get_monotonic_time(); + if (omvs_gst_is_finished(gst)) { + if (!_omvs_quiet) { + g_print("[%p] finish scanning %s\n", (void *)g_thread_self(), + cur_uri); + } + omvs_gst_close(gst); + gst = NULL; + } else if (time2 - time1 > (gint64)((gint64)_omvs_timeout * 1000)) { + if (!_omvs_quiet) { + g_print("[%p] finish scanning %s\n", (void *)g_thread_self(), + cur_uri); + } + omvs_gst_close(gst); + gst = NULL; + } else { + continue; + } + } + + if (ret == 0) { + continue; + } + + caplen = header->caplen; + + if (caplen < sizeof(OMVSEthHdr)) { + continue; + } + + packet += sizeof(OMVSEthHdr); + caplen -= sizeof(OMVSEthHdr); + if (caplen < sizeof(OMVSIPHdr)) { + continue; + } + + ip = (OMVSIPHdr *)packet; + ip_hdr_len = (ip->vhl & 0x0f) * 4; + if (caplen < ip_hdr_len) { + continue; + } + + if (ip->protocol != _OMVS_IPPROTO_UDP) { + continue; + } + + addr = g_inet_address_new_from_bytes( + (const guint8 *)&ip->daddr, G_SOCKET_FAMILY_IPV4); + if (!g_inet_address_get_is_multicast(addr)) { + g_object_unref(addr); + continue; + } + g_object_unref(addr); + + packet += ip_hdr_len; + caplen -= ip_hdr_len; + + if (caplen < sizeof(OMVSUDPHdr)) { + continue; + } + + udp = (OMVSUDPHdr *)packet; + udp_port = g_ntohs(udp->uh_dport); + + haddr = g_ntohl(ip->daddr); + addr_str = g_strdup_printf("%u.%u.%u.%u", + (haddr >> 24) & 0xff, + (haddr >> 16) & 0xff, + (haddr >> 8) & 0xff, + (haddr >> 0) & 0xff); + uri = g_strdup_printf("udp://%s:%u", addr_str, udp_port); + filename = + g_strdup_printf("%s/%s-%d.png", _omvs_outdir, addr_str, udp_port); + g_free(addr_str); + + if (!g_hash_table_insert(urihashtable, uri, NULL)) { + continue; + } + + cur_uri = uri; + if (!_omvs_quiet) { + g_print("[%p] start scanning %s\n", (void *)g_thread_self(), cur_uri); + g_print("[%p] trying to save %s to %s\n", (void *)g_thread_self(), + cur_uri, filename); + } + time1 = g_get_monotonic_time(); + g_assert(gst == NULL); + gst = omvs_gst_open(cur_uri, filename); + } + + g_hash_table_destroy(urihashtable); + + return 0; + +finish_return3: + pcap_close(pcap); +finish_return2: + return -1; +} + int main(int argc, char *argv[]) { GError *error = NULL; GOptionContext *context; @@ -428,7 +579,7 @@ int main(int argc, char *argv[]) { goto finish_return; } - if (argc < 2 || _omvs_net_dev_idx >= _omvs_num_net_devs) { + if ((!_omvs_wait && argc < 2) || _omvs_net_dev_idx >= _omvs_num_net_devs) { gchar *help_msg; help_msg = g_option_context_get_help(context, TRUE, NULL); g_print("%s", help_msg); @@ -439,6 +590,11 @@ int main(int argc, char *argv[]) { g_mkdir(_omvs_outdir, 0755); + if (_omvs_wait) { + _omvs_wait_for_multicast_packet(); + goto finish_return; + } + num_ipaddrs = 0; for (i = 1; i < argc; i++) { GInetAddressMask *mask;