📄 syncserver.c
字号:
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 + -