Networker: send fail message in DB queue; add flood protection.
[citadel.git] / citadel / modules / network / serv_networkclient.c
index 174bf9daeadfd1d280f406ae2477e9a3a8f3c5c3..996d4e042bc72ad92ca1772bbdec2f49bc541638 100644 (file)
@@ -93,25 +93,25 @@ struct CitContext networker_client_CC;
 
 int NetworkClientDebugEnabled = 0;
 
-#define DBGLOG(LEVEL) if ((LEVEL != LOG_DEBUG) || (NetworkClientDebugEnabled != 0))
+#define NCDBGLOG(LEVEL) if ((LEVEL != LOG_DEBUG) || (NetworkClientDebugEnabled != 0))
 
-#define EVN_syslog(LEVEL, FORMAT, ...) \
-       DBGLOG(LEVEL) syslog(LEVEL, \
-              "IO[%ld]CC[%d]NW[%s][%ld]" FORMAT, \
-              IO->ID, CCID, NODE, N, __VA_ARGS__)
+#define EVN_syslog(LEVEL, FORMAT, ...)                                 \
+       NCDBGLOG(LEVEL) syslog(LEVEL,                                   \
+                              "IO[%ld]CC[%d]NW[%s][%ld]" FORMAT,       \
+                              IO->ID, CCID, NODE, N, __VA_ARGS__)
 
-#define EVNM_syslog(LEVEL, FORMAT) \
-       DBGLOG(LEVEL) syslog(LEVEL, \
-              "IO[%ld]CC[%d]NW[%s][%ld]" FORMAT, \
-              IO->ID, CCID, NODE, N)
+#define EVNM_syslog(LEVEL, FORMAT)                                     \
+       NCDBGLOG(LEVEL) syslog(LEVEL,                                   \
+                              "IO[%ld]CC[%d]NW[%s][%ld]" FORMAT,       \
+                              IO->ID, CCID, NODE, N)
 
 #define EVNCS_syslog(LEVEL, FORMAT, ...) \
-       DBGLOG(LEVEL) syslog(LEVEL, "IO[%ld]NW[%s][%ld]" FORMAT, \
-              IO->ID, NODE, N, __VA_ARGS__)
+       NCDBGLOG(LEVEL) syslog(LEVEL, "IO[%ld]NW[%s][%ld]" FORMAT,      \
+                              IO->ID, NODE, N, __VA_ARGS__)
 
 #define EVNCSM_syslog(LEVEL, FORMAT) \
-       DBGLOG(LEVEL) syslog(LEVEL, "IO[%ld]NW[%s][%ld]" FORMAT, \
-              IO->ID, NODE, N)
+       NCDBGLOG(LEVEL) syslog(LEVEL, "IO[%ld]NW[%s][%ld]" FORMAT,      \
+                              IO->ID, NODE, N)
 
 
 typedef enum _eNWCState {
@@ -174,6 +174,25 @@ void DeleteNetworker(void *vptr)
 #define NWC_DBG_READ() EVN_syslog(LOG_DEBUG, ": < %s\n", ChrPtr(NW->IO.IOBuf))
 #define NWC_OK (strncasecmp(ChrPtr(NW->IO.IOBuf), "+OK", 3) == 0)
 
+eNextState SendFailureMessage(AsyncIO *IO)
+{
+       AsyncNetworker *NW = IO->Data;
+       long lens[2];
+       const char *strs[2];
+
+       strs[0] = ChrPtr(NW->node);
+       lens[0] = StrLength(NW->node);
+       
+       strs[1] = ChrPtr(NW->IO.ErrMsg);
+       lens[1] = StrLength(NW->IO.ErrMsg);
+       CtdlAideFPMessage(
+               ChrPtr(NW->IO.ErrMsg),
+               "Networker error",
+               2, strs, (long*) &lens);
+       
+       return eAbort;
+}
+
 eNextState FinalizeNetworker(AsyncIO *IO)
 {
        AsyncNetworker *NW = (AsyncNetworker *)IO->Data;
@@ -200,8 +219,8 @@ eNextState NWC_ReadGreeting(AsyncNetworker *NW)
                             "Connected to node \"%s\" but I was expecting to connect to node \"%s\".",
                             connected_to, ChrPtr(NW->node));
                EVN_syslog(LOG_ERR, "%s\n", ChrPtr(NW->IO.ErrMsg));
-               CtdlAideMessage(ChrPtr(NW->IO.ErrMsg), "Network error");
-               return eAbort;/// todo: aide message in anderer queue speichern
+               StopClientWatchers(IO, 1);
+               return QueueDBOperation(IO, SendFailureMessage);
        }
        return eSendReply;
 }
@@ -227,14 +246,23 @@ eNextState NWC_ReadAuthReply(AsyncNetworker *NW)
        }
        else
        {
+               int Error = atol(ChrPtr(NW->IO.IOBuf));
                if (NW->IO.ErrMsg == NULL)
                        NW->IO.ErrMsg = NewStrBuf();
                StrBufPrintf(NW->IO.ErrMsg,
-                            "Connected to node \"%s\" but my secret wasn't accurate.",
-                            ChrPtr(NW->node));
-               EVN_syslog(LOG_ERR, "%s\n", ChrPtr(NW->IO.ErrMsg));
-               CtdlAideMessage(ChrPtr(NW->IO.ErrMsg), "Network error");
-               
+                            "Connected to node \"%s\" but my secret wasn't accurate.\nReason was:%s\n",
+                            ChrPtr(NW->node), ChrPtr(NW->IO.IOBuf) + 4);
+               if (Error == 552) {
+                       EVN_syslog(LOG_INFO,
+                                  "Already talking to %s; skipping this time.\n",
+                                  ChrPtr(NW->node));
+                       
+               }
+               else {
+                       EVN_syslog(LOG_ERR, "%s\n", ChrPtr(NW->IO.ErrMsg));
+                       StopClientWatchers(IO, 1);
+                       return QueueDBOperation(IO, SendFailureMessage);
+               }
                return eAbort;
        }
 }
@@ -318,6 +346,7 @@ eNextState NWC_SendREAD(AsyncNetworker *NW)
                {
                        FDIOBufferDelete(&NW->IO.IOB);
                        unlink(ChrPtr(NW->tempFileName));
+                       FDIOBufferDelete(&IO->IOB);
                        return eAbort;
                }
                StrBufPrintf(NW->IO.SendBuf.Buf, "READ %ld|%ld\n",
@@ -352,6 +381,7 @@ eNextState NWC_ReadREADState(AsyncNetworker *NW)
                        NW->IO.IOB.ChunkSize = atol(ChrPtr(NW->IO.IOBuf)+4);
                return eReadFile;
        }
+       FDIOBufferDelete(&IO->IOB);
        return eAbort;
 }
 eNextState NWC_ReadREADBlobDone(AsyncNetworker *NW);
@@ -396,7 +426,6 @@ eNextState NWC_ReadREADBlobDone(AsyncNetworker *NW)
                NW->State ++;
 
                FDIOBufferDelete(&NW->IO.IOB);
-
                if (link(ChrPtr(NW->tempFileName), ChrPtr(NW->SpoolFileName)) != 0) {
                        EVN_syslog(LOG_ALERT, 
                               "Could not link %s to %s: %s\n",
@@ -428,6 +457,7 @@ eNextState NWC_ReadCLOSReply(AsyncNetworker *NW)
 {
        AsyncIO *IO = &NW->IO;
        NWC_DBG_READ();
+       FDIOBufferDelete(&IO->IOB);
        if (ChrPtr(NW->IO.IOBuf)[0] != '2')
                return eTerminateConnection;
        return eSendReply;
@@ -476,6 +506,7 @@ eNextState NWC_SendNUOP(AsyncNetworker *NW)
                NW->State = eQUIT;
                rc = NWC_SendQUIT(NW);
                NWC_DBG_SEND();
+               if (fd > 0) close(fd);
                return rc;
        }
        FDIOBufferInit(&NW->IO.IOB, &NW->IO.SendBuf, fd, TotalSendSize);
@@ -489,8 +520,10 @@ eNextState NWC_ReadNUOPReply(AsyncNetworker *NW)
 {
        AsyncIO *IO = &NW->IO;
        NWC_DBG_READ();
-       if (ChrPtr(NW->IO.IOBuf)[0] != '2')
+       if (ChrPtr(NW->IO.IOBuf)[0] != '2') {
+               FDIOBufferDelete(&IO->IOB);
                return eAbort;
+       }
        return eSendReply;
 }
 
@@ -508,6 +541,7 @@ eNextState NWC_ReadWRITReply(AsyncNetworker *NW)
        NWC_DBG_READ();
        if (ChrPtr(NW->IO.IOBuf)[0] != '7')
        {
+               FDIOBufferDelete(&IO->IOB);
                return eAbort;
        }
 
@@ -556,6 +590,7 @@ eNextState NWC_ReadUCLS(AsyncNetworker *NW)
                EVN_syslog(LOG_DEBUG, "Removing <%s>\n", ChrPtr(NW->SpoolFileName));
                unlink(ChrPtr(NW->SpoolFileName));
        }
+       FDIOBufferDelete(&IO->IOB);
        return eSendReply;
 }
 
@@ -740,7 +775,8 @@ eReadState NWC_ReadServerStatus(AsyncIO *IO)
 
 eNextState NWC_FailNetworkConnection(AsyncIO *IO)
 {
-       return eAbort;
+       StopClientWatchers(IO, 1);
+       return QueueDBOperation(IO, SendFailureMessage);
 }
 
 void NWC_SetTimeout(eNextState NextTCPState, AsyncNetworker *NW)
@@ -979,7 +1015,7 @@ void network_poll_other_citadel_nodes(int full_poll, HashList *ignetcfg)
                    strcmp("0.0.0.0", ChrPtr(NW->host)))
                {
                        NW->Url = NewStrBuf();
-                       StrBufPrintf(NW->Url, "citadel://:%s@%s:%s", 
+                       StrBufPrintf(NW->Url, "citadel://%s@%s:%s", 
                                     ChrPtr(NW->secret),
                                     ChrPtr(NW->host),
                                     ChrPtr(NW->port));
@@ -1036,7 +1072,7 @@ CTDL_MODULE_INIT(network_client)
        {
                CtdlFillSystemContext(&networker_client_CC, "CitNetworker");
                
-               CtdlRegisterSessionHook(network_do_clientqueue, EVT_TIMER);
+               CtdlRegisterSessionHook(network_do_clientqueue, EVT_TIMER, PRIO_SEND + 10);
                CtdlRegisterDebugFlagHook(HKEY("networkclient"), LogDebugEnableNetworkClient, &NetworkClientDebugEnabled);
 
        }