/* Jungle Monkey Search Server * Copyright (C) 2000-2001 The Regents of the University of Michigan * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include #include #include #include #include #include #include #include #ifdef JM_ENABLE_GNOME #include #else #include #endif #include "jmintl.h" #include "util/util.h" #include "mtp_server.h" #include "mtp_mirror.h" #include "mtp_debug.h" #define DUMP_SERVER_TIMEOUT 5 * 60 * 1000 /* 5 minutes */ static gboolean dump_server_cb (gpointer data); static guint read_func(MtpLocalMirror* mirror, guint offset, gchar* buffer, guint length, gpointer user_data); static gboolean timeout_func (gpointer p); /* ******************** */ /* Globals */ static int verbose = 0; static const gchar* filename = NULL; static gboolean sha = FALSE; static gint timeout = 30; static MtpServer* server = NULL; static GURL* url = NULL; static gchar* buffer = NULL; static gint length = 0; static FILE* file = NULL; static guint timer = 0; static MtpLocalMirror* mirror = NULL; static MtpLocalMirror* sha_mirror = NULL; int main (int argc, char* argv[]) { const gchar* url_str = NULL; GMainLoop* main_loop; GInetAddr* iface = NULL; gchar* interface_name = NULL; gint port = 0; gboolean force_port = FALSE; gboolean rendezvous = FALSE; gboolean path = FALSE; struct poptOption jm_options[] = { {"help", 'h', POPT_ARG_NONE, NULL, 1, "Show this help message", NULL}, {"usage", '\0', POPT_ARG_NONE, NULL, 2, "Display brief usage message", NULL}, {"version", 0, POPT_ARG_NONE, NULL, 3, "Output verson information and exit", NULL}, {"verbose", 'v', POPT_ARG_NONE, &verbose, 0, "Print lots of stuff", NULL}, {"interface", '\0', POPT_ARG_STRING, &interface_name, 0, "Interface address for listening socket", "ADDR"}, {"port", '\0', POPT_ARG_INT, &port, 0, "Port for listening socket", "PORT"}, {"force-port", '\0', POPT_ARG_NONE, &force_port, 0, "Fail if can't set port", NULL}, {"rendezvous", '\0', POPT_ARG_NONE, &rendezvous, 0, "Act as rendezvous server also", NULL}, {"sha", '\0', POPT_ARG_NONE, &sha, 0, "Mirror using SHA as name too", NULL}, {"path", '\0', POPT_ARG_NONE, &path, 0, "Use mtp_mirror_path function", NULL}, {"timeout", '\0', POPT_ARG_INT, &timeout, 0, "Remove file from memory after TIMEOUT seconds", "TIMEOUT"}, {"debug-flags", 'd', POPT_ARG_INT, &mtp_debug_flags, 0, "Set the MTP debug flags", "FLAGS"}, {NULL, '\0', 0, NULL, 0, NULL, NULL} }; poptContext ctx; int rc; int exit_status = EXIT_SUCCESS; /* ******************** */ /* Initialize NLS */ #ifdef ENABLE_NLS { /* gtk_set_locale(); */ bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); } #endif /* ******************** */ /* Parse command line */ ctx = poptGetContext (NULL, argc, (const char**) argv, jm_options, 0); poptSetOtherOptionHelp (ctx, _("[OPTION]... [FILENAME] [RENDEZVOUS URL]")); while ((rc = poptGetNextOpt(ctx)) > 0) { switch (rc) { case 1: goto help; break; case 2: goto usage; break; case 3: goto version; break; } } filename = poptGetArg (ctx); url_str = poptGetArg (ctx); poptFreeContext (ctx); /* Must have filename */ if (!filename) my_error (_("You must specify a file to mirror.\n")); /* Must have URL */ if (!url_str) my_error (_("You must specify a URL of a rendezvous server.\n")); if (timeout < 10) timeout = 10; url = gnet_url_new (url_str); if (!url || !url->resource) my_error (_("Malformed rendezvous URL: %s\n"), url_str); /* If an interface was specified, make sure it resoves to an address */ if (interface_name) { /* Convert interface_name to InetAddr. */ iface = gnet_inetaddr_new (interface_name, 0); if (!iface) my_error (_("Bad interface name: %s.\n"), interface_name); } /* Otherwise, auto-detect the interface */ else { iface = gnet_inetaddr_autodetect_internet_interface (); if (!iface) my_error (_("Could not auto-detect an internet interface. " "Use the --interface option to set it manually.\n")); } /* ******************** */ /* Open the file */ length = file_size (filename); if (length < 0) my_error (_("Could not get length of file %s\n"), filename); /* ******************** */ /* Create the server */ gnet_inetaddr_set_port (iface, port); server = mtp_server_new (NULL, iface, force_port, MTP_SERVER_TYPE_MIRROR, TRUE); if (!server) my_error (_("Could not start mirror server.\n")); if (rendezvous) { mtp_server_set_type (server, MTP_SERVER_TYPE_BOTH); server->is_global = TRUE; } server->verbose = verbose; if (verbose) { g_print (_("MTP mirror server started on port %d\n"), server->server->port); g_timeout_add (DUMP_SERVER_TIMEOUT, dump_server_cb, NULL); dump_server_cb (NULL); } if (!path) mirror = mtp_mirror (server, url, read_func, NULL, length); else mirror = mtp_mirror_path (server, url, filename); if (!mirror) g_warning ("Could not create mirror\n"); /* ******************** */ /* Start the main loop */ main_loop = g_main_new (FALSE); g_main_run (main_loop); exit (EXIT_SUCCESS); usage: poptPrintUsage (ctx, stdout, 0); exit (exit_status); help: g_print (_("`mtpmirror' - MTP Mirror Server (NOT USEFUL - FOR TESTING ONLY)\n")); poptPrintHelp (ctx, stdout, 0); g_print (_("\n" "Report bugs to \n")); exit (exit_status); version: g_print (_("mtpmirror %s\n" "Written by David A. Helder\n" "\n" "Copyright (C) 2000-2001 The Regents of the University of Michigan\n" "This is free software; see the source for copying conditions. There is NO\n" "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"), VERSION); exit (exit_status); } /* **************************************** */ static gboolean dump_server_cb (gpointer data) { time_t t; char* time_str; t = time(NULL); t = mktime(gmtime(&t)); time_str = ctime(&t); /* don't free string */ time_str[strlen(time_str) - 1] = '\0'; g_print ("time: %s UTC\n", time_str); mtp_server_print (server, stderr); return TRUE; } static guint read_func (MtpLocalMirror* mirror, guint offset, gchar* buf, guint blength, gpointer user_data) { g_return_val_if_fail (mirror, 0); g_return_val_if_fail (buf, 0); MTPP (1, "read_func offset = %d, length = %d\n", offset, blength); /* Load file if not loaded */ if (!file) { MTPP (1, "LOADING FILE\n"); /* Open file */ file = fopen (filename, "r"); if (!file) goto error; /* Verify length */ if (length != file_size (filename)) goto error; buffer = mmap (NULL, length, PROT_READ, MAP_PRIVATE, fileno(file), 0); if (buffer == NULL || ((int) buffer == -1)) goto error; /* Get SHA if we don't have it */ if (!sha_mirror) { GSHA* sha; gchar* str; GURL* sha_url; sha = gnet_sha_new (buffer, length); str = gnet_sha_get_string (sha); sha_url = gnet_url_clone (url); gnet_url_set_resource (sha_url, str); sha_mirror = mtp_mirror (server, sha_url, read_func, NULL, length); if (!sha_mirror) g_warning (_("Unable to mirror file by SHA.\n")); gnet_sha_delete (sha); g_free (str); gnet_url_delete (sha_url); } } if (!buffer) goto error; if (offset + blength > length) goto error; /* Reset timer */ if (timer) g_source_remove (timer); timer = g_timeout_add (timeout * 1000, timeout_func, NULL); memcpy (buf, &buffer[offset], blength); return blength; error: MTPP (1, "error\n"); if (file) fclose (file); file = NULL; return 0; } static gboolean timeout_func (gpointer p) { g_return_val_if_fail (buffer, FALSE); g_return_val_if_fail (file, FALSE); munmap (buffer, length); buffer = NULL; fclose (file); file = NULL; return FALSE; }