2016-01-12 14:27:58 +09:00

267 lines
7.5 KiB
C

#include <string.h>
#include <pcap.h>
#include <gio/gio.h>
#include <gst/gst.h>
static gchar *_omvs_net_dev;
static gchar *_omvs_output = "omvs_out.txt";
static gint _omvs_jobs = 1;
static gint _omvs_sleep = 1000;
static gint _omvs_timeout = 10000;
static gboolean _omvs_verbose;
static GOptionEntry _omvs_entries[] =
{
{ "interface", 'i', 0, G_OPTION_ARG_STRING, &_omvs_net_dev,
"Network device interface", "dev" },
{ "jobs", 'j', 0, G_OPTION_ARG_INT, &_omvs_jobs,
"Number of jobs", "jobs" },
{ "output", 'o', 0, G_OPTION_ARG_FILENAME, &_omvs_output,
"Output filename", "filename" },
{ "sleep", 's', 0, G_OPTION_ARG_INT, &_omvs_sleep,
"Sleep time(milliseconds) between scans", "ms" },
{ "timeout", 't', 0, G_OPTION_ARG_INT, &_omvs_timeout,
"Timeout time(milliseconds) in each scan", "ms" },
{ "verbose", 'v', 0, G_OPTION_ARG_NONE, &_omvs_verbose,
"Be verbose", NULL },
{ NULL }
};
typedef struct _OMVSPort {
gint port;
gint type;
} OMVSPort;
typedef struct _OMVSIPAddr {
guint32 addr;
OMVSPort *ports;
gint num_ports;
} OMVSIPAddr;
typedef struct _OMVSScanner {
OMVSIPAddr *ipaddrs;
gint num_ipaddrs;
} OMVSScanner;
static gint _omvs_start_scan(OMVSScanner *scanner);
static gpointer _omvs_start_scan_job(gpointer data);
static gpointer _omvs_start_scan_job(gpointer data) {
OMVSScanner *scanner;
GError *error;
GSocket *socket;
GSocketAddress *socket_address;
GInetAddress *inet_address;
gint i;
scanner = (OMVSScanner *)data;
socket = g_socket_new(G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_DATAGRAM,
G_SOCKET_PROTOCOL_DEFAULT, &error);
if (!socket) {
g_printerr("[%p] can't create socket: %s\n", (void *)g_thread_self(),
error->message);
goto finish_return1;
}
inet_address = g_inet_address_new_any(G_SOCKET_FAMILY_IPV4);
socket_address = g_inet_socket_address_new(inet_address, 0xffff);
g_object_unref(inet_address);
if (!g_socket_bind(socket, socket_address, TRUE, &error)) {
g_printerr("[%p] can't bind socket: %s\n", (void *)g_thread_self(),
error->message);
goto finish_return2;
}
for (i = 0; i < scanner->num_ipaddrs; i++) {
guint8 addr[4];
gchar *addr_str;
GInetAddress *group_address;
addr[0] = (guint8)((scanner->ipaddrs[i].addr >> 24) & 0xff);
addr[1] = (guint8)((scanner->ipaddrs[i].addr >> 16) & 0xff);
addr[2] = (guint8)((scanner->ipaddrs[i].addr >> 8) & 0xff);
addr[3] = (guint8)((scanner->ipaddrs[i].addr >> 0) & 0xff);
addr_str =
g_strdup_printf("%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]);
if (_omvs_verbose) {
g_print("[%p] start scanning %s\n", (void *)g_thread_self(), addr_str);
}
group_address = g_inet_address_new_from_string(addr_str);
if (!g_socket_join_multicast_group(
socket, group_address, FALSE, _omvs_net_dev, &error)) {
g_printerr("[%p] can't join %s: %s\n", (void *)g_thread_self(),
addr_str, error->message);
}
g_usleep(_omvs_timeout * 1000);
if (_omvs_verbose) {
g_print("[%p] finish scanning %s\n", (void *)g_thread_self(), addr_str);
}
if (!g_socket_leave_multicast_group(
socket, group_address, FALSE, _omvs_net_dev, &error)) {
g_printerr("[%p] can't leave %s: %s\n", (void *)g_thread_self(),
addr_str, error->message);
}
g_object_unref(group_address);
g_free(addr_str);
g_usleep(_omvs_sleep * 1000);
}
finish_return2:
g_object_unref(socket_address);
g_object_unref(socket);
finish_return1:
return NULL;
}
static gint _omvs_start_scan(OMVSScanner *scanner) {
gint i;
gint num_ipaddrs_for_each_thread;
OMVSScanner *scanners;
GThread **jobs;
num_ipaddrs_for_each_thread = scanner->num_ipaddrs / _omvs_jobs;
if (num_ipaddrs_for_each_thread == 0) {
num_ipaddrs_for_each_thread = 1;
_omvs_jobs = scanner->num_ipaddrs;
}
scanners = g_malloc0(_omvs_jobs * sizeof(OMVSScanner));
jobs = g_malloc0(_omvs_jobs * sizeof(GThread *));
for (i = 0; i < _omvs_jobs; i++) {
scanners[i].ipaddrs = &scanner->ipaddrs[i * num_ipaddrs_for_each_thread];
scanners[i].num_ipaddrs = num_ipaddrs_for_each_thread;
}
scanners[_omvs_jobs - 1].num_ipaddrs += (scanner->num_ipaddrs % _omvs_jobs);
for (i = 0; i < _omvs_jobs; i++) {
jobs[i] = g_thread_new(NULL, _omvs_start_scan_job, &scanners[i]);
}
for (i = 0; i < _omvs_jobs; i++) {
g_thread_join(jobs[i]);
}
g_free(jobs);
g_free(scanners);
return 0;
}
int main(int argc, char *argv[]) {
GError *error = NULL;
GOptionContext *context;
int ret = 0;
gint i;
gint num_ipaddrs;
gint idx_ipaddr;
OMVSScanner omvs_scanner;
context = g_option_context_new("<multicast ip address or net ... [#N]>");
g_option_context_set_summary(context,
"omvs scans to find free video streaming multicast ip addresses."
);
g_option_context_set_description(context,
"Oh! Multicast Video Scanner " OMVS_VERSION " is"
" Written by Taeho Oh <ohhara@postech.edu>.\n"
"http://ohhara.sarang.net");
g_option_context_add_main_entries(context, _omvs_entries, NULL);
g_option_context_add_group(context, gst_init_get_option_group());
if (!g_option_context_parse(context, &argc, &argv, &error)) {
g_print("option parsing failed: %s\n", error->message);
ret = -1;
goto finish_return;
}
if (argc < 2) {
gchar *help_msg;
help_msg = g_option_context_get_help(context, TRUE, NULL);
g_print("%s", help_msg);
g_free(help_msg);
ret = -2;
goto finish_return;
}
num_ipaddrs = 0;
for (i = 1; i < argc; i++) {
GInetAddressMask *mask;
GInetAddress *addr;
guint len;
mask = g_inet_address_mask_new_from_string(argv[i], &error);
if (!mask) {
g_print("%s parsing failed: %s\n", argv[i], error->message);
ret = -3;
goto finish_return;
}
if (g_inet_address_mask_get_family(mask) != G_SOCKET_FAMILY_IPV4) {
g_print("%s is not ipv4 ip address\n", argv[i]);
g_object_unref(mask);
ret = -4;
goto finish_return;
}
addr = g_inet_address_mask_get_address(mask);
if (!g_inet_address_get_is_multicast(addr)) {
g_print("%s is not multicast ip address\n", argv[i]);
g_object_unref(mask);
ret = -4;
goto finish_return;
}
len = g_inet_address_mask_get_length(mask);
if (len) {
num_ipaddrs += (1 << (32 - len));
} else {
num_ipaddrs++;
}
g_object_unref(mask);
}
memset(&omvs_scanner, 0, sizeof(OMVSScanner));
omvs_scanner.ipaddrs = g_malloc0(num_ipaddrs * sizeof(OMVSIPAddr));
omvs_scanner.num_ipaddrs = num_ipaddrs;
idx_ipaddr = 0;
for (i = 1; i < argc; i++) {
GInetAddressMask *mask;
GInetAddress *addr;
guint len;
guint32 start_ipaddr;
const guint8 *addr_bytes;
mask = g_inet_address_mask_new_from_string(argv[i], &error);
addr = g_inet_address_mask_get_address(mask);
len = g_inet_address_mask_get_length(mask);
addr_bytes = g_inet_address_to_bytes(addr);
start_ipaddr =
(((guint32)addr_bytes[0]) << 24) |
(((guint32)addr_bytes[1]) << 16) |
(((guint32)addr_bytes[2]) << 8) |
(((guint32)addr_bytes[3]) << 0);
if (len) {
guint n;
guint j;
n = (1 << (32 - len));
for (j = 0; j < n; j++) {
omvs_scanner.ipaddrs[idx_ipaddr].addr = start_ipaddr;
idx_ipaddr++;
start_ipaddr++;
}
} else {
omvs_scanner.ipaddrs[idx_ipaddr].addr = start_ipaddr;
idx_ipaddr++;
}
}
_omvs_start_scan(&omvs_scanner);
g_free(omvs_scanner.ipaddrs);
finish_return:
g_option_context_free(context);
return ret;
}