How do I handle session id context uninitialized in Thrift - ssl

sorry to bother you guys,
I have a Thrift server program in c++. Whenever a client connects to me, the handshake succeeds, as does the first Thrift command sent, but the second command sent fails with the error "session id context uninitialized".
The client's next command re-establishes the connection and succeeds, but the fourth will fail again with "session id context uninitialized".
The exact error is
TConnectedClient died: SSL_accept: session id context uninitialized (SSL_error_code = 1)
TConnectedClient input close failed: session id context uninitialized (SSL_error_code = 1)
TConnectedClient output close failed: session id context uninitialized (SSL_error_code = 1)
every 'even' command
My problem seems similar to THIS, but I can't seem to figure out how to change the context of my session to set the SSL_OP_NO_TICKET flag.
I tried adding a ServerEventHandler, but I don't think I can change the serverContext that is present there.
Can anyone help me?
Below is the section of main() where I declare and start the server. If more information is needed, please ask. (sorry if I typo-ed any code, I had to retype by hand it here)
::apache::thrift::stdcxx::shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactoryT<TBufferBase>());
::apache::thrift::stdcxx::shared_ptr<My_svrHandler> handler(new My_svrHandler());
::apache::thrift::stdcxx::shared_ptr<TProcessor> processor(new My_svrProcessor(handler));
::apache::thrft::stdcxx::shared_ptr<TSSLSocketFactory> sslSocketFactory(new TSSLSocketFactory(SSL::TLSv1_2));
sslSocketFactory->loadCertificate(certLocation);
sslSocketFactory->loadPrivateKey(keyLocation);
sslSocketFactory->loadTrustedCertificates(CALocation);
sslSocketFactory->authenticate(true);
::apache::thrift::stdcxx::shared_ptr<TServerSocket> serverSocket(new TSSLServerSocket(9090, sslSocketFactory));
::apache::thrift::stdcxx::shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
::apache::thrift::stdcxx::shared_ptr<apache::thrift::server::Tserver> server;
::apache::thrift::stdcxx::shared_ptr<ThreadManager> threadManager = ThreadManager::newSimpleThreadManager(10);
::apache::thrift::stdcxx::shared_ptr<PlatformThreadFactory> threadFactory = ::apache::thrift::stdcxx::shared_ptr<PlatformThreadFactory>(new PlatformThreadFactory());
threadManager->threadFactory(threadFactory);
threadManager->start();
server.reset(new TThreadedPoolServer(processor, serverSocket, transportFactory, protocolFactory, threadmanager));
if(server.get() != NULL)
{
apache::thrift::concurrency::PlatformThreadFactory factory;
::apache::thrift::stdcxx::shared_ptr<apache::thrift::concurrency::Runnable> serverThreadRunner(server);
::apache::thrift::stdcxx::shared_ptr<apache::thrift::concurrency::Thread> thread = factory.newThread(serverThreadRunner);
signal(SIGPIPE, SIG_IGN);
thread->start();
while(1){}
server->stop();
thread->join();
server.reset();
}

Related

Debugging "Transaction simulation failed" when sending program instruction (Solana Solidity)

When attempting to make a call to a program compiled with #solana/solidity, I'm getting the following error:
Transaction simulation failed: Error processing Instruction 0: Program failed to complete
Program jdN1wZjg5P4xi718DG2HraGuxVx1mM7ebjXpxbJ5R3N invoke [1]
Program log: pxKTQePwHC9MiR52J5AYaRtSLAtkVfcoGS3GaLD24YX
Program log: sender account missing from transaction
Program jdN1wZjg5P4xi718DG2HraGuxVx1mM7ebjXpxbJ5R3N consumed 200000 of 200000 compute units
Program failed to complete: BPF program Panicked in solana.c at 285:0
Program jdN1wZjg5P4xi718DG2HraGuxVx1mM7ebjXpxbJ5R3N failed: Program failed to complete
jdN1wZjg5P4xi718DG2HraGuxVx1mM7ebjXpxbJ5R3N is the program's public key and pxKTQePwHC9MiR52J5AYaRtSLAtkVfcoGS3GaLD24YX is the sender's public key.
I'm using a fork of the #solana/solidity library that exposes the Transaction object so that it can be signed and sent by Phantom Wallet on the front end. The code that results in the error is as follows:
// Generate the transaction
const transaction = contract.transactions.send(...args);
// Add recent blockhash and fee payer
const recentBlockhash = (await connection.getRecentBlockhash()).blockhash;
transaction.recentBlockhash = recentBlockhash;
transaction.feePayer = provider.publicKey;
// Sign and send the transaction (throws an error)
const res = await provider.signAndSendTransaction(transaction);
I would attempt to debug this further myself, but I'm not sure where to start. Looking up the error message hasn't yielded any results and the error message isn't very descriptive. I'm not sure if this error is occurring within the program execution itself or if it's an issue with the composition of the transaction object. If it is an issue within the program execution, is there a way for me to add logs to my solidity code? If it's an issue with the transaction object, what could be missing? How can I better debug issues like this?
Thank you for any help.
Edit: I'm getting a different error now, although I haven't changed any of the provided code. The error message is now the following:
Phantom - RPC Error: Transaction creation failed. {code: -32003, message: 'Transaction creation failed.'}
Unfortunately this error message is even less helpful than the last one. I'm not sure if Phantom Wallet was updated or if a project dependency was updated at some point, but given the vague nature of both of these error messages and the fact that none of my code has changed, I believe they're being caused by the same issue. Again, any help or debugging tips are appreciated.
I was able to solve this issue, and although I've run into another issue it's not related to the contents of this question so I'll post it separately.
Regarding my edit, I found that the difference between the error messages came down to how I was sending the transaction. At first, I tried sending it with Phantom's .signAndSendTransaction() method, which yielded the second error message (listed under my edit). Then I tried signing & sending the transaction manually, like so:
const signed = await provider.request({
method: 'signTransaction',
params: {
message: bs58.encode(transaction.serializeMessage()),
},
});
const signature = bs58.decode(signed.signature);
transaction.addSignature(provider.publicKey, signature);
await connection.sendRawTransaction(transaction.serialize())
Which yielded the more verbose error included in my original post. That error message did turn out to be helpful once I realized what to look for -- the sending account's public key was missing from the keys field on the TransactionInstruction on the Transaction. I added it in my fork of the #solana/solidity library and the error went away.
In short, the way I was able to debug this was by
Using provider.request({ method: 'signTransaction' }) and connection.sendRawTransaction(transaction) rather than Phantom's provider.signAndSendTransaction() method for a more verbose error message
Logging the transaction object and inspecting the instructions closely
I hope this helps someone else in the future.

A resource failed to call close

I'm getting the android logcat message "A resource failed to call close". I've tracked it down to where that message gets generated. Here's the code:
Properties defaultProperties = new Properties();
URL propURL = Util.class.getClassLoader().getResource(DEFAULT_PROPERTIES_FILE);
if (propURL != null)
{
InputStream is = null;
try
{
// Load properties from URL.
is = propURL.openConnection().getInputStream();
defaultProperties.load(is);
is.close();
}
catch (Exception ex)
{
The message is generated on the call to "defaultProperties.load(is)".
I put a breakpoint on that line, and when I step over that line, the warning message is generated. I'm not the author of the code but that line gets executed at least two times and its the second time when that line gets called when the warning gets generated. I just don't see how under any circumstances that a resource failed to close would be generated on that line. I'm at a lost to explain how or why that error message would be generated there. Any ideas?
After thinking about this, I've come to the conclusion that the problem doesn't have anything to do with the line "defaultProperties.load(is)" causing the warning. Although the message is always generated the second time that line is called, my current thought is that the problem is happening elsewhere but when this line gets called it's probably yielding to some other VM related thread time to process, and that process is detecting that some resource failed to close. I'm concluding that the problem is related to something altogether different and calling that line is the time when the problem surfaces, but it's not what's causing the problem.

webdriver-io - Cannot init a new session

Sometimes my selenium grid errors out with this error Session [e4b60cfd-88f9-40ad-a14f-18ba46355a30] was terminated due to TIMEOUT" and appears to be related to this issue in SeleniumHQ:
https://github.com/SeleniumHQ/selenium/issues/1557
In my webdriverio code, I can catch this exception like:
.getAttribute('something').then((onSuccess,onError))
And inside onError, I'm trying end the session like:
client.end().then(()=>{
console.log("ending the session due to error");
});
or
client.session('delete').then(()=>{
console.log("deleting the session due to error");
});
Both of these didn't work. Meaning, I never saw my console messages. Possible that the session was terminated already (based on the previous error message).
However, when I try to run the test again, getting this error:
Cannot init a new session, please end your current session first
Whats the proper way to end the session and handle this issue?

Oracle SQL query fails only in one process: "ORA-01405: fetched column value is NULL"

I'm trying to call a system stored procedure in a "plugin" that I've built. When I test my plugin out in a test application, it works fine. When I run the plugin in the targeted app I'm building it for, I get an exception from Oracle that doesn't make any sense.
I'm using Oracle server 11.2.0.1.0, and ODP.NET 2.112.2.0.
Here's the debug trace from ODP.NET from my test app:
(ENTRY) OracleConnection::OracleConnection(1)
(POOL) New connection pool created for: "Data Source=orcl;User ID=scott;"
(ENTRY) OracleConnection::CreateCommand()
OpsSqlPrepare2():SQL: begin DBMS_AQADM.START_QUEUE(queue_name => 'MyQueue'); end;
(EXIT) OpsSqlExecuteNonQuery(): RetCode=0 Line=877
(EXIT) OracleCommand::ExecuteNonQuery()
(ENTRY) OracleConnection::Dispose()
(ENTRY) OracleConnection::Close()
And here's debug trace from ODP.NET from the same code running in the targeted app:
(ENTRY) OracleConnection::OracleConnection(1)
(POOL) New connection pool created for: "Data Source=orcl;User ID=scott;"
(ENTRY) OracleConnection::CreateCommand()
OpsSqlPrepare2():SQL: begin DBMS_AQADM.START_QUEUE(queue_name => 'MyQueue'); end;
(EXIT) OpsSqlExecuteNonQuery(): RetCode=0 Line=877
(EXIT) OracleCommand::ExecuteNonQuery()
(ENTRY) OpsErrGetOpoCtx()
(ERROR) Oracle error code=1405; ORA-01405: fetched column value is NULL
(EXIT) OpsErrGetOpoCtx(): RetCode=0 Line=137
(ENTRY) OracleConnection::Dispose()
(ENTRY) OracleConnection::Close()
I'm at a loss as to what could be different between the test/target applications. Both processes are running as members of the local Administrators group. Both are using the same connection string. Both are running the same .NET code, but with a different outcome from the database server. What could be going on here?
This error comes from old OCI & prec-compiled code where an indicator variable was required to be set to indicate a null return for the field. When there is no indicator variable declared, this error is triggered if a null value is encountered. Obviously, some older code is still layered under the calls you made.
In other words, it is a data issue. I don't know where to start looking offhand.
It turns out that my target application was executing my plugin code while in Distributed XA Transaction (MSDTC in my case). The call to DBMS_AQADM.START_QUEUE has an implicit COMMIT; that I wasn't aware of. The error message is obviously not helpful at all in this case.
The solution is to wrap my call in in the following:
using (var scope = new TransactionScope(TransactionScopeOption.Surpress))
{
// execute DBMS_AQADM.START_QUEUE code here
scope.Complete();
}
This causes the call to DBMS_AQADM.START_QUEUE to run outside of the ambient transaction.

Suppressing NServicebus Transaction to write errors to database

I'm using NServiceBus to handle some calculation messages. I have a new requirement to handle calculation errors by writing them the same database. I'm using NHibernate as my DAL which auto enlists to the NServiceBus transaction and provides rollback in case of exceptions, which is working really well. However if I write this particular error to the database, it is also rolled back which is a problem.
I knew this would be a problem, but I thought I could just wrap the call in a new transaction with the TransactionScopeOption = Suppress. However the error data is still rolled back. I believe that's because it was using the existing session with has already enlisted in the NServiceBus transaction.
Next I tried opening a new session from the existing SessionFactory within the suppression transaction scope. However the first call to the database to retrieve or save data using this new session blocks and then times out.
InnerException: System.Data.SqlClient.SqlException
Message=Timeout expired. The timeout period elapsed prior to completion of the >operation or the server is not responding.
Finally I tried creating a new SessionFactory using it to open a new session within the suppression transaction scope. However again it blocks and times out.
I feel like I'm missing something obvious here, and would greatly appreciate any suggestions on this probably common task.
As Adam suggests in the comments, in most cases it is preferred to let the entire message fail processing, giving the built-in Retry mechanism a chance to get it right, and eventually going to the error queue. Then another process can monitor the error queue and do any required notification, including logging to a database.
However, there are some use cases where the entire message is not a failure, i.e. on the whole, it "succeeds" (whatever the business-dependent definition of that is) but there is some small part that is in error. For example, a financial calculation in which the processing "succeeds" but some human element of the data is "in error". In this case I would suggest catching that exception and sending a new message which, when processed by another endpoint, will log the information to your database.
I could see another case where you want the entire message to fail, but you want the fact that it was attempted noted somehow. This may be closest to what you are describing. In this case, create a new TransactionScope with TransactionScopeOption = Suppress, and then (again) send a new message inside that scope. That message will be sent whether or not your full message transaction rolls back.
You are correct that your transaction is rolling back because the NHibernate session is opened while the transaction is in force. Trying to open a new session inside the suppressed transaction can cause a problem with locking. That's why, most of the time, sending a new message asynchronously is part of the solution in these cases, but how you do it is dependent upon your specific business requirements.
I know I'm late to the party, but as an alternative suggestion, you coudl simply raise another separate log message, which NSB handles independently, for example:
public void Handle(DebitAccountMessage message)
{
var account = this.dbcontext.GetById(message.Id);
if (account.Balance <= 0)
{
// log request - new handler
this.Bus.Send(new DebitAccountLogMessage
{
originalMessage = message,
account = account,
timeStamp = DateTime.UtcNow
});
// throw error - NSB will handle
throw new DebitException("Not enough funds");
}
}
public void Handle(DebitAccountLogMessage message)
{
var messageString = message.originalMessage.Dump();
var accountString = message.account.Dump(DumpOptions.SuppressSecurityTokens);
this.Logger.Log(message.UniqueId, string.Format("{0}, {1}", messageString, accountString);
}