XDR Encode function - c

I have create, with rpcgen, these two file (.h and .c) with my own two structs (the environment is Linux and the programming language is C).
The two structs are these below (this is the .h file):
/*
* Please do not edit this file.
* It was generated using rpcgen.
*/
#ifndef _XDRTYPES_H_RPCGEN
#define _XDRTYPES_H_RPCGEN
#include <rpc/rpc.h>
#ifdef __cplusplus
extern "C" {
#endif
struct Request {
struct {
u_int data_len;
float *data_val;
} data;
bool_t last;
};
typedef struct Request Request;
struct Response {
bool_t error;
float result;
};
typedef struct Response Response;
/* the xdr functions */
#if defined(__STDC__) || defined(__cplusplus)
extern bool_t xdr_Request (XDR *, Request*);
extern bool_t xdr_Response (XDR *, Response*);
#else /* K&R C */
extern bool_t xdr_Request ();
extern bool_t xdr_Response ();
#endif /* K&R C */
#ifdef __cplusplus
}
#endif
#endif /* !_XDRTYPES_H_RPCGEN */
In my main I call #include <rpc/rpc.h> and #include "xdrtypes.h".Then I want send a Request message to the server with a socket (s is the file descriptor s = socket(...)):
stream_socket_w = fdopen(s, "w");
xdrstdio_create(&xdrs_w, stream_socket_w, XDR_ENCODE);
x.data.data_len = 5;
x.last = 1;
x.data.data_val[0] = 5.3;
x.data.data_val[1] = 2.7;
x.data.data_val[2] = 8.4;
x.data.data_val[3] = 2.9;
x.data.data_val[4] = 1.7;
xdr_Request(&xdrs_w, &x);
fflush(stream_socket_w);
The problem is that the execution stop at the line xdr_Request(&xdrs_w, &x) and I obtain "Segmentation Fault". Everybody Can Help me please? Thank you very much.

Are you allocating memory for data_val?
x.data.data_val = malloc(x.data.data_len * sizeof(float));
Where xdr_Request function is defined? do you have its API?

Related

In this case, how to modularize program as well as achieving information hiding?

I created two classes "DEVICE_s" and "DEVICE_SET_s" as following:
Device_Manager.h
typedef struct DEVICE_s DEVICE_s;
typedef struct DEVICE_SET_s DEVICE_SET_s;
Device_Manager.c
struct DEVICE_s
{
uint32_t IP;
TYPE_e Type;
METHOD_e Method;
GROUP_RULE_e GroupRule;
char Name[NAME_SIZE];
};
struct DEVICE_SET_s
{
uint8_t Total;
uint8_t Used;
uint8_t Available;
DEVICE_s Set[SET_SIZE];
};
DEVICE_s Instance;
DEVICE_SET_s Objects;
Because I put these two classes within a same file, all functions that manipulate variables "Instance" and "Objects" are put together inside this file.
I think this way is bad considering to modularity, so I want to create another source file to separately manage class "DEVICE_SET_s", just like:
DeviceSet_Manager.h
typedef struct DEVICE_SET_s DEVICE_SET_s;
DeviceSet_Manager.c
#include "Device_Manager.h"
#include "DeviceSet_Manager.h"
struct DEVICE_SET_s
{
uint8_t Total;
uint8_t Used;
uint8_t Available;
DEVICE_s Set[SET_SIZE]; //Oops! Incomplete Type Is Not Allowed
};
However, In terms of DeviceSet_Manager.c, class "DEVICE_s" is not visible(not a complete type).
How do I fix this? Thanks
What you want are opaque types for
DEVICE
DEVICE_SET
This is straight forward the same way for both:
header, defining
incomplete type for object structure. A pointer to it is the opaque type to handle an object's instance and to be passed to its interfacing functions
interfacing functions' prototypes
implementation of
complete type
interfacing functions
headers
device.h
#ifndef DEVICE_H
#define DEVICE_H
struct device;
struct device * device_new(void);
void device_delete(struct device *);
#endif
device_set.h:
#ifndef DEVICE_H
#define DEVICE_H
#include "device.h"
struct device_set;
struct device_set * device_set_new(size_t);
void device_set_delete(struct device_set *);
int device_set_set_device(struct device_set *, size_t, struct device *);
struct device * device_set_get_device(struct device_set *, size_t);
#endif
implementations
device.c
#include "device.h"
struct device {
...
};
struct device * device_new(void)
{
struct device * pd = malloc(sizeof * pd);
if (NULL != pd)
{
/* Init members here. */
}
return pd;
}
void device_delete(struct device * pd)
{
if (pd)
{
/* de-init (free?) members here. */
}
free(pd);
}
device_set.c:
#include "device_set.h"
struct device_set
{
size_t total;
size_t used;
size_t available; /* what is this for? isn't it just total - used? */
struct device ** pd;
}
struct device_set * device_set_new(size_t nb)
{
struct device_set pds = malloc(sizeof *pds);
if (NULL != pds)
{
pds->pd = malloc(nb * sizeof *pds->pd);
if (NULL == pds->pd)
{
free(pds);
pds = NULL;
}
else
{
for (size_t d = 0; d < nb; ++d)
{
pds->pd[d] = NULL;
}
pds->total = nb;
pds->used = 0;
pds->available = 0;
}
}
return pds;
}
void device_set_delete(struct device_set * pds)
{
if (pds)
{
free(pds->pd);
free(pds)
}
return;
}
int device_set_set_device(struct device_set * pds, size_t d, struct device * pd)
{
int result = 0;
if (pds->total <= d)
{
result = ERANGE;
}
else
{
pds->pd[d] = pd;
}
return;
}
struct device * device_set_get_device(struct device_set * pds, size_t d);
int result = 0;
struct device * pd = NULL;
if (pds->total <= d)
{
result = ERANGE;
}
else
{
pd = pds->pd[d];
}
return pd;
}
Here's what I usually do:
device.h
// insert header guards here
typedef struct DEVICE_s DEVICE_s;
struct DEVICE_s
{
...
};
// method declarations here
DEVICE_Init(DEVICE_s * this, ...);
DEVICE_Foo(DEVICE_s * this, ...);
device.c
#include "device.h"
// method implementations here
deviceset.h
//hguards...
#include "device.h"
typedef struct DEVICE_SET_s DEVICE_SET_s;
struct DEVICE_SET_s
{
uint8_t Total;
uint8_t Used;
uint8_t Available;
DEVICE_s Set[SET_SIZE];
};
// method declarations here
DEVICE_SET_Init(DEVICE_SET_s * this, ...);
DEVICE_SET_Foo(DEVICE_SET_s * this, ...);
deviceset.c
#include "deviceset.h"
// method implementations here
usercode.c
DEVICE_SET_s myDevices;
void func(void) {
DEVICE_SET_Init(&myDevices, a, b, c);
...
}
With this approach it's users responsibility to allocate the memory and call init function (=constructor) to initialize object before use.
It does not give really give you encapsulation, but gives maximum freedom for allocation. For encapsualtion to work well it needs support from the language. Because C is so limited language to begin with, I don't recommend adding more limitations just to satisfy programming paradigm.

Loading dll in windows C for cross-platform design

I wrote a c-code designed for linux platform.
Now, I want to make it cross-platform so to use in Windows as-well.
In my code, I dlopen an so file and utilize the functions inside it.
Below is how my code looks like. But I just found out that in windows, the way to load and use dynamic library is quite different.
void *mydynlib
mydynlib= dlopen("/libpath/dynlib.so",RTLD_LAZY);
void (*dynfunc1)() = dlsym(mydynlib,"dynfunc1");
void (*dynfunc2)(char*, char*, double) = dlsym(mydynlib,"dynfunc2");
int (*dynfunc3)() = dlsym(mydynlib,"dynfunc3");
From what I found, I need to use LoadLibrary & GetProcAddress instead of dlopen & dlsym. However, I do not know how to convert above line for windows using those. I've tried to search some examples for hours but couldn't find exact solution. If someone had this kind of experience, please give me a tip.
Excuse me if this is too obvious problem. I'm quite new to C. I usually write my program in python.
Once in my youth I created something like this:
/* dlfcn.h */
#ifndef DLFCN_H
#define DLFCN_H
#define RTLD_GLOBAL 0x100 /* do not hide entries in this module */
#define RTLD_LOCAL 0x000 /* hide entries in this module */
#define RTLD_LAZY 0x000 /* accept unresolved externs */
#define RTLD_NOW 0x001 /* abort if module has unresolved externs */
/*
How to call in Windows:
void *h = dlopen ("path\\library.dll", flags)
void (*fun)() = dlsym (h, "entry")
*/
#ifdef __cplusplus
extern "C" {
#endif
void *dlopen (const char *filename, int flag);
int dlclose (void *handle);
void *dlsym (void *handle, const char *name);
const char *dlerror (void);
#ifdef __cplusplus
}
#endif
#endif
and dlfcn.c:
/* dlfcn.c */
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
static struct {
long lasterror;
const char *err_rutin;
} var = {
0,
NULL
};
void *dlopen (const char *filename, int flags)
{
HINSTANCE hInst;
hInst= LoadLibrary (filename);
if (hInst==NULL) {
var.lasterror = GetLastError ();
var.err_rutin = "dlopen";
}
return hInst;
}
int dlclose (void *handle)
{
BOOL ok;
int rc= 0;
ok= FreeLibrary ((HINSTANCE)handle);
if (! ok) {
var.lasterror = GetLastError ();
var.err_rutin = "dlclose";
rc= -1;
}
return rc;
}
void *dlsym (void *handle, const char *name)
{
FARPROC fp;
fp= GetProcAddress ((HINSTANCE)handle, name);
if (!fp) {
var.lasterror = GetLastError ();
var.err_rutin = "dlsym";
}
return (void *)(intptr_t)fp;
}
const char *dlerror (void)
{
static char errstr [88];
if (var.lasterror) {
sprintf (errstr, "%s error #%ld", var.err_rutin, var.lasterror);
return errstr;
} else {
return NULL;
}
}
You could use a set of macros that change depending on the OS you're on:
#ifdef __linux__
#define LIBTYPE void*
#define OPENLIB(libname) dlopen((libname), RTLD_LAZY)
#define LIBFUNC(lib, fn) dlsym((lib), (fn))
#elif defined(WINVER)
#define LIBTYPE HINSTANCE
#define OPENLIB(libname) LoadLibraryW(L ## libname)
#define LIBFUNC(lib, fn) GetProcAddress((lib), (fn))
#endif

OpenSSL RSA_size with EVP_PKEY

I have a question regarding RSA_size.
Version that crash on WIN32 but works on linux platforms :
...
EVP_PKEY* pPublicKey = null;
unsigned int uKeySize = 0;
const unsigned char *pData;
pData = a_publicKey->Key.Data; /* Key.Data = unsigned char *p containing the Key in a string version */
pPublicKey = d2i_PublicKey(EVP_PKEY_RSA, null, &pData, a_publicKey->Key.Length);
if(pPublicKey != null)
{
uKeySize = RSA_size(pPublicKey->pkey.rsa); //Crash
}
...
Version that work on win32 (not tested on linux but I suppose it works as well):
...
EVP_PKEY* pPublicKey = null;
RSA* pRsaPublicKey = null;
unsigned int uKeySize = 0;
const unsigned char *pData;
pData = a_publicKey->Key.Data; /* Key.Data = unsigned char *p containing the Key in a string version */
pPublicKey = d2i_PublicKey(EVP_PKEY_RSA, null, &pData, a_publicKey->Key.Length);
if(pPublicKey != null)
{
pRsaPublicKey = EVP_PKEY_get1_RSA(pPublicKey);
EVP_PKEY_free(pPublicKey);
uKeySize = RSA_size(pRsaPublicKey);
}
...
I do not understand why the first version crash. But when I look into the pkey.rsa structure, values are not the same as in the RSA pointer in the 2nd version.
Any ideas ?
I looked into EVP_PKEY struct and it seems that WIN32 and linux version are different...
So I guess i am using a really old one for my WIN32.
WIN32 version :
struct evp_pkey_st
{
int type;
int save_type;
int references;
union {
char *ptr;
#ifndef OPENSSL_NO_RSA
struct rsa_st *rsa; /* RSA */
#endif
#ifndef OPENSSL_NO_DSA
struct dsa_st *dsa; /* DSA */
#endif
#ifndef OPENSSL_NO_DH
struct dh_st *dh; /* DH */
#endif
#ifndef OPENSSL_NO_EC
struct ec_key_st *ec; /* ECC */
#endif
} pkey;
int save_parameters;
STACK_OF(X509_ATTRIBUTE) *attributes; /* [ 0 ] */
} /* EVP_PKEY */;
linux :
struct evp_pkey_st
{
int type;
int save_type;
int references;
const EVP_PKEY_ASN1_METHOD *ameth;
ENGINE *engine;
union {
char *ptr;
#ifndef OPENSSL_NO_RSA
struct rsa_st *rsa; /* RSA */
#endif
#ifndef OPENSSL_NO_DSA
struct dsa_st *dsa; /* DSA */
#endif
#ifndef OPENSSL_NO_DH
struct dh_st *dh; /* DH */
#endif
#ifndef OPENSSL_NO_EC
struct ec_key_st *ec; /* ECC */
#endif
} pkey;
int save_parameters;
STACK_OF(X509_ATTRIBUTE) *attributes; /* [ 0 ] */
} /* EVP_PKEY */;

rpc remote proceduer compile error

I'm working on a rpc sample program on linux. When I try to compile my remote procedure I get this error :
msg_proc.c:10:7: error: conflicting types for ‘printmessage_1’
In file included from msg_proc.c:8:0:
msg.h:22:15: note: previous declaration of ‘printmessage_1’ was here
This is the command I used to complie :
cc msg_proc.c msg_svc.c -o msg_server -lnsl
And these are my header and procedure files :
/*msg.h
*
* Please do not edit this file.
* It was generated using rpcgen.
*/
#ifndef _MSG_H_RPCGEN
#define _MSG_H_RPCGEN
#include <rpc/rpc.h>
#ifdef __cplusplus
extern "C" {
#endif
#define MESSAGEPROG 0x20000001
#define PRINTMESSAGEVERS 1
#if defined(__STDC__) || defined(__cplusplus)
#define PRINTMESSAGE 1
extern int * printmessage_1(char **, CLIENT *);
extern int * printmessage_1_svc(char **, struct svc_req *);
extern int messageprog_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
#else /* K&R C */
#define PRINTMESSAGE 1
extern int * printmessage_1();
extern int * printmessage_1_svc();
extern int messageprog_1_freeresult ();
#endif /* K&R C */
#ifdef __cplusplus
}
#endif
#endif /* !_MSG_H_RPCGEN */
/*
* msg_proc.c: implementation of the
* remote procedure "printmessage"
*/
#include <stdio.h>
#include <rpc/rpc.h>
#include "msg.h"
int * printmessage_1(char **msg, struct svc_req *req) {
static int result; /* must be static! */
FILE *f;
f = fopen("/dev/console", "w");
if (f == (FILE *) NULL) {
result = 0;
return (&result);
}
fprintf(f, "%s\n", *msg);
fclose(f);
result = 1;
return (&result);
}
What's wrong with my code ?
The argument types in your printmessage_1 function match the declaration of printmessage_1_svc, not printmessage_1. – Barmar

RPC - conflicting types error

I have the following .x file called paper.x . When I create a server in rpc in order to call the function the error below occurs
paperserverproc.c:23:5: error: conflicting types for ‘add_procedure_1_svc’
paper.h:46:15: note: previous declaration of ‘add_procedure_1_svc’ was here
#include <limits.h>
struct paper_saved{
char author_name[CHAR_MAX];
char paper_title[CHAR_MAX];
int paper_id;
char paper_file_name[CHAR_MAX];
char paper_content[CHAR_MAX];
};
struct paper_info_saved{
char author_name[CHAR_MAX];
char paper_title[CHAR_MAX];
int paper_id;
char paper_file_name[CHAR_MAX];
};
struct list_papers{
paper_saved paper;
struct list_papers *next;
};
program PAPER_PROGRAM
{
version PAPER_VERSION
{
int ADD_PROCEDURE(paper_saved) = 1; /* Procedure nb */
void LIST_PROCEDURE(void)=2;
paper_info_saved INFO_PROCEDURE(int)=3;
paper_saved FETCH_PROCEDURE(int)=4;
void REMOVE_PROCEDURE(int)=5;
} = 1; /* Version nb */
} = 0x20001234; /* Program number */
I call the procedure with this way and the line 23 is the line when I declare the function as below
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "paper.h"
#include <ctype.h>
#include <limits.h>
.......
int add_procedure_1_svc(paper_saved *paper_pointer, struct svc_req *rqstp)
This is the paper.h file generated by rpcgen and I dont know what's the problem in line 46 that it mentions
/*
* Please do not edit this file.
* It was generated using rpcgen.
*/
#ifndef _PAPER_H_RPCGEN
#define _PAPER_H_RPCGEN
#include <rpc/rpc.h>
#ifdef __cplusplus
extern "C" {
#endif
struct paper_saved {
char author_name[127];
char paper_title[127];
int paper_id;
char paper_file_name[127];
char paper_content[127];
};
typedef struct paper_saved paper_saved;
struct paper_info_saved {
char author_name[127];
char paper_title[127];
int paper_id;
char paper_file_name[127];
};
typedef struct paper_info_saved paper_info_saved;
struct list_papers {
paper_saved paper;
struct list_papers *next;
};
typedef struct list_papers list_papers;
#define PAPER_PROGRAM 0x20001234
#define PAPER_VERSION 1
#if defined(__STDC__) || defined(__cplusplus)
#define ADD_PROCEDURE 1
extern int * add_procedure_1(paper_saved *, CLIENT *);
extern int * add_procedure_1_svc(paper_saved *, struct svc_req *);
#define LIST_PROCEDURE 2
extern void * list_procedure_1(void *, CLIENT *);
extern void * list_procedure_1_svc(void *, struct svc_req *);
#define INFO_PROCEDURE 3
extern paper_info_saved * info_procedure_1(int *, CLIENT *);
extern paper_info_saved * info_procedure_1_svc(int *, struct svc_req *);
#define FETCH_PROCEDURE 4
extern paper_saved * fetch_procedure_1(int *, CLIENT *);
extern paper_saved * fetch_procedure_1_svc(int *, struct svc_req *);
#define REMOVE_PROCEDURE 5
extern void * remove_procedure_1(int *, CLIENT *);
extern void * remove_procedure_1_svc(int *, struct svc_req *);
extern int paper_program_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
#else /* K&R C */
#define ADD_PROCEDURE 1
extern int * add_procedure_1();
extern int * add_procedure_1_svc();
#define LIST_PROCEDURE 2
extern void * list_procedure_1();
extern void * list_procedure_1_svc();
#define INFO_PROCEDURE 3
extern paper_info_saved * info_procedure_1();
extern paper_info_saved * info_procedure_1_svc();
#define FETCH_PROCEDURE 4
extern paper_saved * fetch_procedure_1();
extern paper_saved * fetch_procedure_1_svc();
#define REMOVE_PROCEDURE 5
extern void * remove_procedure_1();
extern void * remove_procedure_1_svc();
extern int paper_program_1_freeresult ();
#endif /* K&R C */
/* the xdr functions */
#if defined(__STDC__) || defined(__cplusplus)
extern bool_t xdr_paper_saved (XDR *, paper_saved*);
extern bool_t xdr_paper_info_saved (XDR *, paper_info_saved*);
extern bool_t xdr_list_papers (XDR *, list_papers*);
#else /* K&R C */
extern bool_t xdr_paper_saved ();
extern bool_t xdr_paper_info_saved ();
extern bool_t xdr_list_papers ();
#endif /* K&R C */
#ifdef __cplusplus
}
#endif
#endif /* !_PAPER_H_RPCGEN */
So the correct one .h file is
#include <limits.h>
struct paper_saved{
char author_name[CHAR_MAX];
char paper_title[CHAR_MAX];
int paper_id;
char paper_file_name[CHAR_MAX];
char paper_content[CHAR_MAX];
};
struct paper_info_saved{
char author_name[CHAR_MAX];
char paper_title[CHAR_MAX];
int paper_id;
char paper_file_name[CHAR_MAX];
};
struct list_papers{
paper_saved paper;
struct list_papers *next;
};
typedef int p_id;
program PAPER_PROGRAM
{
version PAPER_VERSION
{
p_id ADD_PROCEDURE(paper_saved) = 1; /* Procedure nb */
void LIST_PROCEDURE(void)=2;
paper_info_saved INFO_PROCEDURE(int)=3;
paper_saved FETCH_PROCEDURE(int)=4;
void REMOVE_PROCEDURE(int)=5;
} = 1; /* Version nb */
} = 0x20001234; /* Program number */
The function is declared as returning int:
int add_procedure_1_svc(paper_saved *paper_pointer, struct svc_req *rqstp)
but the extern as returning int*
extern int * add_procedure_1_svc(paper_saved *, struct svc_req *);
one of them must be wrong.
What does line 46 of file paper.h have? . Check the paper.h file on the line 46 to see if the function signature is same.Is it auto generated by rpcgen ?

Resources