├── .gitignore ├── AsyncIpc.sln ├── README.md ├── ipc ├── ReadMe.txt ├── ipc.vcxproj ├── ipc.vcxproj.filters ├── ipc_channel.cpp ├── ipc_channel.h ├── ipc_channel_handle.h ├── ipc_channel_reader.cpp ├── ipc_channel_reader.h ├── ipc_common.h ├── ipc_endpoint.cpp ├── ipc_endpoint.h ├── ipc_interface.h ├── ipc_listener.h ├── ipc_logging.cc ├── ipc_logging.h ├── ipc_message.cpp ├── ipc_message.h ├── ipc_sender.h ├── ipc_thread.cpp ├── ipc_thread.h ├── ipc_utils.cpp ├── ipc_utils.h ├── stdafx.cpp └── stdafx.h ├── ipc_dll ├── ReadMe.txt ├── ipc_dll.cpp ├── ipc_dll.def ├── ipc_dll.h ├── ipc_dll.vcxproj ├── ipc_dll.vcxproj.filters ├── ipc_endpoint_impl.cpp ├── ipc_endpoint_impl.h ├── ipc_factory_impl.cpp ├── ipc_factory_impl.h ├── stdafx.cpp ├── stdafx.h └── targetver.h └── sample ├── ReadMe.txt ├── common.cpp ├── common.h ├── sample_client.cpp ├── sample_client.h ├── sample_client.vcxproj ├── sample_client.vcxproj.filters ├── sample_dll_client.cpp ├── sample_dll_client.h ├── sample_dll_client.vcxproj ├── sample_dll_client.vcxproj.filters ├── stdafx.cpp ├── stdafx.h └── targetver.h /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Visual Studio 3 | ################# 4 | 5 | ## Ignore Visual Studio temporary files, build results, and 6 | ## files generated by popular Visual Studio add-ons. 7 | 8 | # User-specific files 9 | *.suo 10 | *.user 11 | *.sln.docstates 12 | 13 | # Build results 14 | #[Dd]ebug/ 15 | #[Rr]elease/ 16 | *_i.c 17 | *_p.c 18 | *.ilk 19 | *.meta 20 | *.obj 21 | *.pch 22 | *.pdb 23 | *.pgc 24 | *.pgd 25 | *.rsp 26 | *.sbr 27 | *.tlb 28 | *.tli 29 | *.tlh 30 | *.tmp 31 | *.vspscc 32 | .builds 33 | *.dotCover 34 | 35 | # Visual C++ cache files 36 | ipch/ 37 | *.aps 38 | *.ncb 39 | *.opensdf 40 | *.sdf 41 | 42 | # Visual Studio profiler 43 | *.psess 44 | *.vsp 45 | 46 | ################# 47 | /build/ 48 | /output/ 49 | /ipch/ -------------------------------------------------------------------------------- /AsyncIpc.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.30501.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ipc", "ipc\ipc.vcxproj", "{896C53B4-9517-429A-911C-1A2B634B8319}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample_client", "sample\sample_client.vcxproj", "{ADD3A329-4FB0-4B04-8C47-98DBFE5A06D4}" 9 | EndProject 10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ipc_dll", "ipc_dll\ipc_dll.vcxproj", "{A808021A-C2FF-4B8D-A24A-B3535BCA0637}" 11 | EndProject 12 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample_dll_client", "sample\sample_dll_client.vcxproj", "{F15D047E-1369-432E-91C0-03E932370D55}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Win32 = Debug|Win32 17 | Release|Win32 = Release|Win32 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {896C53B4-9517-429A-911C-1A2B634B8319}.Debug|Win32.ActiveCfg = Debug|Win32 21 | {896C53B4-9517-429A-911C-1A2B634B8319}.Debug|Win32.Build.0 = Debug|Win32 22 | {896C53B4-9517-429A-911C-1A2B634B8319}.Release|Win32.ActiveCfg = Release|Win32 23 | {896C53B4-9517-429A-911C-1A2B634B8319}.Release|Win32.Build.0 = Release|Win32 24 | {ADD3A329-4FB0-4B04-8C47-98DBFE5A06D4}.Debug|Win32.ActiveCfg = Debug|Win32 25 | {ADD3A329-4FB0-4B04-8C47-98DBFE5A06D4}.Debug|Win32.Build.0 = Debug|Win32 26 | {ADD3A329-4FB0-4B04-8C47-98DBFE5A06D4}.Release|Win32.ActiveCfg = Release|Win32 27 | {ADD3A329-4FB0-4B04-8C47-98DBFE5A06D4}.Release|Win32.Build.0 = Release|Win32 28 | {A808021A-C2FF-4B8D-A24A-B3535BCA0637}.Debug|Win32.ActiveCfg = Debug|Win32 29 | {A808021A-C2FF-4B8D-A24A-B3535BCA0637}.Debug|Win32.Build.0 = Debug|Win32 30 | {A808021A-C2FF-4B8D-A24A-B3535BCA0637}.Release|Win32.ActiveCfg = Release|Win32 31 | {A808021A-C2FF-4B8D-A24A-B3535BCA0637}.Release|Win32.Build.0 = Release|Win32 32 | {F15D047E-1369-432E-91C0-03E932370D55}.Debug|Win32.ActiveCfg = Debug|Win32 33 | {F15D047E-1369-432E-91C0-03E932370D55}.Debug|Win32.Build.0 = Debug|Win32 34 | {F15D047E-1369-432E-91C0-03E932370D55}.Release|Win32.ActiveCfg = Release|Win32 35 | {F15D047E-1369-432E-91C0-03E932370D55}.Release|Win32.Build.0 = Release|Win32 36 | EndGlobalSection 37 | GlobalSection(SolutionProperties) = preSolution 38 | HideSolutionNode = FALSE 39 | EndGlobalSection 40 | EndGlobal 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #AsyncIpc 2 | ======== 3 | 4 | * 异步进程间通信库 5 | * 提供静态库和动态dll加载方式 6 | * 轻量,动态dll只有40K 7 | -------------------------------------------------------------------------------- /ipc/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | STATIC LIBRARY : ipc Project Overview 3 | ======================================================================== 4 | 5 | AppWizard has created this ipc library project for you. 6 | 7 | No source files were created as part of your project. 8 | 9 | 10 | ipc.vcxproj 11 | This is the main project file for VC++ projects generated using an Application Wizard. 12 | It contains information about the version of Visual C++ that generated the file, and 13 | information about the platforms, configurations, and project features selected with the 14 | Application Wizard. 15 | 16 | ipc.vcxproj.filters 17 | This is the filters file for VC++ projects generated using an Application Wizard. 18 | It contains information about the association between the files in your project 19 | and the filters. This association is used in the IDE to show grouping of files with 20 | similar extensions under a specific node (for e.g. ".cpp" files are associated with the 21 | "Source Files" filter). 22 | 23 | ///////////////////////////////////////////////////////////////////////////// 24 | Other notes: 25 | 26 | AppWizard uses "TODO:" comments to indicate parts of the source code you 27 | should add to or customize. 28 | 29 | ///////////////////////////////////////////////////////////////////////////// 30 | -------------------------------------------------------------------------------- /ipc/ipc.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {896C53B4-9517-429A-911C-1A2B634B8319} 15 | Win32Proj 16 | ipc 17 | 18 | 19 | 20 | StaticLibrary 21 | true 22 | v120_xp 23 | Unicode 24 | 25 | 26 | StaticLibrary 27 | false 28 | v120_xp 29 | true 30 | Unicode 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | ..\output\$(Configuration)\ 44 | ..\build\$(ProjectName)\$(Configuration)\ 45 | 46 | 47 | ..\output\$(Configuration)\ 48 | ..\build\$(ProjectName)\$(Configuration)\ 49 | 50 | 51 | 52 | 53 | 54 | Level3 55 | Disabled 56 | WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) 57 | true 58 | $(projectdir)..;%(AdditionalIncludeDirectories) 59 | stdafx.h 60 | 61 | 62 | Windows 63 | true 64 | 65 | 66 | 67 | 68 | Level3 69 | 70 | 71 | MaxSpeed 72 | true 73 | true 74 | WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) 75 | true 76 | $(projectdir)..;%(AdditionalIncludeDirectories) 77 | stdafx.h 78 | 79 | 80 | Windows 81 | true 82 | true 83 | true 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /ipc/ipc.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {e70582e1-e6af-4bde-9881-706dd6704a4f} 6 | 7 | 8 | {1535d84c-3a6e-47e7-ac29-be88e042a049} 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | ipc 17 | 18 | 19 | ipc 20 | 21 | 22 | ipc 23 | 24 | 25 | ipc 26 | 27 | 28 | ipc 29 | 30 | 31 | ipc 32 | 33 | 34 | ipc 35 | 36 | 37 | ipc 38 | 39 | 40 | build 41 | 42 | 43 | ipc 44 | 45 | 46 | ipc 47 | 48 | 49 | 50 | 51 | ipc 52 | 53 | 54 | ipc 55 | 56 | 57 | ipc 58 | 59 | 60 | ipc 61 | 62 | 63 | build 64 | 65 | 66 | ipc 67 | 68 | 69 | ipc 70 | 71 | 72 | -------------------------------------------------------------------------------- /ipc/ipc_channel.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hicdre/AsyncIpc/8253b2bad7a6f17f972294827ae13df47292f047/ipc/ipc_channel.cpp -------------------------------------------------------------------------------- /ipc/ipc_channel.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #ifndef IPC_IPC_CHANNEL_WIN_H_ 6 | #define IPC_IPC_CHANNEL_WIN_H_ 7 | 8 | #include 9 | #include 10 | 11 | #include "ipc/ipc_common.h" 12 | #include "ipc/ipc_thread.h" 13 | #include "ipc/ipc_sender.h" 14 | #include "ipc/ipc_channel_handle.h" 15 | #include "ipc/ipc_channel_reader.h" 16 | 17 | namespace IPC 18 | { 19 | class Channel 20 | : public Sender 21 | , public internal::ChannelReader 22 | , public Thread::IOHandler 23 | { 24 | public: 25 | enum { 26 | HELLO_MESSAGE_TYPE = kuint16max // Maximum value of message type (uint16), 27 | // to avoid conflicting with normal 28 | // message types, which are enumeration 29 | // constants starting from 0. 30 | }; 31 | 32 | // The maximum message size in bytes. Attempting to receive a message of this 33 | // size or bigger results in a channel error. 34 | static const size_t kMaximumMessageSize = 128 * 1024 * 1024; 35 | 36 | // Mirror methods of Channel, see ipc_channel.h for description. 37 | Channel(const IPC::ChannelHandle &channel_handle, 38 | Listener* listener, Thread* thread); 39 | ~Channel(); 40 | bool Connect(); 41 | void Close(); 42 | virtual bool Send(Message* message) override; 43 | DWORD peer_pid() const { return peer_pid_; } 44 | 45 | private: 46 | // Returns true if a named server channel is initialized on the given channel 47 | // ID. Even if true, the server may have already accepted a connection. 48 | static bool IsNamedServerInitialized(const std::string& channel_id); 49 | 50 | // Generates a channel ID that's non-predictable and unique. 51 | static std::string GenerateUniqueRandomChannelID(); 52 | 53 | // Generates a channel ID that, if passed to the client as a shared secret, 54 | // will validate that the client's authenticity. On platforms that do not 55 | // require additional this is simply calls GenerateUniqueRandomChannelID(). 56 | // For portability the prefix should not include the \ character. 57 | static std::string GenerateVerifiedChannelID(const std::string& prefix); 58 | private: 59 | // ChannelReader implementation. 60 | virtual ReadState ReadData(char* buffer, 61 | int buffer_len, 62 | int* bytes_read) override; 63 | virtual bool WillDispatchInputMessage(Message* msg) override; 64 | bool DidEmptyInputBuffers() override; 65 | virtual void HandleHelloMessage(Message* msg) override; 66 | 67 | static const std::wstring PipeName(const std::string& channel_id, 68 | int32* secret); 69 | bool CreatePipe(const IPC::ChannelHandle &channel_handle); 70 | 71 | bool ProcessConnection(); 72 | bool ProcessOutgoingMessages(Thread::IOContext* context, 73 | DWORD bytes_written); 74 | 75 | // MessageLoop::IOHandler implementation. 76 | virtual void OnIOCompleted(Thread::IOContext* context, 77 | DWORD bytes_transfered, 78 | DWORD error); 79 | 80 | private: 81 | struct State { 82 | explicit State(Channel* channel); 83 | ~State(); 84 | Thread::IOContext context; 85 | bool is_pending; 86 | }; 87 | 88 | State input_state_; 89 | State output_state_; 90 | 91 | HANDLE pipe_; 92 | 93 | DWORD peer_pid_; 94 | 95 | // Messages to be sent are queued here. 96 | std::queue output_queue_; 97 | 98 | // In server-mode, we have to wait for the client to connect before we 99 | // can begin reading. We make use of the input_state_ when performing 100 | // the connect operation in overlapped mode. 101 | bool waiting_connect_; 102 | 103 | // This flag is set when processing incoming messages. It is used to 104 | // avoid recursing through ProcessIncomingMessages, which could cause 105 | // problems. TODO(darin): make this unnecessary 106 | bool processing_incoming_; 107 | 108 | // Determines if we should validate a client's secret on connection. 109 | bool validate_client_; 110 | 111 | // This is a unique per-channel value used to authenticate the client end of 112 | // a connection. If the value is non-zero, the client passes it in the hello 113 | // and the host validates. (We don't send the zero value fto preserve IPC 114 | // compatability with existing clients that don't validate the channel.) 115 | int32 client_secret_; 116 | 117 | Thread* thread_; 118 | 119 | DISALLOW_COPY_AND_ASSIGN(Channel); 120 | }; 121 | 122 | } // namespace IPC 123 | 124 | #endif // IPC_IPC_CHANNEL_WIN_H_ 125 | -------------------------------------------------------------------------------- /ipc/ipc_channel_handle.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #ifndef IPC_IPC_CHANNEL_HANDLE_H_ 6 | #define IPC_IPC_CHANNEL_HANDLE_H_ 7 | 8 | #include 9 | #include 10 | 11 | // On Windows, any process can create an IPC channel and others can fetch 12 | // it by name. We pass around the channel names over IPC. 13 | // On Windows the initialization of ChannelHandle with an existing pipe 14 | // handle is provided for convenience. 15 | // NOTE: A ChannelHandle with a pipe handle Will NOT be marshalled over IPC. 16 | 17 | // On POSIX, we instead pass around handles to channel endpoints via IPC. 18 | // When it's time to IPC a new channel endpoint around, we send both the 19 | // channel name as well as a base::FileDescriptor, which is itself a special 20 | // type that knows how to copy a socket endpoint over IPC. 21 | // 22 | // In sum, this data structure can be used to pass channel information by name 23 | // in both Windows and Posix. When passing a handle to a channel over IPC, 24 | // use this data structure only for POSIX. 25 | 26 | namespace IPC { 27 | 28 | struct ChannelHandle { 29 | // Note that serialization for this object is defined in the ParamTraits 30 | // template specialization in ipc_message_utils.h. 31 | ChannelHandle() {} 32 | // The name that is passed in should be an absolute path for Posix. 33 | // Otherwise there may be a problem in IPC communication between 34 | // processes with different working directories. 35 | ChannelHandle(const std::string& n) : name(n) {} 36 | ChannelHandle(const char* n) : name(n) {} 37 | explicit ChannelHandle(HANDLE h) : pipe(h) {} 38 | 39 | std::string name; 40 | // A simple container to automatically initialize pipe handle 41 | struct PipeHandle { 42 | PipeHandle() : handle(NULL) {} 43 | PipeHandle(HANDLE h) : handle(h) {} 44 | HANDLE handle; 45 | }; 46 | PipeHandle pipe; 47 | }; 48 | 49 | } // namespace IPC 50 | 51 | #endif // IPC_IPC_CHANNEL_HANDLE_H_ 52 | -------------------------------------------------------------------------------- /ipc/ipc_channel_reader.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include "ipc/ipc_channel_reader.h" 6 | 7 | #include "ipc/ipc_listener.h" 8 | #include "ipc/ipc_message.h" 9 | #include "ipc/ipc_channel.h" 10 | //#include "ipc/ipc_logging.h" 11 | #include 12 | 13 | namespace IPC { 14 | namespace internal { 15 | 16 | ChannelReader::ChannelReader(Listener* listener) : listener_(listener) { 17 | memset(input_buf_, 0, sizeof(input_buf_)); 18 | } 19 | 20 | ChannelReader::~ChannelReader() { 21 | } 22 | 23 | bool ChannelReader::ProcessIncomingMessages() { 24 | while (true) { 25 | int bytes_read = 0; 26 | ReadState read_state = ReadData(input_buf_, kReadBufferSize, 27 | &bytes_read); 28 | if (read_state == READ_FAILED) 29 | return false; 30 | if (read_state == READ_PENDING) 31 | return true; 32 | 33 | assert(bytes_read > 0); 34 | if (!DispatchInputData(input_buf_, bytes_read)) 35 | return false; 36 | } 37 | } 38 | 39 | bool ChannelReader::AsyncReadComplete(int bytes_read) { 40 | return DispatchInputData(input_buf_, bytes_read); 41 | } 42 | 43 | bool ChannelReader::IsHelloMessage(Message* m) const { 44 | return m->routing_id() == MSG_ROUTING_NONE && 45 | m->type() == Channel::HELLO_MESSAGE_TYPE; 46 | } 47 | 48 | bool ChannelReader::DispatchInputData(const char* input_data, 49 | int input_data_len) { 50 | const char* p; 51 | const char* end; 52 | 53 | // Possibly combine with the overflow buffer to make a larger buffer. 54 | if (input_overflow_buf_.empty()) { 55 | p = input_data; 56 | end = input_data + input_data_len; 57 | } else { 58 | if (input_overflow_buf_.size() + input_data_len > 59 | Channel::kMaximumMessageSize) { 60 | input_overflow_buf_.clear(); 61 | //assert(ERROR) << "IPC message is too big"; 62 | return false; 63 | } 64 | input_overflow_buf_.append(input_data, input_data_len); 65 | p = input_overflow_buf_.data(); 66 | end = p + input_overflow_buf_.size(); 67 | } 68 | 69 | // Dispatch all complete messages in the data buffer. 70 | while (p < end) { 71 | const char* message_tail = Message::FindNext(p, end); 72 | if (message_tail) { 73 | int len = static_cast(message_tail - p); 74 | Message* m = new Message(p, len); 75 | m->AddRef(); 76 | if (!WillDispatchInputMessage(m)) 77 | return false; 78 | 79 | #ifdef IPC_MESSAGE_LOG_ENABLED 80 | Logging* logger = Logging::GetInstance(); 81 | std::string name; 82 | logger->GetMessageText(m.type(), &name, &m, NULL); 83 | TRACE_EVENT1("ipc", "ChannelReader::DispatchInputData", "name", name); 84 | #else 85 | //TRACE_EVENT2("ipc", "ChannelReader::DispatchInputData", 86 | // "class", IPC_MESSAGE_ID_CLASS(m.type()), 87 | // "line", IPC_MESSAGE_ID_LINE(m.type())); 88 | #endif 89 | //m.TraceMessageEnd(); 90 | if (IsHelloMessage(m)) 91 | HandleHelloMessage(m); 92 | else 93 | listener_->OnMessageReceived(m); 94 | p = message_tail; 95 | } else { 96 | // Last message is partial. 97 | break; 98 | } 99 | } 100 | 101 | // Save any partial data in the overflow buffer. 102 | input_overflow_buf_.assign(p, end - p); 103 | 104 | if (input_overflow_buf_.empty() && !DidEmptyInputBuffers()) 105 | return false; 106 | return true; 107 | } 108 | 109 | 110 | } // namespace internal 111 | } // namespace IPC 112 | -------------------------------------------------------------------------------- /ipc/ipc_channel_reader.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #ifndef IPC_IPC_CHANNEL_READER_H_ 6 | #define IPC_IPC_CHANNEL_READER_H_ 7 | 8 | #include "ipc/ipc_listener.h" 9 | #include "ipc/ipc_common.h" 10 | 11 | namespace IPC { 12 | namespace internal { 13 | 14 | // This class provides common pipe reading functionality for the 15 | // platform-specific IPC channel implementations. 16 | // 17 | // It does the common input buffer management and message dispatch, while the 18 | // platform-specific parts provide the pipe management through a virtual 19 | // interface implemented on a per-platform basis. 20 | // 21 | // Note that there is no "writer" corresponding to this because the code for 22 | // writing to the channel is much simpler and has very little common 23 | // functionality that would benefit from being factored out. If we add 24 | // something like that in the future, it would be more appropriate to add it 25 | // here (and rename appropriately) rather than writing a different class. 26 | class ChannelReader { 27 | public: 28 | // Amount of data to read at once from the pipe. 29 | static const size_t kReadBufferSize = 4 * 1024; 30 | 31 | explicit ChannelReader(Listener* listener); 32 | virtual ~ChannelReader(); 33 | 34 | void set_listener(Listener* listener) { listener_ = listener; } 35 | 36 | // Call to process messages received from the IPC connection and dispatch 37 | // them. Returns false on channel error. True indicates that everything 38 | // succeeded, although there may not have been any messages processed. 39 | bool ProcessIncomingMessages(); 40 | 41 | // Handles asynchronously read data. 42 | // 43 | // Optionally call this after returning READ_PENDING from ReadData to 44 | // indicate that buffer was filled with the given number of bytes of 45 | // data. See ReadData for more. 46 | bool AsyncReadComplete(int bytes_read); 47 | 48 | // Returns true if the given message is the "hello" message sent on channel 49 | // set-up. 50 | bool IsHelloMessage(Message* m) const; 51 | 52 | protected: 53 | enum ReadState { READ_SUCCEEDED, READ_FAILED, READ_PENDING }; 54 | 55 | Listener* listener() const { return listener_; } 56 | 57 | // Populates the given buffer with data from the pipe. 58 | // 59 | // Returns the state of the read. On READ_SUCCESS, the number of bytes 60 | // read will be placed into |*bytes_read| (which can be less than the 61 | // buffer size). On READ_FAILED, the channel will be closed. 62 | // 63 | // If the return value is READ_PENDING, it means that there was no data 64 | // ready for reading. The implementation is then responsible for either 65 | // calling AsyncReadComplete with the number of bytes read into the 66 | // buffer, or ProcessIncomingMessages to try the read again (depending 67 | // on whether the platform's async I/O is "try again" or "write 68 | // asynchronously into your buffer"). 69 | virtual ReadState ReadData(char* buffer, int buffer_len, int* bytes_read) = 0; 70 | 71 | // Loads the required file desciptors into the given message. Returns true 72 | // on success. False means a fatal channel error. 73 | // 74 | // This will read from the input_fds_ and read more handles from the FD 75 | // pipe if necessary. 76 | virtual bool WillDispatchInputMessage(Message* msg) = 0; 77 | 78 | // Performs post-dispatch checks. Called when all input buffers are empty, 79 | // though there could be more data ready to be read from the OS. 80 | virtual bool DidEmptyInputBuffers() = 0; 81 | 82 | // Handles the first message sent over the pipe which contains setup info. 83 | virtual void HandleHelloMessage(Message* msg) = 0; 84 | 85 | private: 86 | // Takes the given data received from the IPC channel and dispatches any 87 | // fully completed messages. 88 | // 89 | // Returns true on success. False means channel error. 90 | bool DispatchInputData(const char* input_data, int input_data_len); 91 | 92 | Listener* listener_; 93 | 94 | // We read from the pipe into this buffer. Managed by DispatchInputData, do 95 | // not access directly outside that function. 96 | char input_buf_[kReadBufferSize]; 97 | 98 | // Large messages that span multiple pipe buffers, get built-up using 99 | // this buffer. 100 | std::string input_overflow_buf_; 101 | 102 | DISALLOW_COPY_AND_ASSIGN(ChannelReader); 103 | }; 104 | 105 | } // namespace internal 106 | } // namespace IPC 107 | 108 | #endif // IPC_IPC_CHANNEL_READER_H_ 109 | -------------------------------------------------------------------------------- /ipc/ipc_common.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | typedef signed char schar; 6 | typedef signed char int8; 7 | typedef short int16; 8 | typedef int int32; 9 | 10 | typedef long long int64; 11 | 12 | typedef unsigned char uint8; 13 | typedef unsigned short uint16; 14 | typedef unsigned int uint32; 15 | 16 | typedef unsigned long long uint64; 17 | 18 | const uint16 kuint16max = ((uint16)0xFFFF); 19 | const int32 kint32max = ((int32)0x7FFFFFFF); 20 | 21 | // A macro to disallow the copy constructor and operator= functions 22 | // This should be used in the private: declarations for a class 23 | #define DISALLOW_COPY_AND_ASSIGN(TypeName) \ 24 | TypeName(const TypeName&); \ 25 | void operator=(const TypeName&) 26 | -------------------------------------------------------------------------------- /ipc/ipc_endpoint.cpp: -------------------------------------------------------------------------------- 1 | #include "ipc_endpoint.h" 2 | #include "ipc/ipc_message.h" 3 | #include 4 | 5 | namespace IPC 6 | { 7 | 8 | Endpoint::Endpoint(const std::string& name, Listener* listener, bool start_now) 9 | : name_(name) 10 | , listener_(listener) 11 | , is_connected_(false) 12 | { 13 | thread_.Start(); 14 | if (start_now) 15 | Start(); 16 | } 17 | 18 | Endpoint::~Endpoint() 19 | { 20 | SetConnected(false); 21 | if (channel_) 22 | { 23 | HANDLE wait_event = ::CreateEvent(NULL, FALSE, FALSE, NULL); 24 | thread_.PostTask(std::bind(&Endpoint::CloseChannel, this, wait_event)); 25 | DWORD ret = ::WaitForSingleObject(wait_event, 2000); 26 | assert(ret == WAIT_OBJECT_0); 27 | CloseHandle(wait_event); 28 | delete channel_; 29 | channel_ = NULL; 30 | } 31 | thread_.Stop(); 32 | thread_.Wait(2000); 33 | } 34 | 35 | void Endpoint::Start() 36 | { 37 | if (channel_ == NULL) 38 | thread_.PostTask(std::bind(&Endpoint::CreateChannel, this)); 39 | } 40 | 41 | 42 | bool Endpoint::IsConnected() const 43 | { 44 | AutoLock lock(lock_); 45 | return is_connected_; 46 | } 47 | 48 | 49 | void Endpoint::SetConnected(bool c) 50 | { 51 | AutoLock lock(lock_); 52 | is_connected_ = c; 53 | } 54 | 55 | 56 | void Endpoint::CreateChannel() 57 | { 58 | if (channel_) 59 | return; 60 | 61 | channel_ = new Channel(name_, this, &thread_); 62 | channel_->Connect(); 63 | } 64 | 65 | bool Endpoint::Send(Message* message) 66 | { 67 | scoped_refptr m(message); 68 | if (channel_ == NULL || !IsConnected()) { 69 | return false; 70 | } 71 | thread_.PostTask(std::bind(&Endpoint::OnSendMessage, this, m)); 72 | return true; 73 | } 74 | 75 | 76 | void Endpoint::OnSendMessage(scoped_refptr message) 77 | { 78 | if (channel_ == NULL) 79 | return; 80 | 81 | channel_->Send(message.get()); 82 | } 83 | 84 | 85 | bool Endpoint::OnMessageReceived(Message* message) 86 | { 87 | return listener_->OnMessageReceived(message); 88 | } 89 | 90 | void Endpoint::OnChannelConnected(int32 peer_pid) 91 | { 92 | SetConnected(true); 93 | listener_->OnChannelConnected(peer_pid); 94 | } 95 | 96 | void Endpoint::OnChannelError() 97 | { 98 | Channel* ch = channel_; 99 | channel_ = NULL; 100 | delete ch; 101 | SetConnected(false); 102 | listener_->OnChannelError(); 103 | Start(); 104 | } 105 | 106 | void Endpoint::CloseChannel(HANDLE wait_event) 107 | { 108 | Channel* ch = channel_; 109 | channel_ = NULL; 110 | delete ch; 111 | SetEvent(wait_event); 112 | } 113 | 114 | 115 | } -------------------------------------------------------------------------------- /ipc/ipc_endpoint.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "ipc/ipc_thread.h" 3 | #include "ipc/ipc_channel.h" 4 | #include "ipc/ipc_listener.h" 5 | 6 | namespace IPC 7 | { 8 | class Endpoint : public Sender, public Listener 9 | { 10 | public: 11 | Endpoint(const std::string& name, Listener* listener, bool start_now = true); 12 | ~Endpoint(); 13 | 14 | void Start(); 15 | 16 | bool IsConnected() const; 17 | 18 | virtual bool Send(Message* message) override; 19 | 20 | virtual bool OnMessageReceived(Message* message) override; 21 | 22 | virtual void OnChannelConnected(int32 peer_pid) override; 23 | 24 | virtual void OnChannelError() override; 25 | 26 | private: 27 | void CreateChannel(); 28 | void OnSendMessage(scoped_refptr message); 29 | void CloseChannel(HANDLE wait_event); 30 | void SetConnected(bool c); 31 | std::string name_; 32 | Thread thread_; 33 | 34 | Channel* channel_; 35 | Listener* listener_; 36 | //std::queue 37 | 38 | mutable Lock lock_; 39 | bool is_connected_; 40 | }; 41 | } -------------------------------------------------------------------------------- /ipc/ipc_interface.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace IPC 4 | { 5 | enum ErrorCode 6 | { 7 | ERROR_OK = 0, 8 | 9 | ERROR_MESSAGE_READONLY = 1, 10 | 11 | ERROR_DEST_DISCONNECTED = 2, 12 | }; 13 | 14 | class IListener 15 | { 16 | public: 17 | virtual void AddRef() const = 0; 18 | virtual void Release() const = 0; 19 | virtual void OnMessageReceived(const char* message, size_t len) {}; 20 | virtual void OnDestConnected(int process_id) {} 21 | virtual void OnDestDisconnected() {} 22 | }; 23 | 24 | class IEndpoint 25 | { 26 | public: 27 | virtual void AddRef() const = 0; 28 | virtual void Release() const = 0; 29 | virtual ErrorCode Send(const char* message, size_t len) = 0; 30 | virtual bool HasListener() const = 0; 31 | virtual void SetListener(IListener* listener) = 0; 32 | }; 33 | 34 | } -------------------------------------------------------------------------------- /ipc/ipc_listener.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #ifndef IPC_IPC_LISTENER_H_ 6 | #define IPC_IPC_LISTENER_H_ 7 | 8 | #include "ipc/ipc_common.h" 9 | 10 | namespace IPC { 11 | 12 | class Message; 13 | 14 | // Implemented by consumers of a Channel to receive messages. 15 | class Listener { 16 | public: 17 | // Called when a message is received. Returns true iff the message was 18 | // handled. 19 | virtual bool OnMessageReceived(Message* message) = 0; 20 | 21 | // Called when the channel is connected and we have received the internal 22 | // Hello message from the peer. 23 | virtual void OnChannelConnected(int32 peer_pid) {} 24 | 25 | // Called when an error is detected that causes the channel to close. 26 | // This method is not called when a channel is closed normally. 27 | virtual void OnChannelError() {} 28 | 29 | protected: 30 | virtual ~Listener() {} 31 | }; 32 | 33 | } // namespace IPC 34 | 35 | #endif // IPC_IPC_LISTENER_H_ 36 | -------------------------------------------------------------------------------- /ipc/ipc_logging.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include "ipc/ipc_logging.h" 6 | 7 | #ifdef IPC_MESSAGE_LOG_ENABLED 8 | #define IPC_MESSAGE_MACROS_LOG_ENABLED 9 | #endif 10 | 11 | #include "base/bind.h" 12 | #include "base/bind_helpers.h" 13 | #include "base/command_line.h" 14 | #include "base/location.h" 15 | #include "base/logging.h" 16 | #include "base/message_loop.h" 17 | #include "base/process_util.h" 18 | #include "base/string_number_conversions.h" 19 | #include "base/string_util.h" 20 | #include "base/threading/thread.h" 21 | #include "base/time.h" 22 | #include "ipc/ipc_switches.h" 23 | #include "ipc/ipc_sync_message.h" 24 | #include "ipc/ipc_message_utils.h" 25 | #include "ipc/ipc_sender.h" 26 | 27 | #if defined(OS_POSIX) 28 | #include 29 | #endif 30 | 31 | #ifdef IPC_MESSAGE_LOG_ENABLED 32 | 33 | using base::Time; 34 | 35 | namespace IPC { 36 | 37 | const int kLogSendDelayMs = 100; 38 | 39 | // We use a pointer to the function table to avoid any linker dependencies on 40 | // all the traits used as IPC message parameters. 41 | LogFunctionMap* Logging::log_function_map_; 42 | 43 | Logging::Logging() 44 | : enabled_(false), 45 | enabled_on_stderr_(false), 46 | enabled_color_(false), 47 | queue_invoke_later_pending_(false), 48 | sender_(NULL), 49 | main_thread_(base::MessageLoop::current()), 50 | consumer_(NULL) { 51 | #if defined(OS_WIN) 52 | // getenv triggers an unsafe warning. Simply check how big of a buffer 53 | // would be needed to fetch the value to see if the enviornment variable is 54 | // set. 55 | size_t requiredSize = 0; 56 | getenv_s(&requiredSize, NULL, 0, "CHROME_IPC_LOGGING"); 57 | bool logging_env_var_set = (requiredSize != 0); 58 | if (requiredSize <= 6) { 59 | char buffer[6]; 60 | getenv_s(&requiredSize, buffer, sizeof(buffer), "CHROME_IPC_LOGGING"); 61 | if (requiredSize && !strncmp("color", buffer, 6)) 62 | enabled_color_ = true; 63 | } 64 | #else // !defined(OS_WIN) 65 | const char* ipc_logging = getenv("CHROME_IPC_LOGGING"); 66 | bool logging_env_var_set = (ipc_logging != NULL); 67 | if (ipc_logging && !strcmp(ipc_logging, "color")) 68 | enabled_color_ = true; 69 | #endif //defined(OS_WIN) 70 | if (logging_env_var_set) { 71 | enabled_ = true; 72 | enabled_on_stderr_ = true; 73 | } 74 | } 75 | 76 | Logging::~Logging() { 77 | } 78 | 79 | Logging* Logging::GetInstance() { 80 | return Singleton::get(); 81 | } 82 | 83 | void Logging::SetConsumer(Consumer* consumer) { 84 | consumer_ = consumer; 85 | } 86 | 87 | void Logging::Enable() { 88 | enabled_ = true; 89 | } 90 | 91 | void Logging::Disable() { 92 | enabled_ = false; 93 | } 94 | 95 | void Logging::OnSendLogs() { 96 | queue_invoke_later_pending_ = false; 97 | if (!sender_) 98 | return; 99 | 100 | Message* msg = new Message( 101 | MSG_ROUTING_CONTROL, IPC_LOGGING_ID, Message::PRIORITY_NORMAL); 102 | WriteParam(msg, queued_logs_); 103 | queued_logs_.clear(); 104 | sender_->Send(msg); 105 | } 106 | 107 | void Logging::SetIPCSender(IPC::Sender* sender) { 108 | sender_ = sender; 109 | } 110 | 111 | void Logging::OnReceivedLoggingMessage(const Message& message) { 112 | std::vector data; 113 | PickleIterator iter(message); 114 | if (!ReadParam(&message, &iter, &data)) 115 | return; 116 | 117 | for (size_t i = 0; i < data.size(); ++i) { 118 | Log(data[i]); 119 | } 120 | } 121 | 122 | void Logging::OnSendMessage(Message* message, const std::string& channel_id) { 123 | if (!Enabled()) 124 | return; 125 | 126 | if (message->is_reply()) { 127 | LogData* data = message->sync_log_data(); 128 | if (!data) 129 | return; 130 | 131 | // This is actually the delayed reply to a sync message. Create a string 132 | // of the output parameters, add it to the LogData that was earlier stashed 133 | // with the reply, and log the result. 134 | GenerateLogData("", *message, data, true); 135 | data->channel = channel_id; 136 | Log(*data); 137 | delete data; 138 | message->set_sync_log_data(NULL); 139 | } else { 140 | // If the time has already been set (i.e. by ChannelProxy), keep that time 141 | // instead as it's more accurate. 142 | if (!message->sent_time()) 143 | message->set_sent_time(Time::Now().ToInternalValue()); 144 | } 145 | } 146 | 147 | void Logging::OnPreDispatchMessage(const Message& message) { 148 | message.set_received_time(Time::Now().ToInternalValue()); 149 | } 150 | 151 | void Logging::OnPostDispatchMessage(const Message& message, 152 | const std::string& channel_id) { 153 | if (!Enabled() || 154 | !message.sent_time() || 155 | !message.received_time() || 156 | message.dont_log()) 157 | return; 158 | 159 | LogData data; 160 | GenerateLogData(channel_id, message, &data, true); 161 | 162 | if (base::MessageLoop::current() == main_thread_) { 163 | Log(data); 164 | } else { 165 | main_thread_->PostTask( 166 | FROM_HERE, base::Bind(&Logging::Log, base::Unretained(this), data)); 167 | } 168 | } 169 | 170 | void Logging::GetMessageText(uint32 type, std::string* name, 171 | const Message* message, 172 | std::string* params) { 173 | if (!log_function_map_) 174 | return; 175 | 176 | LogFunctionMap::iterator it = log_function_map_->find(type); 177 | if (it == log_function_map_->end()) { 178 | if (name) { 179 | *name = "[UNKNOWN MSG "; 180 | *name += base::IntToString(type); 181 | *name += " ]"; 182 | } 183 | return; 184 | } 185 | 186 | (*it->second)(name, message, params); 187 | } 188 | 189 | const char* Logging::ANSIEscape(ANSIColor color) { 190 | if (!enabled_color_) 191 | return ""; 192 | switch (color) { 193 | case ANSI_COLOR_RESET: 194 | return "\033[m"; 195 | case ANSI_COLOR_BLACK: 196 | return "\033[0;30m"; 197 | case ANSI_COLOR_RED: 198 | return "\033[0;31m"; 199 | case ANSI_COLOR_GREEN: 200 | return "\033[0;32m"; 201 | case ANSI_COLOR_YELLOW: 202 | return "\033[0;33m"; 203 | case ANSI_COLOR_BLUE: 204 | return "\033[0;34m"; 205 | case ANSI_COLOR_MAGENTA: 206 | return "\033[0;35m"; 207 | case ANSI_COLOR_CYAN: 208 | return "\033[0;36m"; 209 | case ANSI_COLOR_WHITE: 210 | return "\033[0;37m"; 211 | } 212 | return ""; 213 | } 214 | 215 | Logging::ANSIColor Logging::DelayColor(double delay) { 216 | if (delay < 0.1) 217 | return ANSI_COLOR_GREEN; 218 | if (delay < 0.25) 219 | return ANSI_COLOR_BLACK; 220 | if (delay < 0.5) 221 | return ANSI_COLOR_YELLOW; 222 | return ANSI_COLOR_RED; 223 | } 224 | 225 | void Logging::Log(const LogData& data) { 226 | if (consumer_) { 227 | // We're in the browser process. 228 | consumer_->Log(data); 229 | } else { 230 | // We're in the renderer or plugin processes. 231 | if (sender_) { 232 | queued_logs_.push_back(data); 233 | if (!queue_invoke_later_pending_) { 234 | queue_invoke_later_pending_ = true; 235 | base::MessageLoop::current()->PostDelayedTask( 236 | FROM_HERE, 237 | base::Bind(&Logging::OnSendLogs, base::Unretained(this)), 238 | base::TimeDelta::FromMilliseconds(kLogSendDelayMs)); 239 | } 240 | } 241 | } 242 | if (enabled_on_stderr_) { 243 | std::string message_name; 244 | if (data.message_name.empty()) { 245 | message_name = base::StringPrintf("[unknown type %d]", data.type); 246 | } else { 247 | message_name = data.message_name; 248 | } 249 | double receive_delay = 250 | (Time::FromInternalValue(data.receive) - 251 | Time::FromInternalValue(data.sent)).InSecondsF(); 252 | double dispatch_delay = 253 | (Time::FromInternalValue(data.dispatch) - 254 | Time::FromInternalValue(data.sent)).InSecondsF(); 255 | fprintf(stderr, 256 | "ipc %s %d %s %s%s %s%s\n %18.5f %s%18.5f %s%18.5f%s\n", 257 | data.channel.c_str(), 258 | data.routing_id, 259 | data.flags.c_str(), 260 | ANSIEscape(sender_ ? ANSI_COLOR_BLUE : ANSI_COLOR_CYAN), 261 | message_name.c_str(), 262 | ANSIEscape(ANSI_COLOR_RESET), 263 | data.params.c_str(), 264 | Time::FromInternalValue(data.sent).ToDoubleT(), 265 | ANSIEscape(DelayColor(receive_delay)), 266 | Time::FromInternalValue(data.receive).ToDoubleT(), 267 | ANSIEscape(DelayColor(dispatch_delay)), 268 | Time::FromInternalValue(data.dispatch).ToDoubleT(), 269 | ANSIEscape(ANSI_COLOR_RESET) 270 | ); 271 | } 272 | } 273 | 274 | void GenerateLogData(const std::string& channel, const Message& message, 275 | LogData* data, bool get_params) { 276 | if (message.is_reply()) { 277 | // "data" should already be filled in. 278 | std::string params; 279 | Logging::GetMessageText(data->type, NULL, &message, ¶ms); 280 | 281 | if (!data->params.empty() && !params.empty()) 282 | data->params += ", "; 283 | 284 | data->flags += " DR"; 285 | 286 | data->params += params; 287 | } else { 288 | std::string flags; 289 | if (message.is_sync()) 290 | flags = "S"; 291 | 292 | if (message.is_reply()) 293 | flags += "R"; 294 | 295 | if (message.is_reply_error()) 296 | flags += "E"; 297 | 298 | std::string params, message_name; 299 | Logging::GetMessageText(message.type(), &message_name, &message, 300 | get_params ? ¶ms : NULL); 301 | 302 | data->channel = channel; 303 | data->routing_id = message.routing_id(); 304 | data->type = message.type(); 305 | data->flags = flags; 306 | data->sent = message.sent_time(); 307 | data->receive = message.received_time(); 308 | data->dispatch = Time::Now().ToInternalValue(); 309 | data->params = params; 310 | data->message_name = message_name; 311 | } 312 | } 313 | 314 | } 315 | 316 | #endif // IPC_MESSAGE_LOG_ENABLED 317 | -------------------------------------------------------------------------------- /ipc/ipc_logging.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #ifndef IPC_IPC_LOGGING_H_ 6 | #define IPC_IPC_LOGGING_H_ 7 | 8 | #include "ipc_message.h" // For IPC_MESSAGE_LOG_ENABLED. 9 | 10 | #ifdef IPC_MESSAGE_LOG_ENABLED 11 | 12 | #include 13 | 14 | #include "base/hash_tables.h" 15 | #include "base/memory/scoped_ptr.h" 16 | #include "base/memory/singleton.h" 17 | #include "base/message_loop.h" 18 | #include "ipc/ipc_export.h" 19 | 20 | // Logging function. |name| is a string in ASCII and |params| is a string in 21 | // UTF-8. 22 | typedef void (*LogFunction)(std::string* name, 23 | const IPC::Message* msg, 24 | std::string* params); 25 | 26 | typedef base::hash_map LogFunctionMap; 27 | 28 | namespace IPC { 29 | 30 | class Message; 31 | class Sender; 32 | 33 | // One instance per process. Needs to be created on the main thread (the UI 34 | // thread in the browser) but OnPreDispatchMessage/OnPostDispatchMessage 35 | // can be called on other threads. 36 | class IPC_EXPORT Logging { 37 | public: 38 | // Implemented by consumers of log messages. 39 | class Consumer { 40 | public: 41 | virtual void Log(const LogData& data) = 0; 42 | 43 | protected: 44 | virtual ~Consumer() {} 45 | }; 46 | 47 | void SetConsumer(Consumer* consumer); 48 | 49 | ~Logging(); 50 | static Logging* GetInstance(); 51 | 52 | // Enable and Disable are NOT cross-process; they only affect the 53 | // current thread/process. If you want to modify the value for all 54 | // processes, perhaps your intent is to call 55 | // g_browser_process->SetIPCLoggingEnabled(). 56 | void Enable(); 57 | void Disable(); 58 | bool Enabled() const { return enabled_; } 59 | 60 | // Called by child processes to give the logger object the channel to send 61 | // logging data to the browser process. 62 | void SetIPCSender(Sender* sender); 63 | 64 | // Called in the browser process when logging data from a child process is 65 | // received. 66 | void OnReceivedLoggingMessage(const Message& message); 67 | 68 | void OnSendMessage(Message* message, const std::string& channel_id); 69 | void OnPreDispatchMessage(const Message& message); 70 | void OnPostDispatchMessage(const Message& message, 71 | const std::string& channel_id); 72 | 73 | // Like the *MsgLog functions declared for each message class, except this 74 | // calls the correct one based on the message type automatically. Defined in 75 | // ipc_logging.cc. 76 | static void GetMessageText(uint32 type, std::string* name, 77 | const Message* message, std::string* params); 78 | 79 | static void set_log_function_map(LogFunctionMap* functions) { 80 | log_function_map_ = functions; 81 | } 82 | 83 | static LogFunctionMap* log_function_map() { 84 | return log_function_map_; 85 | } 86 | 87 | private: 88 | typedef enum { 89 | ANSI_COLOR_RESET = -1, 90 | ANSI_COLOR_BLACK, 91 | ANSI_COLOR_RED, 92 | ANSI_COLOR_GREEN, 93 | ANSI_COLOR_YELLOW, 94 | ANSI_COLOR_BLUE, 95 | ANSI_COLOR_MAGENTA, 96 | ANSI_COLOR_CYAN, 97 | ANSI_COLOR_WHITE 98 | } ANSIColor; 99 | const char* ANSIEscape(ANSIColor color); 100 | ANSIColor DelayColor(double delay); 101 | 102 | friend struct DefaultSingletonTraits; 103 | Logging(); 104 | 105 | void OnSendLogs(); 106 | void Log(const LogData& data); 107 | 108 | bool enabled_; 109 | bool enabled_on_stderr_; // only used on POSIX for now 110 | bool enabled_color_; // only used on POSIX for now 111 | 112 | std::vector queued_logs_; 113 | bool queue_invoke_later_pending_; 114 | 115 | Sender* sender_; 116 | base::MessageLoop* main_thread_; 117 | 118 | Consumer* consumer_; 119 | 120 | static LogFunctionMap* log_function_map_; 121 | }; 122 | 123 | } // namespace IPC 124 | 125 | #endif // IPC_MESSAGE_LOG_ENABLED 126 | 127 | #endif // IPC_IPC_LOGGING_H_ 128 | -------------------------------------------------------------------------------- /ipc/ipc_message.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #include "ipc/ipc_message.h" 6 | 7 | #include 8 | #include 9 | 10 | namespace { 11 | 12 | int32 g_ref_num = 0; 13 | 14 | const int kPayloadUnit = 32; 15 | 16 | const size_t kCapacityReadOnly = static_cast(-1); 17 | 18 | 19 | 20 | // Create a reference number for identifying IPC messages in traces. The return 21 | // values has the reference number stored in the upper 24 bits, leaving the low 22 | // 8 bits set to 0 for use as flags. 23 | inline uint32 GetRefNumUpper24() { 24 | int32 pid = 0; 25 | int32 count = InterlockedExchangeAdd(reinterpret_cast(&g_ref_num), 1); 26 | // The 24 bit hash is composed of 14 bits of the count and 10 bits of the 27 | // Process ID. With the current trace event buffer cap, the 14-bit count did 28 | // not appear to wrap during a trace. Note that it is not a big deal if 29 | // collisions occur, as this is only used for debugging and trace analysis. 30 | return ((pid << 14) | (count & 0x3fff)) << 8; 31 | } 32 | 33 | } // namespace 34 | 35 | namespace IPC { 36 | 37 | const uint32 Message::kHeaderSize = sizeof(Message::Header); 38 | 39 | //------------------------------------------------------------------------------ 40 | 41 | Message::~Message() { 42 | if (capacity_ != kCapacityReadOnly) 43 | free(header_); 44 | } 45 | 46 | Message::Message() 47 | : header_(NULL) 48 | , capacity_(0) 49 | , ref_count_(0) 50 | , variable_buffer_offset_(0) { 51 | Resize(kPayloadUnit); 52 | 53 | header()->payload_size = 0; 54 | header()->routing = header()->type = 0; 55 | header()->flags = GetRefNumUpper24(); 56 | 57 | 58 | 59 | InitLoggingVariables(); 60 | } 61 | 62 | Message::Message(int32 routing_id, uint32 type, PriorityValue priority) 63 | : header_(NULL) 64 | , capacity_(0) 65 | , ref_count_(0) 66 | , variable_buffer_offset_(0) { 67 | Resize(kPayloadUnit); 68 | 69 | header()->payload_size = 0; 70 | header()->routing = routing_id; 71 | header()->type = type; 72 | assert((priority & 0xffffff00) == 0); 73 | header()->flags = priority | GetRefNumUpper24(); 74 | 75 | 76 | InitLoggingVariables(); 77 | } 78 | 79 | Message::Message(const char* data, int data_len) 80 | : header_(reinterpret_cast(const_cast(data))) 81 | , capacity_(kCapacityReadOnly) 82 | , ref_count_(0) 83 | , variable_buffer_offset_(0) { 84 | 85 | if (kHeaderSize > static_cast(data_len)) 86 | header_ = NULL; 87 | 88 | if (header_ && header_->payload_size + kHeaderSize > static_cast(data_len)) 89 | header_ = NULL; 90 | 91 | InitLoggingVariables(); 92 | } 93 | 94 | void Message::InitLoggingVariables() { 95 | #ifdef IPC_MESSAGE_LOG_ENABLED 96 | received_time_ = 0; 97 | dont_log_ = false; 98 | log_data_ = NULL; 99 | #endif 100 | } 101 | 102 | void Message::SetHeaderValues(int32 routing, uint32 type, uint32 flags) { 103 | // This should only be called when the message is already empty. 104 | assert(payload_size() == 0); 105 | 106 | header()->routing = routing; 107 | header()->type = type; 108 | header()->flags = flags; 109 | } 110 | 111 | #ifdef IPC_MESSAGE_LOG_ENABLED 112 | void Message::set_sent_time(int64 time) { 113 | DCHECK((header()->flags & HAS_SENT_TIME_BIT) == 0); 114 | header()->flags |= HAS_SENT_TIME_BIT; 115 | WriteInt64(time); 116 | } 117 | 118 | int64 Message::sent_time() const { 119 | if ((header()->flags & HAS_SENT_TIME_BIT) == 0) 120 | return 0; 121 | 122 | const char* data = end_of_payload(); 123 | data -= sizeof(int64); 124 | return *(reinterpret_cast(data)); 125 | } 126 | 127 | void Message::set_received_time(int64 time) const { 128 | received_time_ = time; 129 | } 130 | #endif 131 | 132 | Message::Header* Message::header() 133 | { 134 | return static_cast(header_); 135 | } 136 | 137 | const Message::Header* Message::header() const 138 | { 139 | return static_cast(header_); 140 | } 141 | 142 | bool Message::Resize(size_t new_capacity) 143 | { 144 | new_capacity = AlignInt(new_capacity, kPayloadUnit); 145 | 146 | assert(capacity_ != kCapacityReadOnly); 147 | void* p = realloc(header_, new_capacity); 148 | if (!p) 149 | return false; 150 | 151 | header_ = reinterpret_cast(p); 152 | capacity_ = new_capacity; 153 | return true; 154 | } 155 | 156 | const char* Message::FindNext(const char* range_start, const char* range_end) 157 | { 158 | if (static_cast(range_end - range_start) < sizeof(Header)) 159 | return NULL; 160 | 161 | const Header* hdr = reinterpret_cast(range_start); 162 | const char* payload_base = range_start + sizeof(Header); 163 | const char* payload_end = payload_base + hdr->payload_size; 164 | if (payload_end < payload_base) 165 | return NULL; 166 | 167 | return (payload_end > range_end) ? NULL : payload_end; 168 | } 169 | 170 | bool Message::WriteString(const std::string& value) 171 | { 172 | if(!WriteInt(static_cast(value.size()))) 173 | return false; 174 | 175 | return WriteBytes(value.data(), static_cast(value.size())); 176 | } 177 | 178 | bool Message::WriteString(const std::wstring& value) 179 | { 180 | if (!WriteInt(static_cast(value.size()))) 181 | return false; 182 | 183 | return WriteBytes(value.data(), 184 | static_cast(value.size() * sizeof(wchar_t))); 185 | } 186 | 187 | bool Message::WriteData(const char* data, int length) 188 | { 189 | return length >= 0 && WriteInt(length) && WriteBytes(data, length); 190 | } 191 | 192 | bool Message::WriteBytes(const void* data, int data_len) 193 | { 194 | assert(kCapacityReadOnly != capacity_); 195 | 196 | size_t offset = header_->payload_size; 197 | 198 | size_t new_size = offset + data_len; 199 | size_t needed_size = sizeof(Header) + new_size; 200 | if (needed_size > capacity_ && !Resize((std::max)(capacity_ * 2, needed_size))) 201 | return false; 202 | 203 | header_->payload_size = static_cast(new_size); 204 | char* dest = const_cast(payload()) + offset; 205 | memcpy(dest, data, data_len); 206 | return true; 207 | } 208 | 209 | void Message::AddRef() const 210 | { 211 | InterlockedIncrement(&ref_count_); 212 | } 213 | 214 | void Message::Release() const 215 | { 216 | if (InterlockedDecrement(&ref_count_) == 0) 217 | { 218 | delete this; 219 | } 220 | } 221 | 222 | 223 | MessageReader::MessageReader(Message* m) 224 | : read_ptr_(m->payload()) 225 | , read_end_ptr_(m->end_of_payload()) 226 | { 227 | 228 | } 229 | 230 | template 231 | inline bool MessageReader::ReadBuiltinType(Type* result) { 232 | const char* read_from = GetReadPointerAndAdvance(sizeof(Type)); 233 | if (!read_from) 234 | return false; 235 | memcpy(result, read_from, sizeof(*result)); 236 | return true; 237 | } 238 | 239 | const char* MessageReader::GetReadPointerAndAdvance(int num_bytes) { 240 | if (num_bytes < 0 || read_end_ptr_ - read_ptr_ < num_bytes) 241 | return NULL; 242 | const char* current_read_ptr = read_ptr_; 243 | read_ptr_ += num_bytes; 244 | return current_read_ptr; 245 | } 246 | 247 | const char* MessageReader::GetReadPointerAndAdvance(int num_elements, size_t size_element) 248 | { 249 | // Check for int32 overflow. 250 | int64 num_bytes = static_cast(num_elements)* size_element; 251 | int num_bytes32 = static_cast(num_bytes); 252 | if (num_bytes != static_cast(num_bytes32)) 253 | return NULL; 254 | return GetReadPointerAndAdvance(num_bytes32); 255 | } 256 | 257 | bool MessageReader::ReadBool(bool* result) 258 | { 259 | return ReadBuiltinType(result); 260 | } 261 | 262 | bool MessageReader::ReadInt(int* result) 263 | { 264 | return ReadBuiltinType(result); 265 | } 266 | 267 | bool MessageReader::ReadUInt16(uint16* result) 268 | { 269 | return ReadBuiltinType(result); 270 | } 271 | 272 | bool MessageReader::ReadUInt32(uint32* result) 273 | { 274 | return ReadBuiltinType(result); 275 | } 276 | 277 | bool MessageReader::ReadInt64(int64* result) 278 | { 279 | return ReadBuiltinType(result); 280 | } 281 | 282 | bool MessageReader::ReadUInt64(uint64* result) 283 | { 284 | return ReadBuiltinType(result); 285 | } 286 | 287 | bool MessageReader::ReadFloat(float* result) 288 | { 289 | return ReadBuiltinType(result); 290 | } 291 | 292 | bool MessageReader::ReadString(std::string* result) 293 | { 294 | int len; 295 | if (!ReadInt(&len)) 296 | return false; 297 | const char* read_from = GetReadPointerAndAdvance(len); 298 | if (!read_from) 299 | return false; 300 | 301 | result->assign(read_from, len); 302 | return true; 303 | } 304 | 305 | bool MessageReader::ReadWString(std::wstring* result) 306 | { 307 | int len; 308 | if (!ReadInt(&len)) 309 | return false; 310 | const char* read_from = GetReadPointerAndAdvance(len, sizeof(wchar_t)); 311 | if (!read_from) 312 | return false; 313 | 314 | result->assign(reinterpret_cast(read_from), len); 315 | return true; 316 | } 317 | 318 | bool MessageReader::ReadData(const char** data, int* length) 319 | { 320 | *length = 0; 321 | *data = 0; 322 | 323 | if (!ReadInt(length)) 324 | return false; 325 | 326 | return ReadBytes(data, *length); 327 | } 328 | 329 | bool MessageReader::ReadBytes(const char** data, int length) 330 | { 331 | const char* read_from = GetReadPointerAndAdvance(length); 332 | if (!read_from) 333 | return false; 334 | *data = read_from; 335 | return true; 336 | } 337 | 338 | } // namespace IPC 339 | -------------------------------------------------------------------------------- /ipc/ipc_message.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hicdre/AsyncIpc/8253b2bad7a6f17f972294827ae13df47292f047/ipc/ipc_message.h -------------------------------------------------------------------------------- /ipc/ipc_sender.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | #ifndef IPC_IPC_SENDER_H_ 6 | #define IPC_IPC_SENDER_H_ 7 | 8 | namespace IPC { 9 | 10 | class Message; 11 | 12 | class Sender { 13 | public: 14 | // Sends the given IPC message. The implementor takes ownership of the 15 | // given Message regardless of whether or not this method succeeds. This 16 | // is done to make this method easier to use. Returns true on success and 17 | // false otherwise. 18 | virtual bool Send(Message* msg) = 0; 19 | 20 | protected: 21 | virtual ~Sender() {} 22 | }; 23 | 24 | } // namespace IPC 25 | 26 | #endif // IPC_IPC_SENDER_H_ 27 | -------------------------------------------------------------------------------- /ipc/ipc_thread.cpp: -------------------------------------------------------------------------------- 1 | #include "ipc_thread.h" 2 | #include 3 | 4 | namespace IPC 5 | { 6 | Thread::Thread() 7 | : thread_(NULL) 8 | , should_quit_(false) 9 | { 10 | io_port_ = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 1); 11 | } 12 | 13 | Thread::~Thread() 14 | { 15 | ::CloseHandle(io_port_); 16 | } 17 | 18 | void Thread::RegisterIOHandler(HANDLE file, IOHandler* handler) 19 | { 20 | ULONG_PTR key = HandlerToKey(handler, true); 21 | HANDLE port = CreateIoCompletionPort(file, io_port_, key, 1); 22 | assert(port); 23 | } 24 | 25 | ULONG_PTR Thread::HandlerToKey(IOHandler* handler, bool has_valid_io_context) 26 | { 27 | ULONG_PTR key = reinterpret_cast(handler); 28 | 29 | // |IOHandler| is at least pointer-size aligned, so the lowest two bits are 30 | // always cleared. We use the lowest bit to distinguish completion keys with 31 | // and without the associated |IOContext|. 32 | assert((key & 1) == 0); 33 | 34 | // Mark the completion key as context-less. 35 | if (!has_valid_io_context) 36 | key = key | 1; 37 | return key; 38 | } 39 | 40 | Thread::IOHandler* Thread::KeyToHandler(ULONG_PTR key, bool* has_valid_io_context) 41 | { 42 | *has_valid_io_context = ((key & 1) == 0); 43 | return reinterpret_cast(key & ~static_cast(1)); 44 | } 45 | 46 | void Thread::PostTask(const Task& task) 47 | { 48 | { 49 | AutoLock lock(task_mutex_); 50 | task_queue_.push_back(task); 51 | } 52 | ScheduleWork(); 53 | } 54 | 55 | void Thread::Start() 56 | { 57 | if (thread_ == NULL) 58 | { 59 | should_quit_ = false; 60 | thread_ = ::CreateThread(0, 0, IOThreadMain, this, 0, 0); 61 | } 62 | } 63 | 64 | 65 | void Thread::Stop() 66 | { 67 | should_quit_ = true; 68 | 69 | if (thread_) 70 | { 71 | ::WaitForSingleObject(thread_, 1000); 72 | CloseHandle(thread_); 73 | thread_ = NULL; 74 | } 75 | } 76 | 77 | 78 | void Thread::Wait(DWORD timeout) 79 | { 80 | ::WaitForSingleObject(thread_, timeout); 81 | } 82 | 83 | 84 | 85 | DWORD WINAPI Thread::IOThreadMain(LPVOID params) 86 | { 87 | reinterpret_cast(params)->Run(); 88 | return 0; 89 | } 90 | 91 | void Thread::Run() 92 | { 93 | for (;;) { 94 | 95 | bool more_work_is_plausible = DoScheduledWork(); 96 | 97 | if (should_quit_) 98 | break; 99 | 100 | more_work_is_plausible |= WaitForIOCompletion(0, NULL); 101 | 102 | if (should_quit_) 103 | break; 104 | 105 | if (more_work_is_plausible) 106 | continue; 107 | 108 | if (should_quit_) 109 | break; 110 | 111 | WaitForWork(); // Wait (sleep) until we have work to do again. 112 | } 113 | } 114 | 115 | bool Thread::DoScheduledWork() 116 | { 117 | std::deque work_queue; 118 | { 119 | AutoLock lock(task_mutex_); 120 | if (task_queue_.empty()) 121 | return false; 122 | work_queue.swap(task_queue_); 123 | } 124 | 125 | do 126 | { 127 | Task t = work_queue.front(); 128 | work_queue.pop_front(); 129 | 130 | t(); 131 | } while (!work_queue.empty()); 132 | 133 | return false; 134 | } 135 | 136 | bool Thread::WaitForIOCompletion(DWORD timeout, IOHandler* filter) 137 | { 138 | IOItem item; 139 | if (completed_io_.empty() || !MatchCompletedIOItem(filter, &item)) { 140 | // We have to ask the system for another IO completion. 141 | if (!GetIOItem(timeout, &item)) 142 | return false; 143 | 144 | if (ProcessInternalIOItem(item)) 145 | return true; 146 | } 147 | 148 | // If |item.has_valid_io_context| is false then |item.context| does not point 149 | // to a context structure, and so should not be dereferenced, although it may 150 | // still hold valid non-pointer data. 151 | if (!item.has_valid_io_context || item.context->handler) { 152 | if (filter && item.handler != filter) { 153 | // Save this item for later 154 | completed_io_.push_back(item); 155 | } 156 | else { 157 | assert(!item.has_valid_io_context || 158 | (item.context->handler == item.handler)); 159 | item.handler->OnIOCompleted(item.context, item.bytes_transfered, 160 | item.error); 161 | } 162 | } 163 | else { 164 | // The handler must be gone by now, just cleanup the mess. 165 | delete item.context; 166 | } 167 | return true; 168 | } 169 | 170 | void Thread::WaitForWork() 171 | { 172 | int timeout; 173 | timeout = INFINITE; 174 | WaitForIOCompletion(timeout, NULL); 175 | } 176 | 177 | bool Thread::MatchCompletedIOItem(IOHandler* filter, IOItem* item) 178 | { 179 | for (std::list::iterator it = completed_io_.begin(); 180 | it != completed_io_.end(); ++it) { 181 | if (!filter || it->handler == filter) { 182 | *item = *it; 183 | completed_io_.erase(it); 184 | return true; 185 | } 186 | } 187 | return false; 188 | } 189 | 190 | bool Thread::GetIOItem(DWORD timeout, IOItem* item) 191 | { 192 | memset(item, 0, sizeof(*item)); 193 | ULONG_PTR key = NULL; 194 | OVERLAPPED* overlapped = NULL; 195 | if (!GetQueuedCompletionStatus(io_port_, &item->bytes_transfered, &key, 196 | &overlapped, timeout)) { 197 | if (!overlapped) 198 | return false; // Nothing in the queue. 199 | item->error = GetLastError(); 200 | item->bytes_transfered = 0; 201 | } 202 | 203 | item->handler = KeyToHandler(key, &item->has_valid_io_context); 204 | item->context = reinterpret_cast(overlapped); 205 | return true; 206 | } 207 | 208 | bool Thread::ProcessInternalIOItem(const IOItem& item) 209 | { 210 | if (this == reinterpret_cast(item.context) && 211 | this == reinterpret_cast(item.handler)) { 212 | // This is our internal completion. 213 | assert(!item.bytes_transfered); 214 | return true; 215 | } 216 | return false; 217 | } 218 | 219 | void Thread::ScheduleWork() 220 | { 221 | PostQueuedCompletionStatus(io_port_, 0, 222 | reinterpret_cast(this), 223 | reinterpret_cast(this)); 224 | } 225 | 226 | } 227 | -------------------------------------------------------------------------------- /ipc/ipc_thread.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "ipc/ipc_common.h" 3 | #include "ipc/ipc_utils.h" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | namespace IPC 10 | { 11 | class Thread 12 | { 13 | public: 14 | typedef std::function Task; 15 | 16 | struct IOContext; 17 | 18 | class IOHandler { 19 | public: 20 | virtual ~IOHandler() {} 21 | // This will be called once the pending IO operation associated with 22 | // |context| completes. |error| is the Win32 error code of the IO operation 23 | // (ERROR_SUCCESS if there was no error). |bytes_transfered| will be zero 24 | // on error. 25 | virtual void OnIOCompleted(IOContext* context, DWORD bytes_transfered, 26 | DWORD error) = 0; 27 | }; 28 | 29 | struct IOContext { 30 | OVERLAPPED overlapped; 31 | IOHandler* handler; 32 | }; 33 | 34 | Thread(); 35 | ~Thread(); 36 | 37 | void Start(); 38 | void Stop(); 39 | void Wait(DWORD timeout); 40 | 41 | void RegisterIOHandler(HANDLE file, IOHandler* handler); 42 | bool WaitForIOCompletion(DWORD timeout, IOHandler* filter); 43 | 44 | void PostTask(const Task& task); 45 | private: 46 | struct IOItem { 47 | IOHandler* handler; 48 | IOContext* context; 49 | DWORD bytes_transfered; 50 | DWORD error; 51 | 52 | // In some cases |context| can be a non-pointer value casted to a pointer. 53 | // |has_valid_io_context| is true if |context| is a valid IOContext 54 | // pointer, and false otherwise. 55 | bool has_valid_io_context; 56 | }; 57 | 58 | static DWORD WINAPI IOThreadMain(LPVOID params); 59 | // Converts an IOHandler pointer to a completion port key. 60 | // |has_valid_io_context| specifies whether completion packets posted to 61 | // |handler| will have valid OVERLAPPED pointers. 62 | static ULONG_PTR HandlerToKey(IOHandler* handler, bool has_valid_io_context); 63 | static IOHandler* KeyToHandler(ULONG_PTR key, bool* has_valid_io_context); 64 | 65 | void Run(); 66 | bool DoScheduledWork(); 67 | void ScheduleWork(); 68 | void WaitForWork(); 69 | 70 | bool MatchCompletedIOItem(IOHandler* filter, IOItem* item); 71 | bool GetIOItem(DWORD timeout, IOItem* item); 72 | bool ProcessInternalIOItem(const IOItem& item); 73 | void WillProcessIOEvent(); 74 | void DidProcessIOEvent(); 75 | 76 | HANDLE thread_; 77 | bool should_quit_; 78 | 79 | HANDLE io_port_; 80 | std::list completed_io_; 81 | 82 | Lock task_mutex_; 83 | std::deque task_queue_; 84 | }; 85 | } -------------------------------------------------------------------------------- /ipc/ipc_utils.cpp: -------------------------------------------------------------------------------- 1 | #include "ipc_utils.h" 2 | #include 3 | #include 4 | 5 | Lock::Lock() 6 | { 7 | ::InitializeCriticalSectionAndSpinCount(&cs, 2000); 8 | } 9 | 10 | Lock::~Lock() 11 | { 12 | ::DeleteCriticalSection(&cs); 13 | } 14 | 15 | bool Lock::Try() 16 | { 17 | if (::TryEnterCriticalSection(&cs) != FALSE) { 18 | return true; 19 | } 20 | return false; 21 | } 22 | 23 | void Lock::Dolock() 24 | { 25 | ::EnterCriticalSection(&cs); 26 | } 27 | 28 | void Lock::Unlock() 29 | { 30 | ::LeaveCriticalSection(&cs); 31 | } 32 | 33 | AutoLock::AutoLock(Lock& m) 34 | : m_(m) 35 | { 36 | m_.Dolock(); 37 | } 38 | 39 | AutoLock::~AutoLock() 40 | { 41 | m_.Unlock(); 42 | } 43 | 44 | uint32 RandUint32() { 45 | uint32 number; 46 | rand_s(&number); 47 | return number; 48 | } 49 | 50 | uint64 RandUint64() { 51 | uint32 first_half = RandUint32(); 52 | uint32 second_half = RandUint32(); 53 | return (static_cast(first_half) << 32) + second_half; 54 | } 55 | 56 | int RandInt(int min, int max) 57 | { 58 | assert(min < max); 59 | 60 | uint64 range = static_cast(max)-min + 1; 61 | int result = min + static_cast(RandGenerator(range)); 62 | return result; 63 | } 64 | 65 | uint64 RandGenerator(uint64 range) 66 | { 67 | assert(range > 0u); 68 | // We must discard random results above this number, as they would 69 | // make the random generator non-uniform (consider e.g. if 70 | // MAX_UINT64 was 7 and |range| was 5, then a result of 1 would be twice 71 | // as likely as a result of 3 or 4). 72 | uint64 max_acceptable_value = 73 | ((std::numeric_limits::max)() / range) * range - 1; 74 | 75 | uint64 value; 76 | do { 77 | value = RandUint64(); 78 | } while (value > max_acceptable_value); 79 | 80 | return value % range; 81 | } 82 | 83 | std::wstring ASCIIToWide(const std::string& mb) 84 | { 85 | if (mb.empty()) 86 | return std::wstring(); 87 | 88 | int mb_length = static_cast(mb.length()); 89 | // Compute the length of the buffer. 90 | int charcount = MultiByteToWideChar(CP_UTF8, 0, 91 | mb.data(), mb_length, NULL, 0); 92 | if (charcount == 0) 93 | return std::wstring(); 94 | 95 | std::wstring wide; 96 | wide.resize(charcount); 97 | MultiByteToWideChar(CP_UTF8, 0, mb.data(), mb_length, &wide[0], charcount); 98 | 99 | return wide; 100 | } 101 | -------------------------------------------------------------------------------- /ipc/ipc_utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "ipc/ipc_common.h" 3 | 4 | class Lock 5 | { 6 | public: 7 | Lock(); 8 | ~Lock(); 9 | 10 | bool Try(); 11 | 12 | // Take the lock, blocking until it is available if necessary. 13 | void Dolock(); 14 | 15 | // Release the lock. This must only be called by the lock's holder: after 16 | // a successful call to Try, or a call to Lock. 17 | void Unlock(); 18 | 19 | private: 20 | CRITICAL_SECTION cs; 21 | DISALLOW_COPY_AND_ASSIGN(Lock); 22 | }; 23 | 24 | class AutoLock 25 | { 26 | public: 27 | explicit AutoLock(Lock& m); 28 | ~AutoLock(); 29 | 30 | private: 31 | Lock& m_; 32 | DISALLOW_COPY_AND_ASSIGN(AutoLock); 33 | }; 34 | 35 | class StaticAtomicSequenceNumber { 36 | public: 37 | inline int GetNext() { 38 | return static_cast( 39 | InterlockedExchangeAdd(reinterpret_cast(&seq_), 1)); 40 | } 41 | 42 | private: 43 | friend class AtomicSequenceNumber; 44 | 45 | inline void Reset() { 46 | seq_ = 0; 47 | } 48 | 49 | int32 seq_; 50 | }; 51 | 52 | template 53 | class scoped_refptr 54 | { 55 | public: 56 | scoped_refptr(T* t) 57 | { 58 | p_ = t; 59 | if (p_) 60 | p_->AddRef(); 61 | } 62 | ~scoped_refptr() 63 | { 64 | Clear(); 65 | } 66 | scoped_refptr(const scoped_refptr& r) : p_(r.p_) { 67 | if (p_) 68 | p_->AddRef(); 69 | } 70 | void Clear() 71 | { 72 | if (p_) 73 | p_->Release(); 74 | } 75 | T* operator->() const 76 | { 77 | return p_; 78 | } 79 | T* get() const 80 | { 81 | return p_; 82 | } 83 | 84 | 85 | private: 86 | T* p_; 87 | }; 88 | 89 | int RandInt(int min, int max); 90 | 91 | uint64 RandGenerator(uint64 range); 92 | 93 | std::wstring ASCIIToWide(const std::string& str); -------------------------------------------------------------------------------- /ipc/stdafx.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" -------------------------------------------------------------------------------- /ipc/stdafx.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define _CRT_RAND_S 4 | #define _CRT_SECURE_NO_WARNINGS 5 | 6 | #include 7 | #include 8 | 9 | 10 | #include -------------------------------------------------------------------------------- /ipc_dll/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | DYNAMIC LINK LIBRARY : ipc_dll Project Overview 3 | ======================================================================== 4 | 5 | AppWizard has created this ipc_dll DLL for you. 6 | 7 | This file contains a summary of what you will find in each of the files that 8 | make up your ipc_dll application. 9 | 10 | 11 | ipc_dll.vcxproj 12 | This is the main project file for VC++ projects generated using an Application Wizard. 13 | It contains information about the version of Visual C++ that generated the file, and 14 | information about the platforms, configurations, and project features selected with the 15 | Application Wizard. 16 | 17 | ipc_dll.vcxproj.filters 18 | This is the filters file for VC++ projects generated using an Application Wizard. 19 | It contains information about the association between the files in your project 20 | and the filters. This association is used in the IDE to show grouping of files with 21 | similar extensions under a specific node (for e.g. ".cpp" files are associated with the 22 | "Source Files" filter). 23 | 24 | ipc_dll.cpp 25 | This is the main DLL source file. 26 | 27 | ///////////////////////////////////////////////////////////////////////////// 28 | Other standard files: 29 | 30 | StdAfx.h, StdAfx.cpp 31 | These files are used to build a precompiled header (PCH) file 32 | named ipc_dll.pch and a precompiled types file named StdAfx.obj. 33 | 34 | ///////////////////////////////////////////////////////////////////////////// 35 | Other notes: 36 | 37 | AppWizard uses "TODO:" comments to indicate parts of the source code you 38 | should add to or customize. 39 | 40 | ///////////////////////////////////////////////////////////////////////////// 41 | -------------------------------------------------------------------------------- /ipc_dll/ipc_dll.cpp: -------------------------------------------------------------------------------- 1 | // ipc_dll.cpp : Defines the exported functions for the DLL application. 2 | // 3 | 4 | #include "stdafx.h" 5 | #include "ipc_dll.h" 6 | #include "ipc_factory_impl.h" 7 | 8 | 9 | IPC::FactoryImpl* gFactory = NULL; 10 | 11 | bool GetIPCEndPoint(void** instance, const char* name, void* listener /*= 0*/) 12 | { 13 | if (!gFactory) 14 | return false; 15 | IPC::IEndpoint* endpoint = gFactory->GetEndPoint(name, (IPC::IListener*)listener); 16 | *instance = endpoint; 17 | return !!endpoint; 18 | } 19 | 20 | 21 | BOOL APIENTRY DllMain(HMODULE hModule, 22 | DWORD ul_reason_for_call, 23 | LPVOID lpReserved 24 | ) 25 | { 26 | switch (ul_reason_for_call) 27 | { 28 | case DLL_PROCESS_ATTACH: 29 | gFactory = new IPC::FactoryImpl; 30 | break; 31 | case DLL_THREAD_ATTACH: 32 | case DLL_THREAD_DETACH: 33 | break; 34 | case DLL_PROCESS_DETACH: 35 | if (gFactory) 36 | { 37 | delete gFactory; 38 | gFactory = NULL; 39 | } 40 | break; 41 | } 42 | return TRUE; 43 | } 44 | -------------------------------------------------------------------------------- /ipc_dll/ipc_dll.def: -------------------------------------------------------------------------------- 1 | LIBRARY 2 | EXPORTS 3 | GetIPCEndPoint @ 1 4 | -------------------------------------------------------------------------------- /ipc_dll/ipc_dll.h: -------------------------------------------------------------------------------- 1 | // The following ifdef block is the standard way of creating macros which make exporting 2 | // from a DLL simpler. All files within this DLL are compiled with the IPC_DLL_EXPORTS 3 | // symbol defined on the command line. This symbol should not be defined on any project 4 | // that uses this DLL. This way any other project whose source files include this file see 5 | // IPC_DLL_API functions as being imported from a DLL, whereas this DLL sees symbols 6 | // defined with this macro as being exported. 7 | 8 | __declspec(dllexport) bool GetIPCEndPoint(void** instance, const char* name, void* listener = 0); 9 | -------------------------------------------------------------------------------- /ipc_dll/ipc_dll.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {A808021A-C2FF-4B8D-A24A-B3535BCA0637} 15 | Win32Proj 16 | ipc_dll 17 | 18 | 19 | 20 | DynamicLibrary 21 | true 22 | v120_xp 23 | Unicode 24 | 25 | 26 | DynamicLibrary 27 | false 28 | v120_xp 29 | true 30 | Unicode 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | true 44 | ..\output\$(Configuration)\ 45 | ..\build\$(ProjectName)\$(Configuration)\ 46 | 47 | 48 | false 49 | ..\output\$(Configuration)\ 50 | ..\build\$(ProjectName)\$(Configuration)\ 51 | 52 | 53 | 54 | Use 55 | Level3 56 | Disabled 57 | WIN32;_DEBUG;_WINDOWS;_USRDLL;IPC_DLL_EXPORTS;%(PreprocessorDefinitions) 58 | true 59 | $(projectdir)..;%(AdditionalIncludeDirectories) 60 | 61 | 62 | Windows 63 | true 64 | ipc_dll.def 65 | 66 | 67 | 68 | 69 | Level3 70 | Use 71 | MaxSpeed 72 | true 73 | true 74 | WIN32;NDEBUG;_WINDOWS;_USRDLL;IPC_DLL_EXPORTS;%(PreprocessorDefinitions) 75 | true 76 | $(projectdir)..;%(AdditionalIncludeDirectories) 77 | 78 | 79 | Windows 80 | true 81 | true 82 | true 83 | ipc_dll.def 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | Create 103 | Create 104 | 105 | 106 | 107 | 108 | {896c53b4-9517-429a-911c-1a2b634b8319} 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /ipc_dll/ipc_dll.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | Header Files 32 | 33 | 34 | Header Files 35 | 36 | 37 | Header Files 38 | 39 | 40 | 41 | 42 | Source Files 43 | 44 | 45 | Source Files 46 | 47 | 48 | Source Files 49 | 50 | 51 | Source Files 52 | 53 | 54 | 55 | 56 | Source Files 57 | 58 | 59 | -------------------------------------------------------------------------------- /ipc_dll/ipc_endpoint_impl.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "ipc_endpoint_impl.h" 3 | #include "ipc/ipc_message.h" 4 | #include 5 | 6 | namespace IPC 7 | { 8 | 9 | 10 | EndpointImpl::EndpointImpl(const std::string& name, IListener* listener) 11 | : endpoint_(new Endpoint(name, this)) 12 | { 13 | listener_ = listener; 14 | if (listener_) 15 | listener_->AddRef(); 16 | } 17 | 18 | EndpointImpl::~EndpointImpl() 19 | { 20 | assert(endpoint_); 21 | delete endpoint_; 22 | endpoint_ = NULL; 23 | 24 | if (listener_) 25 | listener_->Release(); 26 | } 27 | 28 | void EndpointImpl::AddRef() const 29 | { 30 | InterlockedIncrement(&ref_count_); 31 | } 32 | 33 | void EndpointImpl::Release() const 34 | { 35 | if (InterlockedDecrement(&ref_count_) == 0) 36 | { 37 | delete this; 38 | } 39 | } 40 | 41 | IPC::ErrorCode EndpointImpl::Send(const char* message, size_t len) 42 | { 43 | scoped_refptr m(new Message); 44 | m->WriteString(std::string(message, len)); 45 | return endpoint_->Send(m.get()) ? ERROR_OK : ERROR_DEST_DISCONNECTED; 46 | } 47 | 48 | void EndpointImpl::SetListener(IListener* listener) 49 | { 50 | AutoLock lock(lock_); 51 | if (listener_) 52 | listener_->Release(); 53 | listener_ = listener; 54 | if (listener_) 55 | listener_->AddRef(); 56 | } 57 | 58 | 59 | bool EndpointImpl::HasListener() const 60 | { 61 | AutoLock lock(lock_); 62 | return listener_ != NULL; 63 | } 64 | 65 | 66 | bool EndpointImpl::OnMessageReceived(Message* message) 67 | { 68 | std::string s; 69 | MessageReader reader(message); 70 | if (!reader.ReadString(&s)) 71 | return true; 72 | AutoLock lock(lock_); 73 | if (listener_) 74 | listener_->OnMessageReceived(s.c_str(), s.size()); 75 | return true; 76 | } 77 | 78 | void EndpointImpl::OnChannelConnected(int32 peer_pid) 79 | { 80 | AutoLock lock(lock_); 81 | if (listener_) 82 | listener_->OnDestConnected(peer_pid); 83 | } 84 | 85 | void EndpointImpl::OnChannelError() 86 | { 87 | AutoLock lock(lock_); 88 | if (listener_) 89 | listener_->OnDestDisconnected(); 90 | } 91 | 92 | } -------------------------------------------------------------------------------- /ipc_dll/ipc_endpoint_impl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "ipc/ipc_interface.h" 3 | #include "ipc/ipc_endpoint.h" 4 | #include 5 | 6 | namespace IPC 7 | { 8 | class EndpointImpl : public IEndpoint, public Listener 9 | { 10 | public: 11 | EndpointImpl(const std::string& name, IListener* listener); 12 | ~EndpointImpl(); 13 | virtual void AddRef() const override; 14 | virtual void Release() const override; 15 | virtual ErrorCode Send(const char* message, size_t len) override; 16 | virtual void SetListener(IListener* listener) override; 17 | virtual bool HasListener() const override; 18 | private: 19 | virtual bool OnMessageReceived(Message* message) override; 20 | virtual void OnChannelConnected(int32 peer_pid) override; 21 | virtual void OnChannelError() override; 22 | private: 23 | Endpoint* endpoint_; 24 | IListener* listener_; 25 | 26 | mutable Lock lock_; 27 | mutable LONG ref_count_; 28 | }; 29 | } -------------------------------------------------------------------------------- /ipc_dll/ipc_factory_impl.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "ipc_factory_impl.h" 3 | 4 | namespace IPC 5 | { 6 | FactoryImpl::FactoryImpl() 7 | { 8 | 9 | } 10 | 11 | FactoryImpl::~FactoryImpl() 12 | { 13 | for (auto iter : endpoint_map_) 14 | { 15 | iter.second->Release(); 16 | } 17 | } 18 | 19 | 20 | IEndpoint* FactoryImpl::GetEndPoint(const char* name, IListener* listener) 21 | { 22 | if (name == NULL) 23 | return NULL; 24 | auto iter = endpoint_map_.find(name); 25 | if (iter != endpoint_map_.end()) 26 | return iter->second; 27 | EndpointImpl* p = new EndpointImpl(name, listener); 28 | p->AddRef(); 29 | endpoint_map_[name] = p; 30 | return p; 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /ipc_dll/ipc_factory_impl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "ipc/ipc_interface.h" 3 | #include "ipc_endpoint_impl.h" 4 | #include 5 | 6 | namespace IPC 7 | { 8 | class FactoryImpl 9 | { 10 | public: 11 | FactoryImpl(); 12 | ~FactoryImpl(); 13 | IEndpoint* GetEndPoint(const char* name, IListener* listener); 14 | private: 15 | std::unordered_map endpoint_map_; 16 | }; 17 | } -------------------------------------------------------------------------------- /ipc_dll/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // ipc_dll.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /ipc_dll/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #include "targetver.h" 9 | 10 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 11 | // Windows Header Files: 12 | #include 13 | 14 | 15 | 16 | // TODO: reference additional headers your program requires here 17 | -------------------------------------------------------------------------------- /ipc_dll/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /sample/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | CONSOLE APPLICATION : sample Project Overview 3 | ======================================================================== 4 | 5 | AppWizard has created this sample application for you. 6 | 7 | This file contains a summary of what you will find in each of the files that 8 | make up your sample application. 9 | 10 | 11 | sample.vcxproj 12 | This is the main project file for VC++ projects generated using an Application Wizard. 13 | It contains information about the version of Visual C++ that generated the file, and 14 | information about the platforms, configurations, and project features selected with the 15 | Application Wizard. 16 | 17 | sample.vcxproj.filters 18 | This is the filters file for VC++ projects generated using an Application Wizard. 19 | It contains information about the association between the files in your project 20 | and the filters. This association is used in the IDE to show grouping of files with 21 | similar extensions under a specific node (for e.g. ".cpp" files are associated with the 22 | "Source Files" filter). 23 | 24 | sample.cpp 25 | This is the main application source file. 26 | 27 | ///////////////////////////////////////////////////////////////////////////// 28 | Other standard files: 29 | 30 | StdAfx.h, StdAfx.cpp 31 | These files are used to build a precompiled header (PCH) file 32 | named sample.pch and a precompiled types file named StdAfx.obj. 33 | 34 | ///////////////////////////////////////////////////////////////////////////// 35 | Other notes: 36 | 37 | AppWizard uses "TODO:" comments to indicate parts of the source code you 38 | should add to or customize. 39 | 40 | ///////////////////////////////////////////////////////////////////////////// 41 | -------------------------------------------------------------------------------- /sample/common.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "common.h" 3 | 4 | 5 | const char kChannelName[] = "SampleServer"; -------------------------------------------------------------------------------- /sample/common.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | extern const char kChannelName[]; -------------------------------------------------------------------------------- /sample/sample_client.cpp: -------------------------------------------------------------------------------- 1 | // sample.cpp : Defines the entry point for the console application. 2 | // 3 | 4 | #include "stdafx.h" 5 | 6 | #include "sample_client.h" 7 | #include "ipc/ipc_message.h" 8 | 9 | 10 | int _tmain(int argc, _TCHAR* argv[]) 11 | { 12 | SampleClient listener; 13 | IPC::Endpoint endpoint(kChannelName, &listener); 14 | std::string cmd; 15 | while (true) 16 | { 17 | std::cout << ">>"; 18 | std::cin >> cmd; 19 | if (cmd == "exit") 20 | { 21 | break; 22 | } 23 | else 24 | { 25 | scoped_refptr m(new IPC::Message(GetCurrentProcessId(), 0, (IPC::Message::PriorityValue)0)); 26 | m->WriteString(cmd); 27 | //std::cout << "Process [" << GetCurrentProcessId() << "]: " << cmd << std::endl; 28 | endpoint.Send(m.get()); 29 | } 30 | } 31 | 32 | return 0; 33 | } 34 | 35 | 36 | void SampleClient::OnChannelError() 37 | { 38 | std::cout << "Process [" << id_ << "] Disconnected" << std::endl; 39 | } 40 | 41 | void SampleClient::OnChannelConnected(int32 peer_pid) 42 | { 43 | id_ = peer_pid; 44 | std::cout << "Process [" << peer_pid << "] Connected" << std::endl; 45 | } 46 | 47 | bool SampleClient::OnMessageReceived(IPC::Message* msg) 48 | { 49 | std::string s; 50 | msg->routing_id(); 51 | IPC::MessageReader reader(msg); 52 | reader.ReadString(&s); 53 | std::cout << "Process [" << id_ << "]: " << s << std::endl; 54 | return true; 55 | } 56 | 57 | -------------------------------------------------------------------------------- /sample/sample_client.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ipc/ipc_endpoint.h" 4 | 5 | #include "common.h" 6 | 7 | #include 8 | #include 9 | 10 | class SampleClient : public IPC::Listener 11 | { 12 | public: 13 | virtual bool OnMessageReceived(IPC::Message* msg); 14 | 15 | virtual void OnChannelConnected(int32 peer_pid); 16 | 17 | virtual void OnChannelError(); 18 | protected: 19 | int32 id_; 20 | }; 21 | -------------------------------------------------------------------------------- /sample/sample_client.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {ADD3A329-4FB0-4B04-8C47-98DBFE5A06D4} 15 | Win32Proj 16 | sample 17 | 18 | 19 | 20 | Application 21 | true 22 | v120_xp 23 | Unicode 24 | 25 | 26 | Application 27 | false 28 | v120_xp 29 | true 30 | Unicode 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | true 44 | ..\output\$(Configuration)\ 45 | ..\build\$(ProjectName)\$(Configuration)\ 46 | 47 | 48 | false 49 | ..\output\$(Configuration)\ 50 | ..\build\$(ProjectName)\$(Configuration)\ 51 | 52 | 53 | 54 | Use 55 | Level3 56 | Disabled 57 | WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 58 | true 59 | $(ProjectDir)..;%(AdditionalIncludeDirectories) 60 | 61 | 62 | Console 63 | true 64 | 65 | 66 | 67 | 68 | Level3 69 | Use 70 | MaxSpeed 71 | true 72 | true 73 | WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 74 | true 75 | $(ProjectDir)..;%(AdditionalIncludeDirectories) 76 | 77 | 78 | Console 79 | true 80 | true 81 | true 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | Create 98 | Create 99 | 100 | 101 | 102 | 103 | {896c53b4-9517-429a-911c-1a2b634b8319} 104 | 105 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /sample/sample_client.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | Header Files 32 | 33 | 34 | 35 | 36 | Source Files 37 | 38 | 39 | Source Files 40 | 41 | 42 | Source Files 43 | 44 | 45 | -------------------------------------------------------------------------------- /sample/sample_dll_client.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | 3 | #include "sample_dll_client.h" 4 | 5 | 6 | void SampleDllClient::OnDestDisconnected() 7 | { 8 | std::cout << "Process [" << id_ << "] Disconnected" << std::endl; 9 | } 10 | 11 | void SampleDllClient::OnDestConnected(int peer_pid) 12 | { 13 | id_ = peer_pid; 14 | std::cout << "Process [" << peer_pid << "] Connected" << std::endl; 15 | } 16 | 17 | void SampleDllClient::OnMessageReceived(const char* message, size_t len) 18 | { 19 | std::string s(message, len); 20 | std::cout << "Process [" << id_ << "]: " << s << std::endl; 21 | } 22 | 23 | void SampleDllClient::AddRef() const 24 | { 25 | InterlockedIncrement(&ref_count_); 26 | } 27 | 28 | void SampleDllClient::Release() const 29 | { 30 | if (InterlockedDecrement(&ref_count_) == 0) 31 | { 32 | delete this; 33 | } 34 | } 35 | 36 | SampleDllClient::SampleDllClient() 37 | : ref_count_(0) 38 | , id_(0) 39 | , module_(NULL) 40 | , endpoint_(NULL) 41 | { 42 | Init(); 43 | } 44 | 45 | 46 | SampleDllClient::~SampleDllClient() 47 | { 48 | if (endpoint_) 49 | { 50 | endpoint_->Release(); 51 | endpoint_ = NULL; 52 | } 53 | if (module_) 54 | { 55 | FreeLibrary(module_); 56 | module_ = NULL; 57 | } 58 | } 59 | 60 | 61 | void SampleDllClient::Send(const std::string& cmd) 62 | { 63 | if (endpoint_) 64 | endpoint_->Send(cmd.c_str(), cmd.size()); 65 | } 66 | 67 | void SampleDllClient::Init() 68 | { 69 | module_ = LoadLibrary(L"ipc_dll.dll"); 70 | if (module_ == NULL) 71 | return; 72 | 73 | typedef bool (*FuncGetIPCEndPoint)(void** instance, const char* name, void* listener); 74 | FuncGetIPCEndPoint pfn = (FuncGetIPCEndPoint)GetProcAddress(module_, "GetIPCEndPoint"); 75 | if (!pfn) 76 | return; 77 | 78 | if (pfn((void**)&endpoint_, kChannelName, this)) 79 | { 80 | endpoint_->AddRef(); 81 | } 82 | } 83 | 84 | 85 | int _tmain(int argc, _TCHAR* argv[]) 86 | { 87 | SampleDllClient* client = new SampleDllClient; 88 | client->AddRef(); 89 | 90 | std::string cmd; 91 | while (true) 92 | { 93 | std::cout << ">>"; 94 | std::cin >> cmd; 95 | if (cmd == "exit") 96 | { 97 | break; 98 | } 99 | else 100 | { 101 | client->Send(cmd); 102 | } 103 | } 104 | 105 | client->Release(); 106 | 107 | return 0; 108 | } 109 | -------------------------------------------------------------------------------- /sample/sample_dll_client.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ipc/ipc_interface.h" 4 | #include "ipc/ipc_thread.h" 5 | #include "ipc/ipc_listener.h" 6 | 7 | #include "common.h" 8 | 9 | #include 10 | 11 | class SampleDllClient : public IPC::IListener 12 | { 13 | public: 14 | SampleDllClient(); 15 | ~SampleDllClient(); 16 | 17 | virtual void AddRef() const override; 18 | 19 | virtual void Release() const override; 20 | 21 | virtual void OnMessageReceived(const char* message, size_t len) override; 22 | 23 | virtual void OnDestConnected(int peer_pid) override; 24 | 25 | virtual void OnDestDisconnected() override; 26 | 27 | void Send(const std::string& cmd); 28 | private: 29 | void Init(); 30 | int id_; 31 | mutable LONG ref_count_; 32 | IPC::IEndpoint* endpoint_; 33 | HMODULE module_; 34 | }; 35 | 36 | -------------------------------------------------------------------------------- /sample/sample_dll_client.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {F15D047E-1369-432E-91C0-03E932370D55} 15 | Win32Proj 16 | sample 17 | sample_dll_client 18 | 19 | 20 | 21 | Application 22 | true 23 | v120_xp 24 | Unicode 25 | 26 | 27 | Application 28 | false 29 | v120_xp 30 | true 31 | Unicode 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | true 45 | ..\output\$(Configuration)\ 46 | ..\build\$(ProjectName)\$(Configuration)\ 47 | 48 | 49 | false 50 | ..\output\$(Configuration)\ 51 | ..\build\$(ProjectName)\$(Configuration)\ 52 | 53 | 54 | 55 | Use 56 | Level3 57 | Disabled 58 | WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 59 | true 60 | $(ProjectDir)..;%(AdditionalIncludeDirectories) 61 | 62 | 63 | Console 64 | true 65 | 66 | 67 | 68 | 69 | Level3 70 | Use 71 | MaxSpeed 72 | true 73 | true 74 | WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 75 | true 76 | $(ProjectDir)..;%(AdditionalIncludeDirectories) 77 | 78 | 79 | Console 80 | true 81 | true 82 | true 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | Create 99 | Create 100 | 101 | 102 | 103 | 104 | {896c53b4-9517-429a-911c-1a2b634b8319} 105 | 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /sample/sample_dll_client.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /sample/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // sample.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /sample/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #include "targetver.h" 9 | 10 | #define _CRT_RAND_ 11 | #include 12 | #include 13 | 14 | 15 | 16 | // TODO: reference additional headers your program requires here 17 | -------------------------------------------------------------------------------- /sample/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | --------------------------------------------------------------------------------