Previous patch

Home

Next patch

./src/localcache.c

Patch: Additional logging in NTP

+/***************************************
+
+    This is part of frox: A simple transparent FTP proxy
+    Copyright (C) 2000 James Hollingshead
+
+    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
+
+  localcache.c -- cache code if we are doing our own caching. This is
+  experimental.
+
+  ***************************************/
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <fcntl.h>
+#include "common.h"
+#include "cache.h"
+#include "control.h"
+#include "vscan.h"
+
+extern sstr *cachemgr_init(char *cd, int cs);
+
+int file_cached(const sstr * uri, const sstr * mdtm, int size, int offset);
+
+static sstr *socket_file;
+
+/*FIXME These two should really not be global*/
+static int fd;
+static enum { CACHED, CACHING, NONE } cache_status = NONE;
+
+int l_geninit(void)
+{
+  socket_file = cachemgr_init(config.chroot, config.cachesize * 1024);
+  if(!socket_file)
+    return (-1);
+  write_log(VERBOSE, "Cachemgr socket file == %s",
+      sstr_buf(socket_file));
+  return (0);
+}
+
+/* ------------------------------------------------------------- ** 
+** If we have the file return a fd to it. Otherwise return -1.
+** ------------------------------------------------------------- */
+int l_retr_start(const sstr * host, const sstr * file, const sstr * mdtm,
+     int size, int offset, int type)
+{
+  static sstr *uri = NULL;
+  if(!uri)
+    uri = sstr_init(512);
+
+  if(sstr_len(mdtm) == 0) {
+    write_log(VERBOSE, "Server didn't like MDTM. Can't cache :(");
+    cache_status = NONE;
+    return (-1);
+  }
+
+  sstr_cpy2(uri, "ftp://");
+  if(!info->anonymous)
+    sstr_apprintf(uri, "%s@", sstr_buf(info->username));
+  sstr_cat(uri, host);
+  sstr_cat(uri, file);
+  if(type == 0)
+    sstr_ncat2(uri, ";type=an", 8);
+
+  if(!file_cached(uri, mdtm, size, offset)) {
+    write_log(INFO, "Cache miss for %s", sstr_buf(uri));
+    info->cached = 0;
+    return (-1);
+  }
+  write_log(INFO, "Cache hit for %s.", sstr_buf(uri));
+  info->cached = 1;
+
+  vscan_new(size);
+  if(!vscan_parsed_reply(150, NULL))
+    send_cmessage(150, "Starting transfer");
+
+  return (fd);
+}
+
+/* ------------------------------------------------------------- **
+** Called whenever we get incoming data from server.
+** Write data to cache.
+** ------------------------------------------------------------- */
+void l_inc_data(sstr * inc)
+{
+  if(cache_status == CACHING) {
+    vscan_inc(inc);
+    sstr_write(fd, inc, 0);
+  }
+}
+
+int l_retr_end(void)
+{
+  if(cache_status == CACHED) {
+    if(!vscan_parsed_reply(226, NULL))
+      send_cmessage(226, "Transfer complete");
+  }
+  if(cache_status == CACHING) {
+    vscan_end();
+    close(fd);
+  }
+  cache_status = NONE;
+  return (-1);
+}
+
+/* ------------------------------------------------------------- ** 
+** Return TRUE if we have an up to date copy of the file. 
+** Also set global variable fd to the file if we have it, or to where
+** we should write the file if we don't.
+**
+** Each cache file has a header of "NNNN MDTM SIZE TYPE URI\n" where
+** NNNN is the number of bytes in the header not including the "NNNN ".
+** MDTM and SIZE are the returns from those functions, and TYPE is 0 
+** for ascii, and 1 for binary.
+**
+** REST handling is fairly simplistic. If offset>0 and we have the
+** portion of the file which is not requested then we seek to offset
+** in it and overwrite with what we retrieve to complete our cached
+** copy. Otherwise we give up. 
+** ------------------------------------------------------------- */
+int file_cached(const sstr * uri, const sstr * mdtm, int size, int offset)
+{
+  int type = 1;
+   /*FIXME*/ int cmgrfd;
+  struct sockaddr_un addr;
+  sstr *sbuf;
+
+  sbuf = sstr_init(MAX_LINE_LEN * 2);
+  sstr_apprintf(sbuf, "G %s %s %d %d %d\n", sstr_buf(uri),
+          sstr_buf(mdtm), size, type, offset);
+
+  addr.sun_family = AF_UNIX;
+  strcpy(addr.sun_path, sstr_buf(socket_file));
+  if((cmgrfd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
+    debug_perr("socket");
+    die(ERROR, "Error creating socket for caching", 0, NULL, -1);
+  }
+  if(connect(cmgrfd, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
+    debug_perr("Error connecting to cache manager");
+    write_log(ERROR, "Unable to connect to cache manager."
+        "Abandoning caching");
+    return FALSE;
+  }
+
+  write(cmgrfd, sstr_buf(sbuf), sstr_len(sbuf));
+  switch (recv_fd(cmgrfd, &fd)) {
+  case 0:
+    debug_err("cache error");
+    cache_status = NONE;
+    close(cmgrfd);
+    return FALSE;
+  case 'A':
+    write_log(VERBOSE, "Unable to use caching for this d/l.");
+    cache_status = NONE;
+    close(cmgrfd);
+    return FALSE;
+  case 'R':
+    /*No need to set read lock. We are only here if the
+       complete file is cached. Cachemgr will never try and
+       overwrite part of a complete file -- it will unlink
+       it and create a new one (and we'll continue
+       accessing the old file) */
+    cache_status = CACHED;
+    close(cmgrfd);
+    return TRUE;
+  case 'W':
+    set_write_lock(fd);
+    cache_status = CACHING;
+    close(cmgrfd);
+    return FALSE;
+  default:
+    debug_err("Shouldn't get here");
+    close(cmgrfd);
+    die(0, NULL, 0, NULL, -1);
+  }
+  return (-1);
+}
+-