gSOAP: How to pass info inside soap header - gsoap

I wish to send some information like authentication token inside SOAP header. I am using gSOAP/c/Linux. Please help me how to pass?
My SOAP_ENV__Header looks like
/* SOAP Header: */
struct SOAP_ENV__Header
{
struct ns3__Header *ns3__MyHeader; /* mustUnderstand */
};
and ns3__Header looks like
/* ns3:Header */
struct ns3__Header
{
char *Value; /* optional element of type xsd:string */
};

Sorry for bothering everybody. I figured it out. I did it like:
soap_init(&mysoap);
mysoap.header = (SOAP_ENV__Header *)soap_malloc(&mysoap, sizeof(SOAP_ENV__Header));
mysoap.header->ns3__MyHeader = (ns3__Header*)malloc(sizeof(ns3__Header));
mysoap.header->ns3__MyHeader->Value = (char*)malloc(10 * sizeof(char));
strcpy(mysoap.header->ns3__MyHeader->Value, str);
But I had to suppress the MustUnderstand attribute like the following:
SOAP_FMAC3 int SOAP_FMAC4 soap_out_SOAP_ENV__Header(struct soap *soap, const char *tag, int id, const struct SOAP_ENV__Header *a, const char *type)
{
if (soap_element_begin_out(soap, tag, soap_embedded_id(soap, id, a, SOAP_TYPE_SOAP_ENV__Header), type))
return soap->error;
//KNG
//soap->mustUnderstand = 1;
if (soap_out_PointerTons3__Header(soap, "ns3:MyHeader", -1, &a->ns3__MyHeader, ""))
return soap->error;
return soap_element_end_out(soap, tag);
}

Related

Gsoap header include subscriptionId

I need to insert in soap header the "subscriptionId" obtained from the call "CreatePullPointSubscription".
In my header don't have a reference about this.
This is my header structure :
struct SOAP_ENV__Header
{
public:
char *wsa5__MessageID; /* optional element of type wsa5:MessageID */
struct wsa5__RelatesToType *wsa5__RelatesTo; /* optional element of type wsa5:RelatesTo */
struct wsa5__EndpointReferenceType *wsa5__From; /* optional element of type wsa5:From */
struct wsa5__EndpointReferenceType *wsa5__ReplyTo; /* mustUnderstand */
struct wsa5__EndpointReferenceType *wsa5__FaultTo; /* mustUnderstand */
char *wsa5__To; /* mustUnderstand */
char *wsa5__Action; /* mustUnderstand */
struct chan__ChannelInstanceType *chan__ChannelInstance; /* optional element of type chan:ChannelInstanceType */
struct _wsse__Security *wsse__Security; /* mustUnderstand */
public:
int soap_type() const { return 42; } /* = unique type id SOAP_TYPE_SOAP_ENV__Header */
};
How to include subscriptionId field ?

libwebsockets write to all active connections after receive

I am toying around with a libwebsockets tutorial trying to make it such that, after it receives a message from a connection over a given protocol, it sends a response to all active connections implementing that protocol. I have used the function libwebsocket_callback_all_protocol but it is not doing what I think it should do from its name (I'm not quite sure what it does from the documentation).
The goal is to have two webpages open and, when info is sent from one, the result will be relayed to both. Below is my code - you'll see that libwebsocket_callback_all_protocol is called in main (which currently does nothing, I think....) :
#include <stdio.h>
#include <stdlib.h>
#include <libwebsockets.h>
#include <string.h>
static int callback_http(struct libwebsocket_context * this,
struct libwebsocket *wsi,
enum libwebsocket_callback_reasons reason, void *user,
void *in, size_t len)
{
return 0;
}
static int callback_dumb_increment(struct libwebsocket_context * this,
struct libwebsocket *wsi,
enum libwebsocket_callback_reasons reason,
void *user, void *in, size_t len)
{
switch (reason) {
case LWS_CALLBACK_ESTABLISHED: // just log message that someone is connecting
printf("connection established\n");
break;
case LWS_CALLBACK_RECEIVE: { // the funny part
// create a buffer to hold our response
// it has to have some pre and post padding. You don't need to care
// what comes there, libwebsockets will do everything for you. For more info see
// http://git.warmcat.com/cgi-bin/cgit/libwebsockets/tree/lib/libwebsockets.h#n597
unsigned char *buf = (unsigned char*) malloc(LWS_SEND_BUFFER_PRE_PADDING + len +
LWS_SEND_BUFFER_POST_PADDING);
int i;
// pointer to `void *in` holds the incomming request
// we're just going to put it in reverse order and put it in `buf` with
// correct offset. `len` holds length of the request.
for (i=0; i < len; i++) {
buf[LWS_SEND_BUFFER_PRE_PADDING + (len - 1) - i ] = ((char *) in)[i];
}
// log what we recieved and what we're going to send as a response.
// that disco syntax `%.*s` is used to print just a part of our buffer
// http://stackoverflow.com/questions/5189071/print-part-of-char-array
printf("received data: %s, replying: %.*s\n", (char *) in, (int) len,
buf + LWS_SEND_BUFFER_PRE_PADDING);
// send response
// just notice that we have to tell where exactly our response starts. That's
// why there's `buf[LWS_SEND_BUFFER_PRE_PADDING]` and how long it is.
// we know that our response has the same length as request because
// it's the same message in reverse order.
libwebsocket_write(wsi, &buf[LWS_SEND_BUFFER_PRE_PADDING], len, LWS_WRITE_TEXT);
// release memory back into the wild
free(buf);
break;
}
default:
break;
}
return 0;
}
static struct libwebsocket_protocols protocols[] = {
/* first protocol must always be HTTP handler */
{
"http-only", // name
callback_http, // callback
0, // per_session_data_size
0
},
{
"dumb-increment-protocol", // protocol name - very important!
callback_dumb_increment, // callback
0, // we don't use any per session data
0
},
{
NULL, NULL, 0, 0 /* End of list */
}
};
int main(void) {
// server url will be http://localhost:9000
int port = 9000;
const char *interface = NULL;
struct libwebsocket_context *context;
// we're not using ssl
const char *cert_path = NULL;
const char *key_path = NULL;
// no special options
int opts = 0;
// create libwebsocket context representing this server
struct lws_context_creation_info info;
memset(&info, 0, sizeof info);
info.port = port;
info.iface = interface;
info.protocols = protocols;
info.extensions = libwebsocket_get_internal_extensions();
info.ssl_cert_filepath = cert_path;
info.ssl_private_key_filepath = key_path;
info.gid = -1;
info.uid = -1;
info.options = opts;
info.user = NULL;
info.ka_time = 0;
info.ka_probes = 0;
info.ka_interval = 0;
/*context = libwebsocket_create_context(port, interface, protocols,
libwebsocket_get_internal_extensions,
cert_path, key_path, -1, -1, opts);
*/
context = libwebsocket_create_context(&info);
if (context == NULL) {
fprintf(stderr, "libwebsocket init failed\n");
return -1;
}
libwebsocket_callback_all_protocol(&protocols[1], LWS_CALLBACK_RECEIVE);
printf("starting server...\n");
// infinite loop, to end this server send SIGTERM. (CTRL+C)
while (1) {
libwebsocket_service(context, 50);
// libwebsocket_service will process all waiting events with their
// callback functions and then wait 50 ms.
// (this is a single threaded webserver and this will keep our server
// from generating load while there are not requests to process)
}
libwebsocket_context_destroy(context);
return 0;
}
I had the same problem, the libwebsocket_write on LWS_CALLBACK_ESTABLISHED generate some random segfault so using the mail list the libwebsockets developer Andy Green instructed me the correct way is to use libwebsocket_callback_on_writable_all_protocol, the file test-server/test-server.c in library source code shows sample of use.
libwebsocket_callback_on_writable_all_protocol(libwebsockets_get_protocol(wsi))
It worked very well to notify all instances, but it only call the write method in all connected instances, it do not define the data to send. You need to manage the data yourself. The sample source file test-server.c show a sample ring buffer to do it.
http://ml.libwebsockets.org/pipermail/libwebsockets/2015-January/001580.html
Hope it helps.
From what I can quickly grab from the documentation, in order to send a message to all clients, what you should do is store somewhere (in a vector, a hashmap, an array, whatever) the struct libwebsocket * wsi that you have access when your clients connect.
Then when you receive a message and want to broadcast it, simply call libwebsocket_write on all wsi * instances.
That's what I'd do, anyway.

Bonjour DNS-SD callback not being called, where's a mistake in my code?

I'm trying to learn how to use Bonjour using this blog article as a reference:
http://marknelson.us/2011/10/25/dns-service-discovery-on-windows/
I've download sample project linked at the bottom of that page, it works like charm. Now I'm trying to reproduce service discovery from scratch in my console application:
#include <iostream>
#include <assert.h>
#include "dns/dns_sd.h"
class CDnsSd
{
public:
bool discoverAsync ();
private:
static void DNSSD_API onDiscoveryFinished (DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
DNSServiceErrorType errorCode, const char *serviceName, const char *regtype,
const char *replyDomain, void *context);
};
bool CDnsSd::discoverAsync()
{
DNSServiceRef client = NULL;
const DNSServiceErrorType err = DNSServiceBrowse( &client, 0, 0, ""_services._dns-sd._udp"", "", onDiscoveryFinished, this );
return err == kDNSServiceErr_NoError;
}
void DNSSD_API CDnsSd::onDiscoveryFinished( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain, void *context )
{
std::cout << __FUNCTION__;
}
void main ()
{
CDnsSd dnsSd;
const bool ret = dnsSd.discoverAsync();
assert(ret);
Sleep(10000000);
}
DNSServiceBrowse returns kDNSServiceErr_NoError, but the callback is never called. What's wrong?
You need a main loop processing Bonjour events. Look at the link you provided carefully. It's there in the "Driving the Callbacks" section.
I had to call the method named DNSServiceProcessResult to make it work for my part.
I hope it helped

Deserialize Protocol Buffers using boost::mpl

I create my RPC Protocol with PB like:
enum EMessages {
E_MSG_METHOD_CONNECT = 0x8001,
E_MSG_EVENT_CONNECT = 0xA001,
...
}
struct MsgHeader {
required int32 sessionRef = 1;
required int32 transactionId = 2;
required int32 status = 3;
}
struct MSG_METHOD_CONNECT {
optional Messages opCode = 1 [default = E_MSG_METHOD_CONNECT];
required MsgHeader header = 2;
.. other fields ..
}
Now, I defined an interface and a template class to add a level of indirection:
class IMessage {
virtual INT getOpCode() = 0;
virtual STRING getName() = 0;
virtual size_t getSize() = 0;
virtual INT SerializeToString(STRING& out) = 0;
virtual INT ParseFromString(STRING& in) = 0;
....
}
template<class MESSAGE>
class IMessageImpl : public IMessage {
protected:
MESSAGE m_Message; ///< The Message Implementation
public:
virtual MESSAGE& getMessage() = 0;
};
And I will use it as:
IMessageImpl<MSG_METHOD_CONNECT> MsgConnect;
Now, when I receive the data from an endpoint I need, of course, to deserialize it according with the message opCode.
Reading this article I'm thinking to use a type map like boost::mpl::map but, since I never use it, I'm searching for some suggestions.
<< ------------------------ [EDIT] ------------------------ >>
Regarding the code above, I try to code it in the following way:
template<class MESSAGE>
class PBMessage : public IMessageImpl<MESSAGE>
{
public:
PBMessage() {};
/* ... other methods ... */
};
// Map of types. The key is the Message opCode
typedef typename mpl::map< mpl::pair<mpl::int_[100], PBMessage<MSG_METHOD_CONNECT> >,
mpl::pair<mpl::int_[101], PBMessage<MSG_EVENT_CONNECT> >,
> TMessageMap;
// The Message type
template < typename MessageMap, int opCode >
typedef typename mpl::at<MessageMap, mpl::int_<opCode> >::type::value TMessage;
And, to create a message from a received buffer I try to code (take it as pseudo-code):
class PBMessageFactory : public IMessageFactory {
public:
IMessage* createMessage(CHAR* buff, UINT size) {
int opCode = buff[0];
TMessage<TMessageMap, opCode> msg;
msg.ParseFromString( STRING(buff) );
}
};
But with no success...Is there someone could give me some suggestions how to retrieve types from a mpl::map?
Thanks,
Daniele.

implementation of mib2c generated code

/*
* Note: this file originally auto-generated by mib2c using
* $
*/
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include "pool.h"
/** Initializes the pool module */
void
init_pool(void)
{
/* here we initialize all the tables we're planning on supporting */
initialize_table_poolTable();
}
//Determine the first/last column names
/** Initialize the poolTable table by defining its contents and how it's structured */
void
initialize_table_poolTable(void)
{
const oid poolTable_oid[] = {1,3,6,1,4,1,21068,4,2};
const size_t poolTable_oid_len = OID_LENGTH(poolTable_oid);
netsnmp_handler_registration *reg;
netsnmp_iterator_info *iinfo;
netsnmp_table_registration_info *table_info;
DEBUGMSGTL(("pool:init", "initializing table poolTable\n"));
reg = netsnmp_create_handler_registration(
"poolTable", poolTable_handler,
poolTable_oid, poolTable_oid_len,
HANDLER_CAN_RONLY
);
table_info = SNMP_MALLOC_TYPEDEF( netsnmp_table_registration_info );
netsnmp_table_helper_add_indexes(table_info,
ASN_INTEGER, /* index: ifIndex */
0);
table_info->min_column = 1;
table_info->max_column = COLUMN_POOLINOCTETS;
iinfo = SNMP_MALLOC_TYPEDEF( netsnmp_iterator_info );
iinfo->get_first_data_point = poolTable_get_first_data_point;
iinfo->get_next_data_point = poolTable_get_next_data_point;
iinfo->table_reginfo = table_info;
netsnmp_register_table_iterator( reg, iinfo );
/* Initialise the contents of the table here */
}
/* Typical data structure for a row entry */
struct poolTable_entry {
/* Index values */
long ifIndex;
/* Column values */
u_long poolInOctets;
/* Illustrate using a simple linked list */
int valid;
struct poolTable_entry *next;
};
struct poolTable_entry *poolTable_head;
/* create a new row in the (unsorted) table */
struct poolTable_entry *
poolTable_createEntry(
long ifIndex
) {
struct poolTable_entry *entry;
entry = SNMP_MALLOC_TYPEDEF(struct poolTable_entry);
if (!entry)
return NULL;
entry->ifIndex = ifIndex;
entry->next = poolTable_head;
poolTable_head = entry;
return entry;
}
/* remove a row from the table */
void
poolTable_removeEntry( struct poolTable_entry *entry ) {
struct poolTable_entry *ptr, *prev;
if (!entry)
return; /* Nothing to remove */
for ( ptr = poolTable_head, prev = NULL;
ptr != NULL;
prev = ptr, ptr = ptr->next ) {
if ( ptr == entry )
break;
}
if ( !ptr )
return; /* Can't find it */
if ( prev == NULL )
poolTable_head = ptr->next;
else
prev->next = ptr->next;
SNMP_FREE( entry ); /* XXX - release any other internal resources */
}
/* Example iterator hook routines - using 'get_next' to do most of the work */
netsnmp_variable_list *
poolTable_get_first_data_point(void **my_loop_context,
void **my_data_context,
netsnmp_variable_list *put_index_data,
netsnmp_iterator_info *mydata)
{
*my_loop_context = poolTable_head;
return poolTable_get_next_data_point(my_loop_context, my_data_context,
put_index_data, mydata );
}
netsnmp_variable_list *
poolTable_get_next_data_point(void **my_loop_context,
void **my_data_context,
netsnmp_variable_list *put_index_data,
netsnmp_iterator_info *mydata)
{
struct poolTable_entry *entry = (struct poolTable_entry *)*my_loop_context;
netsnmp_variable_list *idx = put_index_data;
if ( entry ) {
snmp_set_var_typed_integer( idx, ASN_INTEGER, entry->ifIndex );
idx = idx->next_variable;
*my_data_context = (void *)entry;
*my_loop_context = (void *)entry->next;
return put_index_data;
} else {
return NULL;
}
}
/** handles requests for the poolTable table */
int
poolTable_handler(
netsnmp_mib_handler *handler,
netsnmp_handler_registration *reginfo,
netsnmp_agent_request_info *reqinfo,
netsnmp_request_info *requests) {
netsnmp_request_info *request;
netsnmp_table_request_info *table_info;
struct poolTable_entry *table_entry;
DEBUGMSGTL(("pool:handler", "Processing request (%d)\n", reqinfo->mode));
switch (reqinfo->mode) {
/*
* Read-support (also covers GetNext requests)
*/
case MODE_GET:
for (request=requests; request; request=request->next) {
table_entry = (struct poolTable_entry *)
netsnmp_extract_iterator_context(request);
table_info = netsnmp_extract_table_info( request);
switch (table_info->colnum) {
case COLUMN_POOLINOCTETS:
if ( !table_entry ) {
netsnmp_set_request_error(reqinfo, request,
SNMP_NOSUCHINSTANCE);
continue;
}
snmp_set_var_typed_integer( request->requestvb, ASN_COUNTER,
table_entry->poolInOctets);
break;
default:
netsnmp_set_request_error(reqinfo, request,
SNMP_NOSUCHOBJECT);
break;
}
}
break;
}
return SNMP_ERR_NOERROR;
}
above is my mib2c generated code. I am compiling it as subagent... but it is not showing any kind of values. What should be my next step to implement it ? from where can I get data? Please help me to implement it.
snmpwalk -c public -v 2c localhost 1.3.6.1.4.1.21068
POOL-MIB::elite = No Such Object available on this agent at this OID
Thansks in advance.
You need to add data to the poolTable_head linked list of data. You can do this like so:
struct poolTable_entry *entry = poolTable_createEntry(1);
entry->poolInOctets = 42;
And then put that code, which is just very basic example code with static numbers, somewhere that will get called. You could, for example, put it at the bottom of the initialize_table_poolTable() function.
Note that mib2c generates a lot of different coding styles, and based on what I see above I'm not quite convinced you chose the right style as it doesn't look like your data will be highly static and thus you'll need to set an alarm (see snmp_alarm(3)) to update the poolInOctets numbers on a regular basis.

Resources