hi there i am trying to develop 3 tier server with embedded database.
my issue is that i am able to save data in gdbm database but when i try to retrieve data from other functions it always returns null value. i have also point out the issue which is the null termination (verified through gdb output) of key value while i am saving data key does not ends with \0 but while retrieving data it is terminated by \0 i am not quite sure about this theory and don't know how to solve it.
things that i have tried:
i have attached minimum code to reproduce same error hope so someone will point out my mistake in the mean time i will still try to resolve this issue but your guideline can be helpful.
source Code
#include <gdbm.h>
#include <string.h>
#include <stdio.h>
#define STR_SIZE 20
#define BUFFER_SIZE 256
typedef struct UserData
{
char name[STR_SIZE];
char accountNumber[STR_SIZE];
char password[STR_SIZE];
long balence;
} userData;
void simulateSelect(GDBM_FILE dbFile);
void simulateInsert(GDBM_FILE dbFile);
int main(int argc, char **argv)
{
GDBM_FILE dbFile = gdbm_open("newSampleDB", 0, GDBM_WRCREAT | GDBM_READER, 0660, 0);
simulateInsert(dbFile);
simulateSelect(dbFile);
return 0;
}
void simulateInsert(GDBM_FILE dbFile)
{
//RPC call data sent to server [function mode [data for function call]
char *request = "signup user fawad 10120 11223 120";
//server receiving end
char buffer[BUFFER_SIZE];
char name[STR_SIZE];
char id[STR_SIZE];
char pass[STR_SIZE];
char bal[STR_SIZE];
char temp[STR_SIZE];
char mode[STR_SIZE];
//parse cliet request and slect one of the avaiable opertaion
sscanf(request, "%s %s %s %s %s %s", temp, mode, name, id, pass, bal);
bzero(buffer, BUFFER_SIZE);
//forward request to database server
sprintf(buffer, "insert %s %s %s %s %s", mode, name, id, pass, bal);
// databse server receiving end
userData data;
bzero(name, STR_SIZE);
bzero(id, STR_SIZE);
bzero(pass, STR_SIZE);
//parse request and take actoin
sscanf(buffer, "%s %s %s %s %s %li", temp, temp, name, id, pass, &data.balence);
strcpy(data.name, name);
strcpy(data.accountNumber, id);
strcpy(data.password, pass);
//save data in database
datum key;
// i have checked through gdb at this point key.dptr does not have null termination i.e. \0
// key.dptr = 10120
key.dptr = data.accountNumber;
key.dsize = STR_SIZE + 1;
datum _data;
_data.dptr = (char *)&data;
_data.dsize = sizeof(data);
int res = gdbm_store(dbFile, key, _data, GDBM_INSERT);
printf("Indert Status = %d", res);
//works fine here and data is retrived
datum data3 = gdbm_fetch(dbFile, key);
userData *data1 = (userData *)(data3.dptr);
sprintf(buffer, "1 %s %s %s %li", data1->name, data1->accountNumber, data1->password, data1->balence);
fprintf(stdout, "%s", buffer);
}
void simulateSelect(GDBM_FILE dbFile)
{
//client again initiates request to login
char *request = "login user 10120 11223";
//server end
char buffer[BUFFER_SIZE];
char id[STR_SIZE];
char pass[STR_SIZE];
char temp[STR_SIZE];
char mode[STR_SIZE];
bzero(buffer, BUFFER_SIZE);
//parse request and select operatoin
sscanf(request, "%s %s %s %s", temp, mode, id, pass);
//send request to database server
sprintf(buffer, "select %s %s", mode, id);
//databse server end
bzero(id, STR_SIZE);
//parse request
sscanf(buffer, "%s %s %s", temp, mode, id);
// userData d;
// strcpy(d.accountNumber, id);
datum _data;
datum key;
// at this point key.dptr have null termiantion i.e key.dptr= 10120\0
key.dptr = id;
// key.dptr = d.accountNumber;
key.dsize = STR_SIZE + 1;
_data = gdbm_fetch(dbFile, key);
userData *data = (userData *)(_data.dptr);
// ((userData *)res.dptr)->name)
sprintf(buffer, "1 %s %s %s %li", data->name, data->accountNumber, data->password, data->balence);
fprintf(stdout, "%s", buffer);
}
The problem is very likely that you use the whole (and more!) of the accountNumber
array as key, even the parts beyond the string null-terminator which will be uninitialized and have indeterminate values.
The key you use when you write will thus likely not be exactly the same as the one you use when reading the data.
The solution is to make sure that all of the accountNumber
array will be initialized (as in memset(data.accountNumber, 0, sizeof data.accountNumber)
) before copying the string to it.
The problem with e.g.
bzero(id, STR_SIZE);
// ...
strcpy(data.accountNumber, id);
is that strcpy
will not copy data beyond the string null-terminator, so it doesn't copy the full array id
, only a small part of it. Which will leave the remaining elements of data.accountNumber
uninitialized.
You must initialize data.accountNumber
itself.