C Code, RPC Error "RPC: Can't encode arguments" - c

I saw this question but it doesn't seem to apply.
Heres my function which does most the heavy lifting in the client code:
void
database_1(char *host, char *action, char *message)
{
printf("Action: %s\n", action);
printf("Message: %s\n", message);
CLIENT *clnt;
rpc_args *result_1;
//struct rpc_args action_1_arg;
//rpc arguments struct to pass to server
struct rpc_args *args = malloc(sizeof(struct rpc_args));
char *id = generate_id();
if (strcmp(action, "GET") == 0) {
printf("Client: GET request\n");
strcpy(args->action, action);
strcpy(args->id, id);
} else if(strcmp(action, "PUT") == 0) {
printf("Client: PUT request\n");
strcpy(args->action, action);
strcpy(args->id, id);
strcpy(args->message.content, message);
}
#ifndef DEBUG
clnt = clnt_create (host, DATABASE, ASSIGNMENT_7, "udp");
if (clnt == NULL) {
clnt_pcreateerror (host);
exit (1);
}
#endif /* DEBUG */
result_1 = action_1(args, clnt);
if (result_1 == (rpc_args *) NULL) {
clnt_perror (clnt, "call failed");
}
free(args);
#ifndef DEBUG
clnt_destroy (clnt);
#endif /* DEBUG */
}
Here's my output:
./database_client eecslinab3.case.edu GET
running client, main
Action: GET
Message: (null)
hostname is eecslinab3
The process id is 24697
The unique id is eecslinab324697
Client: GET request
call failed: RPC: Can't encode arguments
Database.x
struct message {
char content[2000];
};
struct rpc_args {
char action[20];
char id[1024];
struct message message;
};
program DATABASE {
version ASSIGNMENT_7 {
rpc_args ACTION(struct rpc_args) = 1;
} = 1;
} = 0x20fff100;

A friend helped me solve the problem but didn't give me much details about why or how the fix works. Basically I reduced the char array sizes in my struct and it worked. Has something to do with the limit of data you can send over UDP.
struct rpc_args {
char action[20];
char id[80];
char message[80];
};
program DATABASE {
version ASSIGNMENT_7 {
rpc_args ACTION(struct rpc_args) = 1;
} = 1;
} = 0x20fff100;

Related

Separate connect function for libmodbus

I am trying to group the operation under libmodbus for Mod-bus connection and get-value into two simpler function as below.
However, it always cause Segmentation fault (core dumped) when I try to get value from the device.(get_float, modbus_read_registers)
Can anyone tell me how to fix it?
int connect(char *ip_addr, struct timeval timeout, modbus_t *ctx){
int fail = 0;
ctx = modbus_new_tcp(ip_addr, MODBUS_SERVER_PORT);
modbus_set_slave(ctx, MODBUS_DEVICE_ID);
modbus_set_debug(ctx, MODBUS_DEBUG);
timeout.tv_sec = MODBUS_TIMEOUT_SEC;
timeout.tv_usec = MODBUS_TIMEOUT_USEC;
modbus_get_byte_timeout(ctx, &timeout.tv_sec, &timeout.tv_usec);
timeout.tv_sec = MODBUS_TIMEOUT_SEC;
timeout.tv_usec = MODBUS_TIMEOUT_USEC;
modbus_set_response_timeout(ctx, timeout.tv_sec, timeout.tv_usec);
fail = modbus_connect(ctx);
if (fail == -1) {
fprintf(stderr, "Connection failed: %s\n",
modbus_strerror(errno));
modbus_free(ctx);
fail = -1;
}
return fail;
}
int get_float(modbus_t *ctx, uint16_t addr, float *val){
int fail = 0;
__uint16_t value[2];
printf("1\n");
fail = modbus_read_registers(ctx, (addr-1), 2, value);
printf("2\n");
if(fail <= 0) {
fprintf(stderr, "Reading error(%d): %s\n", addr, modbus_strerror(errno));
} else {
*val = modbus_get_float_abcd(value);
}
return fail;
}
Besides, I can successfully run the similar code when I put them in same function as below:
int connect_n_getFloat(char *ip_addr, uint16_t addr, float *val){
int fail = 0;
modbus_t *ctx = modbus_new_tcp(ip_addr, MODBUS_SERVER_PORT);
ctxConfig(ctx);
if (modbus_connect(ctx) == 0) {
__uint16_t value[2];
if(modbus_read_registers(ctx, (addr-1), 2, value) > 0) {
*val = modbus_get_float_abcd(value);
} else {
fprintf(stderr, "Reading error(%d): %s\n", addr, modbus_strerror(errno));
fail = -1;
}
} else {
fprintf(stderr, "Connection failed: %s\n",
modbus_strerror(errno));
modbus_free(ctx);
fail = -1;
}
return fail;
}
You're passing a context pointer to the connect function, but should be passing a pointer to a pointer, so you can return the allocated context and continue using it in further calls.
Change the function signature, and ctx usage, from
int connect(char *ip_addr, struct timeval timeout, modbus_t *ctx) {
int fail = 0;
ctx = modbus_new_tcp(ip_addr, MODBUS_SERVER_PORT);
to
int connect(char *ip_addr, struct timeval timeout, modbus_t **ctx) {
int fail = 0;
*ctx = modbus_new_tcp(ip_addr, MODBUS_SERVER_PORT);
This also explains why it works when you put them in the same function.

C program not reading keyboard input

EDIT: the problem is that scanf (and other function I tried here) doesn't wait for the input, the program doesn't pause.
Using Ubuntu 18 on Virtual Box on Mac
I am writing a server/client using POSIX. I am not able to read keyboard input in client.c
char action_type[1];
printf("Chose action: T to request time, S to shut down\n");
scanf(" %c",action_type);
printf("%s", action_type);
if I put the same code as the first thing in main.c it works fine.
full code for server / client and commons is:
server
#include <stdio.h>
#include "mqueue.h"
#include "commons.h"
#include "errno.h"
#include "stdlib.h"
#include <string.h>
#include <time.h>
int status_closing = 0;
void send_time(char* clients_pid);
void send_activation(char* clients_pid);
//VARIABLES related to SERVERS QUEUE
mqd_t server; // server
struct mq_attr servers_attributes; // server creation attributes
struct mq_attr receiving_attributes; // server receiving attributes
// set up attributes
void set_servers_attributes(){
// set up server's attributes
servers_attributes.mq_maxmsg = QUEUE_SIZE;
servers_attributes.mq_msgsize = MESSAGE_SIZE;
printf("attributes set \n");
};
// open server
void open_servers_queue() {
server = mq_open (servers_path,
O_CREAT | O_RDWR | O_EXCL ,
0666, &servers_attributes);
if (server == -1) {
printf("failed to open server's queue\n");
printf(errno);
exit(-1);
} else {
printf("opened servers queue as: %d\n",server);
}
};
// check attributes
void check_attributes(){
if ((mq_getattr(server,&receiving_attributes)) == -1) {
printf("cannot read server's queue\n exit \n");
exit(-1);
}
};
void close_and_unlink_queue(){
printf("At exit closing and unlinking queue\n");
mq_close(server);
mq_unlink(servers_path);
};
int check_for_messages_in_the_queue(){
//printf("checking for messages\n");
int messages_in_queue;
messages_in_queue = receiving_attributes.mq_curmsgs;
//printf("there are %d message in the servers queue\n",messages_in_queue);
// printf("message in the queue!\n");
return messages_in_queue;
};
char* receive_message(){
char *receiving_buffer = malloc(sizeof(char)*MESSAGE_SIZE);
if ((mq_receive(server,receiving_buffer,MESSAGE_SIZE,NULL))>0){
return receiving_buffer;
}
else {
printf("Server failed to receive message");
mq_close(server);
mq_unlink(servers_path);
exit(-1);
}
};
void respond(char *message_type, char* clients_pid) {
printf("responding\n");
char* type_one = "1";
char* type_two = "2";
char *type_three ="3";
if (strcmp(message_type, type_one) == 0) {
printf("TYPE 1\n");
send_activation(clients_pid);
}
if (strcmp(message_type, type_two) == 0) {
printf("TYPE 2\n");
send_time(clients_pid);
}
if (strcmp(message_type, type_three) == 0) {
printf("type 3 - SHUTDOWN INITIATED\n");
}
}
void send_time(char* clients_pid) {
time_t mytime = time(NULL);
char *time_str = ctime(&mytime);
time_str[strlen(time_str)-1] = '\0';
char *clientpath[20];
int clients_pid_int = atoi(clients_pid);
sprintf(clientpath,"/%d",clients_pid_int);
printf("clients path: %s\n",clientpath);
mqd_t client;
client = mq_open(clientpath,O_RDWR , 0666, &servers_attributes);
if (client == -1) {
printf("failes opening client's queue \n");
exit(-1);
} else {
printf("connected to client's queue: %d\n",client);
}
};
void send_activation(char* clients_pid) {
char *clientpath[20];
int clients_pid_int = atoi(clients_pid);
sprintf(clientpath,"/%d",clients_pid_int);
printf("clients path: %s\n",clientpath);
mqd_t client;
client = mq_open(clientpath,O_RDWR , 0666, &servers_attributes);
if (client == -1) {
printf("failes opening client's queue \n");
exit(-1);
} else {
printf("connected to client's queue: %d\n",client);
char* activation = malloc(sizeof(char)*MESSAGE_SIZE);
char* activation_literal = "activation";
sprintf(activation,"%s",activation_literal);
int message_sent = mq_send(client,activation,MESSAGE_SIZE,0);
printf("message sent with: %d",message_sent);
}
};
int main() {
// clean remainings of previous trials
mq_close(server);
mq_unlink(servers_path);
// define atexit behaviour
atexit(close_and_unlink_queue);
//set servers attributes:
set_servers_attributes();
// open server's queue
open_servers_queue();
// receiving messages in the loop
int condition = 1;
while (1) {
check_attributes();
if (check_for_messages_in_the_queue() > 0) {
char *received_message = receive_message();
char *tok_one = strtok(received_message," ");
char *tok_two = strtok(NULL, " ");
//int clients_pid = atoi(tok_two);
respond(tok_one,tok_two);
} else if ((check_for_messages_in_the_queue() ==0) && (status_closing == 1)) {
printf("Server's queue is empty - work finished. closing down\n");
exit(0);
}
}
printf("Hello, World!\n");
return 0;
}
client
#include <stdio.h>
#include <mqueue.h>
#include <unistd.h>
#include "commons.h"
#include <stdlib.h>
#include <errno.h>
#include <string.h>
mqd_t client;
mqd_t server;
char clientpath[20];
char* sending_buffer[MESSAGE_SIZE];
struct mq_attr clients_attributes;
struct mq_attr receiving_attributes;
void connect_to_server(){
server = mq_open(servers_path,O_WRONLY);
if(server == -1) {
printf("connection to server failed\n");
} else {
printf("connected to server with id: %d \n",server);
}
};
void set_clients_attributes(){
// deal with attributes
clients_attributes.mq_maxmsg = QUEUE_SIZE;
clients_attributes.mq_msgsize = MESSAGE_SIZE;
};
void create_clients_queue(){
// create clients path
pid_t client_pid = getpid();
sprintf(clientpath, "/%d", client_pid);
// open clients queue
client = mq_open(clientpath,O_RDONLY | O_CREAT | O_EXCL, 0666, &clients_attributes);
// printf(errno);
if (client == -1) {
printf("failes opening client's queue \n");
exit(-1);
} else {
printf("connected to client's queue: %d\n",client);
}
};
void register_at_server(){
message message;
message.mtype = 1;
int client_pid = getpid();
message.sender = client_pid;
char separator = ' ';
snprintf(sending_buffer,MESSAGE_SIZE,"%ld%c%d",message.mtype,separator,message.sender);
if ((mq_send(server,sending_buffer, MESSAGE_SIZE,0)) == -1) {
printf("failed to send registration request\n");
exit(-1);
}
else {
printf("%s",sending_buffer);
printf("sent registration request\n");
}
};
void close_and_unlink_queue(){
printf("At exit closing and unlinking queue\n");
mq_close(client);
mq_unlink(clientpath);
};
void check_attributes(){
if ((mq_getattr(client,&receiving_attributes)) == -1) {
printf("cannot read own's queue\n exit \n");
exit(-1);
}
};
int check_for_messages_in_the_queue(){
//printf("checking for messages\n");
int messages_in_queue;
messages_in_queue = receiving_attributes.mq_curmsgs;
//printf("there are %d message in the servers queue\n",messages_in_queue);
// printf("message in the queue!\n");
return messages_in_queue;
};
char* receive_message(){
char *receiving_buffer = malloc(sizeof(char)*MESSAGE_SIZE);
if ((mq_receive(client,receiving_buffer,MESSAGE_SIZE,NULL))>0){
return receiving_buffer;
}
else {
printf("Server failed to receive message");
mq_close(client);
mq_unlink(clientpath);
exit(-1);
}
};
void choose_action(){
char action_type[1];
printf("Chose action: T to request time, S to shut down\n");
scanf(" %c",action_type);
printf("%s", action_type);
};
int main() {
mq_close(client);
mq_unlink(clientpath);
connect_to_server();
set_clients_attributes();
create_clients_queue();
register_at_server();
int condition = 1;
int client_active = 0;
while (condition) {
check_attributes();
if (check_for_messages_in_the_queue() > 0) {
char *received_message = receive_message();
if ((strcmp(received_message, "activation")) == 0) {
client_active = 1;
condition = 0;
free(received_message);
}
}
}
char action_type[1];
printf("Chose action: T to request time, S to shut down\n");
scanf(" %c",action_type);
printf("%s", action_type);
printf("Hello, World!\n");
return 0;
}
commons
#ifndef SERVER_COMMONS_H
#define SERVER_COMMONS_H
#include <signal.h>
// define values of server queue attributes
//define message struct
typedef struct messgae {
char content[4096];
pid_t sender;
long mtype;
} message;
#define QUEUE_SIZE 10
#define MESSAGE_SIZE sizeof(message)
// define servers path
const char servers_path[] = "/server";
#endif //SERVER_COMMONS_H
``
this happens because the buffer is not empty and this function read from it.
to empty buffer just try this code:
while( getchar() != '\n');
it will empty the buffer and after it the functions will wait for input.
printf( "Enter a value :");
c = getchar( );
or
#include <stdio.h>
int main( ) {
char str[100];
int i;
printf( "Enter a value :");
scanf("%s %d", str, &i);
printf( "\nYou entered: %s %d ", str, i);
return 0;
}

Reading a socket

I'm trying to simulate a small ftp server to train myself by accepting connexion from clients and communicate with the good replies and do the tasks asked. But I don't understand why my server always encounter error when reading on the socket to get the client's command. I think it probably is because of getline() but I don't see why it would be
Here's the "accepting" function
static int my_startserver(char *path, int ssock)
{
int csock;
struct sockaddr_in addr;
socklen_t size;
size = sizeof(&addr);
printf("Server ready\n");
while (42)
{
if ((csock = accept(ssock, (struct sockaddr*)(&addr), &size)) == -1)
return (my_error(6, NULL, ssock));
printf("New connection detected\n");
if (fork() == 0)
{
close(ssock);
my_newconnexion(my_getdata(csock, path));
}
else
close(csock);
printf("Waiting for new connexion\n\n");
}
return (0);
}
static t_data *my_getdata(int fd, char *path)
{
t_data *data;
if (!(data = malloc(sizeof(t_data*))))
return (NULL);
else
{
if (!(data->fp = fdopen(fd, "r+")))
{
write(fd, "540 A stream creation failed.\r\n", 31);
free(data);
return (NULL);
}
data->fd = fd;
data->path = path;
}
printf("Service ready\n");
fprintf(data->fp, "220 Service ready for new user.\r\n");
return (data);
}
And here's the function that handle the connexion with a client after a fork
void my_newconnexion(t_data *data)
{
char *line;
if (!data)
return;
line = NULL;
printf("Waiting for command\n");
while (getline(&line, NULL, data->fp) > -1)
{
printf("Command: %s\n", line);
if (my_getcommand(data, line, strlen(line) - 2))
{
my_treatcommand(data);
free(data->cmd);
free(data->par);
}
free(line);
line = NULL;
printf("Waiting for command\n");
}
my_quit(data, -1);
}
OK So I replaced getline() by a home-made function that do the same thing but from the file descriptor (the socket) so I don't have to open a file pointer from it with fdopen to give it to getline and now it works perfectly.

DBus: Watch when name disappears from bus

I am implimenting the StatusNotifierWatcher service using the low-level DBus C library. The StatusNotifierWatcher specification requires that the watcher can know when "A StatusNotifierItem instance has disappeared from the bus" So that it can send the StatusNotifierItemUnregistered signal.
An example implimentation:
#include <stdio.h>
#include <stdlib.h>
#include <dbus/dbus.h>
DBusConnection *conn = NULL;
void item_unregistered_signal(const char *name) {
DBusMessage *signal = dbus_message_new_signal(
"/org/freedesktop/StatusNotifierWatcher",
"org.freedesktop.StatusNotifierWatcher",
"StatusNotifierItemUnregistered");
dbus_message_append_args(signal,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_INVALID);
dbus_connection_send(conn, signal, NULL);
dbus_message_unref(signal);
}
void watch_name(const char *name, void(*cb)(const char *)) {
// Not sure how to impliment
}
dbus_bool_t register_item(DBusConnection *connection, DBusMessage *message, void *_data) {
DBusError error;
char *name;
if (!dbus_message_get_args(message, &error,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_INVALID)) {
fprintf(stderr, "Error parsing method args: %s\n", error.message);
return FALSE;
}
watch_name(name, item_unregistered_signal);
return TRUE;
}
static void check_and_abort(DBusError *error) {
if (dbus_error_is_set(error)) {
fprintf(stderr, "dbus_err: %s\n", error->message);
exit(EXIT_FAILURE);
}
}
int main() {
DBusError error;
dbus_error_init(&error);
conn = dbus_bus_get(DBUS_BUS_SESSION, &error);
check_and_abort(&error);
dbus_bus_request_name(conn, "org.freedesktop.StatusNotifierWatcher",
DBUS_NAME_FLAG_REPLACE_EXISTING,
&error);
check_and_abort(&error);
dbus_connection_add_filter(conn, register_item, NULL, free);
while(1) {
dbus_connection_read_write_dispatch(conn, 1000);
}
}
If I have the well-known name to a DBus service, how do I know when the name disappears from the bus?
Well, I figured this out and I'll post an answer for any future poor souls who need to work with libdbus.
org.freedesktop.DBus sends the NameOwnerChanged signal whenever any DBus name changes. One can use this signal to track if an item has disappeared because the NewOwner argument is a null string.
This function can do that:
static DBusHandlerResult signal_handler(DBusConnection *connection,
DBusMessage *message, void *_usr_data) {
if (dbus_message_is_signal(message, "org.freedesktop.DBus",
"NameOwnerChanged")) {
const char *name;
const char *old_owner;
const char *new_owner;
if (!dbus_message_get_args(message, NULL,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_STRING, &old_owner,
DBUS_TYPE_STRING, &new_owner,
DBUS_TYPE_INVALID)) {
fprintf(stderr, "Error getting OwnerChanged args");
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
if (strcmp(name, "") != 0) {
// Name not lost, just swapped owners
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
name_lost(name);
return DBUS_HANDLER_RESULT_HANDLED;
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
One also needs to add a match so that your program will be called with this signal. I added this in main()
dbus_bus_add_match(conn,
"type='signal',\
sender='org.freedesktop.DBus',\
interface='org.freedesktop.DBus',\
member='NameOwnerChanged'",
&error);
check_and_abort(&error);
dbus_connection_add_filter(conn, signal_handler, NULL, free);
For those using GDBus (recommended) instead of libdbus (discouraged), the equivalent is g_bus_watch_name().

Something happened when I created and added values to my struct thats resulting in a segfault

So I made some updates to my RPC program and now its segfaulting, I'm not sure what I'm doing wrong here. The difference between the two is the removal of the if statements that assign values to the args struct.
Segfaults
void
database_1(char *host, char *action, char *message)
{
printf("Action: %s\n", action);
printf("Message: %s\n", message);
CLIENT *clnt;
rpc_args *result_1;
//struct rpc_args action_1_arg;
//rpc arguments struct to pass to server
struct rpc_args *args = malloc(sizeof(struct rpc_args));
char *id = generate_id();
if (strcmp(action, "GET") == 0) {
strcpy(args->action, action);
strcpy(args->id, id);
} else if(strcmp(action, "PUT") == 0) {
strcpy(args->action, action);
strcpy(args->id, id);
strcpy(args->message.content, message);
}
#ifndef DEBUG
clnt = clnt_create (host, DATABASE, ASSIGNMENT_7, "udp");
if (clnt == NULL) {
clnt_pcreateerror (host);
exit (1);
}
#endif /* DEBUG */
result_1 = action_1(args, clnt);
if (result_1 == (rpc_args *) NULL) {
clnt_perror (clnt, "call failed");
}
#ifndef DEBUG
free(args);
clnt_destroy (clnt);
#endif /* DEBUG */
}
Doesn't SegFault
void
database_1(char *host, char *action, char *message)
{
printf("Action: %s\n", action);
printf("Message: %s\n", message);
CLIENT *clnt;
rpc_args *result_1;
//struct rpc_args action_1_arg;
//rpc arguments struct to pass to server
struct rpc_args *args = malloc(sizeof(struct rpc_args));
char *id = generate_id();
#ifndef DEBUG
clnt = clnt_create (host, DATABASE, ASSIGNMENT_7, "udp");
if (clnt == NULL) {
clnt_pcreateerror (host);
exit (1);
}
#endif /* DEBUG */
result_1 = action_1(args, clnt);
if (result_1 == (rpc_args *) NULL) {
clnt_perror (clnt, "call failed");
}
#ifndef DEBUG
free(args);
clnt_destroy (clnt);
#endif /* DEBUG */
}
You did not show us the definition of the struct, but make sure it looks something like this:
#define MAX_STRING_SIZE 128
struct rpc_args {
/* other members here */
char action[MAX_STRING_SIZE];
char id[MAX_STRING_SIZE];
};
Similarly, the struct used at args->message.content must also be defined this way.
If you use something like the above implementation, make sure you check the length of the strings you are copying to be less than MAX_STRING_SIZE - 1.
Alternatively, before using strcpy into those members, you can dynamically allocate space for the strings with malloc, then free them when you clean up the structure.

Resources