]> arthur.barton.de Git - netatalk.git/commitdiff
AFP replay cache, first shot
authorFrank Lahm <franklahm@googlemail.com>
Tue, 15 Feb 2011 15:35:55 +0000 (16:35 +0100)
committerFrank Lahm <franklahm@googlemail.com>
Tue, 15 Feb 2011 15:35:55 +0000 (16:35 +0100)
NEWS
etc/afpd/afp_dsi.c
include/atalk/afp.h
include/atalk/dsi.h
libatalk/dsi/dsi_opensess.c

diff --git a/NEWS b/NEWS
index 4b86a33b0ec08e715e7630f0519f04742b8f6953..a811ac7e5abafa99d6f907c6cf8e76d7a32a7e23 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,7 +1,8 @@
 Changes in 2.2beta2
 ====================
 
-* NEW: primary reconnect
+* NEW: afpd: primary AFP reconnect
+* NEW: afpd: AFP replay cache
 
 Changes in 2.2beta1
 ====================
index 261834f508116dfc3ba9197fa7ee98c3d5056758..c90c8a70f50364e5f9e957a181c98735b9db0858 100644 (file)
@@ -64,6 +64,18 @@ static struct {
     int tickle;
 } child;
 
+typedef struct {
+    uint16_t DSIreqID;
+    uint8_t  AFPcommand;
+    uint32_t result;
+} rc_elem_t;
+
+/*
+ * AFP replay cache:
+ * - fix sized array
+ * - indexed just by taking DSIreqID mod REPLAYCACHE_SIZE
+ */
+rc_elem_t replaycache[REPLAYCACHE_SIZE];
 
 static void afp_dsi_close(AFPObj *obj)
 {
@@ -322,6 +334,7 @@ static void pending_request(DSI *dsi)
 void afp_over_dsi(AFPObj *obj)
 {
     DSI *dsi = (DSI *) obj->handle;
+    int rc_idx;
     u_int32_t err, cmd;
     u_int8_t function;
     struct sigaction action;
@@ -507,33 +520,50 @@ void afp_over_dsi(AFPObj *obj)
 
             function = (u_char) dsi->commands[0];
 
-            /* send off an afp command. in a couple cases, we take advantage
-             * of the fact that we're a stream-based protocol. */
-            if (afp_switch[function]) {
-                dsi->datalen = DSI_DATASIZ;
-                child.flags |= CHILD_RUNNING;
+            /* AFP replay cache */
+            rc_idx = REPLAYCACHE_SIZE % dsi->clientID;
+            LOG(log_debug, logtype_afpd, "DSI request ID: %u", dsi->clientID);
 
-                LOG(log_debug, logtype_afpd, "<== Start AFP command: %s", AfpNum2name(function));
+            if (replaycache[rc_idx].DSIreqID == dsi->clientID
+                && replaycache[rc_idx].AFPcommand == function) {
+                LOG(log_debug, logtype_afpd, "AFP Replay Cache match: id: %u / cmd: %s",
+                    dsi->clientID, AfpNum2name(function));
+                err = replaycache[rc_idx].result;
+            /* AFP replay cache end */
+            } else {
+                /* send off an afp command. in a couple cases, we take advantage
+                 * of the fact that we're a stream-based protocol. */
+                if (afp_switch[function]) {
+                    dsi->datalen = DSI_DATASIZ;
+                    child.flags |= CHILD_RUNNING;
 
-                err = (*afp_switch[function])(obj,
-                                              (char *)&dsi->commands, dsi->cmdlen,
-                                              (char *)&dsi->data, &dsi->datalen);
+                    LOG(log_debug, logtype_afpd, "<== Start AFP command: %s", AfpNum2name(function));
 
-                LOG(log_debug, logtype_afpd, "==> Finished AFP command: %s -> %s",
-                    AfpNum2name(function), AfpErr2name(err));
+                    err = (*afp_switch[function])(obj,
+                                                  (char *)&dsi->commands, dsi->cmdlen,
+                                                  (char *)&dsi->data, &dsi->datalen);
+
+                    LOG(log_debug, logtype_afpd, "==> Finished AFP command: %s -> %s",
+                        AfpNum2name(function), AfpErr2name(err));
 
-                dir_free_invalid_q();
+                    dir_free_invalid_q();
 
 #ifdef FORCE_UIDGID
-               /* bring everything back to old euid, egid */
-                if (obj->force_uid)
-                   restore_uidgid ( &obj->uidgid );
+                    /* bring everything back to old euid, egid */
+                    if (obj->force_uid)
+                        restore_uidgid ( &obj->uidgid );
 #endif /* FORCE_UIDGID */
-                child.flags &= ~CHILD_RUNNING;
-            } else {
-                LOG(log_error, logtype_afpd, "bad function %X", function);
-                dsi->datalen = 0;
-                err = AFPERR_NOOP;
+                    child.flags &= ~CHILD_RUNNING;
+
+                    /* Add result to the AFP replay cache */
+                    replaycache[rc_idx].DSIreqID = dsi->clientID;
+                    replaycache[rc_idx].AFPcommand = function;
+                    replaycache[rc_idx].result = err;
+                } else {
+                    LOG(log_error, logtype_afpd, "bad function %X", function);
+                    dsi->datalen = 0;
+                    err = AFPERR_NOOP;
+                }
             }
 
             /* single shot toggle that gets set by dsi_readinit. */
index b93eb8bce4ea0dd129ee25362ee8f4268cc0f57e..550343d6fb5e4fcbf9a73c81fef867b518fa16ff 100644 (file)
@@ -213,4 +213,7 @@ typedef enum {
 #define AFP_SETACL              74
 #define AFP_ACCESS              75
 
+/* more defines */
+#define REPLAYCACHE_SIZE 128
+
 #endif
index 82b98348e6a35e8c41a23a627043535d03bbcde8..f3a79e9fd881f6c0b310ebf6189741b7e8534faf 100644 (file)
@@ -115,6 +115,7 @@ typedef struct DSI {
 /* DSI session options */
 #define DSIOPT_SERVQUANT 0x00   /* server request quantum */
 #define DSIOPT_ATTNQUANT 0x01   /* attention quantum */
+#define DSIOPT_REPLCSIZE 0x02   /* AFP replaycache size supported by the server (that's us) */
 
 /* DSI Commands */
 #define DSIFUNC_CLOSE   1       /* DSICloseSession */
index 92b5029495066375868e1fe9db6148070ec840ba..e8818e6134bd81f5809a80e2b416284005cbbf72 100644 (file)
@@ -19,6 +19,7 @@
 void dsi_opensession(DSI *dsi)
 {
   u_int32_t i = 0; /* this serves double duty. it must be 4-bytes long */
+  int offs;
 
   /* parse options */
   while (i < dsi->cmdlen) {
@@ -39,7 +40,10 @@ void dsi_opensession(DSI *dsi)
   dsi->header.dsi_flags = DSIFL_REPLY;
   dsi->header.dsi_code = 0;
   /* dsi->header.dsi_command = DSIFUNC_OPEN;*/
-  dsi->cmdlen = 2 + sizeof(i); /* length of data. dsi_send uses it. */
+
+  dsi->cmdlen = 2 * (2 + sizeof(i)); /* length of data. dsi_send uses it. */
+
+  /* DSI Option Server Request Quantum */
   dsi->commands[0] = DSIOPT_SERVQUANT;
   dsi->commands[1] = sizeof(i);
   i = htonl(( dsi->server_quantum < DSI_SERVQUANT_MIN || 
@@ -47,5 +51,11 @@ void dsi_opensession(DSI *dsi)
            DSI_SERVQUANT_DEF : dsi->server_quantum);
   memcpy(dsi->commands + 2, &i, sizeof(i));
 
+  /* AFP replaycache size option */
+  offs = 2 + sizeof(i);
+  dsi->commands[offs] = DSIOPT_REPLCSIZE;
+  dsi->commands[offs+1] = sizeof(i);
+  i = htonl(REPLAYCACHE_SIZE);
+  memcpy(dsi->commands + offs + 2, &i, sizeof(i));
   dsi_send(dsi);
 }