I have client and server code communicating with each other using protobuf-c over 0mq
below is the client cod snipped
void *context = zmq_ctx_new ();
void *requester = zmq_socket (context, ZMQ_REQ);
char collector[100];
char buffer[MAX_MSG];
sprintf(collector,"tcp://%s:%s",argv[2],argv[3]);
zmq_connect (requester, collector);
LogMsg proto_msg = LOG_MSG__INIT;
void *buf; // Buffer to store serialized data
unsigned len; // Length of serialized data
proto_msg.name=argv[1];//assigning arg1 the node name
proto_msg.ip="127.0.0.1"; //TODO get IP im connected to
proto_msg.pid=getpid();
proto_msg.has_pid = 1;
//sending Hello to Collector to register
proto_msg.level = "HELLO";
len = log_msg__get_packed_size (&proto_msg);
buf = malloc (len);
log_msg__pack (&proto_msg, buf);
printf("Writing %d serialized bytes to socket: Handshaking with Collector\n",len); // See the length of message
zmq_send(requester, buf,len, 0);
on the Server side i have the following code
#include "generator.h"
int main (void)
{
// Socket to talk to clients
void *context = zmq_ctx_new ();
void *responder = zmq_socket (context, ZMQ_REP);
int rc = zmq_bind (responder, "tcp://*:5555");
uint8_t buffer[MAX_MSG];
int i=0;
assert (rc == 0);
zmq_recv (responder, buffer, MAX_MSG, 0);
printf ("recieved -> %s\n",buffer);
LogMsg *ptr_msg;
ptr_msg = log_msg__unpack(NULL,i,buffer); // Deserialize the serialized input
if (ptr_msg == NULL)
{ // Something failed
fprintf(stderr,"error unpacking incoming message\n");
return 1;
}
log_msg__free_unpacked(ptr_msg,NULL);
return 0;
}
But when the server receives the message it is giving the following error
recieved ->
B1 127.0.0.1??"HELLO/??
message 'Log_msg': missing required field 'name'
For reference .proto file is as below
message Log_msg
{
required string name=1; //Node Name
optional string IP=2 [default = "127.0.0.1"]; //Node IP Addr
optional int32 PID=3 [default = 9999]; //Process ID
optional string level=4 [default = "INFO"]; //Log Info Level
optional int64 datim=5; //UNIX Time Stamp
optional string msg=6; //Log message
}
I assume when i am transmitting it on wire then it gets corrupted. Any ideas how i can send it properly. Examples online show this for c++. I need for C.
zmq_send and zmq_recv seems to handle zmq_msg_t structures rather than just the buffer.
Maybe you should try to create such structures rather than just sending your buffer ?
See the examples in http://api.zeromq.org/2-1:zmq-send and http://api.zeromq.org/2-1:zmq-recv
Related
Curently I`m developing chat aplication using C and libevent library for both client and server. I started from simple prototype, where client simply send plain string, server recive it and send it to every connected user except the sender. But now I need to send not only the string, but also some information about the user, for example - his name. So, what the best wey to send complicated data (structs for exmaple) through sockets in C?
I have some code, that sends and recives structure as byte array, but i dont know, is it right to send it like that, or better to use JSON serialization for example. Thanks.
Client method, that read line and send it to server:
void *readmsg_and_send_msg(void *arg)
{
struct client *cl = (struct client *)arg;
struct sock_data data;
uint8_t sendbuff_array[DATA_BUFF_LENGTH];
data.type = SENDMSG_REQUEST;
char *line;
while (1)
{
line = getline();
if (line)
{
memcpy(data.data, (void *)line, strlen(line));
memcpy(sendbuff_array, &data, sizeof(data));
printf("%s\n", (char *)sendbuff_array);
bufferevent_write(cl->buf_ev, (void *)sendbuff_array, sizeof(sendbuff_array));
}
}
}
Server "on read" method:
void buffered_on_read(struct bufferevent *bev,
void *arg)
{
struct client *this_client = arg;
struct client *client;
sock_data_t *sockdata;
uint8_t data[DATA_BUFF_LENGTH];
size_t n;
/* Read 8k at a time and send it to all connected clients. */
for (;;)
{
n = bufferevent_read(bev, &data, sizeof(data));
//if 0 - end reading
if (n <= 0)
break;
}
sockdata = (sock_data_t *)data;
if (sockdata->type == SENDMSG_REQUEST)
{
printf("\033[0;36mNew message %s from %d recived\033[0m\n", (char *)sockdata->data, this_client->fd);
TAILQ_FOREACH(client, &client_tailq_head, entries)
{
if (client != this_client)
{
bufferevent_write(client->buf_ev, (void *)sockdata->data, sizeof(sockdata->data));
printf("Message %s successfully sended to user %d\n", (char *)sockdata->data, client->fd);
}
}
}
else
{
printf("%s - %d\n", (char *)sockdata->data, sockdata->type);
printf("Unimplemented request type\n");
return;
}
}
Struct, that I`m trying to send/recive:
#pragma pack(push, 1)
typedef struct sock_data_s
{
request_type_e type;
uint8_t data[DATA_BUFF_LENGTH];
} sock_data_t;
#pragma pack(pop)
Where request_type_e - enum, using for definding type on incoming request:
typedef enum request_type
{
REG_REQUEST = 0x0, //registration request
LOG_REQUEST, // login request
GETMSG_REQUEST, // get list of room`s messages request
SENDMSG_REQUEST, // send message to room
} request_type_e;
I have the following code, and I am getting SIGSEGV on the line:
if ( SSL_connect(ssl) == FAIL )
The fault Im getting is:
Program received signal SIGSEGV, Segmentation fault.
0x00007ffffe5a41e0 in __GI___libc_malloc (bytes=104) at malloc.c:2926
2926 malloc.c: No such file or directory.
The program basically is designed to take loads of data and push it into firebase.
The first one element, is to check if we are registered, the next bit is to actually do the registration.
Cutting the program back to basics, we have the following opening gambit:
int main(int argc, char *argv[]) {
int iRegistered = checkRegistered();
int result = registerCar();
}
If we swap those two lines, so we register before we check the registration, then we don't get a SIGSEGV.
Here's the checkRegistration function:
int checkRegistered() {
int firebaseRegistered = 0;
char *carId;
carId = (char *) malloc(256);
strcpy(carId, "aabbccddeeffgg" );
char *payload;
payload = (char *) malloc(1024);
sprintf(payload, "{ \"carid\": \"%s\" }", carId);
char *response;
response = (char *) malloc(1024);
int result = firebase("isCarRegistered", payload, &response);
if (result == 0) {
// Process JSON Response
cJSON *json = cJSON_Parse(response);
if (json == NULL) {
//
} else {
cJSON *json_registered = NULL;
json_registered = cJSON_GetObjectItemCaseSensitive(json, "registered");
firebaseRegistered = json_registered->valueint;
}
}
free(response);
free(payload);
free(carId);
return firebaseRegistered;
}
And the registerCar function.
They're basically mostly the same format - construct a message, send it to firebase, process the JSON response. We use cJSON to decompile the data returned from Firebase, though we could potentially use it to also compile. But one thing at a time.
You'll see a number of free() statements - I've been trying to work out how best to complete this - ie, generate a char* locally, pass by reference ** to a function, let the function perform the malloc/realloc based on the sizes it can calculate and then we can free it from the calling code once we have dealth with the data. Though I also get a SIGSEGV from that as well.
int registerCar() {
int iResponse = 0;
char *carId;
carId = (char *) malloc(256);
char *authCode;
authCode = (char *) malloc(12);
char *payload;
payload = (char *) malloc(1024);
sprintf(payload, "{ }");
char *response;
response = (char *) malloc(1024);
int result = firebase("registerCar", payload, &response);
if (result == 0) {
// Process JSON Response
cJSON *json = cJSON_Parse(response);
if (json == NULL) {
//
} else {
cJSON *json_auth = NULL;
cJSON *json_car = NULL;
json_auth = cJSON_GetObjectItemCaseSensitive(json, "authcode");
json_car = cJSON_GetObjectItemCaseSensitive(json, "carid");
iResponse = 1;
}
}
free(response);
free(payload);
return iResponse;
}
Here's the firebase routine, it takes a function, a payload and generates a response. Interestingly here, char firebaseLocal and charfirebaseMessage is not always null before the initial malloc.
int firebase(char *firebaseFunction, char *firebasePayload, char **firebaseResponse) {
char buf[1024];
char *firebaseLocal;
char *firebaseMessage;
firebaseMessage = (char *) malloc(1024);
SSL_CTX *ctx;
int server;
SSL *ssl;
int bytes;
ctx = InitCTX();
server = OpenConnection(HOST, atoi(PORT));
ssl = SSL_new(ctx); /* create new SSL connection state */
SSL_set_fd(ssl, server); /* attach the socket descriptor */
if ( SSL_connect(ssl) == FAIL ) /* perform the connection */
ERR_print_errors_fp(stderr);
else {
ShowCerts(ssl); /* get any certs */
char *firebasePost;
generatePostMessage(firebaseFunction, firebasePayload, &firebasePost);
SSL_write(ssl, firebasePost, strlen(firebasePost));
bytes = SSL_read(ssl, buf, sizeof(buf)); /* get reply & decrypt */
buf[bytes] = 0;
//SSL_free(ssl); /* release connection state */
strcpy(firebaseMessage, buf);
firebaseLocal = strstr(firebaseMessage, "\r\n\r\n");
if (firebaseLocal != NULL) {
firebaseLocal +=4;
}
strcpy(*firebaseResponse, firebaseLocal);
}
free(firebaseMessage);
close(server); /* close socket */
SSL_CTX_free(ctx); /* release context */
return 0;
}
This is from an implementation I found on secure sockets.
int OpenConnection(const char *hostname, int port)
{ int sd;
struct hostent *host;
struct sockaddr_in addr;
if ( (host = gethostbyname(hostname)) == NULL )
{
perror(hostname);
abort();
}
sd = socket(PF_INET, SOCK_STREAM, 0);
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = *(long*)(host->h_addr);
if ( connect(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
{
close(sd);
perror(hostname);
abort();
}
return sd;
}
This is from an implementation I found on secure sockets.
SSL_CTX* InitCTX(void)
{
SSL_METHOD *method;
SSL_CTX *ctx;
SSL_library_init();
OpenSSL_add_all_algorithms(); /* Load cryptos, et.al. */
SSL_load_error_strings(); /* Bring in and register error messages */
method = TLSv1_2_client_method(); /* Create new client-method instance */
ctx = SSL_CTX_new(method); /* Create new context */
if ( ctx == NULL )
{
ERR_print_errors_fp(stderr);
abort();
}
return ctx;
}
This is from an implementation I found on secure sockets.
void ShowCerts(SSL* ssl)
{ X509 *cert;
char *line;
cert = SSL_get_peer_certificate(ssl); /* get the server's certificate */
if ( cert != NULL )
{
printf("Server certificates:\n");
line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
printf("Subject: %s\n", line);
free(line); /* free the malloc'ed string */
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
printf("Issuer: %s\n", line);
free(line); /* free the malloc'ed string */
X509_free(cert); /* free the malloc'ed certificate copy */
}
else
printf("Info: No client certificates configured.\n");
}
This is something that I wrote to generate a post message from message
void generatePostMessage(char *firebaseFunction, char *firebaseMessage, char **response) {
int intPayloadSize = strlen(firebaseMessage);
char *charPayloadSize;
charPayloadSize = (char *) malloc(8);
sprintf(charPayloadSize, "%d", intPayloadSize);
char *postmessage = "POST /%s HTTP/1.1\r\n"
"Host: us-central1-carconnect-e763e.cloudfunctions.net\r\n"
"User-Agent: USER_AGENT\r\n"
"Content-Type: application/json\r\n"
"Accept: text/plain\r\n"
"Content-Length: %d\r\n\r\n"
"%s";
// Allocate size of postmessage less the inserts, plus the payload size, plus the payload size digits, plus null
int responseLength = (strlen(postmessage) - 4) + intPayloadSize + strlen(charPayloadSize)+1;
// Round up Four Bytes.
int responseIncrease = responseLength % 4;
if (responseIncrease > 0) {
responseLength += (4 - responseIncrease);
}
*response = (char *) malloc(responseLength);
sprintf(*response, postmessage, firebaseFunction, intPayloadSize, firebaseMessage);
}
As advised, whether the registration or registration check is called first, the first call works fine.
If I perform the registration before the check, then both commands work fine. Further testing also does confirm the problem is the registration check. I can perform registration several times without fail. The registration check and any follow up calls fail completely at the SSL_connect line. I don't know why.
The SSL_free command in the firebase connection always fails. I also get a SIGSEGV if I try to free(firebasePost) after the SSL_Write - which suggests I cannot free a pointer that has been passed by reference and mallocced in a function.
Part of me wonders whether any of this is caused by the fact Im debugging on Windows. I've always had problems with malloc() on Windows just not working the way I would expect.
The problem, or at least one of them, is in generatePostMessage. Not enough buffer is allocated for response. sprintf will then run off the end of the allocated buffer and cause heap corruption, which manifests itself on next invocation of malloc. Try:
int responseLength = strlen(firebaseFunction) + (strlen(postmessage) - 4) + intPayloadSize + strlen(charPayloadSize)+1;
The problem I am having is specifically printing out the response of a dbus method call in C using the low level API. I am new to C's libdbus, but have done some work in python-dbus.
I know how to write dbus methods and method calls in python as well as the CLI
I can find code on the internet to invoke dbus methods, but they don't return or print out the response
I have been looking at the libdbus doxygen api, but cannot determine how to pull out the response.
The way I have my code set up, a python dbus daemon runs with methods I want to call. Some of them return a string. I want a C program to connect to the session bus, call the method, print out the reply and exit.
This is what I have currently:
#include <stdio.h>
#include <dbus/dbus.h>
static void send_dbus_message (DBusConnection *connection, const char *msg)
{
DBusMessage *message;
//initialize the message
message = dbus_message_new_signal ("/org/example/foo/bar",
"org.example.foo.bar",
msg);
//send the message
dbus_connection_send (connection, message, NULL);
//deallocate the message
dbus_message_unref (message);
}
int main (int argc, char **argv)
{
DBusConnection *connection;
DBusError error;
//init error message
dbus_error_init (&error);
connection = dbus_bus_get (DBUS_BUS_SESSION, &error);
if (!connection)
{
printf ("Connection to D-BUS daemon failed: %s", error.message);
//deallocate error message
dbus_error_free (&error);
return 1;
}
send_dbus_message (connection, "HelloWorld");
return 0;
}
Can be synchronous or asynchronous.
You can use the method mentioned in http://www.matthew.ath.cx/misc/dbus to get a method reply message.
Once you have a dbus message you can use following method to extract the data.
To parse a dbus message, you need a argument iterator. Initalize it to read contents of the incoming message.
DBusMessageIter MsgIter;
dbus_message_iter_init(msg, &MsgIter);//msg is pointer to dbus message received
You have to validate the signature of the incoming message before reading it. Or you can also go for argument by argument verification. For example, if the argument type is string
if (DBUS_TYPE_STRING == dbus_message_iter_get_arg_type(&MsgIter)){
char* str = NULL;
dbus_message_iter_get_basic(&MsgIter, &str);//this function is used to read basic dbus types like int, string etc.
}
For complex types, like structures, arrays, variants and dict entries, you have to create corresponding child iterators to parse contents of each complex element. Say, for a dbus signature ofs(i{ii}i)u, the extraction is done as below
//Parsing a signature s(i{ii}i)u
DBusMessageIter rootIter;
dbus_message_iter_init(msg, &rootIter);
if (DBUS_TYPE_STRING == dbus_message_iter_get_arg_type(&rootIter))
{
char* str = NULL;
dbus_message_iter_get_basic(&rootIter, &str);//this function is used to read basic dbus types like int, string etc.
dbus_message_iter_next(&rootIter);//Go to next argument of root iter
//Block to enter and read structure
if (DBUS_TYPE_STRUCT == dbus_message_iter_get_arg_type(&rootIter))
{
DBusMessageIter structIter;
dbus_message_iter_recurse(&rootIter, &structIter);//Initialize iterator for struct
//Argument 1 is int32
if (DBUS_TYPE_INT32 == dbus_message_iter_get_arg_type(&structIter))
{
int a;
dbus_message_iter_get_basic(&structIter, &a);//Read integer
dbus_message_iter_next(&structIter);//Go to next argument of structiter
if (DDBUS_TYPE_DICT_ENTRY == dbus_message_iter_get_arg_type(&structIter))
{
DBusMessageIter dictIter;
dbus_message_iter_recurse(&structIter, &dictIter);//Initialize iterator for dictentry
if (DBUS_TYPE_INT32 == dbus_message_iter_get_arg_type(&dictIter))
{
dbus_message_iter_get_basic(&dictIter, &a);//Read integer
dbus_message_iter_next(&dictIter);//Go to next argument of dictentry
if (DBUS_TYPE_INT32 == dbus_message_iter_get_arg_type(&dictIter))
{
dbus_message_iter_get_basic(&dictIter, &a);//Read integer
}
}
}
dbus_message_iter_next(&structIter);//Go to next argument of structiter
if (DBUS_TYPE_INT32 == dbus_message_iter_get_arg_type(&structIter))
{
dbus_message_iter_get_basic(&structIter, &a);//Read integer
}
}
}
dbus_message_iter_next(&rootIter);//Go to next argument of root iterator
if (DBUS_TYPE_UINT32 == dbus_message_iter_get_arg_type(&rootIter))
{
uint32_t b;
dbus_message_iter_get_basic(&rootIter, &b);//Read integer
}
}
In above code, I used argument by argument signature check. Instead you can do a one time verfication using dbus_message_iter_get_signature. Refer to libdbus api for more info.
#
From your reply I understand that you have problems with connection setup ,
here is a full example, where a method call is invoked on a server and the result is printed
if the first argument is a string.
#
#include <stdio.h>
#include <stdlib.h>
#include <dbus/dbus.h>
#include <assert.h>
DBusConnection* conn = NULL;
//Helper function to setup connection
void vsetupconnection();
//Send method call, Returns NULL on failure, else pointer to reply
DBusMessage* sendMethodCall(const char* objectpath, \
const char* busname, \
const char* interfacename, \
const char* methodname);
#define TEST_BUS_NAME "org.freedesktop.DBus"
#define TEST_OBJ_PATH "/org/freedesktop/DBus"
#define TEST_INTERFACE_NAME "org.freedesktop.DBus.Introspectable"
#define TEST_METHOD_NAME "Introspect"
int main (int argc, char **argv)
{
vsetupconnection();
DBusMessage* reply = sendMethodCall(TEST_OBJ_PATH, TEST_BUS_NAME, TEST_INTERFACE_NAME, TEST_METHOD_NAME);
if(reply != NULL) {
DBusMessageIter MsgIter;
dbus_message_iter_init(reply, &MsgIter);//msg is pointer to dbus message received
if (DBUS_TYPE_STRING == dbus_message_iter_get_arg_type(&MsgIter)){
char* str = NULL;
dbus_message_iter_get_basic(&MsgIter, &str);
printf("Received string: \n %s \n",str);
}
dbus_message_unref(reply);//unref reply
}
dbus_connection_close(conn);
return 0;
}
void vsetupconnection()
{
DBusError err;
// initialise the errors
dbus_error_init(&err);
// connect to session bus
conn = dbus_bus_get(DBUS_BUS_SESSION, &err);
if (dbus_error_is_set(&err)) {
printf("Connection Error (%s)\n", err.message);
dbus_error_free(&err);
}
if (NULL == conn) {
exit(1);
}
else {
printf("Connected to session bus\n");
}
}
DBusMessage* sendMethodCall(const char* objectpath, const char* busname, const char* interfacename, const char* methodname)
{
assert(objectpath != NULL); assert(busname != NULL); assert(interfacename != NULL);
assert(methodname != NULL); assert(conn != NULL);
DBusMessage* methodcall = dbus_message_new_method_call(busname,objectpath, interfacename, methodname);
if (methodcall == NULL) {
printf("Cannot allocate DBus message!\n");
}
//Now do a sync call
DBusPendingCall* pending;
DBusMessage* reply;
if (!dbus_connection_send_with_reply(conn, methodcall, &pending, -1))//Send and expect reply using pending call object
{
printf("failed to send message!\n");
}
dbus_connection_flush(conn);
dbus_message_unref(methodcall);
methodcall = NULL;
dbus_pending_call_block(pending);//Now block on the pending call
reply = dbus_pending_call_steal_reply(pending);//Get the reply message from the queue
dbus_pending_call_unref(pending);//Free pending call handle
assert(reply != NULL);
if(dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
printf("Error : %s",dbus_message_get_error_name(reply));
dbus_message_unref(reply);
reply = NULL;
}
return reply;
}
ORIGINAL POST:
I'm writing a service in C programming using libevent and zmq.
Msg is pushed from python code to C service using PUSH-PULL pattern.
fd received from zmq socket:
void *receiver = zmq_socket (base.zmq_ctx, ZMQ_PULL);
zmq_connect (receiver, "tcp://localhost:5557");
int fd=0;
size_t fd_len = sizeof(fd);
zmq_getsockopt (receiver, ZMQ_FD, &fd, &fd_len);
Using Libevent, event registered with fd for persistent read
struct event *read_data_on_zmq =event_new(base.evbase, fd, EV_READ | EV_PERSIST , read_data_on_zmq_cb,receiver);
event_add(read_data_on_zmq,NULL);
event_base_dispatch(base.evbase);
On the callback method I'm doing a non-blocking receive
void read_data_on_zmq_cb(evutil_socket_t fd, short what, void *arg)
{
char *msg = calloc(1024,sizeof(char));
int size = zmq_recv (receiver, msg, 255, ZMQ_DONTWAIT);
if (size != -1)
{
puts ("is size is not -1");
printf("msg = %s\n",msg);
}
}
In the python code I'm continuously sending message to the socket.
import zmq
import time
c=zmq.Context()
s=c.socket(zmq.PUSH)
s.bind('tcp://127.0.0.1:5557')
while(True):
s.send("abc")
time.sleep(2)
The problem is I'm only able to receive the message once, after that the event callback never gets hit.
If I do zmq_connect inside the read_data_on_zmq_cb after zmq_recv, then it works fine, but I guess that is redundant and not the correct way to do it. What is the problem here?
EDIT1:
In addition to checking ZMQ_EVENTS after doing zmq_recv(), you need to fetch all the message because zmq is EDGE triggered. A great explanation about EDGE trigered notification is here http://funcptr.net/2012/09/10/zeromq---edge-triggered-notification/
so ultimately my event callback would look like
void read_data_on_zmq_cb(evutil_socket_t fd, short what, void *arg)
{
unsigned int zmq_events;
size_t zmq_events_size = sizeof(zmq_events);
char *msg=NULL;
zmq_getsockopt (receiver, ZMQ_EVENTS, &zmq_events, &zmq_events_size);
while(zmq_events & ZMQ_POLLIN)
{
msg = calloc(1024,sizeof(char));
int size = zmq_recv (receiver, msg, 255, ZMQ_DONTWAIT);
if (size != -1) {
#ifdef DEBUG
printf("msg = %s\n",msg);
#endif
//return msg;
}
zmq_getsockopt (receiver, ZMQ_EVENTS, &zmq_events, &zmq_events_size);
}
}
PLEASE read my EDIT1 for complete answer with code.
The problem was:
I didn't recheck ZMQ_EVENTS after doing zmq_recv(), as the state of the socket changes
at that time.
So calling
zmq_getsockopt (receiver, ZMQ_EVENTS, &fd, &fd_size);
after zmq_recv() solved my problem.
I am unable to receive message serialized in protobuf over ZeroMQ sockets using C.
I have serialized message entered by client and send this buffer to server using s_send() function defined in zhelpers.h. The server code is same test code bundled with zeromq package as an examples.
Here is my client side:
#include "amessage.pb-c.h"
#include "zhelpers.h"
int main (void)
{
AMessage msg = AMESSAGE__INIT; // AMessage
void *buf; // Buffer to store serialized data
unsigned len;
printf ("Connecting to server...\n");
void *context = zmq_ctx_new ();
void *requester = zmq_socket (context, ZMQ_REQ);
char buffer[256] = "";
printf("[client] :");
scanf("%s", buffer );
msg.csmsg = buffer;
len = amessage__get_packed_size(&msg);
buf = malloc(len);
printf("[client]: pack msg len : %d\n ", len);
printf("Sent msg : %d\n", buf);
amessage__pack(&msg,buf);
s_send(requester, buf);
zmq_close (requester);
zmq_ctx_destroy (context);
return 0;
}
And server side:
#include "zhelpers.h"
#include <pthread.h>
#include <stdlib.h>
#include "amessage.pb-c.h"
#define MAX_MSG_SIZE 256
static size_t read_buffer (unsigned max_length, unsigned char *out)
{
size_t cur_len = 0, nread;
uint8_t c;
while ((nread=fread(out + cur_len, 1, max_length - cur_len, stdin)) != 0)
{
cur_len += nread;
if (cur_len == max_length)
{
fprintf(stderr, "[server]: max message length exceeded\n");
exit(1);
}
}
return cur_len;
}
static void * worker_routine (void *context)
{
AMessage *msg;
uint8_t buf[MAX_MSG_SIZE];
char buffer[256];
// Socket to talk to dispatcher
void *receiver = zmq_socket (context, ZMQ_REP);
zmq_connect (receiver, "inproc://workers");
while (1) {
uint8_t *string = s_recv (receiver);
if(string == 0)
printf("[server]: Error: In receiving msg.\n");
else
{
size_t msg_len = read_buffer (MAX_MSG_SIZE, string);
printf("[server]: client msg len is: %d.\n", msg_len);
msg = amessage__unpack(NULL, msg_len, string);
if (msg == NULL)
{
fprintf(stderr, "[server]: error unpacking incoming message\n");
exit(1);
}
printf ("[client]: %s \n", msg->csmsg);
}
amessage__free_unpacked(msg, NULL);
free (string);
// Do some 'work'
sleep (1);
}
zmq_close (receiver);
return NULL;
}
int main (void)
{
void *context = zmq_ctx_new ();
void *clients = zmq_socket (context, ZMQ_ROUTER);
zmq_bind (clients, "tcp://*:5555");
void *workers = zmq_socket (context, ZMQ_DEALER);
zmq_bind (workers, "inproc://workers");
// Launch pool of worker threads
int thread_nbr;
for (thread_nbr = 0; thread_nbr < 5; thread_nbr++) {
pthread_t worker;
pthread_create (&worker, NULL, worker_routine, context);
}
// Connect work threads to client threads via a queue proxy
zmq_proxy (clients, workers, NULL);
zmq_close (clients);
zmq_close (workers);
zmq_ctx_destroy (context);
return 0;
}
Any idea what I am doing wrong?
You are using s_send() which expects a C string as an argument, and calls strlen() to determine its size. However, protocol buffers data is binary data, and may contain null bytes anywhere in the message.
Instead use zmq_send() and give the length of the message to the zmq_msg_init_size() function.