├── .gitattributes ├── .gitignore ├── Client ├── base.h ├── client.c ├── client.h ├── main.c ├── scmload.c ├── scmload.h ├── srvapi.c ├── srvapi.h ├── srvcon.c └── srvcon.h ├── Deploy ├── __init__.py ├── build.py ├── cmd.py ├── load.py ├── multilogger.py ├── settings.py └── ssh.py ├── Driver ├── driver.c ├── fastio.c ├── h │ └── ioctl.h ├── helpers.c ├── inc │ ├── base.h │ ├── driver.h │ ├── fastio.h │ ├── hallocator.h │ ├── helpers.h │ ├── klog.h │ ├── map.h │ ├── mtags.h │ ├── ntapiex.h │ ├── socket.h │ ├── tests.h │ ├── unload_protection.h │ └── worker.h ├── klog.c ├── map.c ├── socket.c ├── tests.c └── worker.c ├── Server ├── api.h ├── base.h ├── btree.c ├── btree.h ├── debug.c ├── debug.h ├── fmt.c ├── fmt.h ├── list_entry.h ├── log.c ├── log.h ├── main.c ├── memalloc.c ├── memalloc.h ├── misc.h ├── server.c ├── server.h ├── spinlock.h ├── time.c └── time.h └── Shared └── error.h /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled source # 2 | ################### 3 | *.com 4 | *.class 5 | *.dll 6 | *.exe 7 | *.o 8 | *.so 9 | *.jar 10 | *.sys 11 | *.lib 12 | *.pdb 13 | !server/csite2/lib/*.jar 14 | !server/libs/*.jar 15 | # Packages # 16 | ############ 17 | # it's better to unpack these files and commit the raw source 18 | # git has its own built in compression methods 19 | *.7z 20 | *.dmg 21 | *.gz 22 | *.iso 23 | *.rar 24 | *.tar 25 | *.zip 26 | 27 | # Logs and databases # 28 | ###################### 29 | *.log 30 | *.log.txt 31 | *.sql 32 | *.sqlite 33 | 34 | # OS generated files # 35 | ###################### 36 | .DS_Store 37 | .DS_Store? 38 | ._* 39 | .Spotlight-V100 40 | .Trashes 41 | Icon? 42 | ehthumbs.db 43 | Thumbs.db 44 | *.*~ 45 | *.pyc 46 | *.oacr.* 47 | 48 | 49 | # Our build files # 50 | build/ 51 | build_tmp/ 52 | 53 | #vs 2013 files # 54 | *.sdf 55 | *.opensdf 56 | *.suo 57 | 58 | #vim# 59 | *.swp 60 | 61 | *.class 62 | 63 | # Mobile Tools for Java (J2ME) 64 | .mtj.tmp/ 65 | 66 | # Package Files # 67 | *.jar 68 | *.war 69 | *.ear 70 | 71 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 72 | hs_err_pid* 73 | 74 | # log files 75 | *.log 76 | *.pyc 77 | # output/bin files 78 | target/ 79 | 80 | #eclipse files 81 | .classpath 82 | .project 83 | .settings/ 84 | #swap files 85 | *.swp 86 | *.lock 87 | *.tar.gz 88 | *.rpm 89 | *.db 90 | 91 | -------------------------------------------------------------------------------- /Client/base.h: -------------------------------------------------------------------------------- 1 | #ifndef __FBACKUP_CLIENT_BASE_H__ 2 | #define __FBACKUP_CLIENT_BASE_H__ 3 | 4 | #define WIN32_LEAN_AND_MEAN 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "..\shared\error.h" 13 | 14 | #endif -------------------------------------------------------------------------------- /Client/client.c: -------------------------------------------------------------------------------- 1 | #include "scmload.h" 2 | #include "client.h" 3 | 4 | #include 5 | 6 | HANDLE CDrvOpen() 7 | { 8 | HANDLE hDevice = CreateFile(FBACKUP_DRV_WIN32_DEVICE_NAME_W, 9 | GENERIC_READ | GENERIC_WRITE, 10 | FILE_SHARE_READ | FILE_SHARE_WRITE, 11 | NULL, 12 | OPEN_EXISTING, 13 | FILE_ATTRIBUTE_NORMAL, 14 | NULL ); 15 | 16 | if (hDevice == INVALID_HANDLE_VALUE) { 17 | printf("ERROR: can not access driver %ws, error %d\n", FBACKUP_DRV_WIN32_DEVICE_NAME_W, GetLastError()); 18 | return NULL; 19 | } 20 | 21 | return hDevice; 22 | } 23 | 24 | DWORD 25 | CDrvClose( 26 | IN HANDLE hDevice 27 | ) 28 | { 29 | DWORD err; 30 | 31 | if (!CloseHandle(hDevice)) { 32 | err = GetLastError(); 33 | printf("CloseHandle error %d\n", err); 34 | } else 35 | err = 0; 36 | return err; 37 | } 38 | 39 | DWORD NTAPI CDrvCtlFltStart() 40 | { 41 | HANDLE hDevice = NULL; 42 | DWORD BytesReturned; 43 | DWORD err; 44 | 45 | hDevice = CDrvOpen(); 46 | if (hDevice == NULL) { 47 | err = GetLastError(); 48 | return err; 49 | } 50 | 51 | if( !DeviceIoControl(hDevice, 52 | IOCTL_FBACKUP_FLT_START, 53 | NULL, 0, 54 | NULL, 0, 55 | &BytesReturned, 56 | NULL ) ) 57 | { 58 | err = GetLastError(); 59 | printf( "Error in IOCTL_FBACKUP_FLT_START %d\n", err); 60 | } else 61 | err = 0; 62 | 63 | CDrvClose(hDevice); 64 | return err; 65 | } 66 | 67 | DWORD NTAPI CDrvCtlFltStop() 68 | { 69 | HANDLE hDevice = NULL; 70 | DWORD BytesReturned; 71 | DWORD err; 72 | 73 | hDevice = CDrvOpen(); 74 | if (hDevice == NULL) { 75 | err = GetLastError(); 76 | return err; 77 | } 78 | 79 | if( !DeviceIoControl(hDevice, 80 | IOCTL_FBACKUP_FLT_STOP, 81 | NULL, 0, 82 | NULL, 0, 83 | &BytesReturned, 84 | NULL ) ) 85 | { 86 | err = GetLastError(); 87 | printf( "Error in IOCTL_FBACKUP_FLT_STOP %d\n", err); 88 | } else 89 | err = 0; 90 | 91 | CDrvClose(hDevice); 92 | return err; 93 | } 94 | 95 | DWORD NTAPI CDrvCtlEcho() 96 | { 97 | HANDLE hDevice = NULL; 98 | DWORD BytesReturned; 99 | DWORD err; 100 | 101 | hDevice = CDrvOpen(); 102 | if (hDevice == NULL) { 103 | err = GetLastError(); 104 | return err; 105 | } 106 | 107 | if (!DeviceIoControl(hDevice, 108 | IOCTL_FBACKUP_ECHO, 109 | NULL, 0, 110 | NULL, 0, 111 | &BytesReturned, 112 | NULL)) 113 | { 114 | err = GetLastError(); 115 | printf("Error in IOCTL_FBACKUP_ECHO %d\n", err); 116 | } else 117 | err = 0; 118 | 119 | CDrvClose(hDevice); 120 | return err; 121 | } 122 | 123 | DWORD NTAPI CDrvCtlBugCheck() 124 | { 125 | HANDLE hDevice = NULL; 126 | DWORD BytesReturned; 127 | DWORD err; 128 | 129 | hDevice = CDrvOpen(); 130 | if (hDevice == NULL) { 131 | err = GetLastError(); 132 | return err; 133 | } 134 | 135 | if (!DeviceIoControl(hDevice, 136 | IOCTL_FBACKUP_BUGCHECK, 137 | NULL, 0, 138 | NULL, 0, 139 | &BytesReturned, 140 | NULL)) 141 | { 142 | err = GetLastError(); 143 | printf("Error in IOCTL_FBACKUP_BUGCHECK %d\n", err); 144 | } else 145 | err = 0; 146 | 147 | CDrvClose(hDevice); 148 | return err; 149 | } 150 | 151 | DWORD NTAPI CDrvCtlTest() 152 | { 153 | HANDLE hDevice = NULL; 154 | DWORD BytesReturned; 155 | DWORD err; 156 | 157 | hDevice = CDrvOpen(); 158 | if (hDevice == NULL) { 159 | err = GetLastError(); 160 | return err; 161 | } 162 | 163 | if (!DeviceIoControl(hDevice, 164 | IOCTL_FBACKUP_TEST, 165 | NULL, 0, 166 | NULL, 0, 167 | &BytesReturned, 168 | NULL)) 169 | { 170 | err = GetLastError(); 171 | printf("Error in IOCTL_FBACKUP_TEST_DRV_LIB %d\n", err); 172 | } else 173 | err = 0; 174 | 175 | CDrvClose(hDevice); 176 | return err; 177 | } 178 | 179 | DWORD NTAPI CDrvInstall(WCHAR *BinPath) 180 | { 181 | SC_HANDLE hScm = NULL; 182 | DWORD err; 183 | WCHAR SysDrvPath[MAX_PATH]; 184 | WCHAR SysDir[MAX_PATH]; 185 | 186 | if (GetSystemDirectory(SysDir, RTL_NUMBER_OF(SysDir)) <= 0) { 187 | err = GetLastError(); 188 | printf("GetSystemDirectory failed with err=%d\n", err); 189 | return err; 190 | } 191 | 192 | _snwprintf_s(SysDrvPath, RTL_NUMBER_OF(SysDrvPath), _TRUNCATE, L"%ws\\drivers\\%ws", SysDir, FBACKUP_DRV_NAME_EXT_W); 193 | printf("Driver path %ws\n", BinPath); 194 | 195 | if (!CopyFileW(BinPath, SysDrvPath, FALSE)) { 196 | err = GetLastError(); 197 | printf("CopyFileW %ws -> %ws err %d\n", BinPath, SysDrvPath, err); 198 | return err; 199 | } 200 | 201 | hScm = ScmOpenSCMHandle(); 202 | if (hScm == NULL) { 203 | err = GetLastError(); 204 | printf("Error OpenSCMHandle %d\n", err); 205 | return err; 206 | } 207 | 208 | err = ScmInstallDriver(hScm, FBACKUP_DRV_NAME_W, SysDrvPath); 209 | if (err) { 210 | if (err == ERROR_SERVICE_EXISTS) { 211 | printf("Service already exists err %d\n", err); 212 | } else { 213 | printf("Error install driver err %x\n", err); 214 | } 215 | } 216 | 217 | ScmCloseSCMHandle(hScm); 218 | 219 | return err; 220 | } 221 | 222 | DWORD NTAPI CDrvUninstall() 223 | { 224 | SC_HANDLE hScm = NULL; 225 | DWORD err; 226 | 227 | hScm = ScmOpenSCMHandle(); 228 | if (hScm == NULL) { 229 | err = GetLastError(); 230 | printf("Error OpenSCMHandle err %d\n", err); 231 | return err; 232 | } 233 | 234 | err = ScmRemoveDriver(hScm, FBACKUP_DRV_NAME_W); 235 | if (err) 236 | printf("Error remove driver err %d\n", err); 237 | 238 | ScmCloseSCMHandle(hScm); 239 | 240 | return err; 241 | } 242 | 243 | DWORD NTAPI CDrvStart() 244 | { 245 | SC_HANDLE hScm = NULL; 246 | DWORD err; 247 | 248 | hScm = ScmOpenSCMHandle(); 249 | if (hScm == NULL) { 250 | err = GetLastError(); 251 | printf("Error OpenSCMHandle err %d\n", err); 252 | return err; 253 | } 254 | 255 | err = ScmStartDriver(hScm, FBACKUP_DRV_NAME_W); 256 | if (err) 257 | printf("Error start driver err %d\n", err); 258 | 259 | ScmCloseSCMHandle(hScm); 260 | return err; 261 | } 262 | 263 | DWORD NTAPI CDrvStop() 264 | { 265 | SC_HANDLE hScm = NULL; 266 | DWORD err; 267 | 268 | hScm = ScmOpenSCMHandle(); 269 | if (hScm == NULL) { 270 | err = GetLastError(); 271 | printf("Error OpenSCMHandle\n"); 272 | return err; 273 | } 274 | 275 | err = ScmStopDriver(hScm, FBACKUP_DRV_NAME_W); 276 | if (err) 277 | printf("Error stop driver %d\n", err); 278 | 279 | ScmCloseSCMHandle(hScm); 280 | 281 | return err; 282 | } 283 | 284 | DWORD NTAPI CDrvLoad(WCHAR *BinPath) 285 | { 286 | DWORD err; 287 | 288 | err = CDrvInstall(BinPath); 289 | if (err) 290 | return err; 291 | 292 | err = CDrvStart(); 293 | if (err) { 294 | CDrvUninstall(); 295 | return err; 296 | } 297 | 298 | return 0; 299 | } 300 | 301 | DWORD NTAPI CDrvUnload() 302 | { 303 | DWORD err; 304 | 305 | err = CDrvStop(); 306 | if (err) { 307 | printf("cant' stop driver service err %d\n", err); 308 | } 309 | 310 | err = CDrvUninstall(); 311 | return err; 312 | } -------------------------------------------------------------------------------- /Client/client.h: -------------------------------------------------------------------------------- 1 | #ifndef __FBACKUP_CTL_CLIENT_H__ 2 | #define __FBACKUP_CTL_CLIENT_H__ 3 | 4 | #include "base.h" 5 | #include "..\driver\h\ioctl.h" 6 | 7 | DWORD NTAPI CDrvCtlBugCheck(); 8 | DWORD NTAPI CDrvCtlTest(); 9 | DWORD NTAPI CDrvCtlEcho(); 10 | 11 | DWORD NTAPI CDrvLoad(WCHAR *BinPath); 12 | DWORD NTAPI CDrvUnload(); 13 | 14 | DWORD NTAPI CDrvCtlFltStart(); 15 | DWORD NTAPI CDrvCtlFltStop(); 16 | 17 | #endif -------------------------------------------------------------------------------- /Client/main.c: -------------------------------------------------------------------------------- 1 | #include "client.h" 2 | #include "srvapi.h" 3 | #include "..\server\api.h" 4 | 5 | typedef struct _SRV_LOAD_TEST_CTX { 6 | HANDLE hThread; 7 | DWORD Err; 8 | ULONG NumReqs; 9 | PWCHAR Host; 10 | } SRV_LOAD_TEST_CTX, *PSRV_LOAD_TEST_CTX; 11 | 12 | DWORD SrvLoadTestWork(PWCHAR Host) 13 | { 14 | DWORD Err; 15 | PSRV_API_CTX ApiCtx; 16 | SYSTEMTIME Time; 17 | 18 | Err = SrvApiInit(); 19 | if (Err) 20 | return Err; 21 | 22 | Err = SrvApiConnect(Host, FB_SRV_PORT, &ApiCtx); 23 | if (Err) 24 | return Err; 25 | 26 | Err = SrvApiGetTime(ApiCtx, &Time); 27 | if (Err) 28 | goto api_close; 29 | 30 | api_close: 31 | SrvApiClose(ApiCtx); 32 | SrvApiRelease(); 33 | return Err; 34 | } 35 | 36 | DWORD SrvLoadTestThread(PSRV_LOAD_TEST_CTX LoadTestCtx) 37 | { 38 | ULONG i; 39 | DWORD Err; 40 | 41 | for (i = 0; i < LoadTestCtx->NumReqs; i++) { 42 | Err = SrvLoadTestWork(LoadTestCtx->Host); 43 | if (Err) 44 | goto ret; 45 | } 46 | Err = 0; 47 | ret: 48 | LoadTestCtx->Err = Err; 49 | return Err; 50 | } 51 | 52 | DWORD SrvLoadTest(PWCHAR Host, ULONG NumTreads, ULONG NumReqs) 53 | { 54 | DWORD Err; 55 | PSRV_LOAD_TEST_CTX *LoadTestCtx, pLoadTestCtx; 56 | ULONG i, j; 57 | ULONG ReqsPerThread; 58 | 59 | printf("SrvLoadTest params: Host %ws, NumTreads %d, NumReqs %d\n", 60 | Host, NumTreads, NumReqs); 61 | 62 | if (!Host || !NumReqs || !NumTreads) 63 | return FB_E_INVAL; 64 | 65 | LoadTestCtx = (PSRV_LOAD_TEST_CTX *)malloc(NumTreads*sizeof(*LoadTestCtx)); 66 | if (!LoadTestCtx) 67 | return FB_E_NO_MEMORY; 68 | 69 | ReqsPerThread = NumReqs/NumTreads; 70 | memset(LoadTestCtx, 0, NumTreads*sizeof(*LoadTestCtx)); 71 | for (i = 0; i < NumTreads; i++) { 72 | pLoadTestCtx = (PSRV_LOAD_TEST_CTX)malloc(sizeof(*LoadTestCtx[i])); 73 | if (!pLoadTestCtx) { 74 | Err = FB_E_NO_MEMORY; 75 | goto fail_free_load_ctx; 76 | } 77 | LoadTestCtx[i] = pLoadTestCtx; 78 | memset(pLoadTestCtx, 0, sizeof(*pLoadTestCtx)); 79 | pLoadTestCtx->NumReqs = ReqsPerThread; 80 | pLoadTestCtx->Host = Host; 81 | pLoadTestCtx->hThread = CreateThread(NULL, 0, SrvLoadTestThread, pLoadTestCtx, 82 | CREATE_SUSPENDED, NULL); 83 | if (!pLoadTestCtx->hThread) { 84 | Err = GetLastError(); 85 | goto fail_stop_load_ctx; 86 | } 87 | } 88 | 89 | for (i = 0; i < NumTreads; i++) { 90 | pLoadTestCtx = LoadTestCtx[i]; 91 | ResumeThread(pLoadTestCtx->hThread); 92 | } 93 | 94 | for (i = 0; i < NumTreads; i++) { 95 | pLoadTestCtx = LoadTestCtx[i]; 96 | WaitForSingleObject(pLoadTestCtx->hThread, INFINITE); 97 | CloseHandle(pLoadTestCtx->hThread); 98 | } 99 | 100 | Err = 0; 101 | for (i = 0; i < NumTreads; i++) { 102 | pLoadTestCtx = LoadTestCtx[i]; 103 | if (pLoadTestCtx->Err) 104 | Err = pLoadTestCtx->Err; 105 | } 106 | 107 | for (i = 0; i < NumTreads; i++) 108 | free(LoadTestCtx[i]); 109 | 110 | free(LoadTestCtx); 111 | return Err; 112 | 113 | fail_stop_load_ctx: 114 | for (j = 0; j < i; j++) { 115 | pLoadTestCtx = LoadTestCtx[i]; 116 | WaitForSingleObject(pLoadTestCtx->hThread, INFINITE); 117 | CloseHandle(pLoadTestCtx->hThread); 118 | } 119 | fail_free_load_ctx: 120 | for (j = 0; j < i; j++) 121 | free(LoadTestCtx[j]); 122 | 123 | free(LoadTestCtx); 124 | return Err; 125 | } 126 | 127 | DWORD SrvPrintTime(PWCHAR Host) 128 | { 129 | DWORD Err; 130 | PSRV_API_CTX ApiCtx; 131 | SYSTEMTIME Time; 132 | 133 | Err = SrvApiInit(); 134 | if (Err) 135 | return Err; 136 | 137 | Err = SrvApiConnect(Host, FB_SRV_PORT, &ApiCtx); 138 | if (Err) 139 | return Err; 140 | 141 | Err = SrvApiGetTime(ApiCtx, &Time); 142 | if (Err) 143 | goto api_close; 144 | 145 | printf("Server time %02d:%02d:%02d.%03d\n", 146 | Time.wHour, Time.wMinute, 147 | Time.wSecond, Time.wMilliseconds); 148 | 149 | api_close: 150 | SrvApiClose(ApiCtx); 151 | SrvApiRelease(); 152 | return Err; 153 | } 154 | 155 | BOOL IsCmdEqual(WCHAR *cmd1, WCHAR *cmd2) 156 | { 157 | if (wcsncmp(cmd1, cmd2, wcslen(cmd1) + 1) == 0) 158 | return TRUE; 159 | else 160 | return FALSE; 161 | } 162 | 163 | int wmain(int argc, WCHAR* argv[]) 164 | { 165 | DWORD Err = ERROR_INVALID_FUNCTION; 166 | WCHAR *Cmd; 167 | 168 | if (argc < 2) { 169 | printf("Wrong num args, should be at least 1\n"); 170 | Err = ERROR_INVALID_PARAMETER; 171 | goto exit; 172 | } 173 | 174 | Cmd = argv[1]; 175 | printf("Cmd %ws\n", Cmd); 176 | if (IsCmdEqual(Cmd, L"load")) { 177 | if (argc != 3) { 178 | printf("Wrong num args, should be 2 args\n"); 179 | Err = ERROR_INVALID_PARAMETER; 180 | goto exit; 181 | } 182 | WCHAR *BinPath = argv[2]; 183 | Err = CDrvLoad(BinPath); 184 | } else if (IsCmdEqual(Cmd, L"unload")) { 185 | Err = CDrvUnload(); 186 | } else if (IsCmdEqual(Cmd, L"fltstart")) { 187 | Err = CDrvCtlFltStart(); 188 | } else if (IsCmdEqual(Cmd, L"fltstop")) { 189 | Err = CDrvCtlFltStop(); 190 | } else if (IsCmdEqual(Cmd, L"echo")) { 191 | Err = CDrvCtlEcho(); 192 | } else if (IsCmdEqual(Cmd, L"bugcheck")) { 193 | Err = CDrvCtlBugCheck(); 194 | } else if (IsCmdEqual(Cmd, L"test")) { 195 | Err = CDrvCtlTest(); 196 | } else if (IsCmdEqual(Cmd, L"srvtime")) { 197 | if (argc != 3) { 198 | printf("Wrong num args, should be 2 args\n"); 199 | Err = ERROR_INVALID_PARAMETER; 200 | goto exit; 201 | } 202 | Err = SrvPrintTime(argv[2]); 203 | } else if (IsCmdEqual(Cmd, L"srvloadtest")) { 204 | if (argc != 5) { 205 | printf("Wrong num args, should be 4 args\n"); 206 | Err = ERROR_INVALID_PARAMETER; 207 | goto exit; 208 | } 209 | Err = SrvLoadTest(argv[2], _wtoi(argv[3]), _wtoi(argv[4])); 210 | } else { 211 | printf("Unknown cmd %ws\n", Cmd); 212 | Err = ERROR_INVALID_FUNCTION; 213 | } 214 | 215 | exit: 216 | printf("ExitCode %d - 0x%x\n", Err, Err); 217 | TerminateProcess(GetCurrentProcess(), Err); 218 | 219 | return 0; 220 | } 221 | 222 | -------------------------------------------------------------------------------- /Client/scmload.c: -------------------------------------------------------------------------------- 1 | #include "scmload.h" 2 | 3 | SC_HANDLE ScmOpenSCMHandle() 4 | { 5 | SC_HANDLE hScm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); 6 | 7 | if (hScm == NULL) { 8 | printf("Error OpenSCManager %d\n", GetLastError()); 9 | } 10 | 11 | return hScm; 12 | } 13 | 14 | VOID ScmCloseSCMHandle(SC_HANDLE hScm) 15 | { 16 | CloseServiceHandle(hScm); 17 | } 18 | 19 | DWORD ScmInstallDriver(SC_HANDLE hScm, LPCTSTR DriverName, LPCTSTR DriverExec) 20 | { 21 | SC_HANDLE hService; 22 | DWORD err; 23 | 24 | hService = CreateService(hScm, 25 | DriverName, 26 | DriverName, 27 | SERVICE_ALL_ACCESS, 28 | SERVICE_KERNEL_DRIVER, 29 | SERVICE_DEMAND_START, 30 | SERVICE_ERROR_NORMAL, 31 | DriverExec, 32 | NULL, 33 | NULL, NULL, NULL, NULL); 34 | if (hService == NULL) 35 | { 36 | err = GetLastError(); 37 | if (err == ERROR_SERVICE_EXISTS) { 38 | printf("Service already exists err %d\n", err); 39 | } else { 40 | printf("Error can't create service %d\n", err); 41 | } 42 | return err; 43 | } 44 | CloseServiceHandle (hService); 45 | return 0; 46 | } 47 | 48 | DWORD ScmRemoveDriver(SC_HANDLE hScm, LPCTSTR DriverName) 49 | { 50 | SC_HANDLE hService; 51 | DWORD err; 52 | 53 | hService = OpenService(hScm, DriverName, SERVICE_ALL_ACCESS); 54 | if (hService == NULL) { 55 | err = GetLastError(); 56 | printf("OpenService error %d\n", err); 57 | return err; 58 | } 59 | 60 | if (!DeleteService(hService)) { 61 | err = GetLastError(); 62 | printf("DeleteService error %d\n", err); 63 | } else 64 | err = 0; 65 | 66 | CloseServiceHandle(hService); 67 | return err; 68 | } 69 | 70 | DWORD ScmStartDriver(SC_HANDLE hScm, LPCTSTR DriverName) 71 | { 72 | SC_HANDLE hService; 73 | DWORD err; 74 | 75 | hService = OpenService(hScm, DriverName, SERVICE_ALL_ACCESS); 76 | if (hService == NULL) { 77 | err = GetLastError(); 78 | printf("OpenService error %d\n", err); 79 | return err; 80 | } 81 | 82 | if (!StartService(hService, 0, NULL)) 83 | { 84 | err = GetLastError(); 85 | if (err == ERROR_SERVICE_ALREADY_RUNNING) { 86 | printf("Service already running err %d\n", err); 87 | } else { 88 | printf("StartService error %d\n", err); 89 | } 90 | } else 91 | err = 0; 92 | 93 | CloseServiceHandle(hService); 94 | return err; 95 | } 96 | 97 | DWORD ScmStopDriver(SC_HANDLE hScm, LPCTSTR DriverName) 98 | { 99 | SC_HANDLE hService; 100 | SERVICE_STATUS ServiceStatus; 101 | DWORD err; 102 | 103 | hService = OpenService (hScm, DriverName, SERVICE_ALL_ACCESS); 104 | if (hService == NULL) 105 | { 106 | err = GetLastError(); 107 | printf("OpenService error %d\n", GetLastError()); 108 | return err; 109 | } 110 | 111 | if (!ControlService(hService, SERVICE_CONTROL_STOP, &ServiceStatus)) 112 | { 113 | err = GetLastError(); 114 | printf("ControlService error %d\n", err); 115 | } else 116 | err = 0; 117 | 118 | CloseServiceHandle (hService); 119 | return err; 120 | } 121 | 122 | -------------------------------------------------------------------------------- /Client/scmload.h: -------------------------------------------------------------------------------- 1 | #ifndef __FBACKUP_CTL_SCM_LOAD_H__ 2 | #define __FBACKUP_CTL_SCM_LOAD_H__ 3 | 4 | #include "base.h" 5 | 6 | SC_HANDLE ScmOpenSCMHandle(); 7 | 8 | VOID ScmCloseSCMHandle(SC_HANDLE hScm); 9 | 10 | DWORD ScmInstallDriver(SC_HANDLE hScm, LPCTSTR DriverName, LPCTSTR DriverExec); 11 | 12 | DWORD ScmRemoveDriver(SC_HANDLE hScm, LPCTSTR DriverName); 13 | 14 | DWORD ScmStartDriver(SC_HANDLE hScm, LPCTSTR DriverName); 15 | 16 | DWORD ScmStopDriver(SC_HANDLE hScm, LPCTSTR DriverName); 17 | 18 | #endif -------------------------------------------------------------------------------- /Client/srvapi.c: -------------------------------------------------------------------------------- 1 | #include "srvapi.h" 2 | #include "..\server\api.h" 3 | 4 | DWORD SrvApiConnect(PWCHAR Host, PWCHAR Port, PSRV_API_CTX *pApiCtx) 5 | { 6 | PSRV_API_CTX ApiCtx; 7 | DWORD Err; 8 | 9 | ApiCtx = malloc(sizeof(*ApiCtx)); 10 | if (!ApiCtx) 11 | return FB_E_NO_MEMORY; 12 | 13 | memset(ApiCtx, 0, sizeof(*ApiCtx)); 14 | Err = SrvConOpen(Host, Port, &ApiCtx->SrvCon); 15 | if (Err) { 16 | free(ApiCtx); 17 | return Err; 18 | } 19 | 20 | *pApiCtx = ApiCtx; 21 | return 0; 22 | } 23 | 24 | DWORD SrvApiRecvResponse(PSRV_API_CTX ApiCtx, PVOID RespBody, ULONG RespBodySize) 25 | { 26 | ULONG Received; 27 | FB_SRV_RESP_HEADER RespHeader; 28 | DWORD Err; 29 | 30 | Err = SrvConRecv(ApiCtx->SrvCon, &RespHeader, sizeof(RespHeader), &Received, NULL); 31 | if (Err) 32 | return Err; 33 | 34 | if (Received != sizeof(RespHeader)) 35 | return FB_E_INCOMP_HEADER; 36 | 37 | if (RespHeader.Magic != FB_SRV_RESP_MAGIC) 38 | return FB_E_BAD_MAGIC; 39 | 40 | Err = RespHeader.Err; 41 | if (Err) 42 | return Err; 43 | 44 | if (RespBodySize != RespHeader.Size) 45 | return FB_E_BAD_SIZE; 46 | 47 | Err = SrvConRecv(ApiCtx->SrvCon, RespBody, RespBodySize, &Received, NULL); 48 | if (Err) 49 | return Err; 50 | 51 | if (RespBodySize != Received) 52 | return FB_E_INCOMP_DATA; 53 | 54 | return 0; 55 | } 56 | 57 | DWORD SrvApiSendRequest(PSRV_API_CTX ApiCtx, ULONG Type, PVOID Body, ULONG BodySize) 58 | { 59 | FB_SRV_REQ_HEADER ReqHeader; 60 | DWORD Err; 61 | 62 | ReqHeader.Magic = FB_SRV_REQ_MAGIC; 63 | ReqHeader.Type = Type; 64 | ReqHeader.Id = 0; 65 | ReqHeader.Size = BodySize; 66 | 67 | Err = SrvConSend(ApiCtx->SrvCon, &ReqHeader, sizeof(ReqHeader)); 68 | if (Err) 69 | return Err; 70 | 71 | if (BodySize) 72 | Err = SrvConSend(ApiCtx->SrvCon, Body, BodySize); 73 | 74 | return Err; 75 | } 76 | 77 | DWORD SrvApiGetTime(PSRV_API_CTX ApiCtx, PSYSTEMTIME pTime) 78 | { 79 | FB_SRV_RESP_TIME Time; 80 | DWORD Err; 81 | 82 | Err = SrvApiSendRequest(ApiCtx, FB_SRV_REQ_TYPE_TIME, NULL, 0); 83 | if (Err) 84 | return Err; 85 | 86 | Err = SrvApiRecvResponse(ApiCtx, &Time, sizeof(Time)); 87 | if (Err) 88 | return Err; 89 | 90 | pTime->wYear = Time.Year; 91 | pTime->wMonth = Time.Month; 92 | pTime->wDayOfWeek = Time.DayOfWeek; 93 | pTime->wDay = Time.Day; 94 | pTime->wHour = Time.Hour; 95 | pTime->wMinute = Time.Minute; 96 | pTime->wSecond = Time.Second; 97 | pTime->wMilliseconds = Time.Milliseconds; 98 | 99 | return 0; 100 | } 101 | 102 | VOID SrvApiClose(PSRV_API_CTX ApiCtx) 103 | { 104 | SrvConClose(ApiCtx->SrvCon); 105 | free(ApiCtx); 106 | return; 107 | } 108 | 109 | DWORD SrvApiInit(VOID) 110 | { 111 | return SrvConInit(); 112 | } 113 | 114 | VOID SrvApiRelease(VOID) 115 | { 116 | SrvConRelease(); 117 | } -------------------------------------------------------------------------------- /Client/srvapi.h: -------------------------------------------------------------------------------- 1 | #ifndef __FBACKUP_CLIENT_SRVAPI_H__ 2 | #define __FBACKUP_CLIENT_SRVAPI_H__ 3 | 4 | #include "base.h" 5 | #include "srvcon.h" 6 | 7 | typedef struct _SRV_API_CTX { 8 | PSRV_CON SrvCon; 9 | } SRV_API_CTX, *PSRV_API_CTX; 10 | 11 | DWORD SrvApiInit(VOID); 12 | VOID SrvApiRelease(VOID); 13 | 14 | DWORD SrvApiConnect(PWCHAR Host, PWCHAR Port, PSRV_API_CTX *pApiCtx); 15 | DWORD SrvApiGetTime(PSRV_API_CTX ApiCtx, PSYSTEMTIME Time); 16 | VOID SrvApiClose(PSRV_API_CTX ApiCtx); 17 | 18 | 19 | #endif -------------------------------------------------------------------------------- /Client/srvcon.c: -------------------------------------------------------------------------------- 1 | #include "srvcon.h" 2 | 3 | DWORD SrvConOpen(PWCHAR Host, PWCHAR Port, PSRV_CON *pSrvCon) 4 | { 5 | SOCKET Socket; 6 | DWORD Err; 7 | ADDRINFOW Hints, *AddrInfo; 8 | PSRV_CON SrvCon; 9 | int OptVal; 10 | 11 | SrvCon = malloc(sizeof(*SrvCon)); 12 | if (!SrvCon) 13 | return FB_E_NO_MEMORY; 14 | 15 | memset(SrvCon, 0, sizeof(*SrvCon)); 16 | memset(&Hints, 0, sizeof(Hints)); 17 | 18 | Hints.ai_family = AF_INET; 19 | Hints.ai_socktype = SOCK_STREAM; 20 | Hints.ai_protocol = IPPROTO_TCP; 21 | Hints.ai_flags = AI_PASSIVE; 22 | 23 | if (GetAddrInfoW(Host, Port, &Hints, &AddrInfo)) { 24 | Err = WSAGetLastError(); 25 | printf("GetAddrInfoW failed Error %d\n", Err); 26 | free(SrvCon); 27 | return Err; 28 | } 29 | 30 | Socket = socket(AddrInfo->ai_family, AddrInfo->ai_socktype, 31 | AddrInfo->ai_protocol); 32 | if (Socket == INVALID_SOCKET) { 33 | Err = WSAGetLastError(); 34 | FreeAddrInfoW(AddrInfo); 35 | free(SrvCon); 36 | return Err; 37 | } 38 | 39 | OptVal = 1; 40 | if (setsockopt(Socket, SOL_SOCKET, SO_REUSEADDR, 41 | (char *) &OptVal, sizeof (OptVal))) { 42 | Err = WSAGetLastError(); 43 | printf("socket connect failed Error %d\n", Err); 44 | FreeAddrInfoW(AddrInfo); 45 | closesocket(Socket); 46 | free(SrvCon); 47 | return Err; 48 | } 49 | 50 | if (connect(Socket, AddrInfo->ai_addr, (int)AddrInfo->ai_addrlen)) { 51 | Err = WSAGetLastError(); 52 | printf("socket connect failed Error %d\n", Err); 53 | FreeAddrInfoW(AddrInfo); 54 | closesocket(Socket); 55 | free(SrvCon); 56 | return Err; 57 | } 58 | 59 | SrvCon->Socket = Socket; 60 | *pSrvCon = SrvCon; 61 | return 0; 62 | } 63 | 64 | DWORD SrvConSend(PSRV_CON SrvCon, PVOID Buf, ULONG Size) 65 | { 66 | int Sent; 67 | ULONG TotalSent = 0; 68 | 69 | while (TotalSent < Size) { 70 | Sent = send(SrvCon->Socket, (PCHAR)Buf + TotalSent, 71 | Size - TotalSent, 0); 72 | if (Sent == SOCKET_ERROR) 73 | return WSAGetLastError(); 74 | 75 | TotalSent+= Sent; 76 | } 77 | 78 | return 0; 79 | } 80 | 81 | DWORD SrvConRecv(PSRV_CON SrvCon, PVOID Buf, ULONG Size, ULONG *pReceived, BOOL *pbClosed) 82 | { 83 | int Received; 84 | ULONG TotalReceived = 0; 85 | 86 | while (TotalReceived < Size) { 87 | Received = recv(SrvCon->Socket, (PCHAR)Buf + TotalReceived, 88 | Size - TotalReceived, 0); 89 | if (Received == SOCKET_ERROR) 90 | return WSAGetLastError(); 91 | 92 | if (Received == 0) { 93 | if (pbClosed) 94 | *pbClosed = TRUE; 95 | break; 96 | } 97 | TotalReceived+= Received; 98 | } 99 | 100 | *pReceived = TotalReceived; 101 | return 0; 102 | } 103 | 104 | VOID SrvConClose(PSRV_CON SrvCon) 105 | { 106 | shutdown(SrvCon->Socket, SD_BOTH); 107 | closesocket(SrvCon->Socket); 108 | free(SrvCon); 109 | } 110 | 111 | DWORD SrvConInit(VOID) 112 | { 113 | WSADATA WsaData; 114 | 115 | return WSAStartup(WINSOCK_VERSION, &WsaData); 116 | } 117 | 118 | VOID SrvConRelease(VOID) 119 | { 120 | WSACleanup(); 121 | } 122 | -------------------------------------------------------------------------------- /Client/srvcon.h: -------------------------------------------------------------------------------- 1 | #ifndef __FBACKUP_CLIENT_SRVCON_H__ 2 | #define __FBACKUP_CLIENT_SRVCON_H__ 3 | 4 | #include "base.h" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | typedef struct _SRV_CON { 11 | SOCKET Socket; 12 | } SRV_CON, *PSRV_CON; 13 | 14 | DWORD SrvConInit(VOID); 15 | VOID SrvConRelease(VOID); 16 | 17 | DWORD SrvConOpen(PWCHAR Host, PWCHAR Port, PSRV_CON *pSrvCon); 18 | DWORD SrvConSend(PSRV_CON SrvCon, PVOID Buf, ULONG Size); 19 | DWORD SrvConRecv(PSRV_CON SrvCon, PVOID Buf, ULONG Size, ULONG *pReceived, BOOL *pbClosed); 20 | VOID SrvConClose(PSRV_CON SrvCon); 21 | 22 | #endif -------------------------------------------------------------------------------- /Deploy/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/irqlevel/filter/5f0d71a90e72ca7c356762604b7aca7800e7cc52/Deploy/__init__.py -------------------------------------------------------------------------------- /Deploy/build.py: -------------------------------------------------------------------------------- 1 | # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 2 | import paramiko 3 | import os 4 | import sys 5 | import time 6 | import inspect 7 | import logging 8 | import shutil 9 | import argparse 10 | 11 | dir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) 12 | 13 | import settings 14 | from cmd import exec_cmd2 15 | import ssh 16 | 17 | logging.config.dictConfig(settings.LOGGING) 18 | log = logging.getLogger('main') 19 | 20 | ch = logging.StreamHandler() 21 | ch.setLevel(logging.DEBUG) 22 | formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') 23 | ch.setFormatter(formatter) 24 | log.addHandler(ch) 25 | 26 | VS_PATH = "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0" 27 | WDK_PATH = "C:\\Program Files (x86)\\Windows Kits\\10" 28 | SDK_PATH = "C:\\Program Files (x86)\\Windows Kits\\10" 29 | WDK_BIN = os.path.join(WDK_PATH, "bin\\x64") 30 | SIGN_TOOL = os.path.join(WDK_BIN, "signtool.exe") 31 | CERT_STORE_NAME = "PrivateCertStore" 32 | CERT_NAME = "Contoso.com(Test)" 33 | 34 | VS_BIN_PATH = os.path.join(VS_PATH, "VC\\bin") 35 | VS_LIB_PATH = os.path.join(VS_PATH, "VC\\lib\\amd64") 36 | 37 | CL_EXE = os.path.join(VS_BIN_PATH, "x86_amd64\\CL.exe") 38 | ML_EXE = os.path.join(VS_BIN_PATH, "x86_amd64\\ml64.exe") 39 | LIB_EXE = os.path.join(VS_BIN_PATH, "Lib.exe") 40 | LINK_EXE = os.path.join(VS_BIN_PATH, "x86_amd64\\link.exe") 41 | 42 | PROJ_ROOT = os.path.dirname(dir) 43 | 44 | BUILD = os.path.join(PROJ_ROOT, "Build") 45 | BUILD_TMP = os.path.join(PROJ_ROOT, "Build_tmp") 46 | 47 | WDK_INC=os.path.join(WDK_PATH, "Include\\10.0.10240.0") 48 | WDK_INC_KM=os.path.join(WDK_INC, "km") 49 | WDK_INC_KM_CRT=os.path.join(WDK_INC, "km\\crt") 50 | WDK_INC_SHARED=os.path.join(WDK_INC, "shared") 51 | WDK_INC_UM=os.path.join(WDK_INC, "um") 52 | 53 | WDK_BIN=os.path.join(WDK_PATH, "bin\\x64") 54 | 55 | WDK_LIB=os.path.join(WDK_PATH, "Lib\\10.0.10240.0") 56 | WDK_KM_LIB=os.path.join(WDK_LIB, "km\\x64") 57 | WDK_UM_LIB=os.path.join(WDK_LIB, "um\\x64") 58 | 59 | SDK_LIB = os.path.join(SDK_PATH, "Lib\\10.0.10240.0") 60 | SDK_UCRT_LIB = os.path.join(SDK_LIB, "ucrt\\x64") 61 | SDK_UM_LIB = os.path.join(SDK_LIB, "um\\x64") 62 | 63 | KCL_ARCH_D_OPTS="/D _WIN64 /D _AMD64_ /D AMD64" 64 | KCL_OPTS="/Zi /nologo /W3 /WX /Od /GF /Gm- /Zp8 /GS /Gy /fp:precise /Zc:wchar_t /Zc:forScope /GR- /Gz /TC /wd4603 /wd4627 /wd4986 /wd4987 /wd4996 /errorReport:prompt /kernel -cbstring -d2epilogunwind /d1nodatetime /d1import_no_registry /d2AllowCompatibleILVersions /d2Zi+" 65 | 66 | KLIB_ARCH_OPTS="/MACHINE:X64" 67 | KLIB_OPTS="/NOLOGO" 68 | KLIBS=["BufferOverflowK.lib", "ntoskrnl.lib", "hal.lib", "wmilib.lib", "netio.lib"] 69 | 70 | KLINK_VERSION="/VERSION:0.0" 71 | KLINK_SUBSYTEM = "/SUBSYSTEM:NATIVE" 72 | KLINK_ARCH_OPTS="/MACHINE:X64" 73 | KLINK_OPTS="/ERRORREPORT:PROMPT /INCREMENTAL:NO /NOLOGO /WX /SECTION:\"INIT,d\" /NODEFAULTLIB /MANIFEST:NO /DEBUG /MERGE:\"_TEXT=.text;_PAGE=PAGE\" /PROFILE /kernel /IGNORE:4198,4010,4037,4039,4065,4070,4078,4087,4089,4221,4108,4088,4218,4218,4235 /pdbcompress /debugtype:pdata /Driver /OPT:REF /OPT:ICF /ENTRY:\"GsDriverEntry\" /RELEASE" 74 | 75 | UCL_D_OPTS="/D NDEBUG /D _CONSOLE /D _LIB /D _UNICODE /D UNICODE" 76 | UCL_ARCH_D_OPTS="/D _WIN64 /D _AMD64_ /D AMD64" 77 | UCL_OPTS="/Zi /nologo /W3 /WX /Od /GL /Gm- /EHsc /MT /GS /Gy /fp:precise /Zc:wchar_t /Zc:forScope /Gd /TC /errorReport:prompt" 78 | 79 | ULINK_ARCH_OPTS="/MACHINE:X64" 80 | ULINK_VERSION="/VERSION:0.0" 81 | ULINK_SUBSYSTEM="/SUBSYSTEM:CONSOLE" 82 | ULINK_OPTS="/ERRORREPORT:PROMPT /INCREMENTAL:NO /NOLOGO /MANIFEST /MANIFESTUAC:\"level='asInvoker' uiAccess='false'\" /manifest:embed /DEBUG /OPT:REF /OPT:ICF /LTCG /TLBID:1 /DYNAMICBASE /NXCOMPAT" 83 | 84 | UVS_LIBS=["libcmt.lib", "oldnames.lib", "libvcruntime.lib", "legacy_stdio_definitions.lib", "legacy_stdio_wide_specifiers.lib"] 85 | UCRT_LIBS = ["libucrt.lib"] 86 | 87 | UWDK_LIBS=["BufferOverflowU.lib", "kernel32.lib", "user32.lib", "gdi32.lib", "winspool.lib", "comdlg32.lib", 88 | "advapi32.lib", "shell32.lib", "ole32.lib", "oleaut32.lib", "uuid.lib", "odbc32.lib", "odbccp32.lib", "ws2_32.lib"] 89 | 90 | VS_BUILD_BINS= ["mspdb140.dll", "mspdbcore.dll", "mspdbsrv.exe", "msobj140.dll", "cvtres.exe"] 91 | WDK_BUILD_BINS= ["rc.exe", "rcdll.dll"] 92 | 93 | 94 | BUILD_OUT_DIR=os.path.join(BUILD, "x64") 95 | 96 | DRIVER_NAME="FBackup" 97 | DRIVER_BUILD_TMP=os.path.join(BUILD_TMP, DRIVER_NAME + "\\x64") 98 | DRIVER_DIR=os.path.join(PROJ_ROOT, "Driver") 99 | DRIVER_OUT=DRIVER_NAME + ".sys" 100 | DRIVER_OUT_PDB=DRIVER_NAME + ".pdb" 101 | 102 | CLIENT_NAME="FBackupCtl" 103 | CLIENT_BUILD_TMP=os.path.join(BUILD_TMP, CLIENT_NAME + "\\x64") 104 | CLIENT_DIR=os.path.join(PROJ_ROOT, "Client") 105 | CLIENT_OUT=CLIENT_NAME + ".exe" 106 | CLIENT_OUT_PDB=CLIENT_NAME + ".pdb" 107 | 108 | SERVER_NAME="FBackupServer" 109 | SERVER_BUILD_TMP=os.path.join(BUILD_TMP, SERVER_NAME + "\\x64") 110 | SERVER_DIR=os.path.join(PROJ_ROOT, "Server") 111 | SERVER_OUT=SERVER_NAME + ".exe" 112 | SERVER_OUT_PDB=SERVER_NAME + ".pdb" 113 | 114 | DRIVER_SOURCES = ["driver.c", "klog.c", "fastio.c", "helpers.c", "worker.c", "socket.c", "map.c", "tests.c"] 115 | 116 | CLIENT_SOURCES = ["client.c", "scmload.c", "main.c", "srvcon.c", "srvapi.c"] 117 | 118 | SERVER_SOURCES = ["log.c", "main.c", "server.c", "memalloc.c", "debug.c", "fmt.c", "time.c", "btree.c"] 119 | 120 | TARGET_WIN7 = "win7" 121 | TARGET_WIN8 = "win8" 122 | TARGET_WIN81 = "win81" 123 | TARGET_WIN10 = "win10" 124 | 125 | TARGETS = [TARGET_WIN7, TARGET_WIN8, TARGET_WIN81, TARGET_WIN10] 126 | 127 | CL_VER_OPTS_WIN7 = "/D _WIN32_WINNT=0x0601 /D WINVER=0x0601 /D WINNT=1 /D NTDDI_VERSION=0x06010000" 128 | CL_VER_OPTS_WIN8 = "/D _WIN32_WINNT=0x0602 /D WINVER=0x0602 /D WINNT=1 /D NTDDI_VERSION=0x06020000" 129 | CL_VER_OPTS_WIN81 = "/D _WIN32_WINNT=0x0603 /D WINVER=0x0603 /D WINNT=1 /D NTDDI_VERSION=0x06030000" 130 | CL_VER_OPTS_WIN10 = "/D _WIN32_WINNT=0x0A00 /D WINVER=0x0A00 /D WINNT=1 /D NTDDI_VERSION=0x0A000000" 131 | 132 | SUBSYSTEM_VER_BY_TARGET = {TARGET_WIN7: "6.01", TARGET_WIN8 : "6.02", TARGET_WIN81 : "6.03", TARGET_WIN10 : "10.0"} 133 | OSVERSION_BY_TARGET = {TARGET_WIN7 : "6.1", TARGET_WIN8 : "6.2", TARGET_WIN81 : "6.3", TARGET_WIN10 : "10.0"} 134 | 135 | CL_VER_OPTS_BY_TARGET = {TARGET_WIN7 : CL_VER_OPTS_WIN7, TARGET_WIN8 : CL_VER_OPTS_WIN8, TARGET_WIN81 : CL_VER_OPTS_WIN81, 136 | TARGET_WIN10 : CL_VER_OPTS_WIN10} 137 | 138 | def do_cmd(cmd, elog): 139 | exec_cmd2(cmd, throw = True, elog = elog) 140 | 141 | def do_copy_file(src, dst, elog): 142 | elog.info("copying %s -> %s" % (src, dst)) 143 | shutil.copy(src, dst) 144 | 145 | def quote_path(path): 146 | return "\"" + path + "\"" 147 | 148 | def inc_path(path): 149 | return " /I" + quote_path(path) 150 | 151 | def replace_ext(path, ext): 152 | return os.path.splitext(path)[0] + ext 153 | 154 | def build_driver(elog, build_dir, tmp_dir, target): 155 | cmd = quote_path(CL_EXE) + " /c" 156 | cmd+= inc_path(WDK_INC_KM) 157 | cmd+= inc_path(WDK_INC_KM_CRT) 158 | cmd+= inc_path(WDK_INC_SHARED) 159 | cmd+= inc_path(PROJ_ROOT) 160 | cmd+=" /Fo" + quote_path(tmp_dir) + "\\" 161 | # cmd+= " /Fd" + quote_path(os.path.join(tmp_dir, "vc120.pdb")) 162 | cmd+=" " + KCL_OPTS + " " + KCL_ARCH_D_OPTS + " " + CL_VER_OPTS_BY_TARGET[target] 163 | for f in DRIVER_SOURCES: 164 | cmd+= " " + quote_path(os.path.join(DRIVER_DIR, f)) 165 | do_cmd(cmd, elog) 166 | 167 | cmd = quote_path(LINK_EXE) 168 | cmd+= " /OUT:" + quote_path(os.path.join(build_dir, DRIVER_OUT)) + " " + KLINK_OPTS + " " + KLINK_ARCH_OPTS + " " + KLINK_VERSION 169 | cmd+= " /osversion:" + OSVERSION_BY_TARGET[target] 170 | cmd+= " " + KLINK_SUBSYTEM + "," + SUBSYSTEM_VER_BY_TARGET[target] 171 | cmd+= " /PDB:" + quote_path(os.path.join(build_dir, DRIVER_OUT_PDB)) 172 | for l in KLIBS: 173 | cmd+= " " + quote_path(os.path.join(WDK_KM_LIB, l)) 174 | 175 | for f in DRIVER_SOURCES: 176 | fobj = replace_ext(f, ".obj") 177 | cmd+= " " + quote_path(os.path.join(tmp_dir, fobj)) 178 | do_cmd(cmd, elog) 179 | 180 | cmd = quote_path(SIGN_TOOL) + " sign /v /s " + CERT_STORE_NAME + " /n " + CERT_NAME 181 | cmd+= " /t http://timestamp.verisign.com/scripts/timstamp.dll " 182 | cmd+= quote_path(os.path.join(build_dir, DRIVER_OUT)) 183 | do_cmd(cmd, elog) 184 | 185 | def build_client(elog, build_dir, tmp_dir, target): 186 | cmd = quote_path(CL_EXE) + " /c" 187 | cmd+= inc_path(WDK_INC_UM) 188 | cmd+= inc_path(WDK_INC_KM_CRT) 189 | cmd+= inc_path(WDK_INC_SHARED) 190 | cmd+= inc_path(PROJ_ROOT) 191 | cmd+=" /Fo" + quote_path(tmp_dir) + "\\" 192 | # cmd+= " /Fd" + quote_path(os.path.join(tmp_dir, "vc120.pdb")) 193 | cmd+=" " + UCL_OPTS + " " + UCL_D_OPTS + " " + UCL_ARCH_D_OPTS + " " + CL_VER_OPTS_BY_TARGET[target] 194 | for f in CLIENT_SOURCES: 195 | cmd+= " " + quote_path(os.path.join(CLIENT_DIR, f)) 196 | do_cmd(cmd, elog) 197 | 198 | cmd = quote_path(LINK_EXE) 199 | cmd+= " /OUT:" + quote_path(os.path.join(build_dir, CLIENT_OUT)) + " " + ULINK_OPTS + " " + ULINK_ARCH_OPTS + " " + ULINK_VERSION 200 | cmd+= " " + ULINK_SUBSYSTEM + "," + SUBSYSTEM_VER_BY_TARGET[target] 201 | cmd+= " /osversion:" + OSVERSION_BY_TARGET[target] 202 | cmd+= " /PDB:" + quote_path(os.path.join(build_dir, CLIENT_OUT_PDB)) 203 | for l in UWDK_LIBS: 204 | cmd+= " " + quote_path(os.path.join(WDK_UM_LIB, l)) 205 | for l in UVS_LIBS: 206 | cmd+= " " + quote_path(os.path.join(VS_LIB_PATH, l)) 207 | for l in UCRT_LIBS: 208 | cmd+= " " + quote_path(os.path.join(SDK_UCRT_LIB, l)) 209 | for f in CLIENT_SOURCES: 210 | fobj = replace_ext(f, ".obj") 211 | cmd+= " " + quote_path(os.path.join(tmp_dir, fobj)) 212 | do_cmd(cmd, elog) 213 | 214 | def build_server(elog, build_dir, tmp_dir, target): 215 | cmd = quote_path(CL_EXE) + " /c" 216 | cmd+= inc_path(WDK_INC_UM) 217 | cmd+= inc_path(WDK_INC_KM_CRT) 218 | cmd+= inc_path(WDK_INC_SHARED) 219 | cmd+= inc_path(PROJ_ROOT) 220 | cmd+=" /Fo" + quote_path(tmp_dir) + "\\" 221 | # cmd+= " /Fd" + quote_path(os.path.join(tmp_dir, "vc120.pdb")) 222 | cmd+=" " + UCL_OPTS + " " + UCL_D_OPTS + " " + UCL_ARCH_D_OPTS + " " + CL_VER_OPTS_BY_TARGET[target] 223 | for f in SERVER_SOURCES: 224 | cmd+= " " + quote_path(os.path.join(SERVER_DIR, f)) 225 | do_cmd(cmd, elog) 226 | 227 | cmd = quote_path(LINK_EXE) 228 | cmd+= " /OUT:" + quote_path(os.path.join(build_dir, SERVER_OUT)) + " " + ULINK_OPTS + " " + ULINK_ARCH_OPTS + " " + ULINK_VERSION 229 | cmd+= " " + ULINK_SUBSYSTEM + "," + SUBSYSTEM_VER_BY_TARGET[target] 230 | cmd+= " /osversion:" + OSVERSION_BY_TARGET[target] 231 | cmd+= " /PDB:" + quote_path(os.path.join(build_dir, SERVER_OUT_PDB)) 232 | for l in UWDK_LIBS: 233 | cmd+= " " + quote_path(os.path.join(WDK_UM_LIB, l)) 234 | for l in UVS_LIBS: 235 | cmd+= " " + quote_path(os.path.join(VS_LIB_PATH, l)) 236 | for l in UCRT_LIBS: 237 | cmd+= " " + quote_path(os.path.join(SDK_UCRT_LIB, l)) 238 | for f in SERVER_SOURCES: 239 | fobj = replace_ext(f, ".obj") 240 | cmd+= " " + quote_path(os.path.join(tmp_dir, fobj)) 241 | do_cmd(cmd, elog) 242 | 243 | def make_dirs(dirs, elog): 244 | for d in dirs: 245 | if os.path.exists(d): 246 | do_cmd("rmdir /s /q " + d, elog) 247 | do_cmd("mkdir " + d, elog) 248 | 249 | def rebuild_target(elog, build_dir, tmp_dir, target, binary): 250 | bdir = os.path.join(build_dir, target) 251 | tdir = os.path.join(tmp_dir, target) 252 | make_dirs([bdir, tdir], elog) 253 | driver_tdir = os.path.join(tdir, "driver") 254 | client_tdir = os.path.join(tdir, "client") 255 | server_tdir = os.path.join(tdir, "server") 256 | make_dirs([client_tdir, driver_tdir, server_tdir], elog) 257 | 258 | if binary == "driver": 259 | build_driver(elog, bdir, client_tdir, target) 260 | elif binary == "client": 261 | build_client(elog, bdir, driver_tdir, target) 262 | elif binary == "server": 263 | build_server(elog, bdir, server_tdir, target) 264 | elif binary == "all": 265 | build_driver(elog, bdir, client_tdir, target) 266 | build_client(elog, bdir, driver_tdir, target) 267 | build_server(elog, bdir, server_tdir, target) 268 | else: 269 | raise Exception("Unknown binary " + binary) 270 | 271 | def rebuild(elog, target, binary): 272 | odir = None 273 | try: 274 | os.system("taskkill /F /im mspdbsrv.exe") 275 | make_dirs([BUILD, BUILD_TMP], elog) 276 | 277 | for f in VS_BUILD_BINS: 278 | do_copy_file(os.path.join(VS_BIN_PATH, f), os.path.join(BUILD_TMP, f), elog) 279 | 280 | for f in WDK_BUILD_BINS: 281 | do_copy_file(os.path.join(WDK_BIN, f), os.path.join(BUILD_TMP, f), elog) 282 | 283 | odir = os.getcwd() 284 | os.chdir(BUILD_TMP) 285 | if target == 'all': 286 | for t in TARGETS: 287 | rebuild_target(elog, BUILD, BUILD_TMP, t, binary) 288 | else: 289 | rebuild_target(elog, BUILD, BUILD_TMP, target, binary) 290 | except Exception as e: 291 | elog.exception(str(e)) 292 | finally: 293 | if odir != None: 294 | os.chdir(odir) 295 | 296 | if __name__ == '__main__': 297 | parser = argparse.ArgumentParser() 298 | parser.add_argument("target", type=str, help="target: win7, win8, win81, win10") 299 | parser.add_argument("binary", type=str, help="binary: client, driver, server, all") 300 | args = parser.parse_args() 301 | rebuild(log, args.target, args.binary) -------------------------------------------------------------------------------- /Deploy/cmd.py: -------------------------------------------------------------------------------- 1 | # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 2 | import httplib 3 | import json 4 | import subprocess 5 | import os 6 | from datetime import datetime 7 | import logging.config 8 | import logging 9 | import uuid 10 | import threading 11 | import copy 12 | import time 13 | import sys 14 | import inspect 15 | import re 16 | 17 | currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) 18 | 19 | import settings 20 | 21 | logging.config.dictConfig(settings.LOGGING) 22 | 23 | log = logging.getLogger('main') 24 | 25 | 26 | 27 | def exec_cmd(cmd, output = False): 28 | args = cmd.split() 29 | log.info("EXEC:" + cmd + ":" + str(args)) 30 | 31 | if output: 32 | process = subprocess.Popen(args, stdout = subprocess.PIPE, stderr = subprocess.PIPE) 33 | else: 34 | process = subprocess.Popen(args) 35 | 36 | stdout, stderr = process.communicate() 37 | process.wait() 38 | 39 | log.info("EXEC:stdout:" + str(stdout)) 40 | log.info("EXEC:stderr:" + str(stderr)) 41 | log.info("EXEC:" + cmd + ":" + str(args) + ":rc=" + str(process.returncode)) 42 | return (process.returncode, stdout, stderr) 43 | 44 | class StdFp(): 45 | def __init__(self, fp, log_extra, elog = None): 46 | self.fp = fp 47 | self.lines = [] 48 | self.lock = threading.Lock() 49 | self.log_extra = log_extra 50 | self.elog = elog 51 | def append(self, l): 52 | self.lock.acquire() 53 | try: 54 | lp = l.replace("\n", "") 55 | if self.elog != None: 56 | self.elog.info(self.log_extra + ":" + lp) 57 | self.lines.append(lp) 58 | except Exception as e: 59 | if self.elog != None: 60 | self.elog.exception(str(e)) 61 | finally: 62 | self.lock.release() 63 | 64 | def get_lines(self): 65 | lines = [] 66 | self.lock.acquire() 67 | try: 68 | lines = copy.deepcopy(self.lines) 69 | except Exception as e: 70 | if self.elog != None: 71 | self.elog.exception(str(e)) 72 | finally: 73 | self.lock.release() 74 | 75 | return lines 76 | 77 | class StdThread(threading.Thread): 78 | def __init__(self, std_fp): 79 | threading.Thread.__init__(self) 80 | self.std_fp = std_fp 81 | self.stopping = False 82 | def run(self): 83 | while not self.stopping: 84 | l = self.std_fp.fp.readline() 85 | if l == '': 86 | break 87 | self.std_fp.append(l) 88 | 89 | class Cmd(): 90 | def __init__(self, cmd, throw = False, elog = None): 91 | self.cmd = cmd 92 | self.stdout = None 93 | self.stderr = None 94 | self.throw = throw 95 | self.elog = elog 96 | 97 | def run(self): 98 | log.info("CMD:" + self.cmd) 99 | if self.elog != None: 100 | self.elog.info("CMD:" + self.cmd) 101 | 102 | process = subprocess.Popen(self.cmd, shell=True, stdout = subprocess.PIPE, stderr = subprocess.PIPE) 103 | 104 | self.stdout = StdFp(process.stdout, "CMD:stdout", elog = self.elog) 105 | self.stderr = StdFp(process.stderr, "CMD:stderr", elog = self.elog) 106 | 107 | self.stderr_t = StdThread(self.stderr) 108 | self.stdout_t = StdThread(self.stdout) 109 | 110 | self.stdout_t.start() 111 | self.stderr_t.start() 112 | 113 | process.wait() 114 | 115 | self.stdout_t.join() 116 | self.stderr_t.join() 117 | 118 | self.rc = process.returncode 119 | 120 | #log.info("CMD:" + self.cmd + ":stdout:" + self.stdout.out) 121 | #log.info("CMD:" + self.cmd + ":stderr:" + self.stderr.out) 122 | if self.rc == 0: 123 | log.info("CMD:" + self.cmd + ":rc:" + str(self.rc)) 124 | if self.elog != None: 125 | self.elog.info("CMD:" + self.cmd + ":rc:" + str(self.rc)) 126 | else: 127 | log.error("CMD:" + self.cmd + ":rc:" + str(self.rc)) 128 | if self.elog != None: 129 | self.elog.error("CMD:" + self.cmd + ":rc:" + str(self.rc)) 130 | 131 | if self.rc != 0 and self.throw: 132 | raise Exception("CMD:" + self.cmd + ":rc:" + str(self.rc)) 133 | 134 | def exec_cmd2(cmd, throw = False, elog = None): 135 | c = Cmd(cmd, throw = throw, elog = elog) 136 | c.run() 137 | return c.rc , c.stdout.lines, c.stderr.lines, c 138 | 139 | def exec_cmd2_list(cmds, elog = None): 140 | rcs = [] 141 | for cmd in cmds: 142 | c = Cmd(cmd, elog = elog) 143 | c.run() 144 | rcs.append(c.rc) 145 | return rcs 146 | 147 | if __name__=="__main__": 148 | exec_cmd2("tasklist") 149 | 150 | -------------------------------------------------------------------------------- /Deploy/load.py: -------------------------------------------------------------------------------- 1 | # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 2 | import paramiko 3 | import os 4 | import sys 5 | import time 6 | import inspect 7 | import logging 8 | import argparse 9 | import build 10 | 11 | dir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) 12 | pdir = os.path.dirname(dir) 13 | 14 | import settings 15 | import cmd 16 | import ssh 17 | 18 | logging.config.dictConfig(settings.LOGGING) 19 | log = logging.getLogger('main') 20 | 21 | ch = logging.StreamHandler() 22 | ch.setLevel(logging.DEBUG) 23 | formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') 24 | ch.setFormatter(formatter) 25 | log.addHandler(ch) 26 | 27 | def rebuild(target): 28 | build.rebuild(log, target) 29 | 30 | def test_run(target, host, bsod = False, test = False): 31 | login = "Administrator" 32 | passwd = "1q2w3eQAZ" 33 | sh = ssh.SshUser(log, host, login, passwd = passwd) 34 | client = "FBackupCtl.exe" 35 | driver = "FBackup.sys" 36 | files = [client, driver, "FBackupCtl.pdb", "FBackup.pdb"] 37 | r_path = "c:\\FBackupTest" 38 | b_path = os.path.join(os.path.join(pdir, "build"), target) 39 | try: 40 | sh.cmd("rmdir /s /q " + r_path, throw = False) 41 | sh.cmd("mkdir " + r_path) 42 | for f in files: 43 | sh.file_put(os.path.join(b_path, f), os.path.join(r_path, f)) 44 | sh.cmd(os.path.join(r_path, client) + " load " + os.path.join(r_path, driver)) 45 | sh.cmd(os.path.join(r_path, client) + " fltstart") 46 | if test: 47 | sh.cmd(os.path.join(r_path, client) + " test") 48 | time.sleep(5) 49 | if bsod: 50 | sh.cmd(os.path.join(r_path, client) + " bugcheck") 51 | sh.cmd(os.path.join(r_path, client) + " fltstop") 52 | except Exception as e: 53 | log.error('Exception=' + str(e)) 54 | finally: 55 | try: 56 | sh.cmd(os.path.join(r_path, client) + " unload") 57 | except: 58 | pass 59 | 60 | if __name__ == '__main__': 61 | parser = argparse.ArgumentParser() 62 | parser.add_argument("-b", "--bsod", action="store_true", help="bsod the node") 63 | parser.add_argument("-t", "--test", action="store_true", help="test drv") 64 | parser.add_argument("-r", "--rebuild", action="store_true", help="rebuild project") 65 | parser.add_argument("target", type=str, help="target") 66 | parser.add_argument("host", type=str, help="host ip") 67 | args = parser.parse_args() 68 | if args.rebuild: 69 | rebuild(args.target) 70 | test_run(args.target, args.host, args.bsod, args.test) -------------------------------------------------------------------------------- /Deploy/multilogger.py: -------------------------------------------------------------------------------- 1 | # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 2 | import httplib 3 | import json 4 | import subprocess 5 | import os 6 | from datetime import datetime 7 | import logging.config 8 | import logging 9 | import uuid 10 | import threading 11 | import copy 12 | import time 13 | import sys 14 | import inspect 15 | import re 16 | 17 | class MultiLogger(): 18 | def __init__(self, logs = []): 19 | self.logs = logs 20 | 21 | def append(self, l): 22 | self.logs.append(l) 23 | 24 | def error(self, msg, *args, **kwargs): 25 | for l in self.logs: 26 | l.error(msg, args, **kwargs) 27 | 28 | def info(self, msg, *args, **kwargs): 29 | for l in self.logs: 30 | l.info(msg, *args, **kwargs) 31 | 32 | def debug(self, msg, *args, **kwargs): 33 | for l in self.logs: 34 | l.debug(msg, *args, **kwargs) 35 | 36 | def critical(self, msg, *args, **kwargs): 37 | for l in self.logs: 38 | l.critical(msg, *args, **kwargs) 39 | 40 | def exception(self, msg, *args): 41 | for l in self.logs: 42 | l.exception(msg, *args) 43 | 44 | -------------------------------------------------------------------------------- /Deploy/settings.py: -------------------------------------------------------------------------------- 1 | # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 2 | import os 3 | import inspect 4 | 5 | currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) 6 | CURR_DIR = os.path.abspath(currentdir) 7 | PROJ_DIR = os.path.dirname(CURR_DIR) 8 | 9 | BUILD_DIR = os.path.join(PROJ_DIR, "build") 10 | X64_BUILD_DIR = os.path.join(BUILD_DIR, "x64") 11 | X64_RELEASE_DIR = os.path.join(X64_BUILD_DIR, "Release") 12 | 13 | LOGGING = { 14 | 'version' : 1, 15 | 'disable_existing_loggers' : False, 16 | 'formatters': { 17 | 'verbose' : { 18 | 'format' : '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s' 19 | }, 20 | 'simple' : { 21 | 'format' : '%(levelname)s %(asctime)s %(module)s %(message)s' 22 | }, 23 | }, 24 | 'handlers' : { 25 | 'file' : { 26 | 'level' : 'DEBUG', 27 | 'class' : 'logging.FileHandler', 28 | 'formatter' : 'simple', 29 | 'filename' : os.path.join(CURR_DIR, 'debug.log'), 30 | }, 31 | }, 32 | 'loggers' : { 33 | 'django.request' : { 34 | 'handlers' : ['file'], 35 | 'level' : 'DEBUG', 36 | 'propagate' : True, 37 | }, 38 | 'main' : { 39 | 'handlers' : ['file'], 40 | 'level' : 'DEBUG', 41 | 'propagate' : True, 42 | }, 43 | }, 44 | } 45 | 46 | -------------------------------------------------------------------------------- /Deploy/ssh.py: -------------------------------------------------------------------------------- 1 | # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 2 | import paramiko 3 | import os 4 | import sys 5 | import time 6 | import inspect 7 | import logging 8 | 9 | currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) 10 | 11 | import settings 12 | from cmd import StdFp, StdThread 13 | 14 | logging.config.dictConfig(settings.LOGGING) 15 | 16 | log = logging.getLogger('main') 17 | 18 | def ssh_cmd(ssh, cmd, throw = False, log = None): 19 | log.info("SSH:" + cmd) 20 | chan = None 21 | out_lines = [] 22 | err_lines = [] 23 | rc = 777 24 | try: 25 | chan = ssh.get_transport().open_session() 26 | chan.exec_command(cmd) 27 | 28 | stdout = StdFp(chan.makefile(), "SSH:stdout", elog = log) 29 | stderr = StdFp(chan.makefile_stderr(), "SSH:stderr", elog = log) 30 | 31 | stderr_t = StdThread(stderr) 32 | stdout_t = StdThread(stdout) 33 | 34 | stdout_t.start() 35 | stderr_t.start() 36 | 37 | rc = chan.recv_exit_status() 38 | stdout_t.join() 39 | stderr_t.join() 40 | out_lines = stdout.lines 41 | err_lines = stderr.lines 42 | 43 | if rc == 0: 44 | log.info("SSH:" + cmd + ":rc:" + str(rc)) 45 | else: 46 | log.error("SSH:" + cmd + ":rc:" + str(rc)) 47 | except Exception as e: 48 | log.exception(str(e)) 49 | finally: 50 | if chan != None: 51 | try: 52 | chan.shutdown(2) 53 | except Exception as e: 54 | log.exception(str(e)) 55 | try: 56 | chan.close() 57 | except Exception as e: 58 | log.exception(str(e)) 59 | if rc != 0 and throw: 60 | raise Exception("SSH:" + cmd + ":rc:" + str(rc)) 61 | 62 | return rc, out_lines, err_lines 63 | 64 | class SshUser: 65 | def __init__(self, log, host, user, passwd = None, key_file = None, ftp = False): 66 | self.log = log 67 | self.host = host 68 | self.user = user 69 | self.passwd = passwd 70 | self.key_file = key_file 71 | self.ftp = ftp 72 | def get_ssh(self, ftp = False): 73 | if ftp or self.ftp: 74 | ftp = True 75 | return SshExec(self.log, self.host, self.user, passwd = self.passwd, key_file = self.key_file, ftp = ftp) 76 | def cmd(self, cmd, throw = True): 77 | s = self.get_ssh() 78 | s.cmd(cmd, throw = throw) 79 | s.close() 80 | def file_get(self, remote_file, local_file): 81 | s = self.get_ssh(ftp = True) 82 | s.file_get(remote_file, local_file) 83 | s.close() 84 | def file_put(self, local_file, remote_file): 85 | s = self.get_ssh(ftp = True) 86 | s.file_put(local_file, remote_file) 87 | s.close() 88 | 89 | class SshExec: 90 | def __init__(self, log, host, user, passwd = None, key_file = None, ftp = False): 91 | self.host = host 92 | self.user = user 93 | self.passwd = passwd 94 | self.key_file = key_file 95 | self.log = log 96 | if self.key_file != None: 97 | self.pkey = paramiko.RSAKey.from_private_key_file(self.key_file) 98 | else: 99 | self.pkey = None 100 | self.ssh = paramiko.SSHClient() 101 | self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 102 | self.ssh.connect(self.host, username=self.user, password = self.passwd, pkey=self.pkey) 103 | if ftp: 104 | self.ftp = self.ssh.open_sftp() 105 | else: 106 | self.ftp = None 107 | self.log.info('SSH:opened to host ' + self.host) 108 | def cmd(self, cmd, throw = True): 109 | return ssh_cmd(self.ssh, cmd, throw = throw, log = self.log) 110 | def file_get(self, remote_file, local_file): 111 | self.log.info("SSH:getfile:" + str(self.host) + " remote:" + remote_file + " local:" + local_file) 112 | self.ftp.get(remote_file, local_file) 113 | self.log.info("SSH:getfile:completed") 114 | def file_put(self, local_file, remote_file): 115 | self.log.info("SSH:putfile:" + str(self.host) + " local:" + local_file + " remote:" + remote_file) 116 | self.ftp.put(local_file, remote_file) 117 | self.log.info("SSH:putfile:completed") 118 | def file_getcwd(self): 119 | return self.ftp.getcwd() 120 | def file_chdir(self, path): 121 | return self.ftp.chdir(path) 122 | def close(self): 123 | if self.ftp: 124 | self.ftp.close() 125 | self.ssh.close() 126 | 127 | -------------------------------------------------------------------------------- /Driver/h/ioctl.h: -------------------------------------------------------------------------------- 1 | #ifndef __FBACKUP_IOCTL_H__ 2 | #define __FBACKUP_IOCTL_H__ 3 | 4 | #ifdef _WINDOWS 5 | #include 6 | #endif 7 | 8 | #define FBACKUP_DRV_NAME_W L"FBackup" 9 | #define FBACKUP_DRV_NAME_EXT_W FBACKUP_DRV_NAME_W L".sys" 10 | #define FBACKUP_DRV_NT_DEVICE_NAME_W L"\\Device\\" FBACKUP_DRV_NAME_W 11 | #define FBACKUP_DRV_DOS_DEVICE_NAME_W L"\\DosDevices\\" FBACKUP_DRV_NAME_W 12 | #define FBACKUP_DRV_WIN32_DEVICE_NAME_W L"\\\\.\\" FBACKUP_DRV_NAME_W 13 | 14 | enum { 15 | FBACKUP_DRV_CTL_FLT_START = 0x801, 16 | FBACKUP_DRV_CTL_FLT_STOP, 17 | FBACKUP_DRV_CTL_TEST, 18 | FBACKUP_DRV_CTL_ECHO, 19 | FBACKUP_DRV_CTL_BUGCHECK 20 | }; 21 | 22 | #define IOCTL_FBACKUP_FLT_START CTL_CODE( \ 23 | FILE_DEVICE_UNKNOWN, FBACKUP_DRV_CTL_FLT_START, METHOD_BUFFERED, FILE_ANY_ACCESS) 24 | 25 | #define IOCTL_FBACKUP_FLT_STOP CTL_CODE ( \ 26 | FILE_DEVICE_UNKNOWN, FBACKUP_DRV_CTL_FLT_STOP, METHOD_BUFFERED, FILE_ANY_ACCESS) 27 | 28 | #define IOCTL_FBACKUP_TEST CTL_CODE( \ 29 | FILE_DEVICE_UNKNOWN, FBACKUP_DRV_CTL_TEST, METHOD_BUFFERED, FILE_ANY_ACCESS) 30 | 31 | #define IOCTL_FBACKUP_ECHO CTL_CODE( \ 32 | FILE_DEVICE_UNKNOWN, FBACKUP_DRV_CTL_ECHO, METHOD_BUFFERED, FILE_ANY_ACCESS) 33 | 34 | #define IOCTL_FBACKUP_BUGCHECK CTL_CODE ( \ 35 | FILE_DEVICE_UNKNOWN, FBACKUP_DRV_CTL_BUGCHECK, METHOD_BUFFERED, FILE_ANY_ACCESS) 36 | 37 | #endif -------------------------------------------------------------------------------- /Driver/helpers.c: -------------------------------------------------------------------------------- 1 | #include "inc\helpers.h" 2 | #include "inc\mtags.h" 3 | #include "inc\klog.h" 4 | #include "inc\ntapiex.h" 5 | 6 | NTSTATUS GetObjectName(PVOID Object, PUNICODE_STRING *pObjectName) 7 | { 8 | POBJECT_NAME_INFORMATION ObjectNameInfo; 9 | NTSTATUS Status; 10 | ULONG ReturnLength; 11 | 12 | ObjectNameInfo = NULL; 13 | Status = ObQueryNameString(Object, ObjectNameInfo, 0, &ReturnLength); 14 | if (!NT_SUCCESS(Status) && (Status != STATUS_INFO_LENGTH_MISMATCH)) { 15 | KLErr("ObQueryNameString Object %p Status 0x%x", Object, Status); 16 | return Status; 17 | } 18 | 19 | ObjectNameInfo = NpAlloc(ReturnLength, MTAG_GEN); 20 | if (!ObjectNameInfo) 21 | return STATUS_INSUFFICIENT_RESOURCES; 22 | 23 | Status = ObQueryNameString(Object, ObjectNameInfo, ReturnLength, &ReturnLength); 24 | if (!NT_SUCCESS(Status)) { 25 | KLErr("ObQueryNameString Object %p Status 0x%x", Object, Status); 26 | NpFree(ObjectNameInfo, MTAG_GEN); 27 | return Status; 28 | } 29 | 30 | *pObjectName = &ObjectNameInfo->Name; 31 | return Status; 32 | } 33 | 34 | NTSTATUS GetObjectByName(PUNICODE_STRING ObjName, POBJECT_TYPE ObjectType, PVOID *pObject) 35 | { 36 | PVOID Object; 37 | NTSTATUS Status; 38 | OBJECT_ATTRIBUTES ObjAttrs; 39 | HANDLE ObjectHandle; 40 | 41 | InitializeObjectAttributes(&ObjAttrs, ObjName, OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE, NULL, NULL); 42 | 43 | Status = ObOpenObjectByName(&ObjAttrs, ObjectType, KernelMode, NULL, 0, NULL, &ObjectHandle); 44 | if (!NT_SUCCESS(Status)) { 45 | KLErr("Can't open object by name Status 0x%x", Status); 46 | return Status; 47 | } 48 | 49 | Status = ObReferenceObjectByHandle(ObjectHandle, 0, ObjectType, KernelMode, &Object, NULL); 50 | if (!NT_SUCCESS(Status)) { 51 | KLErr("Can't reference object by handle %p Status 0x%x", ObjectHandle, Status); 52 | ZwClose(ObjectHandle); 53 | return Status; 54 | } 55 | ZwClose(ObjectHandle); 56 | *pObject = Object; 57 | return STATUS_SUCCESS; 58 | } 59 | -------------------------------------------------------------------------------- /Driver/inc/base.h: -------------------------------------------------------------------------------- 1 | #ifndef __FBACKUP_BASE_H__ 2 | #define __FBACKUP_BASE_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /Driver/inc/driver.h: -------------------------------------------------------------------------------- 1 | #ifndef __FBACKUP_DRIVER_H__ 2 | #define __FBACKUP_DRIVER_H__ 3 | 4 | #include "inc\base.h" 5 | #include "inc\unload_protection.h" 6 | #include "inc\worker.h" 7 | #include "inc\socket.h" 8 | 9 | NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath); 10 | 11 | #define FBDEV_EXT_MAGIC 0xCBDECBDE 12 | #define FBDEV_IRP_CONTEXT_MAGIC 0xBCDEBCDE 13 | 14 | enum { 15 | FastIoCheckIfPossibleIndex = 0, 16 | FastIoReadIndex, 17 | FastIoWriteIndex, 18 | FastIoQueryBasicInfoIndex, 19 | FastIoQueryStandardInfoIndex, 20 | FastIoLockIndex, 21 | FastIoUnlockSingleIndex, 22 | FastIoUnlockAllIndex, 23 | FastIoUnlockAllByKeyIndex, 24 | FastIoDeviceControlIndex, 25 | FastIoAcquireFileIndex, 26 | FastIoReleaseFileIndex, 27 | FastIoDetachDeviceIndex, 28 | FastIoQueryNetworkOpenInfoIndex, 29 | FastIoMdlReadIndex, 30 | FastIoMdlReadCompleteIndex, 31 | FastIoPrepareMdlWriteIndex, 32 | FastIoMdlWriteCompleteIndex, 33 | FastIoAcquireForModWriteIndex, 34 | FastIoReleaseForModWriteIndex, 35 | FastIoAcquireForCcFlushIndex, 36 | FastIoReleaseForCcFlushIndex, 37 | FastIoReadCompressedIndex, 38 | FastIoWriteCompressedIndex, 39 | FastIoMdlReadCompleteCompressedIndex, 40 | FastIoMdlWriteCompleteCompressedIndex, 41 | FastIoQueryOpenIndex, 42 | FastIoMaxIndex 43 | }; 44 | 45 | typedef struct _FBDEV_EXT 46 | { 47 | ULONG Magic; 48 | PDEVICE_OBJECT DeviceObject; 49 | UNICODE_STRING SymLinkName; 50 | BOOLEAN SymLinkCreated; 51 | PDEVICE_OBJECT TargetDevice; 52 | PDEVICE_OBJECT AttachedToDevice; 53 | volatile LONG RefCount; 54 | KEVENT ReleasedEvent; 55 | volatile LONG IrpMjCount[IRP_MJ_MAXIMUM_FUNCTION+1]; 56 | volatile LONG IrpCount; 57 | volatile LONG IrpCompletionCount; 58 | volatile LONG FastIoCountByIndex[FastIoMaxIndex]; 59 | volatile LONG FastIoSuccessCountByIndex[FastIoMaxIndex]; 60 | volatile LONG FastIoCount; 61 | volatile LONG FastIoSuccessCount; 62 | } FBDEV_EXT, *PFBDEV_EXT; 63 | 64 | typedef struct _FBDEV_IRP_CONTEXT { 65 | ULONG Magic; 66 | PIRP Irp; 67 | PFBDEV_EXT DevExt; 68 | } FBDEV_IRP_CONTEXT, *PFBDEV_IRP_CONTEXT; 69 | 70 | typedef struct _FBDRIVER { 71 | RTL_OSVERSIONINFOEXW OsVersion; 72 | PDRIVER_OBJECT Driver; 73 | PDEVICE_OBJECT CtlDevice; 74 | PDRIVER_OBJECT NtfsDriver; 75 | UNLOAD_PROTECTION UnloadProtection; 76 | WORKER MainWorker; 77 | SOCKET_FACTORY SocketFactory; 78 | } FBDRIVER, *PFBDRIVER; 79 | 80 | PFBDRIVER GetFbDriver(VOID); 81 | 82 | VOID FbFltDetachDevice(PDEVICE_OBJECT SourceDevice, PDEVICE_OBJECT TargetDevice); 83 | VOID FbDriverDeviceDelete(PDEVICE_OBJECT Device); 84 | 85 | FORCEINLINE PFBDEV_EXT FbDevExtByDevice(PDEVICE_OBJECT DeviceObject) 86 | { 87 | PFBDEV_EXT DevExt = (PFBDEV_EXT)DeviceObject->DeviceExtension; 88 | 89 | if (DevExt->Magic != FBDEV_EXT_MAGIC) { 90 | __debugbreak(); 91 | return NULL; 92 | } 93 | 94 | return DevExt; 95 | } 96 | 97 | FORCEINLINE VOID FbDevExtReference(PFBDEV_EXT DevExt) 98 | { 99 | InterlockedIncrement(&DevExt->RefCount); 100 | } 101 | 102 | FORCEINLINE VOID FbDevExtDereference(PFBDEV_EXT DevExt) 103 | { 104 | if (0 == InterlockedDecrement(&DevExt->RefCount)) { 105 | KeSetEvent(&DevExt->ReleasedEvent, 0, FALSE); 106 | } 107 | } 108 | 109 | FORCEINLINE VOID FbDevExtWaitRelease(PFBDEV_EXT DevExt) 110 | { 111 | KeWaitForSingleObject(&DevExt->ReleasedEvent, Executive, KernelMode, FALSE, NULL); 112 | } 113 | 114 | #endif -------------------------------------------------------------------------------- /Driver/inc/fastio.h: -------------------------------------------------------------------------------- 1 | #ifndef __FBACKUP_FASTIO_H__ 2 | #define __FBACKUP_FASTIO_H__ 3 | 4 | #include "inc\base.h" 5 | 6 | BOOLEAN 7 | FbFastIoCheckIfPossible( 8 | _In_ PFILE_OBJECT FileObject, 9 | _In_ PLARGE_INTEGER FileOffset, 10 | _In_ ULONG Length, 11 | _In_ BOOLEAN Wait, 12 | _In_ ULONG LockKey, 13 | _In_ BOOLEAN CheckForReadOperation, 14 | PIO_STATUS_BLOCK IoStatus, 15 | _In_ PDEVICE_OBJECT DeviceObject 16 | ); 17 | 18 | BOOLEAN 19 | FbFastIoRead( 20 | _In_ PFILE_OBJECT FileObject, 21 | _In_ PLARGE_INTEGER FileOffset, 22 | _In_ ULONG Length, 23 | _In_ BOOLEAN Wait, 24 | _In_ ULONG LockKey, 25 | _Out_ PVOID Buffer, 26 | _Out_ PIO_STATUS_BLOCK IoStatus, 27 | _In_ PDEVICE_OBJECT DeviceObject 28 | ); 29 | 30 | BOOLEAN 31 | FbFastIoWrite( 32 | _In_ PFILE_OBJECT FileObject, 33 | _In_ PLARGE_INTEGER FileOffset, 34 | _In_ ULONG Length, 35 | _In_ BOOLEAN Wait, 36 | _In_ ULONG LockKey, 37 | _In_ PVOID Buffer, 38 | _Out_ PIO_STATUS_BLOCK IoStatus, 39 | _In_ PDEVICE_OBJECT DeviceObject 40 | ); 41 | 42 | BOOLEAN 43 | FbFastIoQueryBasicInfo( 44 | _In_ PFILE_OBJECT FileObject, 45 | _In_ BOOLEAN Wait, 46 | _Out_ PFILE_BASIC_INFORMATION Buffer, 47 | _Out_ PIO_STATUS_BLOCK IoStatus, 48 | _In_ PDEVICE_OBJECT DeviceObject 49 | ); 50 | 51 | BOOLEAN 52 | FbFastIoQueryStandardInfo( 53 | _In_ PFILE_OBJECT FileObject, 54 | _In_ BOOLEAN Wait, 55 | _Out_ PFILE_STANDARD_INFORMATION Buffer, 56 | _Out_ PIO_STATUS_BLOCK IoStatus, 57 | _In_ PDEVICE_OBJECT DeviceObject 58 | ); 59 | 60 | BOOLEAN 61 | FbFastIoLock ( 62 | _In_ PFILE_OBJECT FileObject, 63 | _In_ PLARGE_INTEGER FileOffset, 64 | _In_ PLARGE_INTEGER Length, 65 | _In_ PEPROCESS ProcessId, 66 | _In_ ULONG Key, 67 | _In_ BOOLEAN FailImmediately, 68 | _In_ BOOLEAN ExclusiveLock, 69 | _Out_ PIO_STATUS_BLOCK IoStatus, 70 | _In_ PDEVICE_OBJECT DeviceObject 71 | ); 72 | 73 | BOOLEAN 74 | FbFastIoUnlockSingle ( 75 | _In_ PFILE_OBJECT FileObject, 76 | _In_ PLARGE_INTEGER FileOffset, 77 | _In_ PLARGE_INTEGER Length, 78 | _In_ PEPROCESS ProcessId, 79 | _In_ ULONG Key, 80 | _Out_ PIO_STATUS_BLOCK IoStatus, 81 | _In_ PDEVICE_OBJECT DeviceObject 82 | ); 83 | 84 | BOOLEAN 85 | FbFastIoUnlockAll( 86 | _In_ PFILE_OBJECT FileObject, 87 | _In_ PEPROCESS ProcessId, 88 | _Out_ PIO_STATUS_BLOCK IoStatus, 89 | _In_ PDEVICE_OBJECT DeviceObject 90 | ); 91 | 92 | 93 | BOOLEAN 94 | FbFastIoUnlockAllByKey( 95 | _In_ PFILE_OBJECT FileObject, 96 | _In_ PVOID ProcessId, 97 | _In_ ULONG Key, 98 | _Out_ PIO_STATUS_BLOCK IoStatus, 99 | _In_ PDEVICE_OBJECT DeviceObject 100 | ); 101 | 102 | 103 | BOOLEAN 104 | FbFastIoDeviceControl( 105 | _In_ PFILE_OBJECT FileObject, 106 | _In_ BOOLEAN Wait, 107 | _In_opt_ PVOID InputBuffer, 108 | _In_ ULONG InputBufferLength, 109 | _Out_opt_ PVOID OutputBuffer, 110 | _In_ ULONG OutputBufferLength, 111 | _In_ ULONG IoControlCode, 112 | _Out_ PIO_STATUS_BLOCK IoStatus, 113 | _In_ PDEVICE_OBJECT DeviceObject 114 | ); 115 | 116 | VOID 117 | FbFastIoDetachDevice( 118 | _In_ PDEVICE_OBJECT SourceDevice, 119 | _In_ PDEVICE_OBJECT TargetDevice 120 | ); 121 | 122 | BOOLEAN 123 | FbFastIoQueryNetworkOpenInfo( 124 | _In_ PFILE_OBJECT FileObject, 125 | _In_ BOOLEAN Wait, 126 | _Out_ PFILE_NETWORK_OPEN_INFORMATION Buffer, 127 | _Out_ PIO_STATUS_BLOCK IoStatus, 128 | _In_ PDEVICE_OBJECT DeviceObject 129 | ); 130 | 131 | BOOLEAN 132 | FbFastIoQueryOpen( 133 | _Inout_ PIRP Irp, 134 | _Out_ PFILE_NETWORK_OPEN_INFORMATION NetworkInformation, 135 | _In_ PDEVICE_OBJECT DeviceObject 136 | ); 137 | 138 | BOOLEAN 139 | FbFastIoMdlRead( 140 | _In_ PFILE_OBJECT FileObject, 141 | _In_ PLARGE_INTEGER FileOffset, 142 | _In_ ULONG Length, 143 | _In_ ULONG LockKey, 144 | _Out_ PMDL *MdlChain, 145 | _Out_ PIO_STATUS_BLOCK IoStatus, 146 | _In_ PDEVICE_OBJECT DeviceObject 147 | ); 148 | 149 | BOOLEAN 150 | FbFastIoMdlReadComplete( 151 | _In_ PFILE_OBJECT FileObject, 152 | _In_ PMDL MdlChain, 153 | _In_ PDEVICE_OBJECT DeviceObject 154 | ); 155 | 156 | 157 | BOOLEAN 158 | FbFastIoPrepareMdlWrite( 159 | _In_ PFILE_OBJECT FileObject, 160 | _In_ PLARGE_INTEGER FileOffset, 161 | _In_ ULONG Length, 162 | _In_ ULONG LockKey, 163 | _Out_ PMDL *MdlChain, 164 | _Out_ PIO_STATUS_BLOCK IoStatus, 165 | _In_ PDEVICE_OBJECT DeviceObject 166 | ); 167 | 168 | BOOLEAN 169 | FbFastIoMdlWriteComplete( 170 | _In_ PFILE_OBJECT FileObject, 171 | _In_ PLARGE_INTEGER FileOffset, 172 | _In_ PMDL MdlChain, 173 | _In_ PDEVICE_OBJECT DeviceObject 174 | ); 175 | 176 | BOOLEAN 177 | FbFastIoReadCompressed( 178 | _In_ PFILE_OBJECT FileObject, 179 | _In_ PLARGE_INTEGER FileOffset, 180 | _In_ ULONG Length, 181 | _In_ ULONG LockKey, 182 | _Out_ PVOID Buffer, 183 | _Out_ PMDL *MdlChain, 184 | _Out_ PIO_STATUS_BLOCK IoStatus, 185 | _Out_ PCOMPRESSED_DATA_INFO CompressedDataInfo, 186 | _In_ ULONG CompressedDataInfoLength, 187 | _In_ PDEVICE_OBJECT DeviceObject 188 | ); 189 | 190 | BOOLEAN 191 | FbFastIoWriteCompressed( 192 | _In_ PFILE_OBJECT FileObject, 193 | _In_ PLARGE_INTEGER FileOffset, 194 | _In_ ULONG Length, 195 | _In_ ULONG LockKey, 196 | _In_ PVOID Buffer, 197 | _Out_ PMDL *MdlChain, 198 | _Out_ PIO_STATUS_BLOCK IoStatus, 199 | _In_ PCOMPRESSED_DATA_INFO CompressedDataInfo, 200 | _In_ ULONG CompressedDataInfoLength, 201 | _In_ PDEVICE_OBJECT DeviceObject 202 | ); 203 | 204 | BOOLEAN 205 | FbFastIoMdlReadCompleteCompressed( 206 | _In_ PFILE_OBJECT FileObject, 207 | _In_ PMDL MdlChain, 208 | _In_ PDEVICE_OBJECT DeviceObject 209 | ); 210 | 211 | BOOLEAN 212 | FbFastIoMdlWriteCompleteCompressed( 213 | _In_ PFILE_OBJECT FileObject, 214 | _In_ PLARGE_INTEGER FileOffset, 215 | _In_ PMDL MdlChain, 216 | _In_ PDEVICE_OBJECT DeviceObject 217 | ); 218 | 219 | VOID 220 | FbFastIoAcquireFileForNtCreateSection( 221 | _In_ PFILE_OBJECT FileObject 222 | ); 223 | 224 | NTSTATUS 225 | FbFastIoReleaseForCcFlush( 226 | _In_ PFILE_OBJECT FileObject, 227 | _In_ PDEVICE_OBJECT DeviceObject 228 | ); 229 | 230 | NTSTATUS 231 | FbFastIoReleaseForModWrite( 232 | _In_ PFILE_OBJECT FileObject, 233 | _In_ PERESOURCE ResourceToRelease, 234 | _In_ PDEVICE_OBJECT DeviceObject 235 | ); 236 | 237 | VOID 238 | FbFastIoReleaseFileForNtCreateSection( 239 | _In_ PFILE_OBJECT FileObject 240 | ); 241 | 242 | #endif 243 | -------------------------------------------------------------------------------- /Driver/inc/hallocator.h: -------------------------------------------------------------------------------- 1 | #ifndef __FBACKUP_HALLOCATOR_H__ 2 | #define __FBACKUP_HALLOCATOR_H__ 3 | 4 | #include "inc/base.h" 5 | #include "inc/helpers.h" 6 | 7 | typedef struct _HALLOCATOR { 8 | ULONG ChunkSize; 9 | ULONG SegmentSize; 10 | ULONG Tag; 11 | LONG PreAllocChunksCount; 12 | SLIST_HEADER SegmentList; 13 | SLIST_HEADER FreeList; 14 | volatile LONG SegmentListDepth; 15 | volatile LONG FreeListDepth; 16 | KDPC GrowDpc; 17 | volatile LONG Releasing; 18 | } HALLOCATOR, *PHALLOCATOR; 19 | 20 | #define HALLOCATOR_DBG 0 21 | 22 | #define HALLOCATOR_CHUNK_SIGNATURE 0xBEDABEDA 23 | 24 | typedef struct _HALLOCATOR_CHUNK { 25 | SLIST_ENTRY ListEntry; 26 | #if HALLOCATOR_DBG 27 | LONG Signature; 28 | #endif 29 | } HALLOCATOR_CHUNK, *PHALLOCATOR_CHUNK; 30 | 31 | typedef struct _HALLOCATOR_SEGMENT{ 32 | SLIST_ENTRY ListEntry; 33 | HALLOCATOR_CHUNK Chunks[1]; 34 | } HALLOCATOR_SEGMENT, *PHALLOCATOR_SEGMENT; 35 | 36 | #define HALLOCATOR_CHUNK_ALIGNMENT MEMORY_ALLOCATION_ALIGNMENT 37 | #define HALLOCATOR_CHUNK_ALIGN(sz) ((sz+HALLOCATOR_CHUNK_ALIGNMENT-1)&(~(HALLOCATOR_CHUNK_ALIGNMENT-1))) 38 | 39 | FORCEINLINE 40 | VOID 41 | HAllocatorGrow( 42 | PHALLOCATOR Allocator 43 | ) 44 | { 45 | PHALLOCATOR_SEGMENT Segment = NULL; 46 | PHALLOCATOR_CHUNK Chunk = NULL; 47 | 48 | Segment = (PHALLOCATOR_SEGMENT)NpAlloc(Allocator->SegmentSize, Allocator->Tag); 49 | if (Segment == NULL) { 50 | __debugbreak(); 51 | return; 52 | } 53 | #if HALLOCATOR_DBG 54 | DbgPrint("HALLOC: alloc segment=%p size= %x\n", Segment, Allocator->SegmentSize); 55 | #endif 56 | 57 | InterlockedPushEntrySList(&Allocator->SegmentList, &Segment->ListEntry); 58 | InterlockedIncrement(&Allocator->SegmentListDepth); 59 | 60 | Chunk = &Segment->Chunks[0]; 61 | 62 | while (((ULONG_PTR)Chunk + Allocator->ChunkSize) <= ((ULONG_PTR)Segment + Allocator->SegmentSize)) { 63 | #if HALLOCATOR_DBG 64 | DbgPrint("HALLOC: grow alloc chunk=%p, size= %x\n", Chunk, Allocator->ChunkSize); 65 | Chunk->Signature = HALLOCATOR_CHUNK_SIGNATURE; 66 | #endif 67 | InterlockedPushEntrySList(&Allocator->FreeList, &Chunk->ListEntry); 68 | InterlockedIncrement(&Allocator->FreeListDepth); 69 | Chunk = (PHALLOCATOR_CHUNK)((ULONG_PTR)Chunk + Allocator->ChunkSize); 70 | } 71 | } 72 | 73 | FORCEINLINE 74 | VOID 75 | HAllocatorFree( 76 | IN PHALLOCATOR Allocator, 77 | IN PVOID Ptr 78 | ) 79 | { 80 | PHALLOCATOR_CHUNK Chunk = (PHALLOCATOR_CHUNK)Ptr; 81 | if (Allocator->Releasing) 82 | return; 83 | 84 | #if HALLOCATOR_DBG 85 | DbgPrint("HALLOC: free push chunk=%p, size= %x\n", Chunk, Allocator->ChunkSize); 86 | Chunk->Signature = HALLOCATOR_CHUNK_SIGNATURE; 87 | #endif 88 | InterlockedPushEntrySList(&Allocator->FreeList, &Chunk->ListEntry); 89 | InterlockedIncrement(&Allocator->FreeListDepth); 90 | } 91 | 92 | FORCEINLINE 93 | PVOID 94 | HAllocatorAlloc( 95 | IN PHALLOCATOR Allocator 96 | ) 97 | { 98 | PHALLOCATOR_CHUNK Chunk = NULL; 99 | if (Allocator->Releasing) 100 | return NULL; 101 | 102 | Chunk = (PHALLOCATOR_CHUNK)InterlockedPopEntrySList(&Allocator->FreeList); 103 | #if HALLOCATOR_DBG 104 | DbgPrint("HALLOC: alloc pop chunk=%p, size= %x\n", Chunk, Allocator->ChunkSize); 105 | #endif 106 | 107 | if (Chunk == NULL) { 108 | #if HALLOCATOR_DBG 109 | DbgPrint("HALLOC: alloc failure\n"); 110 | #endif 111 | __debugbreak(); 112 | return NULL; 113 | } 114 | 115 | #if HALLOCATOR_DBG 116 | if (Chunk->Signature != HALLOCATOR_CHUNK_SIGNATURE) { 117 | DbgPrint("HALLOC: alloc pop chunk=%p, size= %x signature incorrect\n", Chunk, Allocator->ChunkSize); 118 | __debugbreak(); 119 | } 120 | #endif 121 | 122 | if ((InterlockedDecrement(&Allocator->FreeListDepth) < Allocator->PreAllocChunksCount) && (!Allocator->Releasing)) 123 | KeInsertQueueDpc(&Allocator->GrowDpc, NULL, NULL); 124 | 125 | return Chunk; 126 | } 127 | 128 | FORCEINLINE 129 | VOID 130 | HAllocatorGrowDpc( 131 | PKDPC Dpc, 132 | PVOID DeferredContext, 133 | PVOID SystemArgument1, 134 | PVOID SystemArgument2 135 | ) 136 | { 137 | UNREFERENCED_PARAMETER(Dpc); 138 | UNREFERENCED_PARAMETER(SystemArgument1); 139 | UNREFERENCED_PARAMETER(SystemArgument2); 140 | PHALLOCATOR Allocator = (PHALLOCATOR)DeferredContext; 141 | if (!Allocator->Releasing) 142 | HAllocatorGrow(Allocator); 143 | } 144 | 145 | FORCEINLINE 146 | VOID 147 | HAllocatorInit( 148 | PHALLOCATOR Allocator, 149 | ULONG ChunkSize, 150 | LONG PreAllocChunksCount, 151 | ULONG SegmentSize, 152 | ULONG Tag) 153 | { 154 | RtlZeroMemory(Allocator, sizeof(HALLOCATOR)); 155 | 156 | Allocator->SegmentSize = SegmentSize; 157 | Allocator->Tag = Tag; 158 | Allocator->FreeListDepth = 0; 159 | Allocator->PreAllocChunksCount = PreAllocChunksCount; 160 | Allocator->ChunkSize = HALLOCATOR_CHUNK_ALIGN(ChunkSize + sizeof(HALLOCATOR_CHUNK)); 161 | 162 | InitializeSListHead(&Allocator->SegmentList); 163 | InitializeSListHead(&Allocator->FreeList); 164 | KeInitializeDpc(&Allocator->GrowDpc, HAllocatorGrowDpc, Allocator); 165 | 166 | #if HALLOCATOR_DBG 167 | DbgPrint("HALLOC: allocator=%p, FreeListDepth=%x, PreAllocChunksCount=%x chunksize=%x segmentsize=%x\n", Allocator, 168 | Allocator->FreeListDepth, Allocator->PreAllocChunksCount, Allocator->ChunkSize, Allocator->SegmentSize); 169 | #endif 170 | 171 | while (Allocator->FreeListDepth < Allocator->PreAllocChunksCount) { 172 | #if HALLOCATOR_DBG 173 | DbgPrint("HALLOC: allocator=%p, FreeListDepth=%x, PreAllocChunksCount=%x\n", Allocator, 174 | Allocator->FreeListDepth, Allocator->PreAllocChunksCount); 175 | #endif 176 | HAllocatorGrow(Allocator); 177 | } 178 | } 179 | 180 | FORCEINLINE 181 | VOID 182 | HAllocatorRelease( 183 | PHALLOCATOR Allocator 184 | ) 185 | { 186 | PHALLOCATOR_SEGMENT Segment = NULL; 187 | 188 | Allocator->Releasing = 1; 189 | KeFlushQueuedDpcs(); 190 | 191 | while ((Segment = (PHALLOCATOR_SEGMENT)InterlockedPopEntrySList(&Allocator->SegmentList)) != NULL) { 192 | NpFree(Segment, Allocator->Tag); 193 | } 194 | } 195 | #endif -------------------------------------------------------------------------------- /Driver/inc/helpers.h: -------------------------------------------------------------------------------- 1 | #ifndef __FBACKUP_HELPERS_H__ 2 | #define __FBACKUP_HELPERS_H__ 3 | 4 | #include "inc\base.h" 5 | 6 | #ifdef DBG 7 | #define DPRINT DbgPrint 8 | #define DEBUG_BREAK() __debugbreak() 9 | #define DEBUG_BREAK_ON(cond) \ 10 | { \ 11 | if (cond) { \ 12 | DEBUG_BREAK(); \ 13 | } \ 14 | } 15 | #else 16 | #define DPRINT 17 | #define DEBUG_BREAK() 18 | #define DEBUG_BREAK_ON(cond) 19 | #endif 20 | 21 | #define ntohs(x) RtlUshortByteSwap(x) 22 | #define htons(x) RtlUshortByteSwap(x) 23 | 24 | #define ntohl(x) RtlUlongByteSwap(x) 25 | #define htonl(x) RtlUlongByteSwap(x) 26 | 27 | #define ntohll(x) RtlUlonglongByteSwap(x) 28 | #define htonll(x) RtlUlonglongByteSwap(x) 29 | 30 | #define PTR_BY_RVA(Base, Rva) ((PVOID)((ULONG_PTR)(Base) + (ULONG_PTR)(Rva))) 31 | 32 | #define ARRAY_SIZE(arr) (sizeof(arr)/sizeof((arr)[0])) 33 | 34 | FORCEINLINE PVOID NpAlloc(SIZE_T Size, ULONG Tag) 35 | { 36 | return ExAllocatePoolWithTag(NonPagedPool, Size, Tag); 37 | } 38 | 39 | FORCEINLINE VOID NpFree(PVOID Addr, ULONG Tag) 40 | { 41 | ExFreePoolWithTag(Addr, Tag); 42 | } 43 | 44 | FORCEINLINE PVOID PpAlloc(SIZE_T Size, ULONG Tag) 45 | { 46 | return ExAllocatePoolWithTag(PagedPool, Size, Tag); 47 | } 48 | 49 | FORCEINLINE VOID PpFree(PVOID Addr, ULONG Tag) 50 | { 51 | ExFreePoolWithTag(Addr, Tag); 52 | } 53 | 54 | FORCEINLINE LONG64 MillisTo100Ns(ULONG Millis) 55 | { 56 | return 10*1000*((LONG64)Millis); 57 | } 58 | 59 | FORCEINLINE VOID ThreadSleepMs(ULONG Millis) 60 | { 61 | LARGE_INTEGER Interval; 62 | 63 | Interval.QuadPart = -MillisTo100Ns(Millis); 64 | KeDelayExecutionThread(KernelMode, FALSE, &Interval); 65 | } 66 | 67 | NTSTATUS GetObjectName(PVOID Object, PUNICODE_STRING *pObjectName); 68 | NTSTATUS GetObjectByName(PUNICODE_STRING ObjName, POBJECT_TYPE ObjectType, PVOID *pObject); 69 | 70 | #endif -------------------------------------------------------------------------------- /Driver/inc/klog.h: -------------------------------------------------------------------------------- 1 | #ifndef __FBACKUP_KLOG_H__ 2 | #define __FBACKUP_KLOG_H__ 3 | 4 | #include "inc/base.h" 5 | #include "inc/hallocator.h" 6 | 7 | #define KLOG_PATH L"\\??\\C:\\Windows\\System32\\fbackup.log" 8 | #define KLOG_MSG_SZ 488 9 | 10 | typedef struct _KLOG_BUFFER { 11 | LIST_ENTRY ListEntry; 12 | CHAR Msg[KLOG_MSG_SZ]; 13 | ULONG Length; 14 | } KLOG_BUFFER, *PKLOG_BUFFER; 15 | 16 | C_ASSERT(sizeof(KLOG_BUFFER) == 512); 17 | 18 | typedef struct _KLOG_CONTEXT { 19 | volatile BOOLEAN Stopping; 20 | HANDLE ThreadHandle; 21 | PVOID Thread; 22 | HANDLE FileHandle; 23 | LIST_ENTRY FlushQueue; 24 | LIST_ENTRY FreeList; 25 | KSPIN_LOCK Lock; 26 | KEVENT FlushEvent; 27 | KDPC Dpc; 28 | HALLOCATOR LogBufAllocator; 29 | } KLOG_CONTEXT, *PKLOG_CONTEXT; 30 | 31 | PKLOG_CONTEXT KLogCreate(PUNICODE_STRING FileName); 32 | VOID KLogRelease(PKLOG_CONTEXT Log); 33 | 34 | enum { 35 | KL_DBG, 36 | KL_INF, 37 | KL_WRN, 38 | KL_ERR 39 | }; 40 | 41 | VOID KLogInternal(int level, PCHAR file, ULONG line, PCHAR func, const char *fmt, ...); 42 | 43 | #define KLOG_ENABLED 1 44 | #define KLOG_LEVEL KL_INF 45 | 46 | #if (KLOG_ENABLED) 47 | #define KLog(level, fmt, ...) do { \ 48 | if ((level) >= KLOG_LEVEL) { \ 49 | KLogInternal((level), __FILE__, __LINE__, __FUNCTION__, (fmt), ##__VA_ARGS__); \ 50 | } \ 51 | } while (0); 52 | #else 53 | #define KLog(level, fmt, ...) 54 | #endif 55 | 56 | #define KLErr(fmt, ...) \ 57 | KLog(KL_ERR, fmt, ##__VA_ARGS__) 58 | 59 | #define KLDbg(fmt, ...) \ 60 | KLog(KL_DBG, fmt, ##__VA_ARGS__) 61 | 62 | #define KLInf(fmt, ...) \ 63 | KLog(KL_INF, fmt, ##__VA_ARGS__) 64 | 65 | #define KLWrn(fmt, ...) \ 66 | KLog(KL_WRN, fmt, ##__VA_ARGS__) 67 | 68 | extern PKLOG_CONTEXT g_Log; 69 | 70 | NTSTATUS KLogInit(); 71 | VOID KLogDeinit(); 72 | 73 | void GetLocalTimeFields(PTIME_FIELDS pTimeFields); 74 | 75 | #define KLOG_DBG_PRINT 76 | #endif -------------------------------------------------------------------------------- /Driver/inc/map.h: -------------------------------------------------------------------------------- 1 | #ifndef __FBACKUP_MAP_H__ 2 | #define __FBACKUP_MAP_H__ 3 | 4 | #include "inc\base.h" 5 | 6 | #define MAP_TAG '0paM' 7 | 8 | typedef struct _MAP_ENTRY { 9 | ULONG KeySize; 10 | ULONG ValueSize; 11 | PVOID Key; 12 | PVOID Value; 13 | } MAP_ENTRY, *PMAP_ENTRY; 14 | 15 | typedef struct _MAP { 16 | RTL_AVL_TABLE Avl; 17 | ERESOURCE Lock; 18 | } MAP, *PMAP; 19 | 20 | PMAP MapCreate(VOID); 21 | VOID MapDelete(PMAP Map); 22 | 23 | NTSTATUS MapInsertKey(PMAP Map, PVOID Key, ULONG KeySize, PVOID Value, ULONG ValueSize); 24 | NTSTATUS MapLookupKey(PMAP Map, PVOID Key, ULONG KeySize, PVOID *pValue, ULONG *pValueSize); 25 | NTSTATUS MapDeleteKey(PMAP Map, PVOID Key, ULONG KeySize); 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /Driver/inc/mtags.h: -------------------------------------------------------------------------------- 1 | #ifndef __FBACKUP_MTAGS_H__ 2 | #define __FBACKUP_MTAGS_H__ 3 | 4 | #include "inc/base.h" 5 | 6 | #define MTAG_KLOG '10BF' 7 | #define MTAG_DRV '20BF' 8 | #define MTAG_GEN '30BF' 9 | #define MTAG_WRK '40BF' 10 | #define MTAG_SOCKET '50BF' 11 | 12 | #endif -------------------------------------------------------------------------------- /Driver/inc/ntapiex.h: -------------------------------------------------------------------------------- 1 | #ifndef __FBACKUP_NTAPIEX_H__ 2 | #define __FBACKUP_NTAPIEX_H__ 3 | 4 | #include "inc/base.h" 5 | 6 | NTSYSAPI 7 | PEPROCESS PsGetNextProcess(PEPROCESS Process); 8 | 9 | NTSYSAPI 10 | NTSTATUS 11 | PsAcquireProcessExitSynchronization(PEPROCESS Process); 12 | 13 | NTSYSAPI 14 | VOID 15 | PsReleaseProcessExitSynchronization(PEPROCESS Process); 16 | 17 | NTSYSAPI 18 | NTSTATUS 19 | ZwQuerySystemInformation(ULONG InfoClass, PVOID pInfo, ULONG InfoSize, PULONG pReqSize); 20 | 21 | typedef struct _SYSTEM_PROCESS_INFORMATION { 22 | ULONG NextEntryOffset; 23 | ULONG NumberOfThreads; 24 | LARGE_INTEGER SpareLi1; 25 | LARGE_INTEGER SpareLi2; 26 | LARGE_INTEGER SpareLi3; 27 | LARGE_INTEGER CreateTime; 28 | LARGE_INTEGER UserTime; 29 | LARGE_INTEGER KernelTime; 30 | UNICODE_STRING ImageName; 31 | KPRIORITY BasePriority; 32 | HANDLE UniqueProcessId; 33 | HANDLE InheritedFromUniqueProcessId; 34 | ULONG HandleCount; 35 | ULONG SessionId; 36 | ULONG_PTR PageDirectoryBase; 37 | SIZE_T PeakVirtualSize; 38 | SIZE_T VirtualSize; 39 | ULONG PageFaultCount; 40 | SIZE_T PeakWorkingSetSize; 41 | SIZE_T WorkingSetSize; 42 | SIZE_T QuotaPeakPagedPoolUsage; 43 | SIZE_T QuotaPagedPoolUsage; 44 | SIZE_T QuotaPeakNonPagedPoolUsage; 45 | SIZE_T QuotaNonPagedPoolUsage; 46 | SIZE_T PagefileUsage; 47 | SIZE_T PeakPagefileUsage; 48 | SIZE_T PrivatePageCount; 49 | LARGE_INTEGER ReadOperationCount; 50 | LARGE_INTEGER WriteOperationCount; 51 | LARGE_INTEGER OtherOperationCount; 52 | LARGE_INTEGER ReadTransferCount; 53 | LARGE_INTEGER WriteTransferCount; 54 | LARGE_INTEGER OtherTransferCount; 55 | } SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION; 56 | 57 | 58 | typedef struct _SYSTEM_THREAD_INFORMATION { 59 | LARGE_INTEGER KernelTime; 60 | LARGE_INTEGER UserTime; 61 | LARGE_INTEGER CreateTime; 62 | ULONG WaitTime; 63 | PVOID StartAddress; 64 | CLIENT_ID ClientId; 65 | KPRIORITY Priority; 66 | LONG BasePriority; 67 | ULONG ContextSwitches; 68 | ULONG ThreadState; 69 | ULONG WaitReason; 70 | } SYSTEM_THREAD_INFORMATION, *PSYSTEM_THREAD_INFORMATION; 71 | 72 | typedef enum _SYSTEM_INFORMATION_CLASS { 73 | SystemBasicInformation = 0, 74 | SystemPerformanceInformation = 2, 75 | SystemTimeOfDayInformation = 3, 76 | SystemProcessInformation = 5, 77 | SystemProcessorPerformanceInformation = 8, 78 | SystemModuleInformation = 11, 79 | SystemInterruptInformation = 23, 80 | SystemExceptionInformation = 33, 81 | SystemRegistryQuotaInformation = 37, 82 | SystemLookasideInformation = 45, 83 | SystemPolicyInformation = 134, 84 | } SYSTEM_INFORMATION_CLASS; 85 | 86 | typedef enum _KAPC_ENVIRONMENT { 87 | OriginalApcEnvironment, 88 | AttachedApcEnvironment, 89 | CurrentApcEnvironment, 90 | InsertApcEnvironment 91 | } KAPC_ENVIRONMENT; 92 | 93 | 94 | typedef 95 | VOID 96 | (*PKNORMAL_ROUTINE) ( 97 | IN PVOID NormalContext, 98 | IN PVOID SystemArgument1, 99 | IN PVOID SystemArgument2 100 | ); 101 | 102 | 103 | typedef 104 | VOID 105 | (*PKNORMAL_ROUTINE) ( 106 | IN PVOID NormalContext, 107 | IN PVOID SystemArgument1, 108 | IN PVOID SystemArgument2 109 | ); 110 | 111 | typedef 112 | VOID 113 | (*PKKERNEL_ROUTINE) ( 114 | IN struct _KAPC *Apc, 115 | IN OUT PKNORMAL_ROUTINE *NormalRoutine, 116 | IN OUT PVOID *NormalContext, 117 | IN OUT PVOID *SystemArgument1, 118 | IN OUT PVOID *SystemArgument2 119 | ); 120 | 121 | typedef 122 | VOID 123 | (*PKRUNDOWN_ROUTINE) ( 124 | IN struct _KAPC *Apc 125 | ); 126 | 127 | NTSYSAPI 128 | VOID 129 | KeInitializeApc( 130 | __out PRKAPC Apc, 131 | __in PRKTHREAD Thread, 132 | __in KAPC_ENVIRONMENT Environment, 133 | __in PKKERNEL_ROUTINE KernelRoutine, 134 | __in_opt PKRUNDOWN_ROUTINE RundownRoutine, 135 | __in_opt PKNORMAL_ROUTINE NormalRoutine, 136 | __in_opt KPROCESSOR_MODE ProcessorMode, 137 | __in_opt PVOID NormalContext 138 | ); 139 | 140 | 141 | NTSYSAPI 142 | BOOLEAN 143 | KeInsertQueueApc( 144 | __inout PRKAPC Apc, 145 | __in_opt PVOID SystemArgument1, 146 | __in_opt PVOID SystemArgument2, 147 | __in KPRIORITY Increment 148 | ); 149 | 150 | NTSYSAPI 151 | PVOID 152 | PsGetThreadWin32Thread(PETHREAD Thread); 153 | 154 | NTSYSAPI 155 | PVOID 156 | PsGetProcessSectionBaseAddress(PEPROCESS Process); 157 | 158 | NTSYSAPI 159 | PCHAR 160 | PsGetProcessImageFileName(PEPROCESS Process); 161 | 162 | NTSYSAPI 163 | PIMAGE_NT_HEADERS 164 | RtlImageNtHeader(PVOID ImageBase); 165 | 166 | 167 | NTSYSAPI 168 | POBJECT_TYPE ObGetObjectType(PVOID Object); 169 | 170 | NTSYSAPI 171 | NTSTATUS 172 | ObOpenObjectByName( 173 | __in POBJECT_ATTRIBUTES ObjectAttributes, 174 | __in_opt POBJECT_TYPE ObjectType, 175 | __in KPROCESSOR_MODE AccessMode, 176 | __inout_opt PACCESS_STATE AccessState, 177 | __in_opt ACCESS_MASK DesiredAccess, 178 | __inout_opt PVOID ParseContext, 179 | __out PHANDLE Handle 180 | ); 181 | 182 | NTSYSAPI 183 | ULONG 184 | PsGetProcessSessionId( 185 | __in PEPROCESS Process 186 | ); 187 | 188 | 189 | typedef struct _SYSTEM_MODULE_INFORMATION { 190 | PVOID Reserved[2]; 191 | PVOID Base; 192 | ULONG Size; 193 | ULONG Flags; 194 | USHORT Index; 195 | USHORT Unknown; 196 | USHORT LoadCount; 197 | USHORT ModuleNameOffset; 198 | CHAR ImageName[256]; 199 | } SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION; 200 | 201 | NTSYSAPI 202 | PIMAGE_NT_HEADERS 203 | RtlImageNtHeader(IN PVOID ModuleAddress); 204 | 205 | 206 | NTSYSAPI 207 | NTSTATUS 208 | RtlIntegerToChar(ULONG Value, ULONG Base, ULONG Length, PCHAR Str); 209 | 210 | FORCEINLINE BOOLEAN MmIsSessionAddress(PVOID Addr) { 211 | ULONG_PTR uAddr = (ULONG_PTR)Addr; 212 | #if defined(_AMD64_) 213 | return (uAddr >= 0xFFFFF90000000000ULL) ? TRUE : FALSE; 214 | #else 215 | #error "unsupported platform"; 216 | return FALSE; 217 | #endif 218 | } 219 | 220 | #endif 221 | -------------------------------------------------------------------------------- /Driver/inc/socket.h: -------------------------------------------------------------------------------- 1 | #ifndef __FBACKUP_SOCKET_H__ 2 | #define __FBACKUP_SOCKET_H__ 3 | 4 | #include "inc\base.h" 5 | 6 | typedef struct _SOCKET_FACTORY { 7 | WSK_CLIENT_DISPATCH ClientDispatch; 8 | WSK_CLIENT_NPI ClientNpi; 9 | WSK_REGISTRATION Registration; 10 | WSK_PROVIDER_NPI ProviderNpi; 11 | LIST_ENTRY SocketListHead; 12 | KSPIN_LOCK Lock; 13 | volatile LONG Releasing; 14 | } SOCKET_FACTORY, *PSOCKET_FACTORY; 15 | 16 | typedef struct _SOCKET { 17 | LIST_ENTRY ListEntry; 18 | PWSK_SOCKET WskSocket; 19 | PSOCKET_FACTORY SocketFactory; 20 | KSPIN_LOCK Lock; 21 | volatile LONG RefCount; 22 | } SOCKET, *PSOCKET; 23 | 24 | NTSTATUS SocketFactoryInit(PSOCKET_FACTORY SocketFactory); 25 | 26 | VOID SocketFactoryRelease(PSOCKET_FACTORY SocketFactory); 27 | 28 | FORCEINLINE VOID SocketReference(PSOCKET Socket) 29 | { 30 | if (Socket->RefCount <= 0) 31 | __debugbreak(); 32 | InterlockedIncrement(&Socket->RefCount); 33 | } 34 | 35 | VOID SocketDereference(PSOCKET Socket); 36 | 37 | NTSTATUS SocketConnect(PSOCKET_FACTORY SocketFactory, PWCHAR HostName, PWCHAR Port, PSOCKET *pSocket); 38 | 39 | NTSTATUS SocketSend(PSOCKET Socket, PVOID Buf, ULONG Size, PULONG pSent); 40 | 41 | NTSTATUS SocketReceive(PSOCKET Socket, PVOID Buf, ULONG Size, PULONG pReceived, PBOOLEAN pbDisconnected); 42 | 43 | VOID SocketClose(PSOCKET Socket); 44 | 45 | #endif -------------------------------------------------------------------------------- /Driver/inc/tests.h: -------------------------------------------------------------------------------- 1 | #ifndef __FBACKUP_TESTS_H__ 2 | #define __FBACKUP_TESTS_H__ 3 | 4 | #include "inc\base.h" 5 | NTSTATUS RunTests(VOID); 6 | 7 | #endif -------------------------------------------------------------------------------- /Driver/inc/unload_protection.h: -------------------------------------------------------------------------------- 1 | #ifndef __FBACKUP_UNLOAD_PROTECTION_H__ 2 | #define __FBACKUP_UNLOAD_PROTECTION_H__ 3 | 4 | #include "inc\base.h" 5 | #include "inc\helpers.h" 6 | 7 | typedef struct _UNLOAD_PROTECTION { 8 | volatile LONG RefCount; 9 | } UNLOAD_PROTECTION, *PUNLOAD_PROTECTION; 10 | 11 | FORCEINLINE VOID UnloadProtectionCheck(PUNLOAD_PROTECTION Protection) 12 | { 13 | if (Protection->RefCount < 0) 14 | __debugbreak(); 15 | } 16 | 17 | FORCEINLINE VOID UnloadProtectionInit(PUNLOAD_PROTECTION Protection) 18 | { 19 | Protection->RefCount = 1; 20 | } 21 | 22 | FORCEINLINE VOID UnloadProtectionAcquire(PUNLOAD_PROTECTION Protection) 23 | { 24 | UnloadProtectionCheck(Protection); 25 | InterlockedIncrement(&Protection->RefCount); 26 | } 27 | 28 | FORCEINLINE VOID UnloadProtectionRelease(PUNLOAD_PROTECTION Protection) 29 | { 30 | UnloadProtectionCheck(Protection); 31 | InterlockedDecrement(&Protection->RefCount); 32 | UnloadProtectionCheck(Protection); 33 | } 34 | 35 | FORCEINLINE VOID UnloadProtectionWait(PUNLOAD_PROTECTION Protection) 36 | { 37 | UnloadProtectionCheck(Protection); 38 | while (Protection->RefCount != 1) { 39 | ThreadSleepMs(1000); 40 | } 41 | 42 | InterlockedDecrement(&Protection->RefCount); 43 | ThreadSleepMs(1000); 44 | if (Protection->RefCount != 0) 45 | __debugbreak(); 46 | } 47 | 48 | #endif -------------------------------------------------------------------------------- /Driver/inc/worker.h: -------------------------------------------------------------------------------- 1 | #ifndef __FBACKUP_WORKER_H__ 2 | #define __FBACKUP_WORKER_H__ 3 | 4 | #include "inc\base.h" 5 | 6 | typedef NTSTATUS (*PWORKER_CLB)(PVOID Context); 7 | 8 | typedef struct _WORKER_TASK { 9 | LIST_ENTRY ListEntry; 10 | NTSTATUS Status; 11 | KEVENT CompleteEvent; 12 | PWORKER_CLB Clb; 13 | PVOID Context; 14 | BOOLEAN bWait; 15 | } WORKER_TASK, *PWORKER_TASK; 16 | 17 | typedef struct _WORKER { 18 | PETHREAD Thread; 19 | HANDLE hThread; 20 | LIST_ENTRY TaskListHead; 21 | KSPIN_LOCK Lock; 22 | KEVENT WakeupEvent; 23 | volatile BOOLEAN Stopping; 24 | } WORKER, *PWORKER; 25 | 26 | NTSTATUS WorkerStart(PWORKER Worker); 27 | VOID WorkerStop(PWORKER Worker); 28 | 29 | NTSTATUS WorkerExec(PWORKER Worker, PWORKER_CLB Clb, PVOID Context, BOOLEAN bWait); 30 | 31 | #endif -------------------------------------------------------------------------------- /Driver/klog.c: -------------------------------------------------------------------------------- 1 | #include "inc/klog.h" 2 | #include "inc/mtags.h" 3 | 4 | PKLOG_CONTEXT g_Log = NULL; 5 | 6 | VOID KLoggerThreadRoutine(PVOID Context); 7 | 8 | #define KLOG_DPRINT 9 | 10 | PKLOG_BUFFER KLogAllocBuffer(PKLOG_CONTEXT Log) 11 | { 12 | return (PKLOG_BUFFER)HAllocatorAlloc(&Log->LogBufAllocator); 13 | } 14 | 15 | VOID KLogFreeBuffer(PKLOG_CONTEXT Log, PKLOG_BUFFER KLogBuffer) 16 | { 17 | HAllocatorFree(&Log->LogBufAllocator, KLogBuffer); 18 | } 19 | 20 | VOID KLogDpc(KDPC *Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2) 21 | { 22 | PKLOG_CONTEXT Log = (PKLOG_CONTEXT)DeferredContext; 23 | KLOG_DPRINT("In dpc\n"); 24 | KeSetEvent(&Log->FlushEvent, 0, FALSE); 25 | } 26 | 27 | VOID KLogBuffersInit(PKLOG_CONTEXT Log) 28 | { 29 | InitializeListHead(&Log->FreeList); 30 | InitializeListHead(&Log->FlushQueue); 31 | KeInitializeSpinLock(&Log->Lock); 32 | 33 | KeInitializeEvent(&Log->FlushEvent, SynchronizationEvent, FALSE); 34 | KeInitializeDpc(&Log->Dpc, KLogDpc, Log); 35 | 36 | HAllocatorInit(&Log->LogBufAllocator, sizeof(KLOG_BUFFER), 200, 40*PAGE_SIZE, MTAG_KLOG); 37 | } 38 | 39 | VOID KLogThreadStop(PKLOG_CONTEXT Log) 40 | { 41 | KeSetEvent(&Log->FlushEvent, 0, FALSE); 42 | 43 | if (Log->ThreadHandle != NULL) { 44 | ZwWaitForSingleObject(Log->ThreadHandle, FALSE, NULL); 45 | ZwClose(Log->ThreadHandle); 46 | Log->ThreadHandle = NULL; 47 | } 48 | 49 | if (Log->Thread != NULL) { 50 | KeWaitForSingleObject(Log->Thread, Executive, KernelMode, FALSE, NULL); 51 | ObDereferenceObject(Log->Thread); 52 | Log->Thread = NULL; 53 | } 54 | } 55 | 56 | NTSTATUS KLogThreadStart(PKLOG_CONTEXT Log) 57 | { 58 | NTSTATUS Status; 59 | OBJECT_ATTRIBUTES ObjectAttributes; 60 | 61 | InitializeObjectAttributes( 62 | &ObjectAttributes, NULL, 63 | OBJ_KERNEL_HANDLE, 64 | NULL,NULL 65 | ); 66 | 67 | Status = PsCreateSystemThread( &Log->ThreadHandle, 68 | THREAD_ALL_ACCESS, 69 | &ObjectAttributes, 70 | 0L, 71 | NULL, 72 | KLoggerThreadRoutine, 73 | Log 74 | ); 75 | 76 | if (!NT_SUCCESS(Status)) { 77 | KLOG_DPRINT("PsCreateSystemThread failed with err %x\n", Status); 78 | return Status; 79 | } 80 | 81 | Status = ObReferenceObjectByHandle( Log->ThreadHandle, 82 | THREAD_ALL_ACCESS, 83 | *PsThreadType, 84 | KernelMode, 85 | &Log->Thread, 86 | NULL 87 | ); 88 | if (!NT_SUCCESS(Status)) { 89 | KLOG_DPRINT("ObReferenceObjectByHandle failed with err %x\n", Status); 90 | KLogThreadStop(Log); 91 | return Status; 92 | } 93 | 94 | ZwClose(Log->ThreadHandle); 95 | Log->ThreadHandle = NULL; 96 | 97 | return STATUS_SUCCESS; 98 | } 99 | 100 | NTSTATUS KLogFileOpen(PKLOG_CONTEXT Log, PUNICODE_STRING FileName) 101 | { 102 | OBJECT_ATTRIBUTES ObjectAttributes; 103 | IO_STATUS_BLOCK IoStatusBlock; 104 | NTSTATUS Status; 105 | 106 | InitializeObjectAttributes( 107 | &ObjectAttributes, FileName, 108 | OBJ_KERNEL_HANDLE|OBJ_CASE_INSENSITIVE, 109 | NULL,NULL 110 | ); 111 | 112 | Status = ZwCreateFile(&Log->FileHandle, FILE_APPEND_DATA|SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, 113 | FILE_SHARE_READ, FILE_OPEN_IF, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); 114 | 115 | if (!NT_SUCCESS(Status)) { 116 | KLOG_DPRINT("ZwCreateFile failed with err %x\n", Status); 117 | return Status; 118 | } 119 | 120 | return STATUS_SUCCESS; 121 | } 122 | 123 | NTSTATUS KLogFileWrite(PKLOG_CONTEXT Log, PVOID Buffer, ULONG Length) 124 | { 125 | NTSTATUS Status; 126 | IO_STATUS_BLOCK IoStatusBlock; 127 | 128 | 129 | Status =ZwWriteFile(Log->FileHandle, NULL, NULL, NULL, &IoStatusBlock, Buffer, Length, NULL, NULL); 130 | if (!NT_SUCCESS(Status)) { 131 | KLOG_DPRINT("ZwWriteFile failed with err %x\n", Status); 132 | return Status; 133 | } 134 | 135 | return STATUS_SUCCESS; 136 | } 137 | 138 | VOID KLogFileClose(PKLOG_CONTEXT Log) 139 | { 140 | if (Log->FileHandle != NULL) 141 | ZwClose(Log->FileHandle); 142 | Log->FileHandle = NULL; 143 | } 144 | 145 | VOID KLogRelease(PKLOG_CONTEXT Log) 146 | { 147 | Log->Stopping = TRUE; 148 | KeFlushQueuedDpcs(); 149 | KLogThreadStop(Log); 150 | HAllocatorRelease(&Log->LogBufAllocator); 151 | #ifdef KLOG_FILE 152 | KLogFileClose(Log); 153 | #endif 154 | ExFreePool(Log); 155 | } 156 | 157 | PKLOG_CONTEXT KLogCreate(PUNICODE_STRING FileName) 158 | { 159 | NTSTATUS Status; 160 | PKLOG_CONTEXT Log = NULL; 161 | 162 | Log = (PKLOG_CONTEXT)NpAlloc(sizeof(KLOG_CONTEXT), MTAG_KLOG); 163 | if (Log == NULL) { 164 | KLOG_DPRINT("ExAllocatePool failure\n"); 165 | return NULL; 166 | } 167 | RtlZeroMemory(Log, sizeof(KLOG_CONTEXT)); 168 | KLogBuffersInit(Log); 169 | 170 | #ifdef KLOG_FILE 171 | Status = KLogFileOpen(Log, FileName); 172 | if (!NT_SUCCESS(Status)) { 173 | KLOG_DPRINT("KLogFileOpen failed with err %x\n", Status); 174 | NpFree(Log, MTAG_KLOG); 175 | return NULL; 176 | } 177 | #endif 178 | 179 | Status = KLogThreadStart(Log); 180 | if (!NT_SUCCESS(Status)) { 181 | KLOG_DPRINT("KLogThreadStart failed %x\n", Status); 182 | KLogFileClose(Log); 183 | NpFree(Log, MTAG_KLOG); 184 | return NULL; 185 | } 186 | 187 | return Log; 188 | } 189 | 190 | void GetLocalTimeFields(PTIME_FIELDS pTimeFields) 191 | { 192 | LARGE_INTEGER time; 193 | KeQuerySystemTime (&time); 194 | ExSystemTimeToLocalTime(&time, &time); 195 | RtlTimeToTimeFields (&time, pTimeFields); 196 | } 197 | 198 | int WriteMsg2(PCHAR *pBuff, int *pLeft, const char *fmt, va_list argptr) 199 | { 200 | int res; 201 | if (*pLeft < 0) 202 | return -1; 203 | 204 | res = _vsnprintf(*pBuff,*pLeft,fmt,argptr); 205 | if (res>=0) { 206 | *pBuff+=res; 207 | *pLeft-=res; 208 | return 0; 209 | } else { 210 | return -2; 211 | } 212 | } 213 | 214 | VOID _cdecl WriteMsg(PCHAR *pBuff, int *pLeft, const char *fmt, ...) 215 | { 216 | va_list args; 217 | va_start(args,fmt); 218 | WriteMsg2(pBuff,pLeft,fmt,args); 219 | va_end(args); 220 | } 221 | 222 | static PCHAR TruncatePath(PCHAR filename) 223 | { 224 | PCHAR temp,curr=filename; 225 | while(temp = strchr(curr,'\\')) 226 | curr = ++temp; 227 | return curr; 228 | } 229 | 230 | VOID KLogCtx2(PKLOG_CONTEXT Log, int level, PCHAR file, ULONG line, PCHAR func, const char *fmt, va_list args) 231 | { 232 | PKLOG_BUFFER Buffer; 233 | KIRQL Irql; 234 | PCHAR pos; 235 | int left; 236 | int res = 0; 237 | TIME_FIELDS TimeFields; 238 | 239 | if (Log->Stopping) 240 | return; 241 | 242 | Buffer = KLogAllocBuffer(Log); 243 | if (Buffer == NULL) { 244 | __debugbreak(); 245 | return; 246 | } 247 | 248 | pos = (PCHAR)Buffer->Msg; 249 | left = KLOG_MSG_SZ; 250 | 251 | switch (level) { 252 | case KL_INF: 253 | WriteMsg(&pos, &left, "INF"); 254 | break; 255 | case KL_ERR: 256 | WriteMsg(&pos, &left, "ERR"); 257 | break; 258 | case KL_DBG: 259 | WriteMsg(&pos, &left, "DBG"); 260 | break; 261 | case KL_WRN: 262 | WriteMsg(&pos, &left, "WRN"); 263 | break; 264 | default: 265 | WriteMsg(&pos, &left, "UNK"); 266 | } 267 | 268 | GetLocalTimeFields (&TimeFields); 269 | WriteMsg(&pos,&left," %02d:%02d:%02d.%03d ", 270 | TimeFields.Hour, TimeFields.Minute, 271 | TimeFields.Second, TimeFields.Milliseconds); 272 | 273 | WriteMsg(&pos,&left,"t%x",PsGetCurrentThreadId()); 274 | WriteMsg(&pos, &left, " i%x", KeGetCurrentIrql()); 275 | WriteMsg(&pos,&left," %s():%s:%d: ",func,TruncatePath(file),line); 276 | 277 | res = WriteMsg2(&pos,&left, fmt, args); 278 | if (res == -2) { 279 | WriteMsg(&pos, &left, "LOG INVALID FMT OR OVERFLOW:%s\n", fmt); 280 | } else { 281 | WriteMsg(&pos,&left, "\n"); 282 | } 283 | 284 | if (left <= 0) { 285 | Buffer->Length = KLOG_MSG_SZ; 286 | Buffer->Msg[KLOG_MSG_SZ - 1] = '\n';// Avoiding Buffer Overruns 287 | } else 288 | Buffer->Length = KLOG_MSG_SZ - left; 289 | 290 | #ifdef KLOG_DBG_PRINT 291 | DbgPrint(Buffer->Msg); 292 | #endif 293 | 294 | KeAcquireSpinLock(&Log->Lock, &Irql); 295 | InsertTailList(&Log->FlushQueue, &Buffer->ListEntry); 296 | KeReleaseSpinLock(&Log->Lock, Irql); 297 | 298 | KLOG_DPRINT("Insert buff %p data %p len %x\n", Buffer, Buffer->Msg, Buffer->Length); 299 | 300 | if (KeGetCurrentIrql() > DISPATCH_LEVEL) { 301 | KLOG_DPRINT("Insert dpc\n"); 302 | KeInsertQueueDpc(&Log->Dpc, NULL, NULL); 303 | } else { 304 | KLOG_DPRINT("Signal event\n"); 305 | KeSetEvent(&Log->FlushEvent, 0, FALSE); 306 | } 307 | } 308 | 309 | VOID KLogCtx(PKLOG_CONTEXT Log, int level, PCHAR file, ULONG line, PCHAR func, const char *fmt, ...) 310 | { 311 | va_list args; 312 | 313 | va_start(args,fmt); 314 | KLogCtx2(Log, level, file, line, func, fmt, args); 315 | va_end(args); 316 | } 317 | 318 | VOID KLoggerThreadRoutine(PVOID Context) 319 | { 320 | PKLOG_CONTEXT Log = (PKLOG_CONTEXT)Context; 321 | KIRQL Irql; 322 | LIST_ENTRY FlushQueue; 323 | PKLOG_BUFFER KLogBuffer; 324 | PLIST_ENTRY ListEntry; 325 | LARGE_INTEGER Timeout; 326 | 327 | KLOG_DPRINT("Log thread started %p\n", PsGetCurrentThread()); 328 | 329 | Timeout.QuadPart = -20 * 1000 * 10;//20ms 330 | 331 | while (!Log->Stopping) { 332 | KeWaitForSingleObject(&Log->FlushEvent, Executive, KernelMode, FALSE, &Timeout); 333 | KLOG_DPRINT("Log thread %p started processing log\n", PsGetCurrentThread()); 334 | 335 | InitializeListHead(&FlushQueue); 336 | 337 | KeAcquireSpinLock(&Log->Lock, &Irql); 338 | while (!IsListEmpty(&Log->FlushQueue)) { 339 | ListEntry = RemoveHeadList(&Log->FlushQueue); 340 | InsertTailList(&FlushQueue, ListEntry); 341 | } 342 | KeReleaseSpinLock(&Log->Lock, Irql); 343 | 344 | while (!IsListEmpty(&FlushQueue)) { 345 | ListEntry = RemoveHeadList(&FlushQueue); 346 | KLogBuffer = CONTAINING_RECORD(ListEntry, KLOG_BUFFER, ListEntry); 347 | KLOG_DPRINT("Write buff %p data %p len %x\n", KLogBuffer, KLogBuffer->Msg, KLogBuffer->Length); 348 | #ifdef KLOG_FILE 349 | KLogFileWrite(Log, KLogBuffer->Msg, KLogBuffer->Length); 350 | #endif 351 | KLogFreeBuffer(Log, KLogBuffer); 352 | } 353 | } 354 | 355 | KLOG_DPRINT("Log thread stopped %p\n", PsGetCurrentThread()); 356 | } 357 | 358 | NTSTATUS KLogInit() 359 | { 360 | UNICODE_STRING LogFileName = RTL_CONSTANT_STRING(KLOG_PATH); 361 | 362 | KLOG_DPRINT("KLogInit\n"); 363 | 364 | if (g_Log != NULL) 365 | __debugbreak(); 366 | 367 | g_Log = KLogCreate(&LogFileName); 368 | if (g_Log != NULL) 369 | return STATUS_SUCCESS; 370 | else 371 | return STATUS_UNSUCCESSFUL; 372 | } 373 | 374 | VOID KLogDeinit() 375 | { 376 | KLOG_DPRINT("KLogDeinit\n"); 377 | if (g_Log != NULL) { 378 | KLogRelease(g_Log); 379 | g_Log = NULL; 380 | } 381 | } 382 | 383 | VOID KLogInternal(int level, PCHAR file, ULONG line, PCHAR func, const char *fmt, ...) 384 | { 385 | va_list args; 386 | 387 | va_start(args,fmt); 388 | KLogCtx2(g_Log, level, file, line, func, fmt, args); 389 | va_end(args); 390 | } -------------------------------------------------------------------------------- /Driver/map.c: -------------------------------------------------------------------------------- 1 | #include "inc\map.h" 2 | #include "inc\klog.h" 3 | 4 | RTL_GENERIC_COMPARE_RESULTS 5 | MapAvlCmpRoutine(PRTL_AVL_TABLE Table, PMAP_ENTRY Entry1, PMAP_ENTRY Entry2) 6 | { 7 | ULONG Key1Size = Entry1->KeySize, Key2Size = Entry2->KeySize; 8 | PUCHAR pKey1, pKey2; 9 | UCHAR Key1, Key2; 10 | ULONG Index; 11 | 12 | if (Key1Size < Key2Size) 13 | return GenericLessThan; 14 | if (Key1Size > Key2Size) 15 | return GenericGreaterThan; 16 | 17 | pKey1 = Entry1->Key; 18 | pKey2 = Entry2->Key; 19 | 20 | for (Index = 0; Index < Key1Size; Index++) { 21 | Key1 = pKey1[Index]; 22 | Key2 = pKey2[Index]; 23 | if (Key1 > Key2) 24 | return GenericGreaterThan; 25 | if (Key1 < Key2) 26 | return GenericLessThan; 27 | } 28 | 29 | return GenericEqual; 30 | } 31 | 32 | PVOID MapAvlAllocRoutine(PRTL_AVL_TABLE Table, ULONG ByteSize) 33 | { 34 | return ExAllocatePoolWithTag(PagedPool, ByteSize, MAP_TAG); 35 | } 36 | 37 | VOID MapAvlFreeRoutine(PRTL_AVL_TABLE Table, PVOID Buffer) 38 | { 39 | PMAP_ENTRY Entry = (PMAP_ENTRY)((ULONG_PTR)Buffer + sizeof(RTL_BALANCED_LINKS)); 40 | 41 | ExFreePoolWithTag(Entry->Key, MAP_TAG); 42 | ExFreePoolWithTag(Entry->Value, MAP_TAG); 43 | 44 | ExFreePoolWithTag(Buffer, MAP_TAG); 45 | } 46 | 47 | PMAP MapCreate(VOID) 48 | { 49 | PMAP Map; 50 | 51 | Map = ExAllocatePoolWithTag(NonPagedPool, sizeof(*Map), MAP_TAG); 52 | if (!Map) 53 | return NULL; 54 | 55 | RtlInitializeGenericTableAvl(&Map->Avl, MapAvlCmpRoutine, MapAvlAllocRoutine, MapAvlFreeRoutine, NULL); 56 | ExInitializeResourceLite(&Map->Lock); 57 | return Map; 58 | } 59 | 60 | VOID MapDelete(PMAP Map) 61 | { 62 | PMAP_ENTRY Entry; 63 | 64 | KeEnterCriticalRegion(); 65 | ExAcquireResourceExclusiveLite(&Map->Lock, TRUE); 66 | 67 | do { 68 | Entry = (PMAP_ENTRY)RtlEnumerateGenericTableAvl(&Map->Avl, TRUE); 69 | if (Entry) 70 | RtlDeleteElementGenericTableAvl(&Map->Avl, Entry); 71 | } while (Entry); 72 | 73 | ExReleaseResourceLite(&Map->Lock); 74 | KeLeaveCriticalRegion(); 75 | 76 | ExDeleteResourceLite(&Map->Lock); 77 | ExFreePoolWithTag(Map, MAP_TAG); 78 | } 79 | 80 | NTSTATUS MapInsertKey(PMAP Map, PVOID Key, ULONG KeySize, PVOID Value, ULONG ValueSize) 81 | { 82 | MAP_ENTRY Entry; 83 | BOOLEAN NewEntry; 84 | NTSTATUS Status; 85 | PVOID Result; 86 | 87 | if (!Key || !Value || !KeySize || !ValueSize) 88 | return STATUS_INVALID_PARAMETER; 89 | 90 | Entry.Key = ExAllocatePoolWithTag(PagedPool, KeySize, MAP_TAG); 91 | if (!Entry.Key) 92 | return STATUS_INSUFFICIENT_RESOURCES; 93 | Entry.Value = ExAllocatePoolWithTag(PagedPool, ValueSize, MAP_TAG); 94 | if (!Entry.Value) { 95 | ExFreePoolWithTag(Entry.Key, MAP_TAG); 96 | return STATUS_INSUFFICIENT_RESOURCES; 97 | } 98 | RtlCopyMemory(Entry.Key, Key, KeySize); 99 | RtlCopyMemory(Entry.Value, Value, ValueSize); 100 | Entry.KeySize = KeySize; 101 | Entry.ValueSize = ValueSize; 102 | 103 | KeEnterCriticalRegion(); 104 | ExAcquireResourceExclusiveLite(&Map->Lock, TRUE); 105 | 106 | Result = RtlInsertElementGenericTableAvl(&Map->Avl, &Entry, sizeof(Entry), &NewEntry); 107 | 108 | ExReleaseResourceLite(&Map->Lock); 109 | KeLeaveCriticalRegion(); 110 | 111 | if (!Result) { 112 | Status = STATUS_INSUFFICIENT_RESOURCES; 113 | } else { 114 | if (!NewEntry) 115 | Status = STATUS_OBJECT_NAME_COLLISION; 116 | else 117 | Status = STATUS_SUCCESS; 118 | } 119 | 120 | if (!NT_SUCCESS(Status)) { 121 | ExFreePoolWithTag(Entry.Key, MAP_TAG); 122 | ExFreePoolWithTag(Entry.Value, MAP_TAG); 123 | } 124 | 125 | return Status; 126 | } 127 | 128 | NTSTATUS MapLookupKey(PMAP Map, PVOID Key, ULONG KeySize, PVOID *pValue, ULONG *pValueSize) 129 | { 130 | MAP_ENTRY Entry; 131 | PMAP_ENTRY FoundEntry; 132 | PVOID Value; 133 | NTSTATUS Status; 134 | 135 | Entry.Key = Key; 136 | Entry.KeySize = KeySize; 137 | Entry.Value = NULL; 138 | Entry.ValueSize = 0; 139 | 140 | /* 141 | * Since RtlLookupElementGenericTableAvl doesn't modify AVL tree 142 | * we can acquire shared lock here. 143 | */ 144 | 145 | KeEnterCriticalRegion(); 146 | ExAcquireResourceSharedLite(&Map->Lock, TRUE); 147 | 148 | FoundEntry = RtlLookupElementGenericTableAvl(&Map->Avl, &Entry); 149 | if (!FoundEntry) { 150 | Status = STATUS_OBJECT_NAME_NOT_FOUND; 151 | goto unlock; 152 | } 153 | 154 | Value = ExAllocatePoolWithTag(PagedPool, FoundEntry->ValueSize, MAP_TAG); 155 | if (!Value) { 156 | Status = STATUS_INSUFFICIENT_RESOURCES; 157 | goto unlock; 158 | } 159 | 160 | RtlCopyMemory(Value, FoundEntry->Value, FoundEntry->ValueSize); 161 | *pValue = Value; 162 | *pValueSize = FoundEntry->ValueSize; 163 | Status = STATUS_SUCCESS; 164 | unlock: 165 | ExReleaseResourceLite(&Map->Lock); 166 | KeLeaveCriticalRegion(); 167 | return Status; 168 | 169 | } 170 | 171 | NTSTATUS MapDeleteKey(PMAP Map, PVOID Key, ULONG KeySize) 172 | { 173 | MAP_ENTRY Entry; 174 | NTSTATUS Status; 175 | BOOLEAN Deleted; 176 | 177 | Entry.Key = Key; 178 | Entry.KeySize = KeySize; 179 | Entry.Value = NULL; 180 | Entry.ValueSize = 0; 181 | 182 | KeEnterCriticalRegion(); 183 | ExAcquireResourceExclusiveLite(&Map->Lock, TRUE); 184 | 185 | Deleted = RtlDeleteElementGenericTableAvl(&Map->Avl, &Entry); 186 | 187 | ExReleaseResourceLite(&Map->Lock); 188 | KeLeaveCriticalRegion(); 189 | 190 | if (Deleted) 191 | Status = STATUS_SUCCESS; 192 | else 193 | Status = STATUS_OBJECT_NAME_NOT_FOUND; 194 | 195 | return Status; 196 | } 197 | -------------------------------------------------------------------------------- /Driver/socket.c: -------------------------------------------------------------------------------- 1 | #include "inc\socket.h" 2 | #include "inc\klog.h" 3 | #include "inc\mtags.h" 4 | #include "inc\worker.h" 5 | 6 | PSOCKET SocketAlloc(PSOCKET_FACTORY SocketFactory) 7 | { 8 | PSOCKET Socket; 9 | 10 | Socket = NpAlloc(sizeof(*Socket), MTAG_SOCKET); 11 | if (!Socket) 12 | return NULL; 13 | 14 | RtlZeroMemory(Socket, sizeof(*Socket)); 15 | KeInitializeSpinLock(&Socket->Lock); 16 | Socket->RefCount = 1; 17 | Socket->SocketFactory = SocketFactory; 18 | return Socket; 19 | } 20 | 21 | VOID SocketFree(PSOCKET Socket) 22 | { 23 | NpFree(Socket, MTAG_SOCKET); 24 | } 25 | 26 | NTSTATUS SocketFactoryInit(PSOCKET_FACTORY SocketFactory) 27 | { 28 | NTSTATUS Status; 29 | 30 | RtlZeroMemory(SocketFactory, sizeof(*SocketFactory)); 31 | InitializeListHead(&SocketFactory->SocketListHead); 32 | KeInitializeSpinLock(&SocketFactory->Lock); 33 | 34 | SocketFactory->ClientDispatch.Version = MAKE_WSK_VERSION(1, 0); 35 | SocketFactory->ClientDispatch.Reserved = 0; 36 | SocketFactory->ClientDispatch.WskClientEvent = NULL; 37 | 38 | SocketFactory->ClientNpi.ClientContext = NULL; 39 | SocketFactory->ClientNpi.Dispatch = &SocketFactory->ClientDispatch; 40 | 41 | Status = WskRegister(&SocketFactory->ClientNpi, &SocketFactory->Registration); 42 | if (!NT_SUCCESS(Status)) { 43 | KLErr("WskRegister failed Status 0x%x", Status); 44 | return Status; 45 | } 46 | 47 | Status = WskCaptureProviderNPI(&SocketFactory->Registration, WSK_INFINITE_WAIT, 48 | &SocketFactory->ProviderNpi); 49 | if (!NT_SUCCESS(Status)) { 50 | WskDeregister(&SocketFactory->Registration); 51 | KLErr("WskCaptureProviderNPI failed Status 0x%x", Status); 52 | return Status; 53 | } 54 | 55 | return Status; 56 | } 57 | 58 | NTSTATUS SocketWskDisconnectIrpCompletionRoutine(PDEVICE_OBJECT Device, PIRP Irp, PVOID Context) 59 | { 60 | PKEVENT CompletionEvent = (PKEVENT)Context; 61 | 62 | KeSetEvent(CompletionEvent, 2, FALSE); 63 | return STATUS_MORE_PROCESSING_REQUIRED; 64 | } 65 | 66 | PWSK_PROVIDER_CONNECTION_DISPATCH WskSocketDispatch(PWSK_SOCKET WskSocket) 67 | { 68 | return (PWSK_PROVIDER_CONNECTION_DISPATCH)WskSocket->Dispatch; 69 | } 70 | 71 | NTSTATUS SocketWskDisconnect(PWSK_SOCKET WskSocket, ULONG Flags) 72 | { 73 | KEVENT CompEvent; 74 | NTSTATUS Status; 75 | PIRP Irp; 76 | 77 | KeInitializeEvent(&CompEvent, SynchronizationEvent, FALSE); 78 | 79 | Irp = IoAllocateIrp(1, FALSE); 80 | if (Irp == NULL) { 81 | KLErr( "No memory"); 82 | return STATUS_INSUFFICIENT_RESOURCES; 83 | } 84 | 85 | IoSetCompletionRoutine(Irp, 86 | SocketWskDisconnectIrpCompletionRoutine, 87 | &CompEvent, TRUE, TRUE, TRUE); 88 | 89 | Status = WskSocketDispatch(WskSocket)->WskDisconnect(WskSocket, NULL, Flags, Irp); 90 | KLDbg("WskDisconnect Status 0x%x", Status); 91 | 92 | KeWaitForSingleObject(&CompEvent, Executive, KernelMode, FALSE, NULL); 93 | 94 | Status = Irp->IoStatus.Status; 95 | 96 | if (!NT_SUCCESS(Status)) 97 | KLErr("Disconnect Status 0x%x", Status); 98 | 99 | IoFreeIrp(Irp); 100 | 101 | return Status; 102 | } 103 | 104 | NTSTATUS SocketWskCloseIrpCompletionRoutine(PDEVICE_OBJECT Device, PIRP Irp, PVOID Context) 105 | { 106 | PKEVENT CompletionEvent = (PKEVENT)Context; 107 | 108 | KeSetEvent(CompletionEvent, 2, FALSE); 109 | return STATUS_MORE_PROCESSING_REQUIRED; 110 | } 111 | 112 | NTSTATUS SocketWskClose(PWSK_SOCKET WskSocket) 113 | { 114 | KEVENT CompletionEvent; 115 | NTSTATUS Status; 116 | PIRP Irp; 117 | 118 | KeInitializeEvent(&CompletionEvent, SynchronizationEvent, FALSE); 119 | 120 | Irp = IoAllocateIrp(1, FALSE); 121 | if (Irp == NULL) { 122 | KLErr("No memory"); 123 | return STATUS_INSUFFICIENT_RESOURCES; 124 | } 125 | 126 | IoSetCompletionRoutine(Irp, 127 | SocketWskCloseIrpCompletionRoutine, 128 | &CompletionEvent, TRUE, TRUE, TRUE); 129 | 130 | Status = WskSocketDispatch(WskSocket)->WskCloseSocket(WskSocket, Irp); 131 | KLDbg("WskCloseSocket Status 0x%x", Status); 132 | 133 | KeWaitForSingleObject(&CompletionEvent, Executive, KernelMode, FALSE, NULL); 134 | Status = Irp->IoStatus.Status; 135 | 136 | if (!NT_SUCCESS(Status)) 137 | KLErr("Close Status 0x%x", Status); 138 | 139 | IoFreeIrp(Irp); 140 | 141 | return Status; 142 | } 143 | 144 | VOID SocketShutdown(PSOCKET Socket) 145 | { 146 | KIRQL Irql; 147 | PWSK_SOCKET WskSocket; 148 | 149 | KeAcquireSpinLock(&Socket->Lock, &Irql); 150 | WskSocket = Socket->WskSocket; 151 | Socket->WskSocket = NULL; 152 | KeReleaseSpinLock(&Socket->Lock, Irql); 153 | if (WskSocket) { 154 | SocketWskDisconnect(WskSocket, 0); 155 | SocketWskClose(WskSocket); 156 | } 157 | } 158 | 159 | VOID SocketDereference(PSOCKET Socket) 160 | { 161 | if (Socket->RefCount <= 0) 162 | __debugbreak(); 163 | 164 | if (0 == InterlockedDecrement(&Socket->RefCount)) { 165 | SocketShutdown(Socket); 166 | SocketFree(Socket); 167 | } 168 | } 169 | 170 | VOID SocketFactoryRelease(PSOCKET_FACTORY SocketFactory) 171 | { 172 | LIST_ENTRY SocketList; 173 | PLIST_ENTRY ListEntry; 174 | PSOCKET Socket; 175 | KIRQL Irql; 176 | 177 | SocketFactory->Releasing = 1; 178 | InitializeListHead(&SocketList); 179 | KeAcquireSpinLock(&SocketFactory->Lock, &Irql); 180 | while (!IsListEmpty(&SocketFactory->SocketListHead)) { 181 | ListEntry = RemoveHeadList(&SocketFactory->SocketListHead); 182 | InsertTailList(&SocketList, ListEntry); 183 | } 184 | KeReleaseSpinLock(&SocketFactory->Lock, Irql); 185 | 186 | while (!IsListEmpty(&SocketList)) { 187 | ListEntry = RemoveHeadList(&SocketList); 188 | Socket = CONTAINING_RECORD(ListEntry, SOCKET, ListEntry); 189 | SocketShutdown(Socket); 190 | SocketDereference(Socket); 191 | } 192 | WskReleaseProviderNPI(&SocketFactory->Registration); 193 | WskDeregister(&SocketFactory->Registration); 194 | } 195 | 196 | NTSTATUS SocketWskResolveNameCompletionRoutine(PDEVICE_OBJECT Device, PIRP Irp, PVOID Context) 197 | { 198 | PKEVENT CompletionEvent = (PKEVENT)Context; 199 | 200 | KeSetEvent(CompletionEvent, 2, FALSE); 201 | return STATUS_MORE_PROCESSING_REQUIRED; 202 | } 203 | 204 | NTSTATUS SocketFactoryResolveNameInternal(PSOCKET_FACTORY SocketFactory, PUNICODE_STRING NodeName, 205 | PUNICODE_STRING ServiceName, PADDRINFOEXW Hints, 206 | PSOCKADDR_IN ResolvedAddress) 207 | { 208 | NTSTATUS Status; 209 | PIRP Irp; 210 | KEVENT CompletionEvent; 211 | PADDRINFOEXW Results = NULL, AddrInfo = NULL; 212 | 213 | KeInitializeEvent(&CompletionEvent, SynchronizationEvent, FALSE); 214 | 215 | Irp = IoAllocateIrp(1, FALSE); 216 | if (Irp == NULL) { 217 | KLErr("No memory"); 218 | return STATUS_INSUFFICIENT_RESOURCES; 219 | } 220 | 221 | IoSetCompletionRoutine(Irp, SocketWskResolveNameCompletionRoutine, &CompletionEvent, TRUE, TRUE, TRUE); 222 | 223 | SocketFactory->ProviderNpi.Dispatch->WskGetAddressInfo( 224 | SocketFactory->ProviderNpi.Client, 225 | NodeName, 226 | ServiceName, 227 | NS_ALL, 228 | NULL, 229 | Hints, 230 | &Results, 231 | NULL, 232 | NULL, 233 | Irp); 234 | 235 | KeWaitForSingleObject(&CompletionEvent, Executive, 236 | KernelMode, FALSE, NULL); 237 | 238 | Status = Irp->IoStatus.Status; 239 | 240 | IoFreeIrp(Irp); 241 | 242 | if (!NT_SUCCESS(Status)) { 243 | KLErr("ResolveName Status 0x%x", Status); 244 | return Status; 245 | } 246 | 247 | AddrInfo = Results; 248 | if (AddrInfo != NULL) { 249 | *ResolvedAddress = *((PSOCKADDR_IN)(AddrInfo->ai_addr)); 250 | } else { 251 | Status = STATUS_UNSUCCESSFUL; 252 | KLErr("No addresses found"); 253 | } 254 | 255 | SocketFactory->ProviderNpi.Dispatch->WskFreeAddressInfo( 256 | SocketFactory->ProviderNpi.Client, 257 | Results); 258 | 259 | return Status; 260 | } 261 | 262 | NTSTATUS SocketFactoryResolveName(PSOCKET_FACTORY SocketFactory, PWCHAR HostName, PWCHAR Port, 263 | PSOCKADDR_IN ResolvedAddress) 264 | { 265 | UNICODE_STRING NodeName, ServiceName; 266 | SOCKADDR_IN Address; 267 | NTSTATUS Status; 268 | 269 | RtlInitUnicodeString(&NodeName, HostName); 270 | RtlInitUnicodeString(&ServiceName, Port); 271 | 272 | Status = SocketFactoryResolveNameInternal(SocketFactory, &NodeName, &ServiceName, NULL, &Address); 273 | if (!NT_SUCCESS(Status)) { 274 | KLErr("Can't resolve HostName %ws Port %ws Status 0x%x", HostName, Port, Status); 275 | return Status; 276 | } 277 | 278 | *ResolvedAddress = Address; 279 | return Status; 280 | } 281 | 282 | NTSTATUS SocketWskConnectIrpCompletionRoutine(PDEVICE_OBJECT Device, PIRP Irp, PVOID Context) 283 | { 284 | PKEVENT CompletionEvent = (PKEVENT)Context; 285 | 286 | KeSetEvent(CompletionEvent, 2, FALSE); 287 | return STATUS_MORE_PROCESSING_REQUIRED; 288 | } 289 | 290 | NTSTATUS SocketConnectInternal(PSOCKET_FACTORY SocketFactory, USHORT SocketType, ULONG Protocol, 291 | PSOCKADDR LocalAddr, PSOCKADDR RemoteAddr, PSOCKET *pSocket) 292 | { 293 | PSOCKET Socket; 294 | PIRP Irp; 295 | KEVENT CompletionEvent; 296 | KIRQL Irql; 297 | NTSTATUS Status; 298 | 299 | Socket = SocketAlloc(SocketFactory); 300 | if (!Socket) { 301 | KLErr("No memory"); 302 | return STATUS_INSUFFICIENT_RESOURCES; 303 | } 304 | 305 | Irp = IoAllocateIrp(1, FALSE); 306 | if (Irp == NULL) { 307 | KLErr("No memory"); 308 | Status = STATUS_INSUFFICIENT_RESOURCES; 309 | goto FailAllocIrp; 310 | } 311 | 312 | KeInitializeEvent(&CompletionEvent, NotificationEvent, FALSE); 313 | IoSetCompletionRoutine(Irp, 314 | SocketWskConnectIrpCompletionRoutine, 315 | &CompletionEvent, TRUE, TRUE, TRUE); 316 | 317 | Status = SocketFactory->ProviderNpi.Dispatch->WskSocketConnect(SocketFactory->ProviderNpi.Client, 318 | SocketType, 319 | Protocol, 320 | LocalAddr, 321 | RemoteAddr, 322 | 0, 323 | NULL, 324 | NULL, 325 | NULL, 326 | NULL, 327 | NULL, 328 | Irp); 329 | KLDbg("WskSocketConnect Status 0x%x", Status); 330 | if (!NT_SUCCESS(Status)) { 331 | KLErr("WskSocketConnect Status 0x%x", Status); 332 | goto FailConnect; 333 | } 334 | 335 | KeWaitForSingleObject(&CompletionEvent, Executive, KernelMode, FALSE, NULL); 336 | 337 | Status = Irp->IoStatus.Status; 338 | if (!NT_SUCCESS(Status)) { 339 | KLErr("WskSocketConnect status 0x%x", Status); 340 | goto FailConnect; 341 | } 342 | 343 | Socket->WskSocket = (PWSK_SOCKET)Irp->IoStatus.Information; 344 | KeAcquireSpinLock(&SocketFactory->Lock, &Irql); 345 | if (SocketFactory->Releasing) { 346 | KLErr("Socket factory releasing"); 347 | Status = STATUS_TOO_LATE; 348 | } else { 349 | SocketReference(Socket); 350 | InsertHeadList(&SocketFactory->SocketListHead, &Socket->ListEntry); 351 | Status = STATUS_SUCCESS; 352 | } 353 | KeReleaseSpinLock(&SocketFactory->Lock, Irql); 354 | if (!NT_SUCCESS(Status)) 355 | goto FailSocketInsert; 356 | 357 | *pSocket = Socket; 358 | IoFreeIrp(Irp); 359 | return Status; 360 | 361 | FailSocketInsert: 362 | SocketShutdown(Socket); 363 | FailConnect: 364 | IoFreeIrp(Irp); 365 | FailAllocIrp: 366 | SocketDereference(Socket); 367 | return Status; 368 | } 369 | 370 | NTSTATUS SocketConnect(PSOCKET_FACTORY SocketFactory, PWCHAR HostName, PWCHAR Port, PSOCKET *pSocket) 371 | { 372 | NTSTATUS Status; 373 | SOCKADDR_IN LocalAddr, RemoteAddr; 374 | 375 | Status = SocketFactoryResolveName(SocketFactory, HostName, Port, &RemoteAddr); 376 | if (!NT_SUCCESS(Status)) { 377 | KLErr("Can't resolve HostName %ws Port %ws Status 0x%x", HostName, Port, Status); 378 | return Status; 379 | } 380 | 381 | IN4ADDR_SETANY(&LocalAddr); 382 | return SocketConnectInternal(SocketFactory, SOCK_STREAM, IPPROTO_TCP, (PSOCKADDR)&LocalAddr, (PSOCKADDR)&RemoteAddr, pSocket); 383 | } 384 | 385 | NTSTATUS SocketWskSendIrpCompletionRoutine(PDEVICE_OBJECT Device, PIRP Irp, PVOID Context) 386 | { 387 | PKEVENT CompEvent = (PKEVENT)Context; 388 | 389 | KeSetEvent(CompEvent, 2, FALSE); 390 | return STATUS_MORE_PROCESSING_REQUIRED; 391 | } 392 | 393 | NTSTATUS SocketSendInternal(PSOCKET Socket, ULONG Flags, PVOID Buf, ULONG Size, PULONG pSent) 394 | { 395 | WSK_BUF WskBuf; 396 | KEVENT CompEvent; 397 | PIRP Irp = NULL; 398 | PMDL Mdl = NULL; 399 | NTSTATUS Status; 400 | LARGE_INTEGER Timeout; 401 | 402 | *pSent = 0; 403 | KeInitializeEvent(&CompEvent, NotificationEvent, FALSE); 404 | 405 | Irp = IoAllocateIrp(1, FALSE); 406 | if (Irp == NULL) { 407 | KLErr("No memory"); 408 | return STATUS_INSUFFICIENT_RESOURCES; 409 | } 410 | 411 | IoSetCompletionRoutine(Irp, 412 | SocketWskSendIrpCompletionRoutine, 413 | &CompEvent, TRUE, TRUE, TRUE); 414 | 415 | Mdl = IoAllocateMdl(Buf, Size, FALSE, FALSE, NULL); 416 | if (Mdl == NULL) { 417 | KLErr("No memory"); 418 | Status = STATUS_INSUFFICIENT_RESOURCES; 419 | goto Cleanup; 420 | } 421 | MmBuildMdlForNonPagedPool(Mdl); 422 | 423 | WskBuf.Offset = 0; 424 | WskBuf.Length = Size; 425 | WskBuf.Mdl = Mdl; 426 | 427 | KLDbg( "Send irp %p", Irp); 428 | 429 | Status = WskSocketDispatch(Socket->WskSocket)->WskSend(Socket->WskSocket, &WskBuf, Flags, Irp); 430 | KLDbg( "WskSend Status 0x%x", Status); 431 | 432 | /* Wait maximum 10 secs */ 433 | Timeout.QuadPart = -MillisTo100Ns(10000); 434 | Status = KeWaitForSingleObject(&CompEvent, Executive, KernelMode, FALSE, &Timeout); 435 | if (Status == STATUS_TIMEOUT) { 436 | KLErr( "Wait timed out will cancel irp %p", Irp); 437 | if (!IoCancelIrp(Irp)) { 438 | KLErr("Cant cancel irp %p", Irp); 439 | } 440 | KLDbg("Start waiting for event signaled"); 441 | KeWaitForSingleObject(&CompEvent, Executive, KernelMode, FALSE, NULL); 442 | KLDbg("Waited for event signaled"); 443 | } 444 | 445 | Status = Irp->IoStatus.Status; 446 | 447 | if (!NT_SUCCESS(Status)) 448 | KLErr("Send Status 0x%x", Status); 449 | 450 | if (NT_SUCCESS(Status)) { 451 | *pSent = (ULONG)Irp->IoStatus.Information; 452 | } 453 | Cleanup: 454 | if (Irp != NULL) 455 | IoFreeIrp(Irp); 456 | if (Mdl != NULL) 457 | IoFreeMdl(Mdl); 458 | 459 | return Status; 460 | } 461 | 462 | NTSTATUS SocketSend(PSOCKET Socket, PVOID Buf, ULONG Size, PULONG pSent) 463 | { 464 | ULONG BytesSent; 465 | ULONG Offset; 466 | NTSTATUS Status = STATUS_UNSUCCESSFUL; 467 | 468 | Offset = 0; 469 | while (Offset < Size) { 470 | Status = SocketSendInternal(Socket, WSK_FLAG_NODELAY, (PVOID)((ULONG_PTR)Buf + Offset), Size - Offset, &BytesSent); 471 | if (!NT_SUCCESS(Status)) { 472 | KLErr("Send failed with Status 0x%x", Status); 473 | break; 474 | } 475 | Offset += BytesSent; 476 | } 477 | 478 | *pSent = Offset; 479 | 480 | return Status; 481 | } 482 | 483 | NTSTATUS SocketWskReceiveIrpCompletionRoutine(PDEVICE_OBJECT Device, PIRP Irp, PVOID Context) 484 | { 485 | PKEVENT CompEvent = (PKEVENT)Context; 486 | 487 | KeSetEvent(CompEvent, 2, FALSE); 488 | return STATUS_MORE_PROCESSING_REQUIRED; 489 | } 490 | 491 | NTSTATUS SocketReceiveInternal(PSOCKET Socket, ULONG Flags, PVOID Buf, ULONG Size, ULONG *pReceived) 492 | { 493 | WSK_BUF WskBuf; 494 | KEVENT CompEvent; 495 | PIRP Irp = NULL; 496 | PMDL Mdl = NULL; 497 | NTSTATUS Status; 498 | LARGE_INTEGER Timeout; 499 | 500 | *pReceived = 0; 501 | KeInitializeEvent(&CompEvent, SynchronizationEvent, FALSE); 502 | 503 | Irp = IoAllocateIrp(1, FALSE); 504 | if (Irp == NULL) { 505 | KLErr( "No memory"); 506 | return STATUS_INSUFFICIENT_RESOURCES; 507 | } 508 | 509 | IoSetCompletionRoutine(Irp, 510 | SocketWskReceiveIrpCompletionRoutine, 511 | &CompEvent, TRUE, TRUE, TRUE); 512 | 513 | Mdl = IoAllocateMdl(Buf, Size, FALSE, FALSE, NULL); 514 | if (Mdl == NULL) { 515 | KLErr("No memory"); 516 | Status = STATUS_INSUFFICIENT_RESOURCES; 517 | goto Cleanup; 518 | } 519 | MmBuildMdlForNonPagedPool(Mdl); 520 | 521 | WskBuf.Offset = 0; 522 | WskBuf.Length = Size; 523 | WskBuf.Mdl = Mdl; 524 | 525 | KLDbg("Receive irp %p", Irp); 526 | 527 | Status = WskSocketDispatch(Socket->WskSocket)->WskReceive(Socket->WskSocket, &WskBuf, Flags, Irp); 528 | KLDbg("WskReceive Status 0x%x", Status); 529 | 530 | /* Wait maximum 10 secs */ 531 | Timeout.QuadPart = -MillisTo100Ns(10000); 532 | Status = KeWaitForSingleObject(&CompEvent, Executive, KernelMode, FALSE, &Timeout); 533 | if (Status == STATUS_TIMEOUT) { 534 | KLErr( "Wait timed out will cancel irp %p", Irp); 535 | if (!IoCancelIrp(Irp)) { 536 | KLErr("Cant cancel irp %p", Irp); 537 | } 538 | KLDbg("Start waiting for event signaled"); 539 | KeWaitForSingleObject(&CompEvent, Executive, KernelMode, FALSE, NULL); 540 | KLDbg("Waited for event signaled"); 541 | } 542 | 543 | Status = Irp->IoStatus.Status; 544 | 545 | if (!NT_SUCCESS(Status)) 546 | KLErr( "Receive status 0x%x", Status); 547 | 548 | if (NT_SUCCESS(Status)) { 549 | *pReceived = (ULONG)Irp->IoStatus.Information; 550 | } 551 | 552 | Cleanup: 553 | if (Irp != NULL) 554 | IoFreeIrp(Irp); 555 | if (Mdl != NULL) 556 | IoFreeMdl(Mdl); 557 | 558 | return Status; 559 | } 560 | 561 | NTSTATUS SocketReceive(PSOCKET Socket, PVOID Buf, ULONG Size, PULONG pReceived, PBOOLEAN pbDisconnected) 562 | { 563 | ULONG BytesRcv; 564 | ULONG Offset; 565 | NTSTATUS Status = STATUS_UNSUCCESSFUL; 566 | 567 | Offset = 0; 568 | while (Offset < Size) { 569 | Status = SocketReceiveInternal(Socket, 0, (PVOID)((ULONG_PTR)Buf + Offset), Size - Offset, &BytesRcv); 570 | if (!NT_SUCCESS(Status)) { 571 | KLErr("Received Status 0x%x", Status); 572 | break; 573 | } 574 | 575 | if (BytesRcv == 0) { 576 | KLDbg("Received 0 bytes"); 577 | *pbDisconnected = TRUE; 578 | Status = STATUS_SUCCESS; 579 | break; 580 | } 581 | Offset += BytesRcv; 582 | } 583 | 584 | *pReceived = Offset; 585 | 586 | return Status; 587 | } 588 | 589 | VOID SocketClose(PSOCKET Socket) 590 | { 591 | PSOCKET_FACTORY SocketFactory = Socket->SocketFactory; 592 | KIRQL Irql; 593 | 594 | SocketShutdown(Socket); 595 | 596 | KeAcquireSpinLock(&SocketFactory->Lock, &Irql); 597 | RemoveEntryList(&Socket->ListEntry); 598 | KeReleaseSpinLock(&SocketFactory->Lock, Irql); 599 | 600 | SocketDereference(Socket); 601 | SocketDereference(Socket); 602 | } -------------------------------------------------------------------------------- /Driver/tests.c: -------------------------------------------------------------------------------- 1 | #include "inc\tests.h" 2 | #include "inc\map.h" 3 | #include "inc\worker.h" 4 | #include "inc\socket.h" 5 | #include "inc\klog.h" 6 | #include "inc\helpers.h" 7 | 8 | #define TESTS_TAG 'tseT' 9 | 10 | NTSTATUS SocketTest(PVOID Context) 11 | { 12 | PSOCKET_FACTORY SocketFactory = NULL; 13 | PSOCKET Socket; 14 | NTSTATUS Status; 15 | CHAR HttpResponse[4]; 16 | CHAR HttpRequest[] = "GET / HTTP/1.1\nHost: rbc.ru\nUser-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64)\nAccept: */*\n\n"; 17 | ULONG Sent, Received; 18 | BOOLEAN Disconnected; 19 | 20 | SocketFactory = NpAlloc(sizeof(*SocketFactory), TESTS_TAG); 21 | if (!SocketFactory) 22 | return STATUS_INSUFFICIENT_RESOURCES; 23 | 24 | Status = SocketFactoryInit(SocketFactory); 25 | if (!NT_SUCCESS(Status)) { 26 | KLErr("SocketFactoryInit failed Status 0x%x", Status); 27 | goto socket_factory_free; 28 | } 29 | 30 | Status = SocketConnect(SocketFactory, L"rbc.ru", L"80", &Socket); 31 | if (!NT_SUCCESS(Status)) { 32 | KLErr("SocketConnect failed Status 0x%x", Status); 33 | goto socket_factory_release; 34 | } 35 | 36 | Status = SocketSend(Socket, HttpRequest, sizeof(HttpRequest), &Sent); 37 | if (!NT_SUCCESS(Status)) { 38 | KLErr("SocketSend failed Status 0x%x", Status); 39 | goto socket_close; 40 | } 41 | 42 | if (Sent != sizeof(HttpRequest)) { 43 | Status = STATUS_UNSUCCESSFUL; 44 | KLErr("SocketSend failed Sent %d", Sent); 45 | goto socket_close; 46 | } 47 | 48 | Status = SocketReceive(Socket, HttpResponse, sizeof(HttpResponse), &Received, &Disconnected); 49 | if (!NT_SUCCESS(Status)) { 50 | KLErr("SocketReceive failed Status 0x%x", Status); 51 | goto socket_close; 52 | } 53 | 54 | if ((Received != sizeof(HttpResponse)) || Disconnected) { 55 | KLErr("Received %d Disconnected %d", Received, Disconnected); 56 | Status = STATUS_UNSUCCESSFUL; 57 | goto socket_close; 58 | } 59 | 60 | if (4 != RtlCompareMemory(HttpResponse, "HTTP", 4)) { 61 | KLErr("Incorrect data received"); 62 | Status = STATUS_UNSUCCESSFUL; 63 | goto socket_close; 64 | } 65 | 66 | Status = STATUS_SUCCESS; 67 | socket_close: 68 | SocketClose(Socket); 69 | socket_factory_release: 70 | SocketFactoryRelease(SocketFactory); 71 | socket_factory_free: 72 | NpFree(SocketFactory, TESTS_TAG); 73 | KLInf("SocketTest Status 0x%x", Status); 74 | return Status; 75 | } 76 | 77 | NTSTATUS MapTest(PVOID Context) 78 | { 79 | typedef struct _SID_KV { 80 | CHAR *Key; 81 | CHAR *Value; 82 | } SID_KV, *PSID_KV; 83 | 84 | NTSTATUS Status; 85 | PVOID Value; 86 | PMAP Map; 87 | ULONG Index, ValueSize; 88 | SID_KV TestKvs[] = {{"S-1-0-0", "SID0"}, 89 | {"S-1-1-0", "SID1"}, 90 | {"S-1-0", "SID2"}, 91 | {"S-1-1", "SID3"}, 92 | {"S-1-5-21-1180699209-877415012-3182924384-1004", "BIG-SID4"}, 93 | {"S-1-5-20", "SID5"}, 94 | {"S-1-5-21-1180699209-111115012-3182924384-1004", "Another-BIG-SID6"}}; 95 | Map = MapCreate(); 96 | if (!Map) { 97 | KLErr("Can't create map"); 98 | return STATUS_INSUFFICIENT_RESOURCES; 99 | } 100 | 101 | for (Index = 0; Index < RTL_NUMBER_OF(TestKvs); Index++) { 102 | Status = MapInsertKey(Map, TestKvs[Index].Key, (ULONG)(strlen(TestKvs[Index].Key) + 1), 103 | TestKvs[Index].Value, (ULONG)(strlen(TestKvs[Index].Value) + 1)); 104 | if (!NT_SUCCESS(Status)) { 105 | KLErr("MapInsertKey failed Status 0x%x", Status); 106 | goto cleanup; 107 | } 108 | } 109 | 110 | /* Try to insert key 4 again */ 111 | Status = MapInsertKey(Map, TestKvs[4].Key, (ULONG)(strlen(TestKvs[4].Key) + 1), 112 | TestKvs[4].Value, (ULONG)(strlen(TestKvs[4].Value) + 1)); 113 | if (Status != STATUS_OBJECT_NAME_COLLISION) { 114 | Status = STATUS_UNSUCCESSFUL; 115 | KLErr("MapInsertKey duplicate Status 0x%x", Status); 116 | goto cleanup; 117 | } 118 | 119 | /* Delete key 5 */ 120 | Status = MapDeleteKey(Map, TestKvs[5].Key, (ULONG)(strlen(TestKvs[5].Key) + 1)); 121 | if (!NT_SUCCESS(Status)) { 122 | KLErr("MapDeleteKey Status 0x%x", Status); 123 | goto cleanup; 124 | } 125 | 126 | for (Index = 0; Index < RTL_NUMBER_OF(TestKvs); Index++) { 127 | /* Skip key 5 because it's already deleted */ 128 | if (Index == 5) 129 | continue; 130 | Status = MapLookupKey(Map, TestKvs[Index].Key, (ULONG)(strlen(TestKvs[Index].Key) + 1), &Value, &ValueSize); 131 | if (!NT_SUCCESS(Status)) { 132 | KLErr("MapLookupKey failed Status 0x%x", Status); 133 | goto cleanup; 134 | } 135 | 136 | if (ValueSize != (strlen(TestKvs[Index].Value) + 1)) { 137 | KLErr("MapLookupKey returned invalid ValueSize 0x%x", ValueSize); 138 | ExFreePoolWithTag(Value, MAP_TAG); 139 | Status = STATUS_UNSUCCESSFUL; 140 | goto cleanup; 141 | } 142 | if (ValueSize != RtlCompareMemory(Value, TestKvs[Index].Value, ValueSize)) { 143 | KLErr("MapLookupKey returned invalid Value content"); 144 | ExFreePoolWithTag(Value, MAP_TAG); 145 | Status = STATUS_UNSUCCESSFUL; 146 | goto cleanup; 147 | } 148 | ExFreePoolWithTag(Value, MAP_TAG); 149 | } 150 | Status = STATUS_SUCCESS; 151 | cleanup: 152 | MapDelete(Map); 153 | KLInf("MapTest Status 0x%x", Status); 154 | return Status; 155 | } 156 | 157 | NTSTATUS RunTests(VOID) 158 | { 159 | NTSTATUS Status; 160 | WORKER Worker; 161 | 162 | Status = WorkerStart(&Worker); 163 | if (!NT_SUCCESS(Status)) { 164 | KLErr("WorkerStart failed Status 0x%x", Status); 165 | return Status; 166 | } 167 | 168 | Status = WorkerExec(&Worker, SocketTest, NULL, TRUE); 169 | if (!NT_SUCCESS(Status)) { 170 | KLErr("SocketTest failed Status 0x%x", Status); 171 | goto cleanup; 172 | } 173 | 174 | Status = WorkerExec(&Worker, MapTest, NULL, TRUE); 175 | if (!NT_SUCCESS(Status)) { 176 | KLErr("MapTest failed Status 0x%x", Status); 177 | goto cleanup; 178 | } 179 | 180 | cleanup: 181 | KLInf("RunTests Status 0x%x", Status); 182 | WorkerStop(&Worker); 183 | return Status; 184 | } -------------------------------------------------------------------------------- /Driver/worker.c: -------------------------------------------------------------------------------- 1 | #include "inc\worker.h" 2 | #include "inc\helpers.h" 3 | #include "inc\klog.h" 4 | #include "inc\mtags.h" 5 | 6 | VOID WorkerRoutine(PVOID Context) 7 | { 8 | PWORKER Worker = (PWORKER)Context; 9 | PWORKER_TASK Task; 10 | PLIST_ENTRY ListEntry; 11 | LIST_ENTRY TaskList; 12 | KIRQL Irql; 13 | 14 | while (!Worker->Stopping) { 15 | KeWaitForSingleObject(&Worker->WakeupEvent, 16 | Executive, 17 | KernelMode, 18 | FALSE, 19 | NULL); 20 | InitializeListHead(&TaskList); 21 | KeAcquireSpinLock(&Worker->Lock, &Irql); 22 | while (!IsListEmpty(&Worker->TaskListHead)) { 23 | ListEntry = RemoveHeadList(&Worker->TaskListHead); 24 | InsertTailList(&TaskList, ListEntry); 25 | } 26 | KeReleaseSpinLock(&Worker->Lock, Irql); 27 | 28 | while (!IsListEmpty(&TaskList)) { 29 | ListEntry = RemoveHeadList(&TaskList); 30 | Task = CONTAINING_RECORD(ListEntry, WORKER_TASK, ListEntry); 31 | Task->Status = Task->Clb(Task->Context); 32 | if (Task->bWait) { 33 | KeMemoryBarrier(); 34 | KeSetEvent(&Task->CompleteEvent, 0, FALSE); 35 | } else 36 | NpFree(Task, MTAG_WRK); 37 | } 38 | } 39 | 40 | InitializeListHead(&TaskList); 41 | KeAcquireSpinLock(&Worker->Lock, &Irql); 42 | while (!IsListEmpty(&Worker->TaskListHead)) { 43 | ListEntry = RemoveHeadList(&Worker->TaskListHead); 44 | InsertTailList(&TaskList, ListEntry); 45 | } 46 | KeReleaseSpinLock(&Worker->Lock, Irql); 47 | 48 | while (!IsListEmpty(&TaskList)) { 49 | ListEntry = RemoveHeadList(&TaskList); 50 | Task = CONTAINING_RECORD(ListEntry, WORKER_TASK, ListEntry); 51 | Task->Status = STATUS_CANCELLED; 52 | if (Task->bWait) { 53 | KeMemoryBarrier(); 54 | KeSetEvent(&Task->CompleteEvent, 0, FALSE); 55 | } else 56 | NpFree(Task, MTAG_WRK); 57 | } 58 | } 59 | 60 | VOID WorkerStop(PWORKER Worker) 61 | { 62 | Worker->Stopping = TRUE; 63 | KeMemoryBarrier(); 64 | KeSetEvent(&Worker->WakeupEvent, 0, FALSE); 65 | 66 | ZwWaitForSingleObject(Worker->hThread, 67 | FALSE, 68 | NULL); 69 | ZwClose(Worker->hThread); 70 | 71 | if (Worker->Thread) 72 | ObDereferenceObject(Worker->Thread); 73 | } 74 | 75 | NTSTATUS WorkerStart(PWORKER Worker) 76 | { 77 | NTSTATUS Status; 78 | OBJECT_ATTRIBUTES ObjectAttributes; 79 | 80 | RtlZeroMemory(Worker, sizeof(*Worker)); 81 | InitializeListHead(&Worker->TaskListHead); 82 | KeInitializeSpinLock(&Worker->Lock); 83 | KeInitializeEvent(&Worker->WakeupEvent, SynchronizationEvent, FALSE); 84 | 85 | InitializeObjectAttributes( 86 | &ObjectAttributes, NULL, 87 | OBJ_KERNEL_HANDLE, 88 | NULL,NULL 89 | ); 90 | 91 | Status = PsCreateSystemThread(&Worker->hThread, 92 | THREAD_ALL_ACCESS, 93 | &ObjectAttributes, 94 | 0L, 95 | NULL, 96 | WorkerRoutine, 97 | Worker); 98 | if (!NT_SUCCESS(Status)) { 99 | KLErr("Can't create thread Status 0x%x", Status); 100 | return Status; 101 | } 102 | 103 | Status = ObReferenceObjectByHandle(Worker->hThread, 104 | THREAD_ALL_ACCESS, 105 | *PsThreadType, 106 | KernelMode, 107 | &Worker->Thread, 108 | NULL); 109 | if (!NT_SUCCESS(Status)) { 110 | KLErr("Can't create thread Status 0x%x", Status); 111 | WorkerStop(Worker); 112 | return Status; 113 | } 114 | 115 | return Status; 116 | } 117 | 118 | NTSTATUS WorkerExec(PWORKER Worker, PWORKER_CLB Clb, PVOID Context, BOOLEAN bWait) 119 | { 120 | PWORKER_TASK Task; 121 | KIRQL Irql; 122 | NTSTATUS Status; 123 | 124 | Task = NpAlloc(sizeof(*Task), MTAG_WRK); 125 | if (!Task) 126 | return STATUS_INSUFFICIENT_RESOURCES; 127 | 128 | RtlZeroMemory(Task, sizeof(*Task)); 129 | KeInitializeEvent(&Task->CompleteEvent, NotificationEvent, FALSE); 130 | Task->bWait = bWait; 131 | Task->Clb = Clb; 132 | Task->Context = Context; 133 | 134 | KeAcquireSpinLock(&Worker->Lock, &Irql); 135 | InsertTailList(&Worker->TaskListHead, &Task->ListEntry); 136 | KeReleaseSpinLock(&Worker->Lock, Irql); 137 | KeSetEvent(&Worker->WakeupEvent, 0, FALSE); 138 | 139 | if (!bWait) 140 | return STATUS_SUCCESS; 141 | 142 | KeWaitForSingleObject(&Task->CompleteEvent, 143 | Executive, 144 | KernelMode, 145 | FALSE, 146 | NULL); 147 | Status = Task->Status; 148 | NpFree(Task, MTAG_WRK); 149 | 150 | return Status; 151 | } -------------------------------------------------------------------------------- /Server/api.h: -------------------------------------------------------------------------------- 1 | #ifndef __FBACKUP_SERVER_API_H__ 2 | #define __FBACKUP_SERVER_API_H__ 3 | 4 | enum { 5 | FB_SRV_REQ_TYPE_INVALID = 0, 6 | FB_SRV_REQ_TYPE_TIME = 1, 7 | FB_SRV_REQ_TYPE_MAX 8 | }; 9 | 10 | #define FB_SRV_REQ_MAGIC 'qrBF' 11 | #define FB_SRV_RESP_MAGIC 'prBF' 12 | 13 | #define FB_SRV_PORT L"9111" 14 | #define FB_SRV_MAX_BODY_SIZE (64*4096) 15 | 16 | #pragma pack(push, 1) 17 | 18 | typedef struct _FB_SRV_REQ_HEADER { 19 | unsigned long Magic; 20 | unsigned long Size; 21 | unsigned long Type; 22 | unsigned long Id; 23 | } FB_SRV_REQ_HEADER, *PFB_SRV_REQ_HEADER; 24 | 25 | typedef struct _FB_SRV_RESP_HEADER { 26 | unsigned long Magic; 27 | unsigned long Size; 28 | unsigned long Err; 29 | unsigned long Type; 30 | unsigned long Id; 31 | } FB_SRV_RESP_HEADER, *PFB_SRV_RESP_HEADER; 32 | 33 | typedef struct _FB_SRV_RESP_TIME { 34 | unsigned short Year; 35 | unsigned short Month; 36 | unsigned short DayOfWeek; 37 | unsigned short Day; 38 | unsigned short Hour; 39 | unsigned short Minute; 40 | unsigned short Second; 41 | unsigned short Milliseconds; 42 | } FB_SRV_RESP_TIME, *PFB_SRV_RESP_TIME; 43 | 44 | #pragma pack(pop) 45 | 46 | #endif -------------------------------------------------------------------------------- /Server/base.h: -------------------------------------------------------------------------------- 1 | #ifndef __FBACKUP_SERVER_BASE_H__ 2 | #define __FBACKUP_SERVER_BASE_H__ 3 | 4 | #define WIN32_LEAN_AND_MEAN 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "..\shared\error.h" 13 | 14 | #define __FBACKUP_COMPONENT__ "FBackupServer" 15 | 16 | #endif -------------------------------------------------------------------------------- /Server/btree.c: -------------------------------------------------------------------------------- 1 | #include "btree.h" 2 | -------------------------------------------------------------------------------- /Server/btree.h: -------------------------------------------------------------------------------- 1 | #ifndef __FBACKUP_SERVER_BTREE_H__ 2 | #define __FBACKUP_SERVER_BTREE_H__ 3 | 4 | #include "base.h" 5 | 6 | typedef struct _BTreeNode BTreeNode, *PBTreeNode; 7 | 8 | typedef struct _BTreeCallbacks { 9 | ULONG (*BTreeNodeRead)(PVOID Ctx, ULONG64 Position, PBTreeNode Node); 10 | ULONG (*BTreeNodeWrite)(PVOID Ctx, PBTreeNode Node, ULONG_PTR TxId); 11 | ULONG (*BTreeWriteBegin)(PVOID Ctx, ULONG_PTR *pTxId); 12 | ULONG (*BTreeWriteEnd)(PVOID Ctx, ULONG_PTR TxId); 13 | LONG (*BTreeKeyCmp)(PVOID Key1, PVOID Key2); 14 | PVOID (*BTreeValueCopy)(PVOID Value); 15 | } BTreeCallbacks, *PBTreeCallbacks; 16 | 17 | typedef struct _BTree { 18 | PBTreeNode Root; 19 | PVOID Ctx; 20 | BTreeCallbacks Callbacks; 21 | } BTree, *PBTree; 22 | 23 | typedef struct _BTreeNode { 24 | ULONG64 Position; 25 | PVOID *Keys; 26 | ULONG NrKeys; 27 | PVOID *Values; 28 | ULONG NrValues; 29 | ULONG64 *Childs; 30 | ULONG NrChilds; 31 | ULONG TreeT; 32 | } BTreeNode, *PBTreeNode; 33 | 34 | ULONG BTreeOpen(PBTree Tree, ULONG64 RootPosition, PVOID Ctx, PBTreeCallbacks Callbacks); 35 | ULONG BTreeCreate(PBTree Tree, ULONG TreeT, PVOID Ctx, PBTreeCallbacks Callbacks); 36 | ULONG64 BTreeGetPosition(PBTree Tree); 37 | 38 | ULONG BTreeInsert(PBTree Tree, PVOID Key, PVOID Value); 39 | 40 | ULONG BTreeLookup(PBTree Tree, PVOID Key, PVOID *pValue); 41 | 42 | ULONG BTreeDelete(PBTree Tree, PVOID Key); 43 | 44 | ULONG BTreeErase(PBTree Tree); 45 | 46 | typedef ULONG (*BTreeEnumClb)(PVOID Key, PVOID Value); 47 | 48 | ULONG BTreeEnum(PBTree Tree, BTreeEnumClb EnumClb); 49 | 50 | ULONG BTreeRelease(PBTree Tree); 51 | 52 | #endif -------------------------------------------------------------------------------- /Server/debug.c: -------------------------------------------------------------------------------- 1 | #include "debug.h" 2 | #include "fmt.h" 3 | #include "misc.h" 4 | 5 | VOID __DebugPrintf(PCHAR Component, PCHAR File, PCHAR Function, ULONG Line, PCHAR Fmt, ...) 6 | { 7 | va_list Args; 8 | CHAR Output[256]; 9 | ULONG BufLeft; 10 | PCHAR BufPos; 11 | 12 | BufPos = Output; 13 | BufLeft = RTL_NUMBER_OF(Output); 14 | 15 | FmtMsg(&BufPos, &BufLeft, "%s:%s():%s,%d: ", 16 | Component, Function, FmtTruncatePath(File), Line); 17 | 18 | va_start(Args, Fmt); 19 | FmtMsg2(&BufPos, &BufLeft, Fmt, Args); 20 | va_end(Args); 21 | 22 | Output[RTL_NUMBER_OF(Output)-1] = '\0'; 23 | OutputDebugStringA(Output); 24 | } 25 | 26 | PTOP_LEVEL_EXCEPTION_FILTER g_OldUnhandleExceptionFilter; 27 | HMODULE g_ModuleHandle; 28 | 29 | LONG DebugUnhandledExceptionFilter(EXCEPTION_POINTERS *ExceptionInfo) 30 | { 31 | ULONG i; 32 | PEXCEPTION_RECORD ExceptionRecord = ExceptionInfo->ExceptionRecord; 33 | PCONTEXT Context = ExceptionInfo->ContextRecord; 34 | 35 | DebugPrintf("Exc Code 0x%x At %p ModuleBase %p", 36 | ExceptionRecord->ExceptionCode, 37 | ExceptionRecord->ExceptionAddress, g_ModuleHandle); 38 | 39 | for (i = 0; i < ULongMin(ExceptionRecord->NumberParameters, 40 | RTL_NUMBER_OF(ExceptionRecord->ExceptionInformation)); i++) 41 | DebugPrintf("Exc Information[%d]=%p", 42 | i, ExceptionRecord->ExceptionInformation[i]); 43 | 44 | DebugPrintf("Exc RAX %p RBX %p RDX %p RCX %p\n", 45 | Context->Rax, Context->Rbx, Context->Rdx, Context->Rcx); 46 | DebugPrintf("Exc RSI %p RDI %p RSP %p RBP %p\n", 47 | Context->Rsi, Context->Rdi, Context->Rsp, Context->Rbp); 48 | 49 | DebugPrintf("Exc R8 %p R9 %p R10 %p R11 %p\n", 50 | Context->EFlags, Context->R8, Context->R9, Context->R10, Context->R11); 51 | 52 | DebugPrintf("Exc R12 %p R13 %p R14 %p R15 %p\n", 53 | Context->R12, Context->R13, Context->R14, Context->R15); 54 | 55 | DebugPrintf("Exc EFlags 0x%x\n", Context->EFlags); 56 | 57 | if (g_OldUnhandleExceptionFilter) 58 | return g_OldUnhandleExceptionFilter(ExceptionInfo); 59 | else 60 | return EXCEPTION_CONTINUE_SEARCH; 61 | } 62 | 63 | VOID DebugInit(VOID) 64 | { 65 | g_ModuleHandle = GetModuleHandle(NULL); 66 | g_OldUnhandleExceptionFilter = SetUnhandledExceptionFilter(DebugUnhandledExceptionFilter); 67 | } -------------------------------------------------------------------------------- /Server/debug.h: -------------------------------------------------------------------------------- 1 | #ifndef __FBACKUP_SERVER_DEBUG_H__ 2 | #define __FBACKUP_SERVER_DEBUG_H__ 3 | 4 | #include "base.h" 5 | 6 | VOID __DebugPrintf(PCHAR Component, PCHAR File, PCHAR Function, ULONG Line, PCHAR Fmt, ...); 7 | 8 | #define DebugPrintf(Fmt, ...) \ 9 | __DebugPrintf(__FBACKUP_COMPONENT__, __FILE__, __FUNCTION__, __LINE__, (Fmt), ##__VA_ARGS__); 10 | 11 | VOID DebugInit(VOID); 12 | 13 | #endif -------------------------------------------------------------------------------- /Server/fmt.c: -------------------------------------------------------------------------------- 1 | #include "fmt.h" 2 | 3 | LONG FmtMsg2(PCHAR *pBuff, ULONG *pLeft, PCHAR Fmt, va_list Args) 4 | { 5 | LONG Result; 6 | 7 | if (*pLeft < 0) 8 | return -1; 9 | 10 | Result = _vsnprintf(*pBuff, *pLeft, Fmt, Args); 11 | if (Result) { 12 | *pBuff+=Result; 13 | *pLeft-=Result; 14 | } 15 | 16 | return Result; 17 | } 18 | 19 | LONG FmtMsg(PCHAR *pBuff, ULONG *pLeft, PCHAR Fmt, ...) 20 | { 21 | LONG Result; 22 | va_list Args; 23 | 24 | va_start(Args, Fmt); 25 | Result = FmtMsg2(pBuff, pLeft, Fmt, Args); 26 | va_end(Args); 27 | 28 | return Result; 29 | } 30 | 31 | PCHAR FmtTruncatePath(PCHAR FileName) 32 | { 33 | PCHAR BaseName; 34 | 35 | BaseName = strrchr(FileName, '\\'); 36 | if (BaseName) 37 | return ++BaseName; 38 | else 39 | return FileName; 40 | } -------------------------------------------------------------------------------- /Server/fmt.h: -------------------------------------------------------------------------------- 1 | #ifndef __FBACKUP_SERVER_FMT_H__ 2 | #define __FBACKUP_SERVER_FMT_H__ 3 | 4 | #include "base.h" 5 | 6 | LONG FmtMsg2(PCHAR *pBuff, ULONG *pLeft, PCHAR Fmt, va_list Args); 7 | LONG FmtMsg(PCHAR *pBuff, ULONG *pLeft, PCHAR Fmt, ...); 8 | PCHAR FmtTruncatePath(PCHAR FileName); 9 | 10 | #endif -------------------------------------------------------------------------------- /Server/list_entry.h: -------------------------------------------------------------------------------- 1 | #ifndef __FBACKUP_SERVER_LIST_ENTRY_H__ 2 | #define __FBACKUP_SERVER_LIST_ENTRY_H__ 3 | /* 4 | typedef struct _LIST_ENTRY { 5 | struct _LIST_ENTRY *Flink; 6 | struct _LIST_ENTRY *Blink; 7 | } LIST_ENTRY, *PLIST_ENTRY; 8 | */ 9 | #define STATIC_LIST_HEAD(x) LIST_ENTRY x = { &x, &x } 10 | 11 | FORCEINLINE 12 | VOID 13 | InitializeListHead( 14 | PLIST_ENTRY ListHead 15 | ) 16 | 17 | { 18 | ListHead->Flink = ListHead->Blink = ListHead; 19 | return; 20 | } 21 | 22 | FORCEINLINE 23 | BOOLEAN 24 | IsListEmpty( 25 | LIST_ENTRY * ListHead 26 | ) 27 | 28 | { 29 | 30 | return (BOOLEAN)(ListHead->Flink == ListHead); 31 | } 32 | 33 | FORCEINLINE 34 | BOOLEAN 35 | RemoveEntryList( 36 | PLIST_ENTRY Entry 37 | ) 38 | 39 | { 40 | PLIST_ENTRY Blink; 41 | PLIST_ENTRY Flink; 42 | 43 | Flink = Entry->Flink; 44 | Blink = Entry->Blink; 45 | Blink->Flink = Flink; 46 | Flink->Blink = Blink; 47 | return (BOOLEAN)(Flink == Blink); 48 | } 49 | 50 | FORCEINLINE 51 | PLIST_ENTRY 52 | RemoveHeadList( 53 | PLIST_ENTRY ListHead 54 | ) 55 | 56 | { 57 | 58 | PLIST_ENTRY Flink; 59 | PLIST_ENTRY Entry; 60 | 61 | Entry = ListHead->Flink; 62 | Flink = Entry->Flink; 63 | ListHead->Flink = Flink; 64 | Flink->Blink = ListHead; 65 | return Entry; 66 | } 67 | 68 | FORCEINLINE 69 | PLIST_ENTRY 70 | RemoveTailList( 71 | PLIST_ENTRY ListHead 72 | ) 73 | 74 | { 75 | 76 | PLIST_ENTRY Blink; 77 | PLIST_ENTRY Entry; 78 | 79 | Entry = ListHead->Blink; 80 | Blink = Entry->Blink; 81 | ListHead->Blink = Blink; 82 | Blink->Flink = ListHead; 83 | return Entry; 84 | } 85 | 86 | 87 | FORCEINLINE 88 | VOID 89 | InsertTailList( 90 | PLIST_ENTRY ListHead, 91 | PLIST_ENTRY Entry 92 | ) 93 | { 94 | 95 | PLIST_ENTRY Blink; 96 | 97 | Blink = ListHead->Blink; 98 | Entry->Flink = ListHead; 99 | Entry->Blink = Blink; 100 | Blink->Flink = Entry; 101 | ListHead->Blink = Entry; 102 | return; 103 | } 104 | 105 | 106 | FORCEINLINE 107 | VOID 108 | InsertHeadList( 109 | PLIST_ENTRY ListHead, 110 | PLIST_ENTRY Entry 111 | ) 112 | { 113 | 114 | PLIST_ENTRY Flink; 115 | 116 | Flink = ListHead->Flink; 117 | Entry->Flink = Flink; 118 | Entry->Blink = ListHead; 119 | Flink->Blink = Entry; 120 | ListHead->Flink = Entry; 121 | return; 122 | } 123 | 124 | FORCEINLINE 125 | VOID 126 | AppendTailList( 127 | PLIST_ENTRY ListHead, 128 | PLIST_ENTRY ListToAppend 129 | ) 130 | { 131 | 132 | PLIST_ENTRY ListEnd = ListHead->Blink; 133 | 134 | ListHead->Blink->Flink = ListToAppend; 135 | ListHead->Blink = ListToAppend->Blink; 136 | ListToAppend->Blink->Flink = ListHead; 137 | ListToAppend->Blink = ListEnd; 138 | return; 139 | } 140 | 141 | FORCEINLINE 142 | VOID MoveList(PLIST_ENTRY DstListHead, PLIST_ENTRY SrcListHead) 143 | { 144 | PLIST_ENTRY Flink, Blink; 145 | 146 | if (IsListEmpty(SrcListHead)) { 147 | InitializeListHead(DstListHead); 148 | return; 149 | } 150 | 151 | Flink = SrcListHead->Flink; 152 | Blink = SrcListHead->Blink; 153 | 154 | DstListHead->Flink = Flink; 155 | Flink->Blink = DstListHead; 156 | DstListHead->Blink = Blink; 157 | Blink->Flink = DstListHead; 158 | 159 | InitializeListHead(SrcListHead); 160 | } 161 | 162 | #endif 163 | 164 | -------------------------------------------------------------------------------- /Server/log.c: -------------------------------------------------------------------------------- 1 | #include "log.h" 2 | #include "list_entry.h" 3 | #include "memalloc.h" 4 | #include "fmt.h" 5 | 6 | typedef struct _LOG_ENTRY { 7 | CHAR Buf[256]; 8 | ULONG BufUsed; 9 | LIST_ENTRY ListEntry; 10 | } LOG_ENTRY, *PLOG_ENTRY; 11 | 12 | typedef struct _LOG_CONTEXT { 13 | HANDLE hThread; 14 | HANDLE hFile; 15 | HANDLE hEvent; 16 | WCHAR FilePath[256]; 17 | LIST_ENTRY ListHead; 18 | CRITICAL_SECTION Lock; 19 | volatile LONG Stopping; 20 | ULONG Level; 21 | } LOG_CONTEXT, *PLOG_CONTEXT; 22 | 23 | LOG_CONTEXT g_LogCtx; 24 | 25 | DWORD LogFileSetPointerToEnd(PLOG_CONTEXT LogCtx) 26 | { 27 | LARGE_INTEGER Offset; 28 | 29 | Offset.QuadPart = 0; 30 | if (!SetFilePointerEx(LogCtx->hFile, Offset, NULL, FILE_END)) 31 | return GetLastError(); 32 | return 0; 33 | } 34 | 35 | DWORD LogFileLock(PLOG_CONTEXT LogCtx) 36 | { 37 | OVERLAPPED Overlapped; 38 | 39 | memset(&Overlapped, 0, sizeof(Overlapped)); 40 | if (!LockFileEx(LogCtx->hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, 0xFFFFFFFF, 0xFFFFFFFF, &Overlapped)) 41 | return GetLastError(); 42 | 43 | return 0; 44 | } 45 | 46 | VOID LogFileUnlock(PLOG_CONTEXT LogCtx) 47 | { 48 | OVERLAPPED Overlapped; 49 | 50 | memset(&Overlapped, 0, sizeof(Overlapped)); 51 | UnlockFileEx(LogCtx->hFile, 0, 0xFFFFFFFF, 0xFFFFFFFF, &Overlapped); 52 | } 53 | 54 | DWORD LogFileWriteEntry(PLOG_CONTEXT LogCtx, PLOG_ENTRY LogEntry) 55 | { 56 | DWORD WrittenTotal = 0; 57 | DWORD Written; 58 | 59 | while (WrittenTotal < LogEntry->BufUsed) { 60 | if (!WriteFile(LogCtx->hFile, LogEntry->Buf + WrittenTotal, 61 | LogEntry->BufUsed - WrittenTotal, &Written, NULL)) { 62 | return GetLastError(); 63 | } 64 | WrittenTotal+= Written; 65 | } 66 | 67 | return 0; 68 | } 69 | 70 | VOID LogWriteExistingEntries(PLOG_CONTEXT LogCtx, BOOL IgnoreStopping) 71 | { 72 | LIST_ENTRY LogEntries; 73 | PLIST_ENTRY ListEntry; 74 | PLOG_ENTRY LogEntry; 75 | 76 | if (LogCtx->Stopping && !IgnoreStopping) 77 | return; 78 | 79 | EnterCriticalSection(&LogCtx->Lock); 80 | if (LogCtx->Stopping && !IgnoreStopping) { 81 | LeaveCriticalSection(&LogCtx->Lock); 82 | return; 83 | } 84 | MoveList(&LogEntries, &LogCtx->ListHead); 85 | LeaveCriticalSection(&LogCtx->Lock); 86 | 87 | if (0 == LogFileLock(LogCtx)) { 88 | if (0 == LogFileSetPointerToEnd(LogCtx)) { 89 | for (ListEntry = LogEntries.Flink; ListEntry != &LogEntries; ListEntry = ListEntry->Flink) { 90 | LogEntry = CONTAINING_RECORD(ListEntry, LOG_ENTRY, ListEntry); 91 | LogFileWriteEntry(LogCtx, LogEntry); 92 | } 93 | FlushFileBuffers(LogCtx->hFile); 94 | } 95 | LogFileUnlock(LogCtx); 96 | } 97 | 98 | while (!IsListEmpty(&LogEntries)) { 99 | ListEntry = RemoveHeadList(&LogEntries); 100 | LogEntry = CONTAINING_RECORD(ListEntry, LOG_ENTRY, ListEntry); 101 | MemFree(LogEntry); 102 | } 103 | } 104 | 105 | DWORD LogThreadRoutine(PLOG_CONTEXT LogCtx) 106 | { 107 | while (!LogCtx->Stopping) { 108 | WaitForSingleObject(LogCtx->hEvent, INFINITE); 109 | if (!LogCtx->Stopping) 110 | LogWriteExistingEntries(LogCtx, FALSE); 111 | } 112 | 113 | return 0; 114 | } 115 | 116 | DWORD LogInit(PLOG_CONTEXT LogCtx, PWCHAR FilePath, ULONG Level) 117 | { 118 | DWORD Err; 119 | 120 | memset(LogCtx, 0, sizeof(*LogCtx)); 121 | LogCtx->Level = Level; 122 | InitializeListHead(&LogCtx->ListHead); 123 | _snwprintf(LogCtx->FilePath, RTL_NUMBER_OF(LogCtx->FilePath) - 1, L"%ws", FilePath); 124 | InitializeCriticalSection(&LogCtx->Lock); 125 | 126 | LogCtx->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); 127 | if (!LogCtx->hEvent) { 128 | Err = GetLastError(); 129 | goto fail_delete_critical_section; 130 | } 131 | 132 | LogCtx->hFile = CreateFile(LogCtx->FilePath, FILE_GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 133 | NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 134 | if (LogCtx->hFile == INVALID_HANDLE_VALUE) { 135 | Err = GetLastError(); 136 | goto fail_close_event; 137 | } 138 | 139 | LogCtx->hThread = CreateThread(NULL, 0, LogThreadRoutine, LogCtx, 0, NULL); 140 | if (!LogCtx->hThread) { 141 | Err = GetLastError(); 142 | goto fail_close_file; 143 | } 144 | 145 | return 0; 146 | 147 | fail_close_file: 148 | CloseHandle(LogCtx->hFile); 149 | fail_close_event: 150 | CloseHandle(LogCtx->hEvent); 151 | fail_delete_critical_section: 152 | DeleteCriticalSection(&LogCtx->Lock); 153 | return Err; 154 | } 155 | 156 | VOID LogRelease(PLOG_CONTEXT LogCtx) 157 | { 158 | LogCtx->Stopping = 1; 159 | EnterCriticalSection(&LogCtx->Lock); 160 | LeaveCriticalSection(&LogCtx->Lock); 161 | 162 | WaitForSingleObject(LogCtx->hThread, INFINITE); 163 | 164 | LogWriteExistingEntries(LogCtx, TRUE); 165 | 166 | DeleteCriticalSection(&LogCtx->Lock); 167 | CloseHandle(LogCtx->hEvent); 168 | CloseHandle(LogCtx->hFile); 169 | CloseHandle(LogCtx->hThread); 170 | } 171 | 172 | BOOLEAN LogEntryEnqueue(PLOG_CONTEXT LogCtx, PLOG_ENTRY LogEntry) 173 | { 174 | BOOLEAN Inserted; 175 | if (LogCtx->Stopping) 176 | return FALSE; 177 | 178 | EnterCriticalSection(&LogCtx->Lock); 179 | if (!LogCtx->Stopping) { 180 | InsertTailList(&LogCtx->ListHead, &LogEntry->ListEntry); 181 | Inserted = TRUE; 182 | } else 183 | Inserted = FALSE; 184 | LeaveCriticalSection(&LogCtx->Lock); 185 | if (Inserted) 186 | SetEvent(LogCtx->hEvent); 187 | 188 | return Inserted; 189 | } 190 | 191 | VOID Log(PLOG_CONTEXT LogCtx, ULONG Level, PCHAR Component, PCHAR File, 192 | PCHAR Func, ULONG Line, PCHAR Fmt, va_list Args) 193 | { 194 | PLOG_ENTRY LogEntry; 195 | PCHAR BufPos; 196 | ULONG BufSize, BufLeft; 197 | SYSTEMTIME Time; 198 | 199 | if (Level < LogCtx->Level) 200 | return; 201 | 202 | LogEntry = MemAlloc(sizeof(*LogEntry)); 203 | if (!LogEntry) 204 | return; 205 | 206 | LogEntry->BufUsed = 0; 207 | BufPos = LogEntry->Buf; 208 | BufSize = sizeof(LogEntry->Buf); 209 | BufLeft = BufSize; 210 | 211 | switch (Level) { 212 | case LOG_INF: 213 | FmtMsg(&BufPos, &BufLeft, "INF"); 214 | break; 215 | case LOG_ERR: 216 | FmtMsg(&BufPos, &BufLeft, "ERR"); 217 | break; 218 | case LOG_DBG: 219 | FmtMsg(&BufPos, &BufLeft, "DBG"); 220 | break; 221 | case LOG_WRN: 222 | FmtMsg(&BufPos, &BufLeft, "WRN"); 223 | break; 224 | default: 225 | FmtMsg(&BufPos, &BufLeft, "UNK"); 226 | break; 227 | } 228 | 229 | GetSystemTime(&Time); 230 | FmtMsg(&BufPos, &BufLeft," %02d:%02d:%02d.%03d ", 231 | Time.wHour, Time.wMinute, 232 | Time.wSecond, Time.wMilliseconds); 233 | 234 | FmtMsg(&BufPos, &BufLeft,"p%d t%d", GetCurrentProcessId(), GetCurrentThreadId()); 235 | FmtMsg(&BufPos, &BufLeft," %s:%s():%s,%d: ", Component, Func, FmtTruncatePath(File), Line); 236 | 237 | FmtMsg2(&BufPos, &BufLeft, Fmt, Args); 238 | if (FmtMsg(&BufPos, &BufLeft, "\r\n") <= 0) { 239 | LogEntry->Buf[BufSize-2] = '\r'; 240 | LogEntry->Buf[BufSize-1] = '\n'; 241 | LogEntry->BufUsed = BufSize; 242 | } else 243 | LogEntry->BufUsed = BufSize - BufLeft; 244 | 245 | if (!LogEntryEnqueue(LogCtx, LogEntry)) 246 | MemFree(LogEntry); 247 | } 248 | 249 | DWORD GlobalLogInit(PWCHAR FilePath, ULONG Level) 250 | { 251 | return LogInit(&g_LogCtx, FilePath, Level); 252 | } 253 | 254 | VOID GlobalLogRelease() 255 | { 256 | LogRelease(&g_LogCtx); 257 | } 258 | 259 | VOID GlobalLog(ULONG Level, PCHAR Component, PCHAR File, PCHAR Func, 260 | ULONG Line, PCHAR Fmt, ...) 261 | { 262 | va_list Args; 263 | 264 | va_start(Args, Fmt); 265 | Log(&g_LogCtx, Level, Component, File, Func, Line, Fmt, Args); 266 | va_end(Args); 267 | } -------------------------------------------------------------------------------- /Server/log.h: -------------------------------------------------------------------------------- 1 | #ifndef __FBACKUP_SERVER_LOG_H__ 2 | #define __FBACKUP_SERVER_LOG_H__ 3 | 4 | #include "base.h" 5 | 6 | enum { 7 | LOG_DBG, 8 | LOG_INF, 9 | LOG_WRN, 10 | LOG_ERR 11 | }; 12 | 13 | VOID GlobalLog(ULONG Level, PCHAR Component, PCHAR File, PCHAR Func, ULONG Line, PCHAR Fmt, ...); 14 | 15 | #define LErr(Fmt, ...) \ 16 | GlobalLog(LOG_ERR, __FBACKUP_COMPONENT__, __FILE__, __FUNCTION__, __LINE__, (Fmt), ##__VA_ARGS__) 17 | 18 | #define LDbg(Fmt, ...) \ 19 | GlobalLog(LOG_DBG, __FBACKUP_COMPONENT__, __FILE__, __FUNCTION__, __LINE__, (Fmt), ##__VA_ARGS__) 20 | 21 | #define LInf(Fmt, ...) \ 22 | GlobalLog(LOG_INF, __FBACKUP_COMPONENT__, __FILE__, __FUNCTION__, __LINE__, (Fmt), ##__VA_ARGS__) 23 | 24 | #define LWrn(Fmt, ...) \ 25 | GlobalLog(LOG_WRN, __FBACKUP_COMPONENT__, __FILE__, __FUNCTION__, __LINE__, (Fmt), ##__VA_ARGS__) 26 | 27 | DWORD GlobalLogInit(PWCHAR FilePath, ULONG Level); 28 | VOID GlobalLogRelease(); 29 | 30 | #endif -------------------------------------------------------------------------------- /Server/main.c: -------------------------------------------------------------------------------- 1 | #include "base.h" 2 | #include "log.h" 3 | #include "server.h" 4 | #include "memalloc.h" 5 | #include "debug.h" 6 | 7 | #define SVC_NAME L"FBackupServer" 8 | #define SVC_LOG_NAME SVC_NAME L".log" 9 | 10 | typedef struct _SVC_CONTEXT { 11 | SERVICE_STATUS Status; 12 | SERVICE_STATUS_HANDLE StatusHandle; 13 | HANDLE hStopEvent; 14 | HANDLE hStoppedEvent; 15 | volatile LONG Stopping; 16 | } SVC_CONTEXT, *PSVC_CONTEXT; 17 | 18 | SVC_CONTEXT g_SvcCtx; 19 | 20 | PSVC_CONTEXT GetSvcContext(VOID) 21 | { 22 | return &g_SvcCtx; 23 | } 24 | 25 | VOID ReportSvcStatus(DWORD dwCurrentState, 26 | DWORD dwWin32ExitCode, 27 | DWORD dwWaitHint) 28 | { 29 | static DWORD dwCheckPoint = 1; 30 | PSVC_CONTEXT SvcContext = GetSvcContext(); 31 | 32 | SvcContext->Status.dwCurrentState = dwCurrentState; 33 | SvcContext->Status.dwWin32ExitCode = dwWin32ExitCode; 34 | SvcContext->Status.dwWaitHint = dwWaitHint; 35 | 36 | if (dwCurrentState == SERVICE_START_PENDING) 37 | SvcContext->Status.dwControlsAccepted = 0; 38 | else 39 | SvcContext->Status.dwControlsAccepted = SERVICE_ACCEPT_STOP; 40 | 41 | if ((dwCurrentState == SERVICE_RUNNING) || 42 | (dwCurrentState == SERVICE_STOPPED)) 43 | SvcContext->Status.dwCheckPoint = 0; 44 | else 45 | SvcContext->Status.dwCheckPoint = dwCheckPoint++; 46 | 47 | SetServiceStatus(SvcContext->StatusHandle, &SvcContext->Status); 48 | } 49 | 50 | DWORD SvcRun(DWORD argc, WCHAR *argv[]) 51 | { 52 | PSVC_CONTEXT SvcContext = GetSvcContext(); 53 | DWORD Err; 54 | 55 | SvcContext->hStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 56 | if (!SvcContext->hStopEvent) { 57 | Err = GetLastError(); 58 | LErr("Cant create event Error %d", Err); 59 | ReportSvcStatus(SERVICE_STOPPED, Err, 0); 60 | return Err; 61 | } 62 | 63 | SvcContext->hStoppedEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 64 | if (!SvcContext->hStoppedEvent) { 65 | Err = GetLastError(); 66 | LErr("Cant create event Error %d", Err); 67 | CloseHandle(SvcContext->hStopEvent); 68 | ReportSvcStatus(SERVICE_STOPPED, Err, 0); 69 | return Err; 70 | } 71 | 72 | Err = ServerStart(); 73 | if (Err) { 74 | LErr("Server start failed Error %d", Err); 75 | CloseHandle(SvcContext->hStopEvent); 76 | CloseHandle(SvcContext->hStoppedEvent); 77 | ReportSvcStatus(SERVICE_STOPPED, Err, 0); 78 | return Err; 79 | } 80 | 81 | ReportSvcStatus(SERVICE_RUNNING, NO_ERROR, 0); 82 | LInf("Starting waiting stop signal loop"); 83 | while(!SvcContext->Stopping) { 84 | WaitForSingleObject(SvcContext->hStopEvent, INFINITE); 85 | } 86 | 87 | LInf("Stopping"); 88 | ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 0); 89 | 90 | ServerStop(); 91 | 92 | SetEvent(SvcContext->hStoppedEvent); 93 | ReportSvcStatus( SERVICE_STOPPED, NO_ERROR, 0); 94 | 95 | LInf("Stopped"); 96 | 97 | CloseHandle(SvcContext->hStopEvent); 98 | CloseHandle(SvcContext->hStoppedEvent); 99 | return Err; 100 | } 101 | 102 | VOID SvcStop() 103 | { 104 | PSVC_CONTEXT SvcContext = GetSvcContext(); 105 | 106 | SvcContext->Stopping = 1; 107 | SetEvent(SvcContext->hStopEvent); 108 | WaitForSingleObject(SvcContext->hStoppedEvent, INFINITE); 109 | } 110 | 111 | VOID SvcCtrlHandler(DWORD dwCtrl) 112 | { 113 | PSVC_CONTEXT SvcContext = GetSvcContext(); 114 | 115 | LInf("dwCtrl %d", dwCtrl); 116 | 117 | switch(dwCtrl) { 118 | case SERVICE_CONTROL_STOP: 119 | SvcStop(); 120 | return; 121 | case SERVICE_CONTROL_SHUTDOWN: 122 | SvcStop(); 123 | return; 124 | case SERVICE_CONTROL_INTERROGATE: 125 | break; 126 | default: 127 | break; 128 | } 129 | ReportSvcStatus(SvcContext->Status.dwCurrentState, NO_ERROR, 0); 130 | } 131 | 132 | VOID SvcMain(DWORD argc, WCHAR *argv[]) 133 | { 134 | PSVC_CONTEXT SvcContext = GetSvcContext(); 135 | 136 | SvcContext->StatusHandle = RegisterServiceCtrlHandler(SVC_NAME, SvcCtrlHandler); 137 | if (!SvcContext->StatusHandle) { 138 | LErr("Cant create status handle Error %d", GetLastError()); 139 | return; 140 | } 141 | SvcContext->Status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; 142 | SvcContext->Status.dwServiceSpecificExitCode = 0; 143 | 144 | ReportSvcStatus(SERVICE_START_PENDING, NO_ERROR, 3000); 145 | 146 | SvcRun(argc, argv); 147 | } 148 | 149 | SC_HANDLE ScmOpenSCMHandle() 150 | { 151 | SC_HANDLE hScm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); 152 | 153 | if (hScm == NULL) { 154 | LErr("OpenSCManager Error %d", GetLastError()); 155 | } 156 | 157 | return hScm; 158 | } 159 | 160 | VOID ScmCloseSCMHandle(SC_HANDLE hScm) 161 | { 162 | CloseServiceHandle(hScm); 163 | } 164 | 165 | DWORD ScmInstallService(SC_HANDLE hScm, PWCHAR ServiceName, PWCHAR ServiceBinaryPath) 166 | { 167 | SC_HANDLE hService; 168 | DWORD Err; 169 | 170 | hService = CreateService(hScm, 171 | ServiceName, 172 | ServiceName, 173 | SERVICE_ALL_ACCESS, 174 | SERVICE_WIN32_OWN_PROCESS, 175 | SERVICE_DEMAND_START, 176 | SERVICE_ERROR_NORMAL, 177 | ServiceBinaryPath, 178 | NULL, 179 | NULL, NULL, NULL, NULL); 180 | if (hService == NULL) 181 | { 182 | Err = GetLastError(); 183 | if (Err == ERROR_SERVICE_EXISTS) { 184 | LErr("Service already exists Error %d", Err); 185 | } else { 186 | LErr("Can't create service Error %d", Err); 187 | } 188 | return Err; 189 | } 190 | CloseServiceHandle (hService); 191 | return 0; 192 | } 193 | 194 | DWORD ScmDeleteService(SC_HANDLE hScm, PWCHAR ServiceName) 195 | { 196 | SC_HANDLE hService; 197 | DWORD Err; 198 | 199 | hService = OpenService(hScm, ServiceName, SERVICE_ALL_ACCESS); 200 | if (hService == NULL) { 201 | Err = GetLastError(); 202 | LErr("OpenService Error %d", Err); 203 | return Err; 204 | } 205 | 206 | if (!DeleteService(hService)) { 207 | Err = GetLastError(); 208 | LErr("DeleteService Error %d", Err); 209 | } else 210 | Err = 0; 211 | 212 | CloseServiceHandle(hService); 213 | return Err; 214 | } 215 | 216 | DWORD ScmStartService(SC_HANDLE hScm, PWCHAR ServiceName) 217 | { 218 | SC_HANDLE hService; 219 | DWORD Err; 220 | 221 | hService = OpenService(hScm, ServiceName, SERVICE_ALL_ACCESS); 222 | if (hService == NULL) { 223 | Err = GetLastError(); 224 | LErr("OpenService Error %d", Err); 225 | return Err; 226 | } 227 | 228 | if (!StartService(hService, 0, NULL)) 229 | { 230 | Err = GetLastError(); 231 | if (Err == ERROR_SERVICE_ALREADY_RUNNING) { 232 | LErr("Service already running Err %d", Err); 233 | } else { 234 | LErr("StartService Error %d", Err); 235 | } 236 | } else 237 | Err = 0; 238 | 239 | CloseServiceHandle(hService); 240 | return Err; 241 | } 242 | 243 | DWORD ScmStopService(SC_HANDLE hScm, PWCHAR ServiceName) 244 | { 245 | SC_HANDLE hService; 246 | SERVICE_STATUS ServiceStatus; 247 | DWORD Err; 248 | 249 | hService = OpenService (hScm, ServiceName, SERVICE_ALL_ACCESS); 250 | if (hService == NULL) 251 | { 252 | Err = GetLastError(); 253 | LErr("OpenService Error %d", GetLastError()); 254 | return Err; 255 | } 256 | 257 | if (!ControlService(hService, SERVICE_CONTROL_STOP, &ServiceStatus)) 258 | { 259 | Err = GetLastError(); 260 | LErr("ControlService Error %d", Err); 261 | } else 262 | Err = 0; 263 | 264 | CloseServiceHandle (hService); 265 | return Err; 266 | } 267 | 268 | BOOL IsCmdEqual(PWCHAR Arg, PWCHAR Cmd) 269 | { 270 | return (wcsncmp(Arg, Cmd, wcslen(Arg) + 1) == 0); 271 | } 272 | 273 | BOOL GetBinaryPath(PWCHAR BinaryFilePath, PWCHAR BinaryPath) 274 | { 275 | PWCHAR pLastSlash; 276 | ULONG BinaryPathSize; 277 | 278 | pLastSlash = wcsrchr(BinaryFilePath, L'\\'); 279 | if (!pLastSlash) 280 | return FALSE; 281 | 282 | BinaryPathSize = (ULONG)((ULONG_PTR)pLastSlash - (ULONG_PTR)BinaryFilePath); 283 | memcpy(BinaryPath, BinaryFilePath, BinaryPathSize); 284 | BinaryPath[BinaryPathSize/sizeof(WCHAR)] = L'\0'; 285 | 286 | return TRUE; 287 | } 288 | 289 | int wmain(int argc, WCHAR* argv[]) 290 | { 291 | DWORD Err; 292 | SERVICE_TABLE_ENTRY DispatchTable[] = 293 | { 294 | { SVC_NAME, (LPSERVICE_MAIN_FUNCTION) SvcMain }, 295 | { NULL, NULL } 296 | }; 297 | WCHAR BinaryFilePath[MAX_PATH], BinaryPath[MAX_PATH], LogFilePath[MAX_PATH]; 298 | 299 | DebugInit(); 300 | 301 | Err = MemAllocInit(); 302 | if (Err) 303 | goto terminate; 304 | 305 | if (0 == GetModuleFileName(NULL, BinaryFilePath, MAX_PATH)) { 306 | Err = GetLastError(); 307 | goto mem_alloc_release; 308 | } 309 | 310 | if (!GetBinaryPath(BinaryFilePath, BinaryPath)) { 311 | Err = ERROR_INVALID_PARAMETER; 312 | goto mem_alloc_release; 313 | } 314 | 315 | _snwprintf(LogFilePath, RTL_NUMBER_OF(LogFilePath) - 1, L"%ws\\%ws", 316 | BinaryPath, SVC_LOG_NAME); 317 | LogFilePath[RTL_NUMBER_OF(LogFilePath) - 1] = '\0'; 318 | 319 | Err = GlobalLogInit(LogFilePath, LOG_INF); 320 | if (Err) 321 | goto mem_alloc_release; 322 | 323 | LInf("Starting"); 324 | 325 | if (argc == 1) { 326 | if (!StartServiceCtrlDispatcher(DispatchTable)) 327 | Err = GetLastError(); 328 | else 329 | Err = 0; 330 | } else { 331 | if (argc != 2) { 332 | LErr("Invalid number of args"); 333 | Err = ERROR_INVALID_PARAMETER; 334 | goto log_release; 335 | } 336 | 337 | if (IsCmdEqual(argv[1], L"create")) { 338 | SC_HANDLE hScm; 339 | 340 | hScm = ScmOpenSCMHandle(); 341 | if (!hScm) { 342 | Err = GetLastError(); 343 | goto log_release; 344 | } 345 | Err = ScmInstallService(hScm, SVC_NAME, BinaryFilePath); 346 | ScmCloseSCMHandle(hScm); 347 | } else if (IsCmdEqual(argv[1], L"delete")) { 348 | SC_HANDLE hScm; 349 | 350 | hScm = ScmOpenSCMHandle(); 351 | if (!hScm) { 352 | Err = GetLastError(); 353 | goto log_release; 354 | } 355 | Err = ScmDeleteService(hScm, SVC_NAME); 356 | ScmCloseSCMHandle(hScm); 357 | } else if (IsCmdEqual(argv[1], L"start")) { 358 | SC_HANDLE hScm; 359 | 360 | hScm = ScmOpenSCMHandle(); 361 | if (!hScm) { 362 | Err = GetLastError(); 363 | goto log_release; 364 | } 365 | Err = ScmStartService(hScm, SVC_NAME); 366 | ScmCloseSCMHandle(hScm); 367 | } else if (IsCmdEqual(argv[1], L"stop")) { 368 | SC_HANDLE hScm; 369 | 370 | hScm = ScmOpenSCMHandle(); 371 | if (!hScm) { 372 | Err = GetLastError(); 373 | goto log_release; 374 | } 375 | Err = ScmStopService(hScm, SVC_NAME); 376 | ScmCloseSCMHandle(hScm); 377 | } else { 378 | LErr("Invalid parameter %ws", argv[1]); 379 | Err = ERROR_INVALID_PARAMETER; 380 | } 381 | } 382 | log_release: 383 | LInf("Exiting Error %d", Err); 384 | GlobalLogRelease(); 385 | mem_alloc_release: 386 | MemAllocRelease(); 387 | terminate: 388 | TerminateProcess(GetCurrentProcess(), Err); 389 | return 0; 390 | } 391 | 392 | -------------------------------------------------------------------------------- /Server/memalloc.c: -------------------------------------------------------------------------------- 1 | #include "memalloc.h" 2 | #include "debug.h" 3 | #include "list_entry.h" 4 | #include "spinlock.h" 5 | #include "fmt.h" 6 | #include "misc.h" 7 | 8 | #define MEM_ENTRY_MAGIC 'gMeM' 9 | 10 | #pragma pack(push, 1) 11 | typedef struct _MEM_ENTRY { 12 | LIST_ENTRY ListEntry; 13 | ULONG Magic; 14 | ULONG Size; 15 | PCHAR Component; 16 | PCHAR File; 17 | PCHAR Function; 18 | ULONG Line; 19 | } MEM_ENTRY, *PMEM_ENTRY; 20 | #pragma pack(pop) 21 | 22 | #define MEM_CTX_HASH_BITS 10 23 | #define MEM_CTX_HASH_SIZE (1 << MEM_CTX_HASH_BITS) 24 | 25 | typedef struct _MEM_CTX { 26 | LIST_ENTRY MemEntryList[MEM_CTX_HASH_SIZE]; 27 | SPIN_LOCK MemEntryListLock[MEM_CTX_HASH_SIZE]; 28 | } MEM_CTX, *PMEM_CTX; 29 | 30 | PMEM_CTX g_MemCtx; 31 | 32 | PMEM_CTX GetMemCtx() 33 | { 34 | return g_MemCtx; 35 | } 36 | 37 | PVOID __MemAlloc(SIZE_T Size, PCHAR Component, PCHAR File, PCHAR Function, ULONG Line) 38 | { 39 | PMEM_CTX MemCtx = GetMemCtx(); 40 | PMEM_ENTRY MemEntry; 41 | ULONG Bucket; 42 | 43 | if (!MemCtx) 44 | return NULL; 45 | 46 | MemEntry = HeapAlloc(GetProcessHeap(), 0, sizeof(*MemEntry) + Size); 47 | if (!MemEntry) 48 | return NULL; 49 | 50 | MemEntry->Magic = MEM_ENTRY_MAGIC; 51 | MemEntry->Component = Component; 52 | MemEntry->File = File; 53 | MemEntry->Function = Function; 54 | MemEntry->Line = Line; 55 | MemEntry->Size = (ULONG)Size; 56 | 57 | Bucket = HashPtr(MemEntry) & (MEM_CTX_HASH_SIZE - 1); 58 | SpinLockLock(&MemCtx->MemEntryListLock[Bucket]); 59 | InsertHeadList(&MemCtx->MemEntryList[Bucket], 60 | &MemEntry->ListEntry); 61 | SpinLockUnlock(&MemCtx->MemEntryListLock[Bucket]); 62 | 63 | return (PVOID)(MemEntry + 1); 64 | } 65 | 66 | VOID __MemFree(PVOID pMem) 67 | { 68 | PMEM_CTX MemCtx = GetMemCtx(); 69 | PMEM_ENTRY MemEntry = ((PMEM_ENTRY)pMem - 1); 70 | ULONG Bucket; 71 | 72 | if (!MemCtx) { 73 | DebugPrintf("No g_MemCtx!!!\n"); 74 | return; 75 | } 76 | 77 | if (MemEntry->Magic != MEM_ENTRY_MAGIC) { 78 | DebugPrintf("MemEntry %p invalid magic 0x%x\n", 79 | MemEntry, MemEntry->Magic); 80 | return; 81 | } 82 | 83 | Bucket = HashPtr(MemEntry) & (MEM_CTX_HASH_SIZE - 1); 84 | SpinLockLock(&MemCtx->MemEntryListLock[Bucket]); 85 | RemoveEntryList(&MemEntry->ListEntry); 86 | SpinLockUnlock(&MemCtx->MemEntryListLock[Bucket]); 87 | 88 | HeapFree(GetProcessHeap(), 0, MemEntry); 89 | } 90 | 91 | DWORD MemAllocInit(VOID) 92 | { 93 | PMEM_CTX MemCtx; 94 | ULONG i; 95 | 96 | MemCtx = HeapAlloc(GetProcessHeap(), 0, sizeof(*MemCtx)); 97 | if (!MemCtx) { 98 | DebugPrintf("No memory to alloc MemCtx\n"); 99 | return FB_E_NO_MEMORY; 100 | } 101 | 102 | for (i = 0; i < RTL_NUMBER_OF(MemCtx->MemEntryList); i++) { 103 | InitializeListHead(&MemCtx->MemEntryList[i]); 104 | SpinLockInit(&MemCtx->MemEntryListLock[i]); 105 | } 106 | 107 | g_MemCtx = MemCtx; 108 | return 0; 109 | } 110 | 111 | VOID MemAllocRelease(VOID) 112 | { 113 | PMEM_CTX MemCtx = g_MemCtx; 114 | LIST_ENTRY MemEntryList; 115 | PLIST_ENTRY ListEntry; 116 | PMEM_ENTRY MemEntry; 117 | ULONG i; 118 | 119 | g_MemCtx = NULL; 120 | if (!MemCtx) { 121 | DebugPrintf("No MemCtx\n"); 122 | return; 123 | } 124 | 125 | for (i = 0; i < RTL_NUMBER_OF(MemCtx->MemEntryList); i++) { 126 | SpinLockLock(&MemCtx->MemEntryListLock[i]); 127 | MoveList(&MemEntryList, &MemCtx->MemEntryList[i]); 128 | SpinLockUnlock(&MemCtx->MemEntryListLock[i]); 129 | 130 | for (ListEntry = MemEntryList.Flink; ListEntry != &MemEntryList; 131 | ListEntry = ListEntry->Flink) { 132 | MemEntry = CONTAINING_RECORD(ListEntry, MEM_ENTRY, ListEntry); 133 | DebugPrintf("Memory leak %p size %d allocated at %s:%s():%s,%d\n", 134 | MemEntry, MemEntry->Size, MemEntry->Component, 135 | MemEntry->Function, FmtTruncatePath(MemEntry->File), 136 | MemEntry->Line); 137 | } 138 | } 139 | HeapFree(GetProcessHeap(), 0, MemCtx); 140 | } 141 | 142 | -------------------------------------------------------------------------------- /Server/memalloc.h: -------------------------------------------------------------------------------- 1 | #ifndef __FBACKUP_SERVER_MEM_ALLOC_H__ 2 | #define __FBACKUP_SERVER_MEM_ALLOC_H__ 3 | 4 | #include "base.h" 5 | 6 | DWORD MemAllocInit(VOID); 7 | VOID MemAllocRelease(VOID); 8 | 9 | PVOID __MemAlloc(SIZE_T Size, PCHAR Component, PCHAR File, PCHAR Function, ULONG Line); 10 | VOID __MemFree(PVOID pMem); 11 | 12 | #define MemAlloc(Size) \ 13 | __MemAlloc((Size), __FBACKUP_COMPONENT__, __FILE__, __FUNCTION__, __LINE__) 14 | 15 | #define MemFree(pMem) \ 16 | __MemFree((pMem)) 17 | 18 | #endif -------------------------------------------------------------------------------- /Server/misc.h: -------------------------------------------------------------------------------- 1 | #ifndef __FBACKUP_SERVER_MISC_H__ 2 | #define __FBACKUP_SERVER_MISC_H__ 3 | 4 | #include "base.h" 5 | 6 | FORCEINLINE ULONG ULongMin(ULONG Val1, ULONG Val2) 7 | { 8 | return (Val1 < Val2) ? Val1 : Val2; 9 | } 10 | 11 | FORCEINLINE ULONG HashPtr(PVOID Ptr) 12 | { 13 | ULONG_PTR Val = (ULONG_PTR)Ptr; 14 | ULONG Hash; 15 | ULONG i; 16 | UCHAR c; 17 | 18 | Hash = 5381; 19 | Val = Val >> 3; /* ignore lower 3 bits (usually these bits = 0)*/ 20 | for (i = 0; i < sizeof(Val); i++) { 21 | c = Val & 0xFF; 22 | Hash = ((Hash << 5) + Hash) + c; 23 | Val = Val >> 8; 24 | } 25 | 26 | return Hash; 27 | } 28 | 29 | #endif -------------------------------------------------------------------------------- /Server/server.c: -------------------------------------------------------------------------------- 1 | #include "server.h" 2 | #include "log.h" 3 | #include "list_entry.h" 4 | #include "api.h" 5 | #include "memalloc.h" 6 | #include "time.h" 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | typedef struct _FBSERVER FBSERVER, *PFBSERVER; 13 | typedef struct _FBWORKER FBWORKER, *PFBWORKER; 14 | typedef struct _FBCLIENT FBCLIENT, *PFBCLIENT; 15 | 16 | enum { 17 | FBCLIENT_IO_RECEIVE, 18 | FBCLIENT_IO_SEND 19 | }; 20 | 21 | typedef struct _FBCLIENT_IO { 22 | LIST_ENTRY ListEntry; 23 | PFBCLIENT Client; 24 | ULONG Size; 25 | DWORD Err; 26 | ULONG Operation; 27 | WSAOVERLAPPED Overlapped; 28 | WSABUF Buf; 29 | } FBCLIENT_IO, *PFBCLIENT_IO; 30 | 31 | enum { 32 | FBCLIENT_S_CREATED, 33 | FBCLIENT_S_RECV_HEADER, 34 | FBCLIENT_S_RECV_BODY, 35 | FBCLIENT_S_SEND_HEADER, 36 | FBCLIENT_S_SEND_BODY 37 | }; 38 | 39 | typedef struct _FBCLIENT { 40 | LIST_ENTRY ListEntry; 41 | SOCKET Socket; 42 | CRITICAL_SECTION Lock; 43 | PFBSERVER Server; 44 | LIST_ENTRY IoListHead; 45 | ULONG State; 46 | FB_SRV_REQ_HEADER ReqHeader; 47 | FB_SRV_RESP_HEADER RespHeader; 48 | PVOID ReqBody; 49 | PVOID RespBody; 50 | FBTIME ReqRcvTime; 51 | FBTIME ReqSendTime; 52 | FBTIME ReqHandleTime; 53 | } FBCLIENT, *PFBCLIENT; 54 | 55 | typedef struct _FBSERVER { 56 | HANDLE hIoCompPort; 57 | PFBWORKER *Worker; 58 | ULONG NumWorkers; 59 | WSADATA WsaData; 60 | SOCKET ListenSocket; 61 | HANDLE hAcceptThread; 62 | volatile LONG Stopping; 63 | PADDRINFOW AddrInfo; 64 | CRITICAL_SECTION Lock; 65 | LIST_ENTRY ClientListHead; 66 | SYSTEM_INFO SysInfo; 67 | } FBSERVER, *PFBSERVER; 68 | 69 | typedef struct _FBWORKER { 70 | HANDLE hThread; 71 | volatile LONG Stopping; 72 | PVOID Context; 73 | } FBWORKER, *PFBWORKER; 74 | 75 | FBSERVER g_FbServer; 76 | 77 | PFBSERVER GetFbServer(VOID) 78 | { 79 | return &g_FbServer; 80 | } 81 | 82 | VOID ClientIoFree(PFBCLIENT_IO Io) 83 | { 84 | MemFree(Io); 85 | } 86 | 87 | VOID ClientIoDelete(PFBCLIENT_IO Io) 88 | { 89 | PFBCLIENT Client = Io->Client; 90 | 91 | EnterCriticalSection(&Client->Lock); 92 | RemoveEntryList(&Io->ListEntry); 93 | LeaveCriticalSection(&Client->Lock); 94 | ClientIoFree(Io); 95 | } 96 | 97 | PFBCLIENT_IO ClientIoCreate(PFBCLIENT Client, ULONG Operation, PVOID Buf, ULONG Size) 98 | { 99 | PFBCLIENT_IO Io; 100 | 101 | Io = MemAlloc(sizeof(*Io)); 102 | if (!Io) 103 | return NULL; 104 | 105 | memset(Io, 0, sizeof(*Io)); 106 | Io->Client = Client; 107 | Io->Operation = Operation; 108 | Io->Size = Size; 109 | Io->Buf.buf = (PCHAR)Buf; 110 | Io->Buf.len = Size; 111 | 112 | EnterCriticalSection(&Client->Lock); 113 | InsertTailList(&Client->IoListHead, &Io->ListEntry); 114 | LeaveCriticalSection(&Client->Lock); 115 | return Io; 116 | } 117 | 118 | DWORD ClientIoExec(PFBCLIENT_IO ClientIo) 119 | { 120 | PFBCLIENT Client = ClientIo->Client; 121 | DWORD Flags; 122 | int Result; 123 | DWORD Err; 124 | 125 | switch (ClientIo->Operation) { 126 | case FBCLIENT_IO_RECEIVE: 127 | Flags = 0; 128 | Result = WSARecv(Client->Socket, &ClientIo->Buf, 1, NULL, &Flags, &ClientIo->Overlapped, NULL); 129 | break; 130 | case FBCLIENT_IO_SEND: 131 | Flags = 0; 132 | Result = WSASend(Client->Socket, &ClientIo->Buf, 1, NULL, Flags, &ClientIo->Overlapped, NULL); 133 | break; 134 | default: 135 | LErr("Unknown operation %d", ClientIo->Operation); 136 | return ERROR_INVALID_PARAMETER; 137 | } 138 | 139 | if (Result) { 140 | Err = WSAGetLastError(); 141 | if (Err != WSA_IO_PENDING) 142 | LErr("WSARecv err %d", Err); 143 | else 144 | Err = 0; 145 | } else 146 | Err = 0; 147 | 148 | return Err; 149 | } 150 | 151 | DWORD ClientIoQueue(PFBCLIENT Client, ULONG Operation, PVOID Buf, ULONG Size) 152 | { 153 | PFBCLIENT_IO ClientIo; 154 | DWORD Err; 155 | 156 | ClientIo = ClientIoCreate(Client, Operation, Buf, Size); 157 | if (!ClientIo) { 158 | return FB_E_NO_MEMORY; 159 | } 160 | 161 | Err = ClientIoExec(ClientIo); 162 | if (Err) { 163 | ClientIoDelete(ClientIo); 164 | } 165 | 166 | return Err; 167 | } 168 | 169 | VOID ClientIosDelete(PFBCLIENT Client) 170 | { 171 | LIST_ENTRY IoListHead; 172 | PLIST_ENTRY ListEntry; 173 | PFBCLIENT_IO Io; 174 | 175 | EnterCriticalSection(&Client->Lock); 176 | MoveList(&IoListHead, &Client->IoListHead); 177 | LeaveCriticalSection(&Client->Lock); 178 | 179 | while (!IsListEmpty(&IoListHead)) { 180 | ListEntry = RemoveHeadList(&IoListHead); 181 | Io = CONTAINING_RECORD(ListEntry, FBCLIENT_IO, ListEntry); 182 | ClientIoFree(Io); 183 | } 184 | } 185 | 186 | VOID ServerWorkerStop(PFBWORKER Worker, PFBSERVER Server) 187 | { 188 | Worker->Stopping = 1; 189 | WaitForSingleObject(Worker->hThread, INFINITE); 190 | CloseHandle(Worker->hThread); 191 | } 192 | 193 | VOID ClientFree(PFBCLIENT Client) 194 | { 195 | DeleteCriticalSection(&Client->Lock); 196 | if (Client->ReqBody) 197 | MemFree(Client->ReqBody); 198 | if (Client->RespBody) 199 | MemFree(Client->RespBody); 200 | MemFree(Client); 201 | } 202 | 203 | VOID ClientClose(PFBCLIENT Client) 204 | { 205 | EnterCriticalSection(&Client->Lock); 206 | if (Client->Socket != INVALID_SOCKET) { 207 | shutdown(Client->Socket, SD_BOTH); 208 | closesocket(Client->Socket); 209 | Client->Socket = INVALID_SOCKET; 210 | } 211 | LeaveCriticalSection(&Client->Lock); 212 | ClientIosDelete(Client); 213 | } 214 | 215 | VOID ClientDelete(PFBCLIENT Client) 216 | { 217 | PFBSERVER Server = Client->Server; 218 | 219 | EnterCriticalSection(&Server->Lock); 220 | RemoveEntryList(&Client->ListEntry); 221 | LeaveCriticalSection(&Server->Lock); 222 | 223 | Client->Server = NULL; 224 | ClientClose(Client); 225 | ClientFree(Client); 226 | } 227 | 228 | DWORD ServerTimeRequest(PVOID *pRespBody, ULONG *RespBodySize) 229 | { 230 | PFB_SRV_RESP_TIME pTime; 231 | SYSTEMTIME Time; 232 | 233 | pTime = MemAlloc(sizeof(*pTime)); 234 | if (!pTime) 235 | return FB_E_NO_MEMORY; 236 | 237 | GetSystemTime(&Time); 238 | pTime->Year = Time.wYear; 239 | pTime->Month = Time.wMonth; 240 | pTime->DayOfWeek = Time.wDayOfWeek; 241 | pTime->Day = Time.wDay; 242 | pTime->Hour = Time.wHour; 243 | pTime->Minute = Time.wMinute; 244 | pTime->Second = Time.wSecond; 245 | pTime->Milliseconds = Time.wMilliseconds; 246 | 247 | *pRespBody = pTime; 248 | *RespBodySize = sizeof(*pTime); 249 | 250 | return 0; 251 | } 252 | 253 | DWORD ServerHandleRequest(PFB_SRV_REQ_HEADER ReqHeader, PVOID ReqBody, 254 | PFB_SRV_RESP_HEADER RespHeader, PVOID *pRespBody) 255 | { 256 | DWORD Err; 257 | ULONG RespBodySize = 0; 258 | 259 | *pRespBody = NULL; 260 | switch (ReqHeader->Type) { 261 | case FB_SRV_REQ_TYPE_TIME: 262 | Err = ServerTimeRequest(pRespBody, &RespBodySize); 263 | break; 264 | default: 265 | LErr("Unknown request type %d", ReqHeader->Type); 266 | Err = FB_E_UNK_REQUEST; 267 | break; 268 | } 269 | 270 | RespHeader->Magic = FB_SRV_RESP_MAGIC; 271 | RespHeader->Err = Err; 272 | RespHeader->Size = RespBodySize; 273 | RespHeader->Type = ReqHeader->Type; 274 | RespHeader->Id = ReqHeader->Id; 275 | 276 | return Err; 277 | } 278 | 279 | VOID ServerWorkerHandleIo(PFBCLIENT Client, PFBCLIENT_IO ClientIo, ULONG Size, DWORD Err) 280 | { 281 | LDbg("Client %p State %d Size %d ClientIo %p Op %d Err %d", 282 | Client, Client->State, Size, ClientIo, ClientIo->Operation, Err); 283 | 284 | if (Err) { 285 | ClientIoDelete(ClientIo); 286 | goto fail_client; 287 | } 288 | 289 | if (ClientIo->Size != Size) { 290 | if (Size == 0 && ClientIo->Operation == FBCLIENT_IO_RECEIVE) { 291 | ClientIoDelete(ClientIo); 292 | goto close_client; 293 | } 294 | 295 | LErr("Client %p ClientIo %p Size %d vs. Received %d", 296 | Client, ClientIo, ClientIo->Size, Size); 297 | ClientIoDelete(ClientIo); 298 | goto fail_client; 299 | } 300 | 301 | ClientIoDelete(ClientIo); 302 | 303 | restart: 304 | switch (Client->State) { 305 | case FBCLIENT_S_RECV_HEADER: { 306 | PFB_SRV_REQ_HEADER ReqHeader = &Client->ReqHeader; 307 | 308 | if (ReqHeader->Magic != FB_SRV_REQ_MAGIC) { 309 | LErr("Invalid client request magic 0x%x", ReqHeader->Magic); 310 | goto fail_client; 311 | return; 312 | } 313 | 314 | if (ReqHeader->Type <= FB_SRV_REQ_TYPE_INVALID || 315 | ReqHeader->Type >= FB_SRV_REQ_TYPE_MAX) { 316 | LErr("Invalid client request type %d", ReqHeader->Type); 317 | goto fail_client; 318 | } 319 | 320 | if (ReqHeader->Size > FB_SRV_MAX_BODY_SIZE) { 321 | LErr("Invalid client request size %d", ReqHeader->Size); 322 | goto fail_client; 323 | } 324 | 325 | if (ReqHeader->Size) { 326 | Client->ReqBody = MemAlloc(ReqHeader->Size); 327 | if (!Client->ReqBody) { 328 | LErr("No memory"); 329 | goto fail_client; 330 | } 331 | 332 | Client->State = FBCLIENT_S_RECV_BODY; 333 | Err = ClientIoQueue(Client, FBCLIENT_IO_RECEIVE, Client->ReqBody, ReqHeader->Size); 334 | if (Err) 335 | goto fail_client; 336 | } else { 337 | Client->State = FBCLIENT_S_RECV_BODY; 338 | goto restart; 339 | } 340 | break; 341 | } 342 | case FBCLIENT_S_RECV_BODY: 343 | FbTimeStop(&Client->ReqRcvTime); 344 | FbTimeStart(&Client->ReqHandleTime); 345 | Err = ServerHandleRequest(&Client->ReqHeader, Client->ReqBody, 346 | &Client->RespHeader, &Client->RespBody); 347 | if (Err) 348 | goto fail_client; 349 | FbTimeStop(&Client->ReqHandleTime); 350 | 351 | if (Client->ReqBody) { 352 | MemFree(Client->ReqBody); 353 | Client->ReqBody = NULL; 354 | } 355 | 356 | FbTimeStart(&Client->ReqSendTime); 357 | Client->State = FBCLIENT_S_SEND_HEADER; 358 | Err = ClientIoQueue(Client, FBCLIENT_IO_SEND, &Client->RespHeader, sizeof(Client->RespHeader)); 359 | if (Err) 360 | goto fail_client; 361 | break; 362 | case FBCLIENT_S_SEND_HEADER: 363 | if (Client->RespHeader.Size == 0) { 364 | Client->State = FBCLIENT_S_CREATED; 365 | break; 366 | } 367 | 368 | Client->State = FBCLIENT_S_SEND_BODY; 369 | Err = ClientIoQueue(Client, FBCLIENT_IO_SEND, Client->RespBody, Client->RespHeader.Size); 370 | if (Err) 371 | goto fail_client; 372 | break; 373 | case FBCLIENT_S_SEND_BODY: 374 | if (Client->RespBody) { 375 | MemFree(Client->RespBody); 376 | Client->RespBody = NULL; 377 | } 378 | FbTimeStop(&Client->ReqSendTime); 379 | LInf("Req RcvTime=%lld HandleTime=%lld SendTime=%lld", 380 | FbTimeDeltaNs(&Client->ReqRcvTime), FbTimeDeltaNs(&Client->ReqHandleTime), 381 | FbTimeDeltaNs(&Client->ReqSendTime)); 382 | 383 | FbTimeStart(&Client->ReqRcvTime); 384 | Client->State = FBCLIENT_S_RECV_HEADER; 385 | Err = ClientIoQueue(Client, FBCLIENT_IO_RECEIVE, 386 | &Client->ReqHeader, sizeof(Client->ReqHeader)); 387 | if (Err) 388 | goto fail_client; 389 | break; 390 | default: 391 | LErr("Unknown client %p state %d", Client, Client->State); 392 | goto fail_client; 393 | } 394 | 395 | return; 396 | 397 | close_client: 398 | fail_client: 399 | ClientDelete(Client); 400 | return; 401 | } 402 | 403 | DWORD ServerWorkerRoutine(PFBWORKER Worker) 404 | { 405 | PFBSERVER Server = (PFBSERVER)Worker->Context; 406 | DWORD IoBytes; 407 | ULONG_PTR CompKey; 408 | OVERLAPPED *pOverlapped; 409 | DWORD Err; 410 | PFBCLIENT Client; 411 | PFBCLIENT_IO ClientIo; 412 | 413 | LInf("Worker starting"); 414 | 415 | while (!Worker->Stopping) { 416 | if (!GetQueuedCompletionStatus(Server->hIoCompPort, &IoBytes, 417 | &CompKey, &pOverlapped, 1000)) { 418 | Err = GetLastError(); 419 | } else 420 | Err = 0; 421 | 422 | if (Worker->Stopping) 423 | break; 424 | 425 | if (Err == WAIT_TIMEOUT) 426 | continue; 427 | 428 | Client = (PFBCLIENT)CompKey; 429 | ClientIo = CONTAINING_RECORD(pOverlapped, FBCLIENT_IO, Overlapped); 430 | if (Err) 431 | LErr("GetQueuedCompletionStatus failed Error %d", Err); 432 | 433 | ServerWorkerHandleIo(Client, ClientIo, IoBytes, Err); 434 | } 435 | 436 | LInf("Worker stopped"); 437 | return 0; 438 | } 439 | 440 | DWORD ServerWorkerStart(PFBWORKER Worker, PFBSERVER Server) 441 | { 442 | memset(Worker, 0, sizeof(*Worker)); 443 | Worker->Context = Server; 444 | Worker->hThread = CreateThread(NULL, 0, ServerWorkerRoutine, Worker, 0, NULL); 445 | if (!Worker->hThread) 446 | return GetLastError(); 447 | 448 | return 0; 449 | } 450 | 451 | DWORD ServerCreateWorkers(PFBSERVER Server, ULONG NumWorkers) 452 | { 453 | ULONG i, j; 454 | DWORD Err; 455 | 456 | Server->NumWorkers = 0; 457 | Server->Worker = (PFBWORKER *)MemAlloc(NumWorkers*sizeof(PFBWORKER *)); 458 | if (!Server->Worker) 459 | return FB_E_NO_MEMORY; 460 | 461 | memset(Server->Worker, 0, NumWorkers*sizeof(PFBWORKER *)); 462 | for (i = 0; i < NumWorkers; i++) { 463 | Server->Worker[i] = (PFBWORKER)MemAlloc(sizeof(FBWORKER)); 464 | if (!Server->Worker[i]) { 465 | Err = GetLastError(); 466 | goto fail; 467 | } 468 | 469 | Err = ServerWorkerStart(Server->Worker[i], Server); 470 | if (Err) { 471 | MemFree(Server->Worker[i]); 472 | goto fail; 473 | } 474 | } 475 | 476 | Server->NumWorkers = NumWorkers; 477 | return 0; 478 | 479 | fail: 480 | for (j = 0; j < i; j++) 481 | Server->Worker[j]->Stopping = 1; 482 | 483 | for (j = 0; j < i; j++) { 484 | ServerWorkerStop(Server->Worker[i], Server); 485 | MemFree(Server->Worker[i]); 486 | } 487 | MemFree(Server->Worker); 488 | Server->Worker = NULL; 489 | 490 | return Err; 491 | } 492 | 493 | VOID ServerDeleteWorkers(PFBSERVER Server) 494 | { 495 | ULONG i; 496 | 497 | for (i = 0; i < Server->NumWorkers; i++) 498 | Server->Worker[i]->Stopping = 1; 499 | 500 | for (i = 0; i < Server->NumWorkers; i++) { 501 | ServerWorkerStop(Server->Worker[i], Server); 502 | MemFree(Server->Worker[i]); 503 | } 504 | MemFree(Server->Worker); 505 | Server->Worker = NULL; 506 | Server->NumWorkers = 0; 507 | } 508 | 509 | DWORD ServerBind(PFBSERVER Server) 510 | { 511 | SOCKET ListenSocket; 512 | DWORD Err; 513 | ADDRINFOW Hints, *AddrInfo; 514 | 515 | memset(&Hints, 0, sizeof(Hints)); 516 | 517 | Hints.ai_family = AF_INET; 518 | Hints.ai_socktype = SOCK_STREAM; 519 | Hints.ai_protocol = IPPROTO_TCP; 520 | Hints.ai_flags = AI_PASSIVE; 521 | 522 | if (GetAddrInfoW(NULL, FB_SRV_PORT, &Hints, &AddrInfo)) { 523 | Err = WSAGetLastError(); 524 | LErr("GetAddrInfoW failed Error %d", Err); 525 | return Err; 526 | } 527 | 528 | ListenSocket = socket(AddrInfo->ai_family, AddrInfo->ai_socktype, AddrInfo->ai_protocol); 529 | if (ListenSocket == INVALID_SOCKET) { 530 | Err = WSAGetLastError(); 531 | LErr("socket failed Error %d", Err); 532 | FreeAddrInfoW(AddrInfo); 533 | return Err; 534 | } 535 | 536 | if (bind(ListenSocket, AddrInfo->ai_addr, (int)AddrInfo->ai_addrlen)) { 537 | Err = WSAGetLastError(); 538 | LErr("bind failed Error %d", Err); 539 | FreeAddrInfoW(AddrInfo); 540 | closesocket(ListenSocket); 541 | return Err; 542 | } 543 | FreeAddrInfoW(AddrInfo); 544 | 545 | Server->ListenSocket = ListenSocket; 546 | LInf("Binded"); 547 | return 0; 548 | } 549 | 550 | PFBCLIENT ClientCreate(PFBSERVER Server, SOCKET Socket) 551 | { 552 | PFBCLIENT Client; 553 | BOOL Inserted; 554 | 555 | if (Server->Stopping) 556 | return NULL; 557 | 558 | Client = MemAlloc(sizeof(*Client)); 559 | if (!Client) 560 | return NULL; 561 | 562 | memset(Client, 0, sizeof(*Client)); 563 | InitializeListHead(&Client->IoListHead); 564 | InitializeCriticalSection(&Client->Lock); 565 | Client->Socket = Socket; 566 | EnterCriticalSection(&Server->Lock); 567 | if (!Server->Stopping) { 568 | Client->Server = Server; 569 | Client->State = FBCLIENT_S_CREATED; 570 | InsertTailList(&Server->ClientListHead, &Client->ListEntry); 571 | Inserted = TRUE; 572 | } else 573 | Inserted = FALSE; 574 | LeaveCriticalSection(&Server->Lock); 575 | 576 | if (!Inserted) { 577 | Client->Socket = INVALID_SOCKET; 578 | ClientFree(Client); 579 | Client = NULL; 580 | } 581 | 582 | return Client; 583 | } 584 | 585 | DWORD ServerAcceptRoutine(PFBSERVER Server) 586 | { 587 | DWORD Err; 588 | SOCKET Socket; 589 | PFBCLIENT Client; 590 | 591 | while (!Server->Stopping) { 592 | LDbg("Start accepting"); 593 | Socket = accept(Server->ListenSocket, NULL, NULL); 594 | if (Socket == INVALID_SOCKET) { 595 | Err = WSAGetLastError(); 596 | LErr("Accept Error %d", Err); 597 | continue; 598 | } 599 | LDbg("Accept succeded"); 600 | Client = ClientCreate(Server, Socket); 601 | if (!Client) { 602 | if (!Server->Stopping) 603 | LErr("Can't create client"); 604 | else 605 | LWrn("Can't insert client - server stopping"); 606 | continue; 607 | } 608 | 609 | if (!CreateIoCompletionPort((HANDLE)Socket, Server->hIoCompPort, 610 | (ULONG_PTR)Client, 0)) { 611 | Err = GetLastError(); 612 | LErr("CreateIoCompletionPort failed Error %d", Err); 613 | ClientDelete(Client); 614 | } 615 | LDbg("Client %p attached to IO completion port", Client); 616 | FbTimeStart(&Client->ReqRcvTime); 617 | Client->State = FBCLIENT_S_RECV_HEADER; 618 | Err = ClientIoQueue(Client, FBCLIENT_IO_RECEIVE, 619 | &Client->ReqHeader, sizeof(Client->ReqHeader)); 620 | if (Err) { 621 | LErr("ClientIoQueue failed Error %d", Err); 622 | ClientDelete(Client); 623 | } 624 | } 625 | LInf("Accept thread stopped"); 626 | return 0; 627 | } 628 | 629 | DWORD LocalServerConnect(SOCKET *pSocket) 630 | { 631 | SOCKET Socket; 632 | DWORD Err; 633 | ADDRINFOW Hints, *AddrInfo; 634 | 635 | memset(&Hints, 0, sizeof(Hints)); 636 | 637 | Hints.ai_family = AF_INET; 638 | Hints.ai_socktype = SOCK_STREAM; 639 | Hints.ai_protocol = IPPROTO_TCP; 640 | Hints.ai_flags = AI_PASSIVE; 641 | 642 | if (GetAddrInfoW(L"127.0.0.1", FB_SRV_PORT, &Hints, &AddrInfo)) { 643 | Err = WSAGetLastError(); 644 | LErr("GetAddrInfoW failed Error %d", Err); 645 | return Err; 646 | } 647 | 648 | Socket = socket(AddrInfo->ai_family, AddrInfo->ai_socktype, AddrInfo->ai_protocol); 649 | if (Socket == INVALID_SOCKET) { 650 | Err = WSAGetLastError(); 651 | return Err; 652 | } 653 | 654 | if (connect(Socket, AddrInfo->ai_addr, (int)AddrInfo->ai_addrlen)) { 655 | Err = WSAGetLastError(); 656 | LErr("connect failed Error %d", Err); 657 | closesocket(Socket); 658 | return Err; 659 | } 660 | 661 | *pSocket = Socket; 662 | return 0; 663 | } 664 | 665 | DWORD ServerStart(VOID) 666 | { 667 | PFBSERVER Server = GetFbServer(); 668 | DWORD Err; 669 | 670 | LInf("Server starting"); 671 | memset(Server, 0, sizeof(*Server)); 672 | InitializeListHead(&Server->ClientListHead); 673 | InitializeCriticalSection(&Server->Lock); 674 | 675 | GetSystemInfo(&Server->SysInfo); 676 | 677 | Err = WSAStartup(WINSOCK_VERSION, &Server->WsaData); 678 | if (Err) { 679 | LErr("WSAStartup failed Error %d", Err); 680 | Server->Stopping = 1; 681 | goto fail; 682 | } 683 | 684 | LInf("WSA version 0x%x", Server->WsaData.wVersion); 685 | 686 | Err = ServerBind(Server); 687 | if (Err) { 688 | Server->Stopping = 1; 689 | goto fail_wsa_cleanup; 690 | } 691 | 692 | if (listen(Server->ListenSocket, SOMAXCONN)) { 693 | Err = WSAGetLastError(); 694 | LErr("listen Error %d", Err); 695 | goto fail_close_listen_socket; 696 | } 697 | 698 | Server->hAcceptThread = CreateThread(NULL, 0, ServerAcceptRoutine, Server, 0, NULL); 699 | if (!Server->hAcceptThread) { 700 | Err = GetLastError(); 701 | Server->Stopping = 1; 702 | goto fail_close_listen_socket; 703 | } 704 | 705 | Server->hIoCompPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); 706 | if (!Server->hIoCompPort) { 707 | Err = GetLastError(); 708 | Server->Stopping = 1; 709 | goto fail_delete_accept_thread; 710 | } 711 | 712 | LInf("Number of CPU's %d", Server->SysInfo.dwNumberOfProcessors); 713 | Err = ServerCreateWorkers(Server, Server->SysInfo.dwNumberOfProcessors); 714 | if (Err) { 715 | LErr("ServerCreateWorkers Error %d", Err); 716 | Server->Stopping = 1; 717 | goto fail_close_io_comp_port; 718 | } 719 | 720 | Err = NO_ERROR; 721 | LInf("Server start Err %d", Err); 722 | return Err; 723 | fail_close_io_comp_port: 724 | CloseHandle(Server->hIoCompPort); 725 | fail_delete_accept_thread: 726 | WaitForSingleObject(Server->hAcceptThread, INFINITE); 727 | CloseHandle(Server->hAcceptThread); 728 | fail_close_listen_socket: 729 | closesocket(Server->ListenSocket); 730 | fail_wsa_cleanup: 731 | if (WSACleanup()) { 732 | LErr("WSACleanup failed Error %d", WSAGetLastError()); 733 | } 734 | fail: 735 | DeleteCriticalSection(&Server->Lock); 736 | LErr("Server start Error %d", Err); 737 | return Err; 738 | } 739 | 740 | VOID ServerStopAcceptThread(PFBSERVER Server) 741 | { 742 | SOCKET Socket; 743 | 744 | /* Kick accept by connect */ 745 | if (0 == LocalServerConnect(&Socket)) { 746 | closesocket(Socket); 747 | } 748 | 749 | WaitForSingleObject(Server->hAcceptThread, INFINITE); 750 | CloseHandle(Server->hAcceptThread); 751 | } 752 | 753 | VOID ServerDeleteClients(PFBSERVER Server) 754 | { 755 | PLIST_ENTRY ListEntry; 756 | LIST_ENTRY ClientListHead; 757 | PFBCLIENT Client; 758 | 759 | LInf("Moving clients to delete"); 760 | EnterCriticalSection(&Server->Lock); 761 | MoveList(&ClientListHead, &Server->ClientListHead); 762 | LeaveCriticalSection(&Server->Lock); 763 | LInf("Deleting clients"); 764 | while (!IsListEmpty(&ClientListHead)) { 765 | ListEntry = RemoveHeadList(&ClientListHead); 766 | Client = CONTAINING_RECORD(ListEntry, FBCLIENT, ListEntry); 767 | ClientClose(Client); 768 | ClientFree(Client); 769 | } 770 | LInf("Clients deleted"); 771 | } 772 | 773 | VOID ServerStop(VOID) 774 | { 775 | PFBSERVER Server = GetFbServer(); 776 | 777 | LInf("Server stopping"); 778 | 779 | Server->Stopping = 1; 780 | ServerStopAcceptThread(Server); 781 | closesocket(Server->ListenSocket); 782 | 783 | ServerDeleteWorkers(Server); 784 | LInf("Workers stopped"); 785 | 786 | CloseHandle(Server->hIoCompPort); 787 | ServerDeleteClients(Server); 788 | 789 | if (WSACleanup()) { 790 | LErr("WSACleanup failed Error %d", WSAGetLastError()); 791 | } 792 | 793 | DeleteCriticalSection(&Server->Lock); 794 | LInf("Resources released"); 795 | LInf("Server stopped"); 796 | } -------------------------------------------------------------------------------- /Server/server.h: -------------------------------------------------------------------------------- 1 | #ifndef __FBACKUP_SERVER_SERVER_H__ 2 | #define __FBACKUP_SERVER_SERVER_H__ 3 | 4 | #include "base.h" 5 | 6 | DWORD ServerStart(VOID); 7 | VOID ServerStop(VOID); 8 | 9 | #endif -------------------------------------------------------------------------------- /Server/spinlock.h: -------------------------------------------------------------------------------- 1 | #ifndef __FBACKUP_SERVER_SPINLOCK_H__ 2 | #define __FBACKUP_SERVER_SPINLOCK_H__ 3 | 4 | #include "base.h" 5 | 6 | typedef struct _SPIN_LOCK { 7 | volatile LONG Value; 8 | DWORD Owner; 9 | } SPIN_LOCK, *PSPIN_LOCK; 10 | 11 | FORCEINLINE VOID SpinLockInit(PSPIN_LOCK Lock) 12 | { 13 | Lock->Value = 0; 14 | } 15 | 16 | FORCEINLINE VOID SpinLockLock(PSPIN_LOCK Lock) 17 | { 18 | while (1) { 19 | if (0 == InterlockedCompareExchange(&Lock->Value, 1, 0)) 20 | break; 21 | 22 | _mm_pause(); 23 | } 24 | Lock->Owner = GetCurrentThreadId(); 25 | } 26 | 27 | FORCEINLINE VOID SpinLockUnlock(PSPIN_LOCK Lock) 28 | { 29 | Lock->Owner = 0; 30 | InterlockedCompareExchange(&Lock->Value, 0, 1); 31 | } 32 | 33 | #endif -------------------------------------------------------------------------------- /Server/time.c: -------------------------------------------------------------------------------- 1 | #include "time.h" 2 | #include "log.h" 3 | 4 | DWORD FbTimeStart(PFBTIME Time) 5 | { 6 | DWORD Err; 7 | 8 | memset(Time, 0, sizeof(*Time)); 9 | if (!QueryPerformanceCounter(&Time->Start)) { 10 | Err = GetLastError(); 11 | LErr("QueryPerformanceCounter failed Error %d", Err); 12 | return Err; 13 | } 14 | 15 | if (!QueryPerformanceFrequency(&Time->Freq)) { 16 | Err = GetLastError(); 17 | LErr("QueryPerformanceFrequency failed Error %d", Err); 18 | return Err; 19 | } 20 | 21 | if (Time->Freq.QuadPart == 0) { 22 | LErr("Time->Freq.QuadPart == 0"); 23 | return FB_E_INVAL; 24 | } 25 | 26 | return 0; 27 | } 28 | 29 | DWORD FbTimeStop(PFBTIME Time) 30 | { 31 | DWORD Err; 32 | 33 | if (Time->Freq.QuadPart == 0) 34 | return FB_E_INVAL; 35 | 36 | if (!QueryPerformanceCounter(&Time->Stop)) { 37 | Err = GetLastError(); 38 | LErr("QueryPerformanceCounter failed Error %d", Err); 39 | return Err; 40 | } 41 | 42 | if (Time->Stop.QuadPart < Time->Start.QuadPart) { 43 | LErr("Time->Stop.QuadPart < Time->Start.QuadPart"); 44 | return FB_E_INVAL; 45 | } 46 | 47 | Time->DeltaNs = (1000000000ULL*(Time->Stop.QuadPart - Time->Start.QuadPart))/Time->Freq.QuadPart; 48 | return 0; 49 | } -------------------------------------------------------------------------------- /Server/time.h: -------------------------------------------------------------------------------- 1 | #ifndef __FBACKUP_SERVER_TIME_H__ 2 | #define __FBACKUP_SERVER_TIME_H__ 3 | 4 | #include "base.h" 5 | 6 | typedef struct _FBTIME { 7 | LARGE_INTEGER Start; 8 | LARGE_INTEGER Stop; 9 | LARGE_INTEGER Freq; 10 | ULONG64 DeltaNs; 11 | } FBTIME, *PFBTIME; 12 | 13 | DWORD FbTimeStart(PFBTIME Time); 14 | DWORD FbTimeStop(PFBTIME Time); 15 | 16 | FORCEINLINE ULONG64 FbTimeDeltaNs(PFBTIME Time) 17 | { 18 | return Time->DeltaNs; 19 | } 20 | #endif -------------------------------------------------------------------------------- /Shared/error.h: -------------------------------------------------------------------------------- 1 | #ifndef __FBACKUP_ERROR_H__ 2 | #define __FBACKUP_ERROR_H__ 3 | 4 | #define FB_E_BASE (0xD0000000) 5 | #define FB_E_NO_MEMORY (FB_E_BASE + 1) 6 | #define FB_E_UNK_REQUEST (FB_E_BASE + 2) 7 | #define FB_E_INVAL (FB_E_BASE + 3) 8 | #define FB_E_UNIMPL (FB_E_BASE + 4) 9 | #define FB_E_BAD_MAGIC (FB_E_BASE + 5) 10 | #define FB_E_BAD_SIZE (FB_E_BASE + 6) 11 | #define FB_E_INCOMP_HEADER (FB_E_BASE + 7) 12 | #define FB_E_INCOMP_DATA (FB_E_BASE + 8) 13 | #define FB_E_BAD_ALIGNMENT (FB_E_BASE + 9) 14 | 15 | #endif --------------------------------------------------------------------------------