⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 syncserver.c

📁 同步软件源码,作者 Jeroen C. Kessels Internet Engineer
💻 C
📖 第 1 页 / 共 3 页
字号:
  if (dirp == -1L) return(NO);
  Error = NO;
  do {
    if (strcmp(dp.name,".") == 0) continue;
    if (strcmp(dp.name,"..") == 0) continue;
    if ((dp.attrib & _A_SUBDIR) != _A_SUBDIR) {
      sprintf(FilePath,"%s%s",Path,dp.name);
      DateTm = localtime(&dp.time_write);
      sprintf(s1,"%04u%02u%02u%02u%02u%02u %lu %s",DateTm->tm_year + 1900,
        DateTm->tm_mon + 1, DateTm->tm_mday, DateTm->tm_hour, DateTm->tm_min,
        DateTm->tm_sec,dp.size,FilePath);
      Error = SendReply(Socket,s1);
      continue;
      }
    sprintf(FilePath,"%s%s%c*",Path,dp.name,*DIRSEP);
    Error = ListFiles(Socket,FilePath);
    } while ((Error == NO) && (_findnext(dirp,&dp) == 0));
  _findclose(dirp);

  return(Error);
  }






int Synchronize(struct ServerStruct *Data) {
  int Error;
  char Line[BUFSIZ];
  char Command[BUFSIZ];
  char Challenge[100];
  time_t Now;
  FILE *Fout;
  char Password[BUFSIZ];
  unsigned long Size;
  unsigned long BytesLeft;
  unsigned long BytesReceived;
  time_t Mtime;
  struct tm TimeTm;
  char Path[BUFSIZ];
  char TempPath[BUFSIZ];
  md5_byte_t Digest[16];
  md5_state_t Context;
  char Checksum[BUFSIZ];
  struct utimbuf UtimeBuf;
  unsigned long TotalFiles = 0;
  unsigned long TotalBytes = 0;
  char *Here;
  char s1[BUFSIZ];
  char s2[BUFSIZ];
  char *p1;
  int i;

  sprintf(s1,"%s Connected.",Data->RemoteAddress);
  LogMessage(s1);

  /* Receive 1 line of data from the socket. */
  Error = ReceiveLine(Data->ReceiveSocket,Line,BUFSIZ);
  if (Error == YES) {
    SocketErrorStr(WSAGetLastError(),s1);
    LogMessage(s1);
    return(YES);
    }

  /* If the first line is not "SYNCHRONIZE" then exit. */
  if (stricmp(Line,"synchronize") != 0) {
    SafeString(Line,s1,BUFSIZ-30);
    sprintf(s2,"Hacker attempt: %s",s1);
    LogMessage(s2);
    sprintf(s1,"Permission denied.\n");
    SendReply(Data->ReceiveSocket,s1);
    return(YES);
    }

  /* Send a line with the Challenge back. */
  time(&Now);
  srand(Now);
  sprintf(Challenge,"%u%u%lu",rand() % 10000,rand() % 10000,Now);
  Base64encode(Challenge,strlen(Challenge),s2,BUFSIZ);
  sprintf(s1,"Challenge %s",Challenge);
  SendReply(Data->ReceiveSocket,s1);

  /* Loop forever. */
  while (1) {
    Error = ReceiveLine(Data->ReceiveSocket,Line,BUFSIZ-100);
    if (Error == YES) {
      SocketErrorStr(WSAGetLastError(),s1);
      LogMessage(s1);
      sprintf(s2,"FATAL: %s",s1);
      SendReply(Data->ReceiveSocket,s2);
      return(NO);
      }
    Here = AcceptWord(Line,Command,100);

    /* QUIT: close the connection and exit. */
    if (stricmp(Command,"QUIT") == 0) {
      sprintf(s1,"%s %lu files updated, %lu bytes received.",
        Data->RemoteAddress,TotalFiles,TotalBytes);
      LogMessage(s1);
      sprintf(s1,"OK, closing connection.");
      SendReply(Data->ReceiveSocket,s1);
      return(NO);
      }

    /* LIST: Return a list of files currently on disk. */
    if (stricmp(Command,"LIST") == 0) {
      /* Split the LIST line into it's components. */
      Here = AcceptWord(Here,s1,BUFSIZ);
      Base64decode(s1,Password,BUFSIZ);
      striptw(Path,Here);
      FixupPath(Path);
      if (*Path == '\0') {
        sprintf(s1,"Bad line received: %s",Line);
        LogMessage(s1);
        sprintf(s1,"FATAL: Wrong number of parameters.");
        SendReply(Data->ReceiveSocket,s1);
        return(NO);
        }

      /* Test authorization. */
      if (FindSyncItem(Challenge,Password,Path) == NO) {
        sprintf(s1,"Bad password: %s",Line);
        LogMessage(s1);
        sprintf(s1,"FATAL: The password is not authorised to list that path.",Command);
        SendReply(Data->ReceiveSocket,s1);
        return(NO);
        }

      sprintf(s1,"%s Listing: %s",Data->RemoteAddress,Path);
      LogMessage(s1);

      sprintf(s1,"OK, here is the list:");
      Error = SendReply(Data->ReceiveSocket,s1);
      if (Error == NO) Error = ListFiles(Data->ReceiveSocket,Path);
      if (Error == NO) {
        sprintf(s1,".");
        Error = SendReply(Data->ReceiveSocket,s1);
        }
      if (Error == YES) {
        SocketErrorStr(WSAGetLastError(),s1);
        LogMessage(s1);
        return(YES);
        }

      continue;
      }

    /* DELETE: delete the file. */
    if (stricmp(Command,"DELETE") == 0) {
      /* Split the DELETE line into it's components. */
      Here = AcceptWord(Here,s1,BUFSIZ);
      Base64decode(s1,Password,BUFSIZ);
      striptw(Path,Here);
      FixupPath(Path);
      if (*Path == '\0') {
        sprintf(s1,"Bad line received: %s",Line);
        LogMessage(s1);
        sprintf(s1,"FATAL: Wrong number of parameters.");
        SendReply(Data->ReceiveSocket,s1);
        return(NO);
        }

      /* Test authorization. */
      if (FindSyncItem(Challenge,Password,Path) == NO) {
        sprintf(s1,"Bad password: %s",Line);
        LogMessage(s1);
        sprintf(s1,"FATAL: The password is not authorised to delete that file.",Command);
        SendReply(Data->ReceiveSocket,s1);
        return(NO);
        }

      /* Delete the file, or if it's a directory delete it and all
         it's subdirectories. */
      if (PathDelete(Path) == NO) {
        sprintf(s1,"ERROR: the file/dir could not be deleted.",Command);
        SendReply(Data->ReceiveSocket,s1);
        continue;
        }

      /* Finished with the delete. */
      sprintf(s1,"OK, file deleted.",Command);
      SendReply(Data->ReceiveSocket,s1);
      continue;
      }

    /* If not UPDATE then loop. */
    if (stricmp(Command,"UPDATE") != 0) {
      sprintf(s1,"Bad line received: %s",Line);
      LogMessage(s1);
      sprintf(s1,"FATAL: Command '%s' not recognised.",Command);
      SendReply(Data->ReceiveSocket,s1);
      return(NO);
      }

    /* Split the UPDATE line into it's components. */
    Here = AcceptWord(Here,s1,BUFSIZ);           /* Password. */
    Base64decode(s1,Password,BUFSIZ);
    Here = AcceptWord(Here,s1,BUFSIZ);
    p1 = s1;                   /* Convert YYYYMMDDHHMMSS into Unix timestamp. */
    i = *p1++ - '0';
    i = i * 10 + *p1++ - '0';
    i = i * 10 + *p1++ - '0';
    i = i * 10 + *p1++ - '0';
    TimeTm.tm_year = i - 1900;
    i = *p1++ - '0';
    TimeTm.tm_mon = i * 10 + *p1++ - '0' - 1;
    i = *p1++ - '0';
    TimeTm.tm_mday = i * 10 + *p1++ - '0';
    i = *p1++ - '0';
    TimeTm.tm_hour = i * 10 + *p1++ - '0';
    i = *p1++ - '0';
    TimeTm.tm_min = i * 10 + *p1++ - '0';
    i = *p1++ - '0';
    TimeTm.tm_sec = i * 10 + *p1++ - '0';
    TimeTm.tm_isdst = 0;
    Mtime = mktime(&TimeTm);                       /* Calculate as localtime. */
    if (TimeTm.tm_isdst != 0) Mtime = Mtime + timezone;   /* Correct for DST. */
    Here = AcceptWord(Here,s1,BUFSIZ);             /* Size (number of bytes). */
    Size = atol(s1);
    striptw(Path,Here);                            /* Filename. */
    FixupPath(Path);
    if (*Path == '\0') {
      sprintf(s1,"Bad line received: %s",Line);
      LogMessage(s1);
      sprintf(s1,"FATAL: Wrong number of parameters.");
      SendReply(Data->ReceiveSocket,s1);
      return(NO);
      }

    /* Test authorization. */
    if (FindSyncItem(Challenge,Password,Path) == NO) {
      sprintf(s1,"Bad password received: %s",Line);
      LogMessage(s1);
      sprintf(s1,"FATAL: The password is not authorised to upload that file.",Command);
      SendReply(Data->ReceiveSocket,s1);
      return(NO);
      }

    /* Open a temporary file. */
    /* Note: Should be rewritten to be atomic! */
    strcpy(TempPath,Path);
    p1 = strchr(TempPath,'\0');
    do {
      sprintf(p1,".%04u.sync",rand() % 10000);
      } while (FileExists(TempPath) == YES);
    CreatePath(TempPath,NO);
    Fout = fopen(TempPath,"wb");
    if (Fout == NULL) {
      sprintf(s1,"Could not open temporary file: %s",TempPath);
      LogMessage(s1);
      sprintf(s1,"FATAL: temporary file could not be opened: %s",TempPath);
      SendReply(Data->ReceiveSocket,s1);
      return(NO);
      }

    /* Receive the binary data into the temporary file. */
    sprintf(s1,"OK, send this file.",Command);
    SendReply(Data->ReceiveSocket,s1);
    BytesLeft = Size;
    md5_init(&Context);
    while (BytesLeft > 0) {
      if (BytesLeft > BUFSIZ) {
          BytesReceived = recv(Data->ReceiveSocket,Line,BUFSIZ,0);
        } else {
          BytesReceived = recv(Data->ReceiveSocket,Line,BytesLeft,0);
          }
      if ((BytesReceived == SOCKET_ERROR) || (BytesReceived == 0)) {
        fclose(Fout);
        unlink(TempPath);
        SocketErrorStr(WSAGetLastError(),s1);
        LogMessage(s1);
        sprintf(s2,"FATAL: %s",s1);
        SendReply(Data->ReceiveSocket,s2);
        return(NO);
        }
      if (fwrite(Line,1,BytesReceived,Fout) != BytesReceived) {
        fclose(Fout);
        unlink(TempPath);
        sprintf(s1,"Could not write everything to tempfile, maybe disk is full?");
        LogMessage(s1);
        sprintf(s2,"FATAL: %s",s1);
        SendReply(Data->ReceiveSocket,s2);
        return(NO);
        }
      md5_append(&Context,(unsigned char *)Line,BytesReceived);
      BytesLeft = BytesLeft - BytesReceived;
      }
    md5_finish(&Context,Digest);

    /* Close the temporary file. */
    fclose(Fout);

    /* Receive the CHECKSUM line. */
    Error = ReceiveLine(Data->ReceiveSocket,Line,BUFSIZ);
    if (Error == YES) {
      unlink(TempPath);
      SocketErrorStr(WSAGetLastError(),s1);
      LogMessage(s1);
      sprintf(s2,"FATAL: %s",s1);
      SendReply(Data->ReceiveSocket,s2);
      return(NO);
      }
    Here = AcceptWord(Line,s1,BUFSIZ);
    if (stricmp(s1,"ignore") == 0) {
      unlink(TempPath);
      sprintf(s1,"File not stored because it has changed while synchronizing.");
      LogMessage(s1);
      sprintf(s1,"OK, ignoring file.");
      SendReply(Data->ReceiveSocket,s1);
      continue;
      }
    if (stricmp(s1,"checksum") != 0) {
      unlink(TempPath);
      sprintf(s1,"FATAL: unexpected end of input, file not stored.");
      LogMessage(s1);
      SendReply(Data->ReceiveSocket,s1);
      return(NO);
      }

    /* Check if the checksums match. */
    Here = AcceptWord(Here,Checksum,BUFSIZ);
    for (i = 0; i < 16; i++) sprintf(s1+2*i,"%02x",Digest[i]);
    if (strcmp(s1,Checksum) != 0) {
      unlink(TempPath);
      sprintf(s2,"ERROR: Checksums do not match: %s %s",Checksum,s1);
      SendReply(Data->ReceiveSocket,s2);
      continue;
      }

    /* Replace the old file with the temporary file. */
    if (FileExists(Path) == YES) {
        strcpy(s1,Path);
        p1 = strchr(s1,'\0');
        do {
          sprintf(p1,".%04u.sync",rand() % 10000);
          } while (FileExists(s1) == YES);
        if (rename(Path,s1) != 0) {
          sprintf(s2,"ERROR: Could not rename the old file: %s %s",Path,s1);
          SendReply(Data->ReceiveSocket,s2);
          continue;
          }
        if (rename(TempPath,Path) != 0) {
          sprintf(s1,"ERROR: Could not rename the temporary file into the real file: %s %s",TempPath,Path);
          SendReply(Data->ReceiveSocket,s1);
          continue;
          }
        if (unlink(s1) != 0) {
          sprintf(s2,"ERROR: Could not delete the renamed old file: %s",s1);
          SendReply(Data->ReceiveSocket,s2);
          continue;
          }
      } else {
        if (rename(TempPath,Path) != 0) {
          sprintf(s1,"ERROR: Could not rename the temporary file into the real file: %s %s",TempPath,Path);
          SendReply(Data->ReceiveSocket,s1);
          continue;
          }
        }

    /* Set time/date of the file. */
    UtimeBuf.actime = Mtime;
    UtimeBuf.modtime = Mtime;
    if (utime(Path,&UtimeBuf) != 0) {
      sprintf(s1,"ERROR: Cannot change the time/date of the file: %s",Path);
      SendReply(Data->ReceiveSocket,s1);
      continue;
      }

    /* Here we should change the attributes of the file, such as
       Archive, Hidden, Readonly, System. But I don't know how to do
       that (can't use chmod() because it doesn't support all the
       possibilities thanks to fucking Microsoft), so I can't.
       Perhaps just as well, because it might cause problems with
       deleting files.
          _A_ARCH    Archive.
          _A_HIDDEN  Hidden file.
          _A_NORMAL  Normal.
          _A_RDONLY  Read-only.
          _A_SUBDIR  Subdirectory.
          _A_SYSTEM  System file.
       */

    /* Finished with the file. */
    sprintf(s1,"OK, file received and stored.",Command);
    SendReply(Data->ReceiveSocket,s1);

    TotalFiles = TotalFiles + 1;
    TotalBytes = TotalBytes + Size;
    }

  }





/**** Server ****************************************************************/




/* Server thread 4: Handle incoming data. The subroutine will initialise
   stuff and call the Processor(). */
void Server4(struct ServerStruct *Data) {
  int Error;
  SOCKADDR_IN SocketControl;
  int SocketSize;
  char s1[BUFSIZ];
  char s2[BUFSIZ];

  /* Get the ip-address of the local and remote end of the socket.
     The ip-address of the local end is used to select a server
     from the configuration, and the ip-address of the remote is
     used to block spammers, amongst other things. */
  SocketSize = sizeof(SocketControl);
  if (getsockname(Data->ReceiveSocket,(LPSOCKADDR)&SocketControl,&SocketSize) != 0) {
    SocketErrorStr(WSAGetLastError(),s1);
    sprintf(s2,"RunServer4(1): %s",s1);
    LogMessage(s2);
    Data->Running = STOPPED;
    _endthread();
    return;
    }
  sprintf(Data->LocalAddress,"%s",inet_ntoa(SocketControl.sin_addr));
  SocketSize = sizeof(SocketControl);
  if (getpeername(Data->ReceiveSocket,(LPSOCKADDR)&SocketControl,&SocketSize) != 0) {
    SocketErrorStr(WSAGetLastError(),s1);
    sprintf(s2,"RunServer4(2): %s",s1);
    LogMessage(s2);
    Data->Running = STOPPED;
    _endthread();
    return;
    }
  sprintf(Data->RemoteAddress,"%s",inet_ntoa(SocketControl.sin_addr));

  /* Process the incoming data. */
  Error = Synchronize(Data);
  if (Error == NO) Data->ForceStop = NO;

  /* Exit. */
  Data->Running = STOPPED;
  _endthread();
  }





/* Server thread 3: Start a new thread and handle incoming data. Stop
   when the ServiceControl() subroutine sets the ServerRunning flag
   to STOPPING. */
void Server3(struct ServerStruct *Data) {
  int WaitCount;
  char s1[BUFSIZ];
  int i;

  /* Setup the timeouts on the socket. */
  setsockopt(Data->ReceiveSocket,SOL_SOCKET,SO_SNDTIMEO,(char *)&SendTimeout,sizeof(SendTimeout));
  setsockopt(Data->ReceiveSocket,SOL_SOCKET,SO_RCVTIMEO,(char *)&ReceiveTimeout,sizeof(ReceiveTimeout));
  i = 0;
  setsockopt(Data->ReceiveSocket,SOL_SOCKET,SO_KEEPALIVE,(char *)&i,sizeof(i));

  /* Start thread 4 and wait until it is finished, or the ServerRunning
     flag is STOPPING. */
  if (_beginthread(Server4,0,(void *)Data)== -1) {
      LogMessage("Cannot start thread 4.");
    } else {
      while ((Data->Running == RUNNING) &&
             (ServerRunning == RUNNING)) {
        Sleep(500);
        }
      }

  /* If thread 4 is still running then set the Running flag so it knows
     it's supposed to stop. */
  if (Data->Running == RUNNING) Data->Running = STOPPING;

  /* Shutdown the socket. If thread 4 is still running then this will
     release it from a blocking call on the socket no matter what. */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -