📄 syncserver.c
字号:
/*
SyncServer -- Server couterpart of SyncUpload.
>>> SYNCHRONIZE
<<< CHALLENGE random
>>> LIST password path
<<< OK, HERE IS THE LIST:
date size path Date is YYYYMMDDHHMMSS
date size path
.
>>> UPDATE password date size path Date is YYYYMMDDHHMMSS
<<< OK, SEND THIS FILE.
>>> binarydata
CHECKSUM checksum
<<< OK, FILE RECEIVED AND STORED.
>>> DELETE password path
<<< OK, FILE DELETED.
>>> QUIT
<<< OK, CLOSING CONNECTION.
<<< ERROR: ....message....
Copyright: Jeroen C. Kessels
Date: 19 august 2005
Version: 4.*
*/
#include "version.h"
#include <stdio.h>
#include <time.h>
#include <io.h> /* isatty() */
#include <winsock2.h>
#include <process.h>
#include <sys/utime.h>
#include <sys/stat.h>
#include <direct.h>
#include "md5.h"
#include "common.h"
/* General constants and variables. */
#define RUNNING 0
#define STOPPING 1
#define STOPPED 2
#define WS_VERSION_REQD 0x0101 /* The minimum winsock version required. */
int Console = NO; /* If running as a console program. */
/* Service constants and variables. */
#define SZSERVICENAME "Kessels SyncServer" /* Internal name of the service. */
#define SZSERVICEDISPLAYNAME "Kessels SyncServer" /* Displayed name of the service. */
#define SZDEPENDENCIES "\0\0" /* List of service dependencies - "dep1\0dep2\0\0" */
SERVICE_STATUS ServiceStatus; /* Current status of the service. */
SERVICE_STATUS_HANDLE ServiceHandle; /* From RegisterServiceCtrlHandler(). */
char MyName[BUFSIZ]; /* Path to this program. */
char CfgPath[BUFSIZ]; /* Path to the configuration file. */
char LogPath[BUFSIZ]; /* Path to the logfile. */
/* Listener constants and variables. */
int ServerRunning = STOPPED;
short ServerPort = 9577; /* The port to listen to. */
int SendTimeout = 120000; /* Timeout for sending data. */
int ReceiveTimeout = 120000; /* Timeout for receiving data. */
struct ServerStruct {
int Running; /* RUNNING, STOPPING, or STOPPED. */
int ForceStop; /* YES or NO. */
SOCKET ListenSocket;
SOCKET ReceiveSocket;
char LocalAddress[16]; /* IP-address of the local end. */
char RemoteAddress[16]; /* IP-address of the remote end. */
};
/**** General subroutines ***************************************************/
/* Test if a file exists. Return YES if it does. Normally I would use
stat() for this, but apparently some implementations of stat() will
leave some junk on the heap. */
int FileExists(char *Filename) {
FILE *Fin;
Fin = fopen(Filename,"r");
if (Fin == NULL) return NO;
fclose(Fin);
return(YES);
}
/* Create all directories in the path. If IsAdir=NO then the path points
to a filename, otherwise it is a directoryname. Return YES if succes,
NO if failure (see ERRNO). */
int CreatePath(char *Path, int IsAdir) {
char s1[BUFSIZ];
char *p1;
int Result;
if (Path == NULL) return(NO);
/* Create the directory. Return if succesful. */
if (IsAdir == YES) {
#ifdef unix
Result = mkdir(Path,0755);
#else
/* Do not run mkdir() on the drive designator. */
if ((strlen(Path) <= 2) && (Path[1] == ':')) return(YES);
Result = mkdir(Path);
#endif
if (Result == 0) return(YES);
}
/* Strip the highest directory. If there are none then return with NO, creating
the directory has failed. */
strcpy(s1,Path);
p1 = strrchrs(s1,DIRSEP);
if (p1 == NULL) return(NO);
*p1 = '\0';
/* Try to create the lower-level directory. */
if (CreatePath(s1,YES) == NO) return(NO);
/* Create the directory. */
if (IsAdir == NO) return(YES);
#ifdef unix
Result = mkdir(Path,0755);
#else
/* Do not run mkdir() on the drive designator. */
if ((strlen(Path) <= 2) && (Path[1] == ':')) return(YES);
Result = mkdir(Path);
#endif
if (Result == 0) return(YES);
return(NO);
}
/* Delete everything in the path and it's subdirectories. */
int PathDelete(char *Path) {
char Path1[BUFSIZ];
struct stat statbuf;
#ifdef _MSC_VER /* Microsoft does not support <dirent.h>. */
long dirp;
struct _finddata_t dp;
#define NAME dp.name
#else
DIR *dirp;
struct dirent *dp;
#define NAME dp->d_name
#endif
/* If this is a file, then delete it and exit. */
if ((MyStat(Path,&statbuf) == 0) && ((statbuf.st_mode & 0040000) != 0040000)) {
if (unlink(Path) != 0) return(NO);
return(YES);
}
/* Walk through the directory, and iterate into subdirectories by calling
myself. */
#ifdef _MSC_VER
sprintf(Path1,"%s*",Path);
dirp = _findfirst(Path1,&dp);
if (dirp == -1L) return(NO);
do {
#else
dirp = opendir(Path);
if (dirp == NULL) return(NO);
while ((dp = readdir(dirp)) != 0) {
#endif
if (strcmp(NAME,".") == 0) continue;
if (strcmp(NAME,"..") == 0) continue;
sprintf(Path1,"%s%c%s",Path,*DIRSEP,NAME);
if (PathDelete(Path1) == NO) {
#ifdef _MSC_VER
_findclose(dirp);
#else
closedir(dirp);
#endif
return(NO);
}
#ifdef _MSC_VER
} while (_findnext(dirp,&dp) == 0);
_findclose(dirp);
#else
}
closedir(dirp);
#endif
if (rmdir(Path) != 0) return(NO);
return(YES);
}
/**** Logging ***************************************************************/
/* Translate all special characters in the string. */
void SafeString(char *In, char *Out, int Width) {
char *p1;
char *p2;
p1 = In;
p2 = Out;
while ((*In != '\0') && (Width > 1)) {
if ((*In >= 32) && (*In <= 128)) {
*Out++ = *In;
Width--;
} else {
if (Width < 5) break;
sprintf(Out,"[%02X]",*In);
while (*Out != '\0') {
Out++;
Width--;
}
}
In++;
}
*Out = '\0';
}
/* Append a message to the logfile. */
void LogMessage(char *Message) {
FILE *Fout;
char s1[BUFSIZ];
time_t Now;
time(&Now);
strcpy(s1,ctime(&Now));
s1[24] = '\0';
if (Console == YES) {
fprintf(stdout,"%s %s\n",s1,Message);
return;
}
if (*LogPath == '\0') return;
Fout = fopen(LogPath,"a+");
if (Fout == NULL) return;
fprintf(Fout,"%s %s\n",s1,Message);
fclose(Fout);
}
/**** Error messages ********************************************************/
/* Return a string with the error message for GetLastError(). */
void SystemErrorStr(DWORD ErrorCode, char *Out) {
char s1[BUFSIZ];
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY,
NULL,ErrorCode,0,s1,BUFSIZ,NULL);
sprintf(Out,"error %lu: %s",ErrorCode,s1);
}
/* Return a string with the error message for WSAGetLastError(). */
void SocketErrorStr(int ErrorCode, char *Out) {
struct {
int ErrorCode;
char *ErrorText;
} ErrorArray[] = {
{WSAEINTR, "Interrupted system call"},
{WSAEBADF, "Bad file number"},
{WSAEACCES, "Permission denied"},
{WSAEFAULT, "Bad address"},
{WSAEINVAL, "Invalid argument"},
{WSAEMFILE, "Too many open files"},
{WSAEWOULDBLOCK, "Operation would block"},
{WSAEINPROGRESS, "Operation now in progress"},
{WSAEALREADY, "Operation already in progress"},
{WSAENOTSOCK, "Socket operation on non-socket"},
{WSAEDESTADDRREQ, "Destination address required"},
{WSAEMSGSIZE, "Message too long"},
{WSAEPROTOTYPE, "Protocol wrong type for socket"},
{WSAENOPROTOOPT, "Bad protocol option"},
{WSAEPROTONOSUPPORT,"Protocol not supported"},
{WSAESOCKTNOSUPPORT,"Socket type not supported"},
{WSAEOPNOTSUPP, "Operation not supported on socket"},
{WSAEPFNOSUPPORT, "Protocol family not supported"},
{WSAEAFNOSUPPORT, "Address family not supported by protocol family"},
{WSAEADDRINUSE, "Address already in use"},
{WSAEADDRNOTAVAIL, "Can't assign requested address"},
{WSAENETDOWN, "Network is down"},
{WSAENETUNREACH, "Network is unreachable"},
{WSAENETRESET, "Net dropped connection or reset"},
{WSAECONNABORTED, "Software caused connection abort"},
{WSAECONNRESET, "Connection reset by peer"},
{WSAENOBUFS, "No buffer space available"},
{WSAEISCONN, "Socket is already connected"},
{WSAENOTCONN, "Socket is not connected"},
{WSAESHUTDOWN, "Can't send after socket shutdown"},
{WSAETOOMANYREFS, "Too many references, can't splice"},
{WSAETIMEDOUT, "Connection timed out"},
{WSAECONNREFUSED, "Connection refused"},
{WSAELOOP, "Too many levels of symbolic links"},
{WSAENAMETOOLONG, "File name too long"},
{WSAEHOSTDOWN, "Host is down"},
{WSAEHOSTUNREACH, "No Route to Host"},
{WSAENOTEMPTY, "Directory not empty"},
{WSAEPROCLIM, "Too many processes"},
{WSAEUSERS, "Too many users"},
{WSAEDQUOT, "Disc Quota Exceeded"},
{WSAESTALE, "Stale NFS file handle"},
{WSAEREMOTE, "Too many levels of remote in path"},
{WSASYSNOTREADY, "Network SubSystem is unavailable"},
{WSAVERNOTSUPPORTED,"WINSOCK DLL Version out of range"},
{WSANOTINITIALISED, "Successful WSASTARTUP not yet performed"},
{WSAHOST_NOT_FOUND, "Host not found"},
{WSATRY_AGAIN, "Non-Authoritative Host not found"},
{WSANO_RECOVERY, "Non-Recoverable errors: FORMERR, REFUSED, NOTIMP"},
{WSANO_DATA, "Valid name, no data record of requested"},
{WSABASEERR, ""}
};
int i;
i = 0;
while ((ErrorArray[i].ErrorCode != ErrorCode) &&
(*ErrorArray[i].ErrorText != '\0')) i++;
sprintf(Out,"error %lu: %s",ErrorCode,ErrorArray[i].ErrorText);
}
/**** Communication *********************************************************/
/* Receive a single line from a socket. If the incoming data is
more than the size of the buffer then data is ignored. Return
YES if error, NO if allright. */
int ReceiveLine(SOCKET Socket, char *Line, int Width) {
int Here;
int Status;
char c1;
Here = 0;
while (1) {
Status = recv(Socket,&c1,1,0); /* Receive 1 character. */
if (Status == 0) break; /* Leave if no more data. */
if (Status == SOCKET_ERROR) break; /* Leave if error. */
if (c1 == '\r') continue; /* Ignore CR. */
if (c1 == '\0') continue; /* Ignore Null. */
if (c1 == '\n') break; /* Leave after LF. */
if (Here < Width - 1) Line[Here++] = c1; /* Save in Line. */
}
Line[Here] = '\0';
if (Console == YES) fprintf(stdout,"<<< %s\n",Line);
if (Status == SOCKET_ERROR) return(YES);
return(NO);
}
/* Return a message to the remote. */
int SendReply(SOCKET Socket, char *Message) {
int Error;
if (Console == YES) fprintf(stdout,">>> %s\n",Message);
Error = send(Socket,Message,strlen(Message),0);
if (Error == SOCKET_ERROR) return(YES);
Error = send(Socket,"\r\n",2,0);
if (Error == SOCKET_ERROR) return(YES);
return(NO);
}
/**** Program functions *****************************************************/
/* Walk through all items in the configuration fileand return YES
if a line is found that matches the password and mask. */
int FindSyncItem(
char *Challenge,
char *Password,
char *Mask) {
FILE *Fin;
char Line[BUFSIZ];
char *Here;
char Key[BUFSIZ];
int Result;
char s1[BUFSIZ];
char s2[BUFSIZ];
Fin = fopen(CfgPath,"r");
if (Fin == NULL) return(NO);
Result = NO;
while (fgets(Line,BUFSIZ,Fin) != NULL) {
if (*Line == '#') continue;
Here = AcceptWord(Line,Key,BUFSIZ);
if ((stricmp(Key,"access") != 0) && (stricmp(Key,"sync") != 0)) continue;
Here = AcceptWord(Here,s1,BUFSIZ);
PasswordEncode(Challenge,s1,s2);
if (strcmp(Password,s2) != 0) continue;
striptw(s1,Here);
FixupPath(s1);
if (MatchMask(Mask,s1) == NO) continue;
Result = YES;
break;
}
fclose(Fin);
return(Result);
}
/* Dump a list of files. Walk through all files in the root
directory, and iterate for subdirectories. */
int ListFiles(SOCKET Socket, char *InPath) {
char Path[BUFSIZ];
char SearchPath[BUFSIZ];
char FilePath[BUFSIZ];
long dirp;
struct _finddata_t dp;
struct tm *DateTm;
int Error;
char s1[BUFSIZ];
char *p1;
/* Fixup the input path. We need a searchpath with a trailing '*'
and a path that ends in '/'. */
strcpy(Path,InPath);
p1 = strchr(Path,'*');
if (p1 != NULL) {
strcpy(SearchPath,Path);
*p1 = '\0';
} else {
sprintf(SearchPath,"%s*",Path);
p1 = strchr(Path,'\0');
}
while ((p1 != Path) && ((*p1 == '\0') || (strchr(DIRSEP,*p1) == NULL))) p1--;
if (strchr(DIRSEP,*p1) != NULL) p1++;
*p1 = '\0';
dirp = _findfirst(SearchPath,&dp);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -