ChipMaster's trial hacks on C++CMS starting with v1.2.1. Not sure I'll follow on with the v2 since it looks to be breaking and mostly frivolous.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

278 lines
6.4 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (C) 2008-2012 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
  4. //
  5. // See accompanying file COPYING.TXT file for licensing details.
  6. //
  7. ///////////////////////////////////////////////////////////////////////////////
  8. #define CPPCMS_SOURCE
  9. #define NOMINMAX
  10. #include "session_win32_file_storage.h"
  11. #include <cppcms/cppcms_error.h>
  12. #include <cppcms/config.h>
  13. #include <booster/nowide/convert.h>
  14. #include <booster/nowide/cstdio.h>
  15. #include "crc32.h"
  16. #include <booster/auto_ptr_inc.h>
  17. #include <time.h>
  18. #include <sstream>
  19. #include <cppcms/cstdint.h>
  20. #include <windows.h>
  21. namespace cppcms {
  22. namespace sessions {
  23. struct session_file_storage::_data {};
  24. session_file_storage::session_file_storage(std::string path)
  25. {
  26. if(path.empty()){
  27. if(::getenv("TEMP"))
  28. path_=std::string(::getenv("TEMP")) + "/cppcms_sessions";
  29. else if(::getenv("TMP"))
  30. path_=std::string(::getenv("TMP")) + "/cppcms_sessions";
  31. else
  32. path_ = "C:/TEMP";
  33. }
  34. else
  35. path_=path;
  36. if(!::CreateDirectory(path_.c_str(),NULL)) {
  37. if(GetLastError()!=ERROR_ALREADY_EXISTS) {
  38. throw cppcms_error("Failed to create a directory for session storage " + path_);
  39. }
  40. }
  41. }
  42. session_file_storage::~session_file_storage()
  43. {
  44. }
  45. std::string session_file_storage::file_name(std::string const &sid)
  46. {
  47. return path_ + "/" + sid;
  48. }
  49. class session_file_storage::locked_file {
  50. public:
  51. locked_file(session_file_storage *object,std::string sid) :
  52. h_(INVALID_HANDLE_VALUE)
  53. {
  54. name_=object->file_name(sid);
  55. int sleep_time=0;
  56. for(;;) {
  57. h_=::CreateFileW(booster::nowide::convert(name_).c_str(),
  58. GENERIC_READ | GENERIC_WRITE,
  59. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  60. NULL,
  61. OPEN_ALWAYS,
  62. FILE_ATTRIBUTE_NORMAL,
  63. NULL);
  64. if(h_==INVALID_HANDLE_VALUE) {
  65. if(GetLastError()==ERROR_ACCESS_DENIED && sleep_time<1000 ) {
  66. ::Sleep(sleep_time);
  67. sleep_time = sleep_time == 0 ? 1 : sleep_time * 2;
  68. continue;
  69. }
  70. else {
  71. std::ostringstream tmp;
  72. tmp << "Failed to open file:" + name_ + "error code " <<std::hex << ::GetLastError();
  73. throw cppcms_error(tmp.str());
  74. }
  75. }
  76. else
  77. break;
  78. }
  79. OVERLAPPED ov = OVERLAPPED();
  80. if(!::LockFileEx(h_,LOCKFILE_EXCLUSIVE_LOCK,0,0,16,&ov)) {
  81. ::CloseHandle(h_);
  82. h_=INVALID_HANDLE_VALUE;
  83. throw cppcms_error("Failed to lock file:"+name_);
  84. }
  85. }
  86. ~locked_file()
  87. {
  88. if(h_==INVALID_HANDLE_VALUE)
  89. return;
  90. OVERLAPPED ov = OVERLAPPED();
  91. ::UnlockFileEx(h_,0,0,16,&ov);
  92. ::CloseHandle(h_);
  93. }
  94. HANDLE handle() { return h_; }
  95. std::string name() { return name_; }
  96. private:
  97. HANDLE h_;
  98. std::string name_;
  99. };
  100. void session_file_storage::save(std::string const &sid,time_t timeout,std::string const &in)
  101. {
  102. locked_file file(this,sid);
  103. save_to_file(file.handle(),timeout,in);
  104. }
  105. bool session_file_storage::load(std::string const &sid,time_t &timeout,std::string &out)
  106. {
  107. locked_file file(this,sid);
  108. if(!read_from_file(file.handle(),timeout,out)) {
  109. ::DeleteFile(file.name().c_str());
  110. return false;
  111. }
  112. return true;
  113. }
  114. void session_file_storage::remove(std::string const &sid)
  115. {
  116. locked_file file(this,sid);
  117. ::DeleteFile(file.name().c_str());
  118. }
  119. bool session_file_storage::is_blocking()
  120. {
  121. return true;
  122. }
  123. bool session_file_storage::read_timestamp(HANDLE h)
  124. {
  125. int64_t stamp;
  126. if(!read_all(h,&stamp,sizeof(stamp)) || stamp < ::time(0))
  127. return false;
  128. return true;
  129. }
  130. bool session_file_storage::read_from_file(HANDLE h,time_t &timeout,std::string &data)
  131. {
  132. int64_t f_timeout;
  133. uint32_t crc;
  134. uint32_t size;
  135. if(!read_all(h,&f_timeout,sizeof(f_timeout)))
  136. return false;
  137. if(f_timeout < time(0))
  138. return false;
  139. if(!read_all(h,&crc,sizeof(crc)) || !read_all(h,&size,sizeof(size)))
  140. return false;
  141. std::vector<char> buffer(size,0);
  142. impl::crc32_calc crc_calc;
  143. if(size > 0) {
  144. if(!read_all(h,&buffer.front(),size))
  145. return false;
  146. crc_calc.process_bytes(&buffer.front(),size);
  147. }
  148. uint32_t real_crc=crc_calc.checksum();
  149. if(crc != real_crc)
  150. return false;
  151. timeout=f_timeout;
  152. if(size > 0)
  153. data.assign(&buffer.front(),size);
  154. else
  155. data.clear();
  156. return true;
  157. }
  158. void session_file_storage::save_to_file(HANDLE h,time_t timeout,std::string const &in)
  159. {
  160. struct {
  161. int64_t timeout;
  162. uint32_t crc;
  163. uint32_t size;
  164. } tmp = { timeout, 0, in.size() };
  165. impl::crc32_calc crc_calc;
  166. crc_calc.process_bytes(in.data(),in.size());
  167. tmp.crc=crc_calc.checksum();
  168. if(!write_all(h,&tmp,sizeof(tmp)) || !write_all(h,in.data(),in.size()))
  169. throw cppcms_error("Failed to write to file");
  170. }
  171. bool session_file_storage::write_all(HANDLE h,void const *vbuf,int n)
  172. {
  173. DWORD written;
  174. if(!::WriteFile(h,vbuf,n,&written,NULL) || written!=unsigned(n))
  175. return false;
  176. return true;
  177. }
  178. bool session_file_storage::read_all(HANDLE h,void *vbuf,int n)
  179. {
  180. DWORD read;
  181. if(!::ReadFile(h,vbuf,n,&read,NULL) || read!=unsigned(n))
  182. return false;
  183. return true;
  184. }
  185. void session_file_storage::gc()
  186. {
  187. std::auto_ptr<_WIN32_FIND_DATAW> entry(new _WIN32_FIND_DATAW);
  188. HANDLE d=INVALID_HANDLE_VALUE;
  189. std::string search_path = path_ + "/*";
  190. try{
  191. if((d=::FindFirstFileW(booster::nowide::convert(search_path).c_str(),entry.get()))==INVALID_HANDLE_VALUE) {
  192. if(GetLastError() == ERROR_FILE_NOT_FOUND)
  193. return;
  194. throw cppcms_error("Failed to open directory :"+path_);
  195. }
  196. do {
  197. if(entry->cFileName[32]!=0)
  198. continue;
  199. int i;
  200. std::string filename=booster::nowide::convert(entry->cFileName);
  201. for(i=0;i<32;i++) {
  202. if(!isxdigit(filename[i]))
  203. break;
  204. }
  205. if(i!=32)
  206. continue;
  207. {
  208. locked_file file(this,filename);
  209. if(!read_timestamp(file.handle()))
  210. ::DeleteFileW(booster::nowide::convert(file.name()).c_str());
  211. }
  212. } while(::FindNextFileW(d,entry.get()));
  213. ::FindClose(d);
  214. }
  215. catch(...) {
  216. if(d!=INVALID_HANDLE_VALUE) ::FindClose(d);
  217. throw;
  218. }
  219. }
  220. struct session_file_storage_factory::_data {};
  221. session_file_storage_factory::session_file_storage_factory(std::string path) :
  222. storage_(new session_file_storage(path))
  223. {
  224. }
  225. session_file_storage_factory::~session_file_storage_factory()
  226. {
  227. }
  228. booster::shared_ptr<session_storage> session_file_storage_factory::get()
  229. {
  230. return storage_;
  231. }
  232. bool session_file_storage_factory::requires_gc()
  233. {
  234. return true;
  235. }
  236. void session_file_storage_factory::gc_job()
  237. {
  238. storage_->gc();
  239. }
  240. } // sessions
  241. } // cppcms