With help from DizzyDon and kbw (see
https://cplusplus.com/forum/beginner/285198/), I have been able to create a non-blocking socket and read from it. I use this code for writing to the socket. (The code for reading is copied from the previous thread):
1 2 3 4 5
|
int writeData(const std::string & input) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
int bytes_sent = send(Master_sfd, input.c_str(), input.size() + 1, 0);
return bytes_sent;
}
| |
I use this write-function in an authentication procedure for connecting to a Basex server instance. The procedure is based on the information given in
https://docs.basex.org/wiki/Server_Protocol . When using the fake authentication data that are given in this protocol, my procedure produces the same md5 hash so I am pretty confident that that part of my procedure functions well.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
|
BasexSocket& BasexSocket::Authenticate (std::string user, std::string passwd) {
std::string rts = {};
int bytes_read, bytes_sent;
vector <string> strings;
std::string nonce;
std::string code_wd; // Either password (CRAM-MD5) or user:realm:password (Digest)
std::string realm;
std::string md5_codwd = {}; // md5_basex(code_wd)
std::string auth;
std::string def_auth;
std::string sock_read_string = {};
fd_set read_sfd_set;
struct timeval timeout;
FD_ZERO(&read_sfd_set);
FD_SET(Master_sfd, &read_sfd_set);
memset(&timeout, 0, sizeof(timeout));
// 1: Server sends the timestamp
bytes_read = readSocket( rts); // number of read bytes
cout << "0 Realm en timestamp: " << rts << endl;
if (bytes_read == 0) {
warnx("Reading timestamp failed"); Master_sfd = -1;
return *this;
}
// 2: Client sends the user name (must be \0-terminated)
bytes_sent = writeData(user);
// 3: Compose the md5_auth hash, md5_auth code = md5(md5("<user>:BaseX:<password>") + "1234567890123")
int string_cnt = StringSplit( strings , rts, ':'); // Split string on occurence of ':'
if (strings.size() == 1) { // CRAM-MD5
nonce = rts;
code_wd = passwd;
} else { // Digest
code_wd = user; realm = strings[0]; nonce = strings[1];
code_wd.append(":").append(realm).append(":").append(passwd);
}
md5_codwd = md5_basex(code_wd);
auth = md5_codwd.append(nonce);
def_auth = md5_basex(auth);
bytes_sent = writeData(def_auth);
// select(Master_sfd + 1, &read_sfd_set, NULL, NULL, &timeout);
// 4: Handle server-response
sock_read_string.clear();
bytes_read = readSocket( sock_read_string);
if (bytes_read > 0) {
char success = sock_read_string.front();
cout << "Auth-Test: " << success << endl;
if (success != '\0') {
Master_sfd = -1;
warnx("Authentication failed");
cout << endl;
}
} else {
Master_sfd = -1;
warnx("Reading authentication status byte failed");
}
return *this;
};
| |
The problem is that the readSocket function call in line 46 returns \001 ... indicating a failure. I've used the credentials for connecting to a standalone basexclient and am certain that they are correct.
When I was working on the same procedure I developed earlier in R, I ran into a similar problem. When that procedure was performed during 'normal' use, the authentication failed. However, no errors were detected in the debugger.
The problem eventually turned out to be solved there by calling the socketSelect() function. I don't have an explanation for this behaviour. Maybe calling this function inserts a short wait?
My guess is that the select() I use in line 42 comes closest to the socketSelect as used in the R code. Adding select() however has no positive result.
I've used Wireshark to inspect the traffic between the client and the server, but I don't see anything out of the ordinary. The termination zeros are inserted in the correct place.
Assuming that the md5 hash is calculated correctly, I think the only cause that remains is that the writeData function is not working properly.
According to the specification, writeData must be able to be used for sending strings (zero-terminated) or raw data. What 'raw' data is is not further specified. In R, 'raw' data corresponds to hexadecimal values.
writeData returns the correct number of sent bytes but I can't look at the data that is being sent.
Is it possible to see those data?