Providing interface in Microsoft IDL
[
uuid(04802821-F237-486D-BC90-B6BB048DC8B2),
version(1.0)
]
interface RPC
{
void foo([in, string] char * string)
}
Generated stub and header files are rpc_c.c, rpc_s.c and rpc_h.h. In header file rpc_h.h declares function foo
void foo( char * string );
In rpc_c.c automatically defines the client version
void foo( char * string)
{
NdrClientCall(...);
}
But now I want to implement client and server in the same program for testing purpose, which should appear
#include "rpc_h.h"
#include "rpc_c.c"
#include "rpc_s.c"
/*server foo*/
void foo(char * string)
{
printf("%s\n", string);
}
/*server*/
void server()
{
//RpcServerRegisterIfEx(...);
//RpcServerUseProtseqEp(...);
//RpcServerListen(...);
}
int main(int args, char * argv[])
{
/*server runs*/
CreateThread(NULL, 0, server, argv[1], 0, NULL);
/*make RPC as client*/
foo(argv[2]);
}
As you can see, there is certainly an error about re-definition of both client and server foo. So I can't but manually rename client foo in rpc_c.c to be
void foo_client( char * string)
{
NdrClientCall(...);
}
and declare it along with server version in rpc_h.h
void foo_client( char * string );
void foo( char * string );
Therefore when I make RPC as client in main, I do
foo_client(argv[2]);
It works around but looks a bit hacky. Is there a decent solution to this instead?
PS: For those who might concern, I develop with pure system RPC. It's not about COM, COM+, DCOM or even object-orientation at all. I'm developing a peer-to-peer application based on DHT, so I must implement client and server in the same application. Sorry about the com and dcom tags, they are now removed
Don't create the client and server in the same application.
Create a dummy client application on the same machine. Your just making your life difficult.
I had the same question. The solution is to add separate prefixes to the client and server stubs using the midl /prefix switch. For example: midl /prefix client "c_" server "s_"
See midl /prefix switch.
Related
Before I ask the main question, I have two existing client/server win32 projects based on sockets in which the client sends a string request for the server and receives the result as a string using socket functions i.e. send(), recv()
a part of the server code (currently still based on sockets)
struct client_ctx
{
int socket;
CHAR buf_recv[MAX_SEND_BUF_SIZE]; // receive buffer
CHAR buf_send[MAX_SEND_BUF_SIZE]; // send buffer
unsigned int sz_recv; // size of recv buffer
unsigned int sz_send_total; // size of send buffer
unsigned int sz_send; // size of data send
// OVERLAPPED structures for notifications of completition
OVERLAPPED overlap_recv;
OVERLAPPED overlap_send;
OVERLAPPED overlap_cancel;
DWORD flags_recv; // Flags for WSARecv
};
struct client_ctx g_ctxs[1 + MAX_CLIENTS];
void schedule_write(DWORD idx)
{
WSABUF buf; buf.buf = g_ctxs[idx].buf_send + g_ctxs[idx].sz_send;
buf.len = g_ctxs[idx].sz_send_total - g_ctxs[idx].sz_send;
memset(&g_ctxs[idx].overlap_send, 0, sizeof(OVERLAPPED));
WSASend(g_ctxs[idx].socket, &buf, 1, NULL, 0, &g_ctxs[idx].overlap_send, NULL);
}
And using the above functions I send the requested data to the client
The data I send from the server
static class SystemInfo{
public :
static std::string GetOSVersion();
static std::string GetCurrentTimeStr();
static std::string GetTimeSinceStartStr();
static std::string GetFreeMemoryStr();
static std::string GetFreeSpaceStr();
static std::string CheckAccess();
static std::string CheckKeyFileDirectoryAccessRights(wchar_t *char_path, wchar_t *char_buf);
static std::string UserNameFromSid(PSID userSid);
static BOOL FileOrDirectoryExists(LPCTSTR szPath);
};
And the question is: is there any guide on how can I use the midl compiler to be able to represent the methods from SystemInfo class as procedures that can be called remotely? I can't find any manual of How to connect the existing functions with the remote procedure calls (and use them from the client side in my case)
You aren't going to be able to hook the client calls directly to existing server functions. Even when implicit binding handles are used on the client side the actual server function gets a binding handle (otherwise the server wouldn't be able to handle multiple clients). Because of that the signatures simply aren't going to match.
I want to write log files. My application could be run on Linux and Windows. I've pretty much figured out how to do it for the former, thanks to this example:
void SyslogMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
Q_UNUSED(context)
QByteArray localMsg = msg.toLocal8Bit();
switch (type)
{
case QtDebugMsg:
#ifdef __linux__
syslog(LOG_DEBUG, "Message (debug): %s", localMsg.constData());
#elif _WIN32
// WRITE INTO FILE
#else
#endif
break;
// etc.
}
}
int main()
{
// Install our message handler.
qInstallMessageHandler(SyslogMessageHandler);
// Send some messages, which should go to syslog.
qDebug("Debug log message from Qt test program");
}
source (2nd example)
However, I am wondering what would be the fastest way for Windows? Is using QFile or QTextStream an efficient way for writing this kind of information?
I was thinking about storing everything in a simple QString and then put everything in a file when the app closes or crashes (in the latter case, is that possible?).
im learning libcurl and boost:asio from this nice post http://www.lijoantony.com/?p=76
though i do have one question about the source code at:
sample code
the main function looks like:
int main(int argc, char **argv)
{
GlobalInfo g;
CURLMcode rc;
(void)argc;
(void)argv;
memset(&g, 0, sizeof(GlobalInfo));
g.multi = curl_multi_init();
curl_multi_setopt(g.multi, CURLMOPT_SOCKETFUNCTION, sock_cb);
curl_multi_setopt(g.multi, CURLMOPT_SOCKETDATA, &g);
curl_multi_setopt(g.multi, CURLMOPT_TIMERFUNCTION, multi_timer_cb);
curl_multi_setopt(g.multi, CURLMOPT_TIMERDATA, &g);
new_conn((char *)"http://us.download.nvidia.com/XFree86/Linux-x86_64/331.79/NVIDIA-Linux-x86_64-331.79.run", &g); /* add a URL */
/* enter io_service run loop */
io_service.run();
curl_multi_cleanup(g.multi);
fprintf(MSG_OUT, "\ndone.\n");
return 0;
}
i see there is no place calling the curl function curl_multi_perform()
how does the tasks get started at the very begining?
I see there is no place calling the curl function curl_multi_perform()
This is because this sample code uses an alternative API called curl_multi_socket_action:
curl_multi_socket_action is then used instead of curl_multi_perform.
(see the MULTI_SOCKET section of the official documentation for more details)
how does the tasks get started at the very begining?
The magic occurs thanks to the CURLMOPT_TIMERFUNCTION option, curl_multi_add_handle function and corresponding timer logic.
If you refer to the static void new_conn(char *url, GlobalInfo *g ) function you can see that:
static void new_conn(char *url, GlobalInfo *g )
{
/* ... */
rc = curl_multi_add_handle(g->multi, conn->easy);
mcode_or_die("new_conn: curl_multi_add_handle", rc);
/* note that the add_handle() will set a time-out to trigger very soon so
that the necessary socket_action() call will be called by this app */
}
So in practice everything starts by calling new_conn(...) which in turn will trigger multi_timer_cb which then calls timer_cb.
And timer_cb performs the curl_multi_socket_action.
Is there any possible way to access the socket handle inside a boost asio async completion handler ? i looked at the boost asio placeholders but there is no variable which stores the socket handle.
You can just arrange for it, anyway you would outside boost or asio.
To bind a function that takes e.g. a socket to expose a void() function you can use bind:
int foo(std::string const& s, int);
std::function<void()> adapted = std::bind(foo, "hello world", 42);
So, usually you'd have code similar to this:
boost::asio::async_connect(socket_.lowest_layer(), endpoint_iterator,
boost::bind(&client::handle_connect, this, boost::asio::placeholders::error));
Note, by using bind and this, we've bound a member function to the completion handler:
struct client
{
// ....
void handle_connect(boost::system::error_code err)
{
// you can just use `this->socket_` here
// ...
}
};
This implies that in handle_connect we can just use the socket_ member variable.
However, if you want to make things complicated you can use free functions as well
boost::asio::async_connect(socket_.lowest_layer(), endpoint_iterator,
boost::bind(&free_handle_connect, boost::ref(socket_), boost::asio::placeholders::error));
Now the implied handler function looks like
static void free_handle_connect(
boost::asio::ip::tcp::socket& socket_,
boost::system::error_code err)
{
// using `socket_` as it was passed in
int fd = _socket.native_handle_type();
}
I was going over the examples of boost.asio and I am wondering why there isn't an example of a simple server/client example that prints a string on the server and then returns a response to the client.
I tried to modify the echo server but I can't really figure out what I'm doing at all.
Can anyone find me a template of a client and a template of a server?
I would like to eventually create a server/client application that receives binary data and just returns an acknowledgment back to the client that the data is received.
EDIT:
void handle_read(const boost::system::error_code& error,
size_t bytes_transferred) // from the server
{
if (!error)
{
boost::asio::async_write(socket_,
boost::asio::buffer("ACK", bytes_transferred),
boost::bind(&session::handle_write, this,
boost::asio::placeholders::error));
}
else
{
delete this;
}
}
This returns to the client only 'A'.
Also in data_ I get a lot of weird symbols after the response itself.
Those are my problems.
EDIT 2:
Ok so the main problem is with the client.
size_t reply_length = boost::asio::read(s,
boost::asio::buffer(reply, request_length));
Since it's an echo server the 'ACK' will only appear whenever the request length is more then 3 characters.
How do I overcome this?
I tried changing request_length to 4 but that only makes the client wait and not do anything at all.
Eventually I found out that the problem resides in this bit of code in the server:
void handle_read(const boost::system::error_code& error,
size_t bytes_transferred) // from the server
{
if (!error)
{
boost::asio::async_write(socket_,
boost::asio::buffer("ACK", 4), // replaced bytes_transferred with the length of my message
boost::bind(&session::handle_write, this,
boost::asio::placeholders::error));
}
else
{
delete this;
}
}
And in the client:
size_t reply_length = boost::asio::read(s,
boost::asio::buffer(reply, 4)); // replaced request_length with the length of the custom message.
The echo client/server is the simple example. What areas are you having trouble with? The client should be fairly straightforward since it uses the blocking APIs. The server is slightly more complex since it uses the asynchronous APIs with callbacks. When you boil it down to the core concepts (session, server, io_service) it's fairly easy to understand.