How to get the localized return string of C++ strerror? - c++

My Minecraft server crushed caused by insufficient spaces. About 2 hours before crushed, there were some plugins printing exception stack traces including java.io.ioexception: 设备上没有空间 (means java.io.IOException: No space left on device). After I restart it, I found that all the buildings players built in the 2 hours disappeared, and no any plugins can restore it (include CoreProtect, because of insufficient spaces, it can not submit database transactions).
In order to close server immediately when there's no enough spaces, I decided to develop a plugin. Because there's no way to listen exceptions thrown by all threads, I implemented this function by listen logs.
Any code print log like java.io.ioexception: ${message} or [...] ... [...]: java.io.ioexception: ${message} will trigger the shutdown of server.
Pay attention to the error message: In some platforms, it's 设备上没有空间; In some others platforms, it's No space left on device... So It's necessary to get the localized version of it firstly.
This error message, comes from Operating System, is strerror(28) (C++ function) in Windows or Linux. So I create a native function to invoke it:
// cn.chuanwise.nessc.errno.ErrorMessage;
public class ErrorMessage {
public native static String of(int errno, Locale locale);
}
#include "localed-error-message-native.h"
#include <locale>
#include <string.h>
JNIEXPORT jstring JNICALL Java_cn_chuanwise_nessc_errno_ErrorMessage_of(JNIEnv* env, jclass clz, jint code, jobject locale) {
// find locale class
const jclass locale_class = env->FindClass("java/util/Locale");
const jmethodID to_string_method = env->GetMethodID(locale_class, "toString", "()Ljava/lang/String;");
const jobject locale_string = env->CallObjectMethod(locale, to_string_method);
const char* locale_name = env->GetStringUTFChars(reinterpret_cast<jstring>(locale_string), nullptr);
// set locale
std::setlocale(LC_ALL, locale_name);
const char* strerr = strerror(static_cast<int>(code));
if (strerr == nullptr) {
return nullptr;
} else {
return env->NewStringUTF(strerr);
}
}
ErrorMessage.of(28, Locale.getDefault()) returns No space left on device in my device, but this code throws java.io.IOException: 设备上没有空间 in my device:
final File file = new File("test");
// ...
try (OutputStream outputStream = new FileOutputStream(file)) {
final byte[] buf = new byte[1024];
while (true) {
outputStream.write(buf);
}
}
How to get the localized return string of strerror?

Related

Can't connect to SQL database with mysql++

I've been trying to use the mysql++ library in my application (windows x64 based) but I can't seem to connect to my sql server.
Some information:
I used this code to connect to the server:
mysqlpp::Connection conn(db, 0, user, pass, 3306);
this definitely has the right data in it.
and then, my sql server is the standard service from the MySQL install. And I'm pretty sure I used the standard settings. I can connect to it using the MySql Workbench and I edited some new tables and such but my own program doesn't seem to connect.
I read the documentation and I can't find anything specific that might suggest something why I can't connect.
Oh, so many issues, so little time...
Have you checked that your program has permissions to access the database?
Does your program have the correct privileges?
Is your host name correct?
What errors are you getting?
What exception is thrown?
When you use the debugger, what line is the error on?
Here's my method:
sql::Connection * const
Manager ::
get_db_connection(void) const
{
//-------------------------------------------------------------------------
// Use only one connection until proven that more connections will make
// the program more efficient or have a beneficial impact on the user.
// Thus the change in returning sql::Connection * rather than a smart pointer.
// A smart pointer will delete its contents.
//-------------------------------------------------------------------------
static const char host_text[] = "tcp://127.0.0.1:3306/";
static std::string host_name;
if (!m_connection_initialized)
{
host_name = host_text;
initialize_db_driver();
host_name += m_dataset_info.m_dsn_name;
try
{
m_p_connection = m_p_sql_driver->connect(host_name.c_str(),
m_dataset_info.m_user_name.c_str(),
m_dataset_info.m_password.c_str());
}
catch (sql::SQLException &e)
{
/*
The MySQL Connector/C++ throws three different exceptions:
- sql::MethodNotImplementedException (derived from sql::SQLException)
- sql::InvalidArgumentException (derived from sql::SQLException)
- sql::SQLException (derived from std::runtime_error)
*/
wxString wx_text = wxT("# ERR: SQLException in ");
wx_text += wxT(__FILE__);
wxLogDebug(wx_text);
wx_text.Printf(wxT("# ERR: (%s) on line %d"),
__FUNCTION__,
__LINE__);
wxLogDebug(wx_text);
wx_text.Printf(wxT("# ERR: %s (MySQL error code: %d, SQLState: %s)"),
e.what(),
e.getErrorCode(),
e.getSQLState());
wxLogDebug(wx_text);
wxLogDebug(wxT("Verify that mysqlcppconn.dll is in the PATH or in the working directory."));
// throw Manager_Connection_Not_Initialized();
m_connection_initialized = false;
}
catch (...)
{
std::cout << "Unhandled database SQL exception\n" << flush;
m_connection_initialized = false;
}
m_connection_initialized = true;
}
return m_p_connection;
}

Error occured when sending message through Google Play Game Service with Cocos2d-x

I'm developing a multiplayer game with Google Play Services and Cocos2d-x. I already set up communication between Java and C++ using JNI, and can run processes like Sign-in, Create room, Invitation... Everything is fine until I need to send some struct to another players. When receive data from other, an error has occurred.
Here's the structs:
typedef enum
{
MESSAGE_TYPE_PING = -1,
MESSAGE_TYPE_PING_BACK = 0,
MESSAGE_TYPE_RTT = 3
} MESSAGE_TYPE;
typedef struct
{
MESSAGE_TYPE messType;
} MESSAGE;
typedef struct
{
MESSAGE mess;
timeval sendTime;
const char* text;
} PING_MESSAGE;
And in this code snippet I convert struct and send it to another players:
void MyClass::sendData()
{
// Send package
PING_MESSAGE ping;
ping.mess.messType = MESSAGE_TYPE_PING;
ping.sendTime = startTime;
ping.text = "Ohhhhhh";
char byte[sizeof(ping)];
memcpy(byte, &ping, sizeof(ping));
GCHelper::sendReliableRealTimeMessage(&byte[0]);
}
// In GCHelper's implementation
void GCHelper::sendReliableRealTimeMessage(const char* byteMess)
{
// Convert char* to jbyteArray
jbyteArray bArray = env->NewByteArray(16); //env is a static JNIEnv* in this class; 16 since my PING_MESSAGE struct is 16 bytes in size;
env->SetByteArrayRegion(bArray,0,16,(jbyte*)byteMess);
// Make Java call
env->CallStaticVoidMethod(classID, methodID, bArray);
methodInfo.env->DeleteLocalRef(bArray);
methodInfo.env->DeleteLocalRef(classID);
}
Now, Java code take responsibility to send the byte array to participants in room. At receiver side, I'm continue send received data to C++. And error occured here when I convert jbyteArray back to struct:
void Java_package_name_TestMulti_nativeOnRealTimeMessageReceived(JNIEnv *env, jobject thiz, jbyteArray receivedMess)
{
CCLOG("Called from java");
jboolean isCopy;
jbyte * pCData = env->GetByteArrayElements(receivedMess, &isCopy);
jsize size = env->GetArrayLength(receivedMess);
const char* sd = (const char*)pCData;
PING_MESSAGE result;
memcpy(&result, sd, sizeof(result));
CCLOG("TEST size: %d", size); // This log out: "TEST size: 16"
CCLOG("TEST type: %d", result.mess.messType); // This log out: "TEST type: -1"
CCLOG("TEST text: %s", result.text); // AND ERROR!!!!!!!
cocos2d::CCByteArray* data = cocos2d::CCByteArray::createWithData(sd);
cocos2d::CCNotificationCenter::sharedNotificationCenter()->postNotification("onRealTimeMessageReceived", data);
if(isCopy)
{
env->ReleaseByteArrayElements(receivedMess,pCData,JNI_ABORT);
}
}
I'm not understand here. If I don't send byte array to another players yet send that array back to C++ by calling nativeOnRealTimeMessageReceived() method from Java side, it runs fine and logs correctly. It's mean that with the same byte[] package converted from char* in C++, if I just pass it back to C++, it's correct, but if I send it through Google Play Game Services, it goes wrong. What does this mean?

JNI crash outside JVM - EXCEPTION_ACCESS_VIOLATION

I needed a Java application to manipulate the Windows registry. To do this, I wrote some native C++ code and used JNI to call it.
For the most part it works. During testing I hadn't heard of a single problem. However, recently a user experienced a crash in the C++ code that brought down the JVM. The details are below. I have almost no C++ experience, so I think that is where I need the help. I think the issue is related to permissions, since when the Java app is run as an administrator, the problem goes away. The issue there is that not all our users will have admin privileges on their machines.
hs_err_pid log info:
#
# A fatal error has been detected by the Java Runtime Environment:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x0000000076859083, pid=5316, tid=3116
#
# JRE version: 6.0_20-b02
# Java VM: Java HotSpot(TM) 64-Bit Server VM (16.3-b01 mixed mode windows-amd64 )
# Problematic frame:
# C [kernel32.dll+0x9083]
#
# If you would like to submit a bug report, please visit:
# http://java.sun.com/webapps/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
Stack: [0x0000000013010000,0x0000000013110000], sp=0x000000001310f2d0, free space=3fc0000000000000000k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C [kernel32.dll+0x9083]
Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j my.package.WinRegUtils.SetKeyValue(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z+0
j java.lang.Thread.run()V+11
v ~StubRoutines::call_stub
Here is the native code/method in question
JNIEXPORT jboolean JNICALL Java_my_package_WinRegUtils_SetKeyValue
(JNIEnv* env, jclass clazz, jstring jRootKey, jstring jKey, jstring jValueName, jstring jValueData, jstring jDataType)
{
bool success = false;
WCHAR* key_w;
WCHAR* valueName_w;
WCHAR* valueData_w;
WCHAR* dataType_w;
HKEY hKey;
const char* rootKey = env->GetStringUTFChars(jRootKey, false);
const char* key = env->GetStringUTFChars(jKey, false);
convertString(key, &key_w);
const char* valueName = env->GetStringUTFChars(jValueName, false);
convertString(valueName, &valueName_w);
const char* valueData = env->GetStringUTFChars(jValueData, false);
convertString(valueData, &valueData_w);
const char* dataType = env->GetStringUTFChars(jDataType, false);
convertString(dataType, &dataType_w);
HKEY root = GetRootHKEY(rootKey);
if (RegOpenKeyEx(root, key_w, 0, KEY_WRITE, &hKey) == ERROR_SUCCESS)
{
DWORD dwType;
BYTE* data;
DWORD length;
if (strcmp("REG_SZ", dataType) == 0)
{
dwType = REG_SZ;
data = (BYTE*)valueData_w;
length = wcslen(valueData_w) * sizeof(DWORD);
}
else if (strcmp("REG_DWORD", dataType) == 0)
{
dwType = REG_DWORD;
const DWORD intData = atoi(valueData);
data = (BYTE*)&intData;
length = sizeof(DWORD);
}
if (RegSetValueEx(hKey, valueName_w, 0, dwType, data, length) == ERROR_SUCCESS)
{
success = true;
RegCloseKey(hKey);
}
}
env->ReleaseStringUTFChars(jRootKey, rootKey);
env->ReleaseStringUTFChars(jKey, key);
env->ReleaseStringUTFChars(jValueName, valueName);
env->ReleaseStringUTFChars(jValueData, valueData);
env->ReleaseStringUTFChars(jDataType, dataType);
delete[] key_w, valueName_w, valueData_w, dataType_w;
return success;
}
To debug, add a few
printf("debug xxx");
fflush(stdout);
in
Java_my_package_WinRegUtils_SetKeyValue()
to isolate the failing line.

How to Release jstring that is sent from Native Code back to Java?

I have the following native routine:
void sendMessage(const char* text)
{
JNIEnv* env;
if(!_jvm)
return;
_jvm->AttachCurrentThread(&env, NULL);
if(!_nativesCls)
_nativesCls = env->FindClass("com/foo/BaseLib");
if(_nativesCls == 0)
return;
jstring message = env->NewStringUTF(text);
if(!_sendStr)
_sendStr = env->GetStaticMethodID(_nativesCls, "onMessage", "(Ljava/lang/String;)V");
if(_sendStr)
env->CallStaticVoidMethod(_nativesCls, _sendStr, message);
//env->ReleaseStringUTFChars(message, text); // <----- * NOT WORKING
}
If I run this as is, it works fine up until memory fills up and I receive:
ReferenceTable overflow (max=512)
I thought adding the commented line above would fix the issue but it just causes the app to bomb out at that point.
Any suggestions?
DeleteLocalRef(). Just like any other Java object that was allocated within JNI. However, it will be automatically garbage-collected once the JNI method returns. Details here: http://download.oracle.com/javase/1.3/docs/guide/jni/spec/design.doc.html#1242

Dumping Useful Data to Console on Caught Exception

I have a CExceptionHandler class that is invoked whenever my application detects a run-time exception. For example:
if ( val == NULL )
{
TRACE(_T("Unexpected NULL in sequence."));
AfxThrowException( ERROR_INVALID_DATA );
}
AfxThrowException is very simple:
void AfxThrowException( DWORD error )
{
CExceptionHandler * pException = NULL;
if ( error == 0 )
{
error = ::GetLastError();
}
pException = new CExceptionHandler( error );
TRACE(_T("Warning: throwing CSerialException for error %d\n"), error);
THROW(pException);
}
This is the member Dump function of CExceptionHandler:
void CExceptionHandler::Dump( CDumpContext & dc ) const
{
CObject::Dump(dc);
dc << "m_dwError = " << m_dwError;
}
Higher up in my code I have the try/catch statements:
try
{
/* My app does stuff where the exception is thrown. */
}
catch( CExceptionHandler * ex )
{
afxDump << _T("Dumping exceptional data: ") << _T("\r\n");
ex->Dump( afxDump );
afxDump << _T("\r\n");
}
I would like the collected debug information to be dumped to the console. However, when the PC gets into the catch statement (verified with breakpoint), nothing happens on the console. I am using Visual Studio 2008 in Debug mode. Thoughts are appreciated. Thanks.
CDumpContext sends output to the debugger, not to the console (see OutputDebugString for more information), and if you run under the Visual Studio debugger, the output will appear in the Output window.
If you want to also send output to the console, you can configure CDumpContext to write to a CFile by passing a pointer to a CFile object in the CDumpContext constructor.
If your application is built with the 'Use Multi-Byte Character Set' configuration option, you can use CStdioFile to write to either stdout or stderr:
CStdioFile file(stdout);
CDumpContext dumpContext(&file);
ex->Dump(dumpContext);
Or, if you want to use afxDump, you can set its m_pFile member variable directly (it's declared public). For example you could put this code inside your main function:
CStdioFile file(stdout);
afxDump.m_pFile = &file;
But, this won't work if your app is built as Unicode because strings need to be converted to multi-byte to be written to stdout. To do the conversion, write a class that inherits CFile:
class CDumpFile : public CFile
{
public:
virtual void Write(const void* lpBuf, UINT nCount);
};
void CDumpFile::Write(const void* lpBuf, UINT nCount)
{
// Construct string from array of wide chars
const wchar_t* p = static_cast<const wchar_t*>(lpBuf);
UINT len = nCount / sizeof(wchar_t);
CStringW str(p, len);
CStringA astr(str); // Convert wide char to multibyte
fputs((LPCSTR)astr, stdout); // Write multibyte string to stdout
}
and use it like this:
CDumpFile file;
afxDump.m_pFile = &file;
A couple of other points about your code:
You should ensure that the exception object is deleted in the catch block. If your CExceptionHandler class inherits MFC's CException then you should call ex->Delete(). If it doesn't, you need to delete ex.
I'd advise against using the Afx prefix for own functions - you should consider this reserved for use by the MFC library, in my opinion.
I hope this helps!