안녕하세요. 까막입니다.
지난 포스팅에 이어 MSVS 2013 -> MSVS 2019 로 개발 환경을 옮기면서 발생한 2번째 문제입니다.

해당 환경에서 MSVS 2019 로 옮기면서 컴파일러 버전 업 및 옵티마이저 이득을 약간 얻고자 + 
MSVS 2013 기술지원이 종료되었는지 업데이트도 않되고 해서 변경을 진행했습니다.

현상
전체 빌드 프로젝트가 좀 크고 여러개여서 인지는 모르겠지만 전체 빌드 혹은 덩치 큰 플젝 빌드할 경우
윈도우가 파란 화면을 뛰우는 경우가 자주 발생하더군요.

관련 글들
https://developercommunity.visualstudio.com/t/multiple-times-a-day-a-blue-screen-when-working-in/274372

 

multiple times a day a blue screen when working in VS ...

We have 6 identical HP Z440 workstations with a Intel XEON E5-2630 V3 and 64 GB memory in our company for the developers we use all visual studio 201...

developercommunity.visualstudio.com

https://docs.microsoft.com/en-us/answers/questions/342963/visual-studio-2017-crashes-after-every-run-into-a.html

 

Visual Studio 2017 crashes after every run into a blue screen of death - Microsoft Q&A

 

docs.microsoft.com

결론
위와 관련된 자료들을 취합하여 여러가지 방법을 수행하여 보았으나 
최종적으로 윈도우의 페이징 파일을 자동 관리에서, 요청 크기 2배 이상으로 늘린 후 더 이상 현상이 발생하지 않네요.

결론적인 내용이지만 툴이 빌드할 때 페이징 파일을 사용하는지 생각보다 크게 늘어 있었구요
자동 확장되면서 무슨 문제가 생기는게 아닌가 라는 그런 의심만 남은 상태입니다. 

저같은 경우는 자동 상태에서 약 11GB 쓰고 있었는데, 40 GB로 확 늘려 버린 이후로는 약 1주일째 현상이 없네요.

 

PS. 조금 오래된 글들에 첨부된 이미지와 파일들이 모두 깨져 있네요.
       참고 자료 형태로 글을 남기는 곳인데, 저렇게 다 깨져 있어서 ㅡㅜ 
       시간이 될 때 마다, 조금씩 복구 해 보도록 하겠습니다. 

 

안녕하세요. 까막입니다.
오랜만에 글을 남기네요.

C++ 에서 싱글톤 패턴을 적용하여 인스턴스를 생성할 때, 인스턴스가 리턴되지 않고
무한 대기(내부적으로는 아래 설명에 따라 무한 루프)에 빠지는 문제에 대한 내용입니다.
이 문제는 Visual Studio 2015 (c++ 11 포함 이상)부터 상위 버전에서 발생할 수 있는 문제라고 되어 있네요.

 

싱글톤에 대한 간략한 설명 
https://boycoding.tistory.com/109

 

C++ 디자인 패턴 05. 싱글턴 패턴, Singleton Pattern

싱글턴 패턴, Singleton Pattern 오직 한 개의 클래스 인스턴스만을 갖도록 보장하고, 이에 대한 전역적인 접근점을 제공합니다. (GoF의 디자인 패턴 181쪽) GoF의 싱글턴 패턴은 의도와는 달리 득보다는

boycoding.tistory.com

 

MSDN
https://docs.microsoft.com/en-us/cpp/build/reference/zc-threadsafeinit-thread-safe-local-static-initialization?view=msvc-170 

 

/Zc:threadSafeInit (Thread-safe Local Static Initialization)

Learn more about: /Zc:threadSafeInit (Thread-safe Local Static Initialization)

docs.microsoft.com

 

비슷한 현상
https://forum.juce.com/t/calling-my-singleton-causes-eternal-loop-in-init-thread-header/37340

 

Calling my singleton causes eternal loop in _Init_thread_header

Hi there, I’m experiencing issues with one of my singletons, which I assume is related to threads somehow (pardon my modest knowledge of C++ and multithreading). This is what my function looks like: SettingsManager& SettingsManager::getInstance() { stati

forum.juce.com

 

겪은 현상 설명
최근 Visual Studio 2013 버전에서 Visual Studio 2019로 마이그레이션을 진행하면서 겪은 내용을 남겨 놓고자 글을 씁니다.
싱글톤을 리턴할 때 MSDN에서는 스레드 세이프하도록 가드를 넣었다고 설명하고 있습니다.
(아래 그림이 첫번째 인스턴스를 생성할 때, 가드를 치는 c runtime 내부 소스입니다.)

/Zc:threadSafeInit(스레드로부터 안전한 로컬 정적 초기화) - MSDN 설명중 일부 발췌
/ Zc:threadSafeInit 컴파일러 옵션은 컴파일러에게 스레드로부터 안전한 방식으로 정적 로컬(함수 범위) 변수를 초기화하도록 지시하므로 수동 동기화가 필요하지 않습니다. 초기화만 스레드로부터 안전합니다. 다중 스레드에 의한 정적 지역 변수의 사용 및 수정은 여전히 수동으로 동기화되어야 합니다. 이 옵션은 Visual Studio 2015부터 사용할 수 있습니다. 기본적으로 Visual Studio는 이 옵션을 활성화합니다.

즉, 위의 내용은 싱글톤을 패턴을 포함한 정적 로컬 변수의 초기화시 안정성을 보장하는 옵션에 대한 설명이며
Visual Studio 2015 부터는 기본 옵션으로 포함되어 있습니다.

멀티 스레드 환경에서도 정적 변수 초기화시 별다른 lock 없이 사용할 수 있도록 보장하는 내용이지요.
그게 아니라면 별도로 lock 을 걸어서 안정성을 보장해 주어야 합니다.

최근 테스트된 환경에서 고속으로 돌아가는 개별 스레드에서 싱글톤 객체를 생성할 때, 초기화 코드를 호출하고
해당 코드가 리턴되기 전에 다른 스레드에서 또 객체 생성을 호출하면 위 그림의 while 루프에 빠져 무한 루프를
도는 현상이 확인 되었습니다.

통상적으로 코드 자체에는 문제 없고, 로직이나 이런것에 전혀 문제가 없는 상황에서 발생하는데요
이번에 확인된 부분은 콘솔 터미널 에서는 문제없이 돌아가는 실행파일이, 리모트 터미널 환경에서 hang 걸리는 
극악한 환경에서 발생해서 원인을 찾는데 상당히 애를 먹었네요.

아마도 리모트 환경에서는 콘솔에 비하여 바이너리 로딩이나 초기화 등에서 조금더 지연이 발생 하나 봅니다.

해법은 컴파일러 옵션에서 /Zc:threadSafeInit- 옵션을 넣어서 간단하게 해결할 수 있습니다.
즉, 기본옵션인 /Zc:threadSafeInit 를 강제로 해제하는 내용입니다.

이런 경우 해당 객체의 스레드 안정성은 직접 보장해 주시거나, 기존 동작에 문제가 없었다면 옵션만 넣고 빌드하시면 됩니다.

해당 자료를 검색하고, 해결하는 과정에서 작업이 끝나고 보니 아래 자료에 도움될만한 내용이 있었네요.
https://www.slideshare.net/utilforever/c-korea-3rd-seminar-c-visual-studio

 

[C++ Korea 3rd Seminar] 새 C++은 새 Visual Studio에, 좌충우돌 마이그레이션 이야기

C++11을 시작으로 모던 C++이 도입된 지도 어느새 6년이라는 시간이 흘렀습니다. 올해는 C++17 표준이 도입될 예정입니다. 그만큼 많이 개선되고 새로운 기능들이 많이 도입되었기에 실무에서 사용

www.slideshare.net

 

Visual Studio 6.0을 Windows 8 64bit 이상에서 설치하려면 여러가지 문제가 발생하더군요

그러한 부분을 해결하기 위한 팁을 정리해 봅니다.


1. Run : Windows\SysWow64\cmd.exe (32 bit cmd)


2. change directory setup path


3. Run : setup.exe


4. Change option 1


5. Change option 2


6. Install Complete


7. Install service pack 6 ... complete


8. Extract VS6sp61.cab file (exists in SP6 unpacked folder)



9. Copy and overwrite common folder -> VS6 Install path ....\Common


10. go VS6 Install path ... Common\MSDev98\Bin


11. run msdevP.exe or msdevS.exe (compatibility setting)



12. build project ... bla bla bla ....




안녕하세요. 까막임돠~


Microsoft Visual Studio 를 이용하여 프로젝트를 생성하면, 프로젝트 폴더에

각종 더미성 파일들이 생성되지요.


이러한 파일이나 폴더를 한쪽에 몰아서, 소스 폴더를 깔끔하게 관리하는 방법은

인터넷에 많이 있는데, 가끔 까먹어서 자료로 남겨 봅니다.


아래는 MSDN을 참조하여, 파일 확장자 및 내용에 대한 정리를 한것 이구요.


주황색 비끄무리한 색은 아래 방법으로 처리합니다.

폴백 경로를 지정하지 않으면 %TEMP% 경로에 저장되구요, 물리 경로를 지정하면 해당 경로에 생성됩니다.


녹색 비슷한 색은 아래 방법으로 처리합니다.

Configuration 별로 모두 설정해야 합니다. 경로는 원하는 경로에 몰아서 처리 해주시면 됩니다.

(아래의 예시 경로는 다수의 프로젝트가 다중 depth 로 있어서, 상대 경로로 처리해준것 입니다.)

(상대 경로, 절대 경로 모두 사용할 수 있습니다.)


프로젝트를 위와 같은 방법으로 정리하면, 디버깅관련 파일과 각종 OBJ 파일들이 몽땅 다른 곳에 저장되기 때문에

프로젝트 폴더에는 빌드에 꼭 필요한 파일만 남게되어 소스관리툴 등과 연동할 때 편리합니다.



PS. 만약에 실행파일만 다른 경로에 모아서 관리하고 싶다면 다음과 같은 설정을 해주셔야 합니다.

우선 링커 옵션에 Output File 에 실행파일 경로을 넣어주시고요. (물론 Configuration 별로 다 해주셔야 하지요.)


실행파일 경로를 옮기면 디버거가 해당 위치를 못찾을 수 있기 때문에, 아래와 같이, 변경된 경로를 적어 주셔야 합니다.


안녕하세요. 까막입니다.

UAC 관련하여 최근 작업을 진행하면서 찾은 자료를 공유해보고자 올려봅니다.


문제 : UAC 상에서 관리자 권한으로 상승 시킨 어플리케이션과 탐색기 간의 Drag & Drop 가 동작하지 않는 문제

해법 : ChangeWindowMessageFilter 를 이용하여 WM_DROPFILES 관련 메시지를 필터에 걸리지 않도록 수정


용어 1 : UIPI (User Interface Privilege Isolation) 사용자 인터페이스 권한 격리

용어 2 : ChangeWindowMessageFilter 함수


참조 1 : Helge Klein 사이트

참조 2 : 띠깜의 하얀세상


ChangeWindowMessageFilter  함수는 낮은 무결성 수준의 발신자(어플리케이션)로 부터 수신되는 메시지를  

UIPI 의 메시지 필터 기능에 일부 혹은 전부를 추가하거나 삭제하는 기능을 가지고 있습니다.


제가 진행한 작업처럼 관리자 기능을 가진 어플리케이션에, 일반 유저 권한으로 수행된 탐색기의 WM_DROPFILES 메시지가 날라오면

보안 수준이 다르기 때문에 자동으로 필터하여 프로세스의 안전을 보장합니다.


드래그 & 드롭에 관한 메시지는 다음과 같은 메시지 일부를 필터에 추가하여 줌으로써, 기능이 동작하도록 설정할 수 있습니다.

(MSDN 의 Remark 에 따르면 안전한 프로세스 관리를 위하여, 필요한 메시지만 필터하도록 권고 하므로 

 기능이 잘 안된다고 루프를 돌려서 모든 메시지를 추가하는 일이 없도록 주의 하십시오.)

ChangeWindowMessageFilter (WM_DROPFILES, MSGFLT_ADD);

ChangeWindowMessageFilter (WM_COPYDATA, MSGFLT_ADD);

ChangeWindowMessageFilter (0x0049, MSGFLT_ADD); 


위 코드를 프로그램의 초기화 코드 위치나 다이알로그의 WM_INITDIALOG 핸들러 위치에 삽입하시면 됩니다.

아래는 샘플 코드...


BOOL CK4iRestoreDlg::OnInitDialog()

{

CDialog::OnInitDialog();


ChangeWindowMessageFilter(WM_DROPFILES, MSGFLT_ADD);

ChangeWindowMessageFilter(WM_COPYDATA, MSGFLT_ADD);

ChangeWindowMessageFilter(0x0049, MSGFLT_ADD);


      // bla bla bla ...
}

테스트는 아래의 OS 상에서 기능이 테스트 되었습니다.
Windows 2003 Server x64/x86 kor/eng
Windows 2008 Server x64 kor/eng
Windows 2012 Server x64 eng/jp

Windows 7 x64 jp


안녕하세요. 까막입니다.

이번에 겪은 일이 있어, 혹시나 다른 분들도 이런일로 당황하시지 않았으면 하는 바램에 몇자 적어봅니다.

(배포 패키지 수행중에 서버 PC가 자동으로 재부팅이 되어 버리더군요 @.@)


현재 작업하는 제품은 Visual Studio 2013 커뮤니티 에디션으로 작성을 하고 있고요, 언어는 VC++ 입니다.

제품을 패키지화 해서 배포할 때는 아래의 vc redistributable package 를 함께 배포하죠.


Visual C++ Redistributable Packages for Visual Studio 2013



해당 배포 패키지는 위의 그림에서 보시는 것 처럼 몇가지 설치 옵션을 제공합니다.

(해당 옵션은 /? 파라미터로 확인 가능합니다.)


이러한 패키지는 설치하고자 하는 머신에 이미 설치되어 있을 수도 있고, 설치 과정에서

구지 사용자가 일일이 첵크하면서 확인할 필요가 없기 때문에 저는 /quiet 옵션으로 패키지를 구성하였습니다.


설명에도 나와있지만 /norestart 옵션을 구성하지 않는 이상, 장치를 재부팅 할 때는 prompt 하도록 되어있지요.

(/norestart 옵션을 구성하면, 재 부팅을 완전히 막아버리기 때문에 재 부팅에 관한 프롬프트가 아예 안나오겠지요)


여기서 장치를 재부팅한다는 의미는 업데이트를 해야하는데, 쓰기가 금지되었거나 사용중이거나 lock 되어서

업데이트는 필요하지만 지금은 업데이트를 할 수 없으니, 예약 작업을 걸어두고 재시작 되면 자동으로 

업데이트를 진행한다는 의미입니다.


이번 버전의 문제인지 저 /quiet 옵션으로 패키지를 수행하면, 업데이트 필요시 어떠한 프롬프트 없이

자동으로 서버를 재시작 해버립니다. 

(기존 버전은 /q 옵션을 쓰더라도 재시작 과정은 물어보았거든요..)

/quiet 옵션으로 설치 과정이 눈에 보이지 않기 때문에, 왜? 갑자기 꺼지는지 조차 알 길이 없습니다.


반응이 빠른 분은 강제 로그오프 과정중에 재빨리 취소할 수 있긴 하지만 아주 당혹 스럽습니다.


/quiet 옵션 대신에 /passive 옵션을 이용하시길 권장드립니다.


안녕하세요. 까막임돠~

오랜만에 글을 쓰네요, 언제나 항상 오랜만인... 게으른 까막 ㅡㅠ;


오늘은 최근 Open SSL 1.0.2 를 적용하면서 나온 부산물을 글로 적어볼까 합니다.

항상 그렇듯이 windows 기반이고요, 이제는 64 bit OS 만 대상으로 작업을 하게 되네요.

32 bit 는 빌드 환경만 바꾸면 되니, 사실 2개의 작업은 차이가 없습니다.


개발 환경은 Windows 2008 Server R2 x64 이고요, 툴은 MSVS-2013 공짜 버전을 사용하였습니다.


1. 우선 최신 버전을 다운 받아야 겠죠?

   https://www.openssl.org/source/


2. Active Perl 사이트에서 커뮤니티 에이션을 다운 받습니다.

   http://www.activestate.com/activeperl/downloads


3. 소스는 적당한 곳에 압축을 풀고, 펄은 설치를 합니다.


4. MSVS 2013 에서 콘솔 컴파일을 하려면 손으로 환경설정하는 노가다가 아주 끝내줍니다.

   자동으로 이런 환경을 제공해주니 사용해 주어야 겟지요..ㅎ

  

  

   해당 메뉴를 이용하면 다음과 같은 창이 열립니다.



  

  64비트 컴파일 환경을 수행하면 이런 환경 변수가 모두 적용된 cmd 창이 뜹니다.

  모든 작업이 완료될 때까지 쭉 써야할 이쁜이죠..


5. 우선 기본 소스가 풀린 폴더 BASE 라고 표현하죠. 해당 경로로 cmd 창에서 이동합니다.

   가장 첫 번째 작업으로 perl 을 이용하여 64비트 빌드 환경을 마춰주죠.

   cmd> perl Configure VC-WIN64A


   두 번째로. win64a 배치 파일을 수행하여 빌드 환경을 다시 마춰줍니다.

   cmd> ms\do_win64a


   마지막으로, nmake를 이용하여 빌드하면 끝~

   cmd> nmake -f ms\ntdll.mak


   이렇게만 해줘도, BASE 폴더에 out32dll 폴더와, tmp32dll 폴더에 빌드된 파일이 쭉 생기죠.

   모든 lib, dll, exe 는 BASE\out32dll 폴더에 다 들어있습니다.


   이번 1.0.2 버전은 windows 빌드 환경에 세심하게 신경썼는지, 아주 이쁘게 한방에 빌드가 되네요.

   

6. 이렇게 만 끝내면 상당히 아쉽지요?

   다음으로는 보통 가져다 쓰는 libeay32.lib 및 ssleay32.lib 를 사용하게 되는데, 이것 저것 좀 건드리다 보면

   unresolved external symbol 에러를 마주 치는 경우가 많습니다.

   

   분명 소스에는 있는 함수인데, 내가 만드는 프로그램에서 호출해서 쓰면 못쓰는 경우죠.

   라이브러리를 만들 때, 해당 함수를 export 하지 않았기 때문에 외부에서 못쓰는 거죠.


   BASE 폴더의 하위 폴더중에 util 폴더가 있습니다.

   libeay.num파일과 ssleay.num 파일이 있습니다. 


   내가 호출하는 함수가 어느 라이브러리 연관있는지는 개발자 본인이 가장 잘 알테고,

   그렇게 사용해야할 함수를 해당 파일을 열어서 등록해주면 됩니다.

   

   노트패드나 다른 에디터로 열어보시면 그냥 아실 수 있습니다.


   문제는 이러한 export 등록만 하면 되는게 아니고, 해당 함수의 정의부를 사용하는 해더에도 정의 해주어야 합니다.

   BASE\SSL\ssl.h 파일에 내가 사용하는 함수의 정의부를 함께 기록해주어야 합니다.


   이렇게 해주시면 ssl 내부의 함수도 내가 만드는 프로그램에서 자유자재로 쓸 수 있습니다.

 

   요렇게 해서 5번 과정을 이용하여 빌드하고 나면 ms 폴더에 있는 ssleay32.def 나 libeay32.def 파일에 추가한 함수가

   등록되어 있는걸 볼 수 있습니다. 사실 요걸 직접 수정해도 되는데, 환경 설정할 때마다 자동으로 덮어써지는 파일이기 

   때문에 귀찬고 실수 할 여지가 많죠.


7. ssl 을 이용하여 개발할 때 필요한 필수 항목이 디버깅 환경을 갖추는 거죠?

   지금까지는 그냥 release 환경 하에서, 쓸 수 만 있는거지 디버깅은 안됩니다.


   설치 폴더의 ms 폴더에 가서 do_win64a.bat 를 복사하여, do_win64a_debug.bat 파일을 하나 만듭니다.


   

   이 그림이 오리지널 파일이고요.



   

   요 그림이 디버깅 환경으로 변경한 그림입니다. 아주 쉽죠 @.@???

   cmd> ms\do_win64a_debug 

   cmd> nmake -f ms\ntdll_debug.mak


   이렇게 빌드하시면, 디버깅 환경도 짠 갖췄습니다.

   

   라이브러리나 dll 을 .dbg 폴더에 있는걸 가져다 쓰시면 디버깅 준비도 끝났습니다.


8. 이렇게 openssl 1.0.2 를 디버깅 환경하에서 사용할 수 있도록 모든 준비가 끝났지만

   openssl.exe 툴을 이용하여 디버깅을 하려면 저 소스를 이용해서 직접 빌드하고 수정할 수 있어야겠지요?

   저 실행 파일을 직접 디버거에 물려서 소스랑 같이 수정해가면서 빌드하면 좋겠지요?

    

sample.zip


   위의 sample.zip 파일의 압축을 풀어서 해당 내부에 있는 파일 4개를 BASE 폴더의 하부에 있는 apps 폴더에 

   복사하여 넣어 둡니다.

   

   요렇게 선택된 4개의 파일입니다.


   openssl.vcxproj 프로젝트 파일을 열어서 간단하게 F5 키를 눌러서 빌드해 줍니다.


   8.1 아무 문제 없으면 좋겠지만 첫번째 오류는 e_os.h 를 찾을 수 없다는 겁니다.

      BASE\tmp32dll 폴더나 BASE\tmp32dll.dbg 폴더에 있는 e_os.h 를 복사하여

      BASE\apps 폴더에 넣어주고, 다시 빌드 합니다.


   8.2 이렇게 끝나주면 가장 좋구요. 다음과 같이 winsock  관련 오류가 뜨면 한가지 작업을

      더 진행해 주어야 합니다.



     그림과 같이 윈속 관련된 에러가 뜬다. 저번 버전은 안그랬는데.. 안뜨면 좋고 위와 같이 윈속 관련 에러가 뜨면 apps.c 파일의 다      음 위치에 아래 코드를 추가한다.



     

     요렇게 한줄 추가해 주시고, 빌드해주시면 이제 openssl.exe 플젝을 디버거를 걸어 가면서 놀 수 있습니다.

     새로운 플젝을 만들 때도, 위에 소스 대충 가져다 만들면 별다른 문제 없이 쓸 수도 있구요..




     해당 플젝에 디버거 걸어서 소스 트레이스 하는 모습입니다.

     모두 잼난 열공.. 하셔요.. ~





   



SSL Cipher Suites Issue


Windows RT 8.1, Windows 8.1 and Windows Server 2012 R2 Update April, 2004 

해당 업데이트에서 신규 Cipher 와 보안상 문제 취급되던 TLS_RSA_WITH_RC4_128_MD5, TLS_RSA_WITH_RC4_128_SHA

이슈가 발생하고 있네요. 문서상에서는 위 2개의 Cipher를 지원하는 것으로 기록되어 있지만 업데이트된 서버나 

클라이언트 OS의 특성에 따라 해당 2개의 Cipher 가 SSL Cipher Order List에서 사라지는 현상이 있습니다.


또한 Windows 7, Windows Server 2008 부터 Cipher top order 에 있던 AES가 클라이언트 오더링에서 하위로 밀리는

현상도 발생하고 있어서 TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_RSA_WITH_AES_128_CBC_SHA 해당 우선 순위가 

밀려서 다른 Cipher 로 통신하는 현상도 발생되고 있는데.. 같은 OS를 가진 여러서버를 업데이트 하였을 경우

간혹 위 문제를 발생시키는 서버가 발견되고 있습니다.



아래는 해당 업데이트로 새로 추가된 Cipher들의 목록

Cipher suite

FIPS mode enabledProtocolsExchangeEncryptionHash
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384YesTLS 1.2DHAESSHA384
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256YesTLS 1.2DHAESSHA256
TLS_RSA_WITH_AES_256_GCM_SHA384YesTLS 1.2RSAAESSHA384
TLS_RSA_WITH_AES_128_GCM_SHA256YesTLS 1.2RSAAESSHA256

 

아래는 해당 업데이트 이후 새로 정렬된 기본 오더 리스트

TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P384 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA_P256 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA_P384 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA_P256 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA_P384 TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 TLS_RSA_WITH_AES_256_GCM_SHA384 TLS_RSA_WITH_AES_128_GCM_SHA256 TLS_RSA_WITH_AES_256_CBC_SHA256 TLS_RSA_WITH_AES_128_CBC_SHA256 TLS_RSA_WITH_AES_256_CBC_SHA TLS_RSA_WITH_AES_128_CBC_SHA TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384_P384 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256_P256 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256_P384 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384_P384 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256_P256 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256_P384 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA_P256 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA_P384 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA_P256 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA_P384 TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 TLS_DHE_DSS_WITH_AES_256_CBC_SHA TLS_DHE_DSS_WITH_AES_128_CBC_SHA TLS_RSA_WITH_3DES_EDE_CBC_SHA TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA TLS_RSA_WITH_RC4_128_SHA TLS_RSA_WITH_RC4_128_MD5 TLS_RSA_WITH_NULL_SHA256 TLS_RSA_WITH_NULL_SHA SSL_CK_RC4_128_WITH_MD5 SSL_CK_DES_192_EDE3_CBC_WITH_MD5


현재 위의 분홍색2개로 통신하던 어플리케이션들은 분명 오더 리스트에 있음에도 불구하고 통신이 안되는 

폭탄을 맞는 일이 발생하고 있습니다.. 


저 같은 경우는 그런 경우는 아닙니다만, 젤 위의 파랑생 Cipher를 지원하기 위한 OpenSSL 업데이트 작업

그에 따른 프로그램 수정, 테스트와 배포.. 여러가지 폭탄을 맞은듯 ㅠㅠ;;;

요건 MS기술 링크: http://support.microsoft.com/kb/2929781


오랜만에 MMF (Memory Mapped File)를 살펴볼 일이 있어 예전 자료를 찾아다 쓰면서.. 

이것 저것 실험하는 중 불편한 코드 정리 및 대충 알던거 살펴보기.. 잘모르던거 제대로 알기.. 

이런 저런 관점에서 정리해보는 글입니다.


MMF가 무엇인지 어떤 장단점을 가지고 있는지와 관련된 내용이나 참조 사항은 다음 링크..

위키 : http://ko.wikipedia.org/wiki/메모리_맵_파일

이전자료 : http://crowback.tistory.com/198

MSDN : http://msdn.microsoft.com/en-us/library/ms810613.aspx


우선 정리된 클래스 골격



class CMMFObject

{
#define BIGINT LARGE_INTEGER

public:
    CMMFObject()
    {
        m_FileSize.QuadPart = 0;
        m_FileHandle        = INVALID_HANDLE_VALUE;
        m_hMemoryMap        = NULL;
        m_pMemoryMap        = NULL;
        m_bAudoDelete       = false;
        m_FilePath[0]       = 0;
    }

    virtual ~CMMFObject() { Close(); }


    /* 만들어져 있는 MMF를 열 때 사용하는 열기 함수 */
    DWORD Open(const TCHAR* pszMapName, DWORD dwDesiredAccess = FILE_MAP_READ);


    /* 파일 핸들이 있거나 시스템 페이지를 이용하여 MMF를 생성하는 함수 */
    DWORD Create(HANDLE hFile, const TCHAR* pszMapName, LONGLONG iFilesize, LPSECURITY_ATTRIBUTES lpAttributes = NULL);


    /* 파일을 직접 지정하여 MMF를 생성하는 함수 */
    DWORD Create(const TCHAR* pszMapFilePath, const TCHAR* pszMapName, LONGLONG iFilesize, bool bAudoDelete = true, LPSECURITY_ATTRIBUTES lpAttributes = NULL);


    /* 열려 있는 모든 내부정보를 닫고, 초기화 */

    DWORD Close(DWORD rc = ERROR_SUCCESS);


    /* 생성된 MMF의 접근 가능한 주소 */

    LPBYTE GetPtr() { return m_pMemoryMap; }

protected:

    DWORD __MapViewOfFile(DWORD dwDesiredAccess )
    {
        m_pMemoryMap = (BYTE*)::MapViewOfFile(m_hMemoryMap, dwDesiredAccess, 0, 0, 0);
        if(!m_pMemoryMap)
            return Close(GetLastError());

        return ERROR_SUCCESS;
    }

    CMMFObject(const CMMFObject& ) { /* barrier */ }
    CMMFObject& operator = (const CMMFObject &) { return *this; /* barrier */ }

private:
    BIGINT m_FileSize;
    HANDLE m_FileHandle;
    HANDLE m_hMemoryMap;
    LPBYTE m_pMemoryMap;
    TCHAR  m_FilePath[MAX_PATH];
    bool   m_bAudoDelete;
};




간단한 사용법


CMMFObject a;
CMMFObject b;

/* a 객체는 C:\\a.map 파일을 열거나 생성하여 1024 크기로 만들고, 이름을 LOCAL_FILE 으로 지정한다.

    b 객체는 LOCAL_FILE 이름을 가진 MMF를 읽고/쓰기 모드로 연다. */
if(a.Create(_T("C:\\a.map"), _T("LOCAL_FILE"), 1024) == ERROR_SUCCESS)
    _tcscpy((LPTSTR)a.GetPtr(), _T("까마귀날자 배떨어진다."));


if(b.Open(_T("LOCAL_FILE"), FILE_MAP_READ | FILE_MAP_WRITE) == ERROR_SUCCESS)
    _tcscpy((LPTSTR)b.GetPtr(), _T("날아도 배 안떨어져요."));


/* a 객체는 시스템 페이지를 이용하여 1024 크기로 만들고, 이름을 SYSTEM_PAGE 으로 지정한다.

    b 객체는SYSTEM_PAGE 이름을 가진 MMF를 읽기 모드로 연다. */
if(a.Create(INVALID_HANDLE_VALUE, _T("SYSTEM_PAGE"), 1024) == ERROR_SUCCESS)
    _tcscpy((LPTSTR)a.GetPtr(), _T("까마귀날자 배떨어진다."));


if(b.Open(_T("SYSTEM_PAGE"), FILE_MAP_READ) == ERROR_SUCCESS)
    _tcscpy((LPTSTR)b.GetPtr(), _T("날아도 배 안떨어져요.")); <- 에러: 읽기 모드로만 열어서 쓰기 금지


CMMFObject c(a);   <- 에러: 복사 생성에 의한 다중 참조 금지

CMMFObject d = b;  <- 에러: 대입 연산에 의한 다중 참조 금지



코드를 다시 정리하면서...


1. MMF는 생성 시점에 바로 메모리에 올라가지 않는다.

     실제 생성한 MMF를 액세스 하는 시점에 해당 사용한 영역 만큼만 메모리에 올라간다.

     즉, 1 GB 짜리 MMF를 생성해도 시스템 메모리 사용량은 변함이 없고, 거기에 읽고/쓰는 영역이 생기면 그 때 변화한다.


2. 32 Bit OS에서 이론적으로 4GB까지 MMF를 생성할 수 있다고 하는데... 

     일반적으로 32 bit Windows 에서는 1.5~1.8 GB 까지 생성가능하다. 

     쫌더 쓰려면?  /3GB boot parameter 를 이용하여 2.5~2.7 GB 까지 가능하기는 하지만.. 서버용으로는 쓰기 곤란하다.

     즉, 32 Bit OS 에서는 많이 써봐야 1.8 GB 정도로 보면 된다.


3. MMF를 생성하면 메모리가 증가 하겠지만, 오픈 할 때도 증가???

     MMF를 생성하면 당연히 할당한 크기만큼 메모리가 증가한다. 

     그런데 MMF를 열면,  원래 MMF가 지정한 크기만큼 메모리가 다시 증가한다. 또 열면 또 그만큼 증가한다.


     아래의 그림을 참고하자. a는 MMF를 생성, b는 MMF를 읽기모드로 오픈한 객체 정보의 비교이다. 

     데이터에 모두 b 라는 문자열을 가졌지만.. 해당 메모리의 주소가 서로 다르다.

     MMF의 오픈이라는 의미는 생성해둔 MMF 주소를 가져다 빌려쓰는게 아닌.. 같은 크기만큼의 메모리를 만들어서

     미러형식으로 데이터의 동기화를 이루어 공유하는 것처럼 보이는 방식이다.


4. 파일을 직적 연결하여 MMF를 생성했을 때, 메모리 방식과 직접 파일 액세스 방식은 혼용하면 않된다.

     내가 직접 만든 파일로 MMF를 생성할 경우, 2가지 방식으로 액세스 할 수 있는 상태가 된다.

     하나는 직접 파일을  read/write 하는 방식과 다른 하나는 메모리를 매핑된 MMF의 주소를 이용함 메모리 방식이다.

     각각 혹은 2가지 방식을 동시에 사용할 수 있지만.. 매핑된 메모리에 쓴 내용이 바로 디스크에 반영되지 않기 때문에

     2가지 방식으로 데이터를 액세스 하면 같은 위치 영역의 디스크 데이터와  메모리 데이터가 틀어질 수 있다.


5. 그럼 파일이 빠르냐?  MMF가 빠르냐?

     MMF가 디스크에 스왑되어 있을 경우는 메모리에 올라갈 동안 지연이 일부 생기지만.. 일단 메모리에 올라간 이후라면 

     MMF가 빠르다.. 랜덤 액세스일 경우는 성능 차이가 많이 벌어진다. 

     하지만 MMF는 파일 크기를 변경할 수 없기 때문에 쓰기 작업을 이용하여 늘려가면서 쓰는것이 불가능하다.

     또한, 작업중 디스크에 스왑되기 전에 전원이 꺼진다던가 하면 작업 내용이 사라진다..  





아주 오랜만에 글을 써봅니다.
바쁘다는 핑계로 한 번 두 번 글을 미루다 보니
몇 달이 그냥 흘러가 버리네요.
먼가 장편이나 연재글을 쓴다는게 얼마나 어려운 일인지 조금 느꼈습니다.

(작가분들 존경 스럽습니다. @.@);;;

파일 (폴더도 파일의 일종)의 보안 속성 변경

사실 아래의 코드는 원본 코드를 일부 수정한 것입니다.
그 때 당시 필요해서 이것 저것 자료를 찾아서 만든 것인데, SetFileSecurity API 자체를 잘 이해 못하고
필요한 동작만 빠르게 갖추기 위해서 만든 것이었죠. (사실 그 때는 위 API로 폴더가 되는 줄도 몰랐음)

좀 오래된 자료이긴 하지만, 그 때는 잘 썼는데..
폴더의 보안 속성을 못바꾸는 이유가.. 개념도 없이 잡탕해 놓은 소스라서 그렇다고 하니... -_-;;;
어쨋든 그런 이유로 좀더 보완하여 수정한 코드입니다.


지금 이 코드도 그리 크게 쓸만한 깔끔한 코드는 아닙니다. 단지 파일과 폴더에 특정 유저 권한을

완전히 풀어줄 때 급하게 땜빵하는 용도로는 쓰는데 무리는 없을겁니다.

제대로 만들어 지려면
1. 기존 파일/폴더의 보안 권한 목록을 얻어오고
2. 내가 원하는 사용자가 있는지 검출할 수 있어야 하며
3. 없으면 만들어서 해당 사용자를 추가 할 수 있어야 하고
4. 있으면 해당 권한을 수정해 줄 수 있어야 겠죠.

이 글을 보시는 분들 중에 미리 저러한 기능이 필요해서 만들어 두신게 있으시면..
살짝 리플달아 주세요.. 서로 나눠 먹자구요 ^^;;;






+ Recent posts