static int lua_proto_append_challenge_packet (lua_State *L) {
	GString *packet;
	network_mysqld_auth_challenge *auth_challenge;

	luaL_checktype(L, 1, LUA_TTABLE);

	auth_challenge = network_mysqld_auth_challenge_new();

	LUA_IMPORT_INT(auth_challenge, protocol_version);
	LUA_IMPORT_INT(auth_challenge, server_version);
	LUA_IMPORT_INT(auth_challenge, thread_id);
	LUA_IMPORT_INT(auth_challenge, capabilities);
	LUA_IMPORT_INT(auth_challenge, charset);
	LUA_IMPORT_INT(auth_challenge, server_status);

	LUA_IMPORT_STR_FROM(auth_challenge, auth_plugin_data, "challenge");

	packet = g_string_new(NULL);	
	network_mysqld_proto_append_auth_challenge(packet, auth_challenge);
	
	network_mysqld_auth_challenge_free(auth_challenge);

	lua_pushlstring(L, S(packet));
	
	g_string_free(packet, TRUE);

	return 1;
}
void test_mysqld_handshake(void) {
	const char raw_packet[] = "J\0\0\0"
		"\n"
		"5.0.45-Debian_1ubuntu3.3-log\0"
		"w\0\0\0"
		"\"L;!3|8@"
		"\0"
		",\242" /* 0x2c 0xa2 */
		"\10"
		"\2\0"
		"\0\0\0\0\0\0\0\0\0\0\0\0\0"
		"vV,s#PLjSA+Q"
		"\0";
	network_mysqld_auth_challenge *shake;
	network_packet packet;

	shake = network_mysqld_auth_challenge_new();
	
	packet.data = g_string_new(NULL);
	packet.offset = 0;
	g_string_append_len(packet.data, C(raw_packet));

	g_assert_cmpint(packet.data->len, ==, 78);

	g_assert_cmpint(0, ==, network_mysqld_proto_skip_network_header(&packet));
	g_assert_cmpint(0, ==, network_mysqld_proto_get_auth_challenge(&packet, shake));

	g_assert(shake->server_version == 50045);
	g_assert(shake->thread_id == 119);
	g_assert(shake->server_status == 
			SERVER_STATUS_AUTOCOMMIT);
	g_assert(shake->charset == 8);
	g_assert(shake->capabilities ==
			(CLIENT_CONNECT_WITH_DB |
			CLIENT_LONG_FLAG |

			CLIENT_COMPRESS |

			CLIENT_PROTOCOL_41 |

			CLIENT_TRANSACTIONS |
			CLIENT_SECURE_CONNECTION));

	g_assert(shake->challenge->len == 20);
	g_assert(0 == memcmp(shake->challenge->str, "\"L;!3|8@vV,s#PLjSA+Q", shake->challenge->len));

	/* ... and back */
	g_string_truncate(packet.data, 0);
	g_string_append_len(packet.data, C("J\0\0\0"));
	network_mysqld_proto_append_auth_challenge(packet.data, shake);

	g_assert_cmpint(packet.data->len, ==, sizeof(raw_packet) - 1);

	g_assert(0 == memcmp(packet.data->str, raw_packet, packet.data->len));

	network_mysqld_auth_challenge_free(shake);
	g_string_free(packet.data, TRUE);
}
static PyObject *
python_proto_append_challenge_packet (PyObject *self, PyObject *args) {
	GString *packet;
	network_mysqld_auth_challenge *auth_challenge;

	PyObject *dict;
	if(!PyArg_ParseTuple(args, "O!", &PyDict_Type, &dict))
		return NULL;

	auth_challenge = network_mysqld_auth_challenge_new();

#define PYTHON_IMPORT_INT(x, y) \
	PyObject *v_ ## y = PyDict_GetItemString(dict, #y);\
	if(v_ ## y){\
		if(PyInt_Check(v_ ## y))\
			x->y = PyInt_AsLong(v_ ## y);\
		else{\
			PyErr_SetString(PyExc_ValueError, #x "." #y "must be an int");\
			Py_DECREF(v_ ## y);\
			return NULL;\
		}\
	}

#define PYTHON_IMPORT_STR(x, y) \
	PyObject *v_ ## y = PyDict_GetItemString(dict, #y);\
	if(v_ ## y){\
		if(PyString_Check(v_ ## y)){\
			int len;\
			char *str;\
			PyString_AsStringAndSize(v_ ## y, &str, &len);\
			g_string_assign_len(x->y, str, len);\
		} else{\
			PyErr_SetString(PyExc_ValueError, #x "." #y "must be an string");\
			Py_DECREF(v_ ## y);\
			return NULL;\
		}\
	}

	PYTHON_IMPORT_INT(auth_challenge, protocol_version);
	PYTHON_IMPORT_INT(auth_challenge, server_version);
	PYTHON_IMPORT_INT(auth_challenge, thread_id);
	PYTHON_IMPORT_INT(auth_challenge, capabilities);
	PYTHON_IMPORT_INT(auth_challenge, charset);
	PYTHON_IMPORT_INT(auth_challenge, server_status);

	PYTHON_IMPORT_STR(auth_challenge, challenge);

	packet = g_string_new(NULL);
	network_mysqld_proto_append_auth_challenge(packet, auth_challenge);

	network_mysqld_auth_challenge_free(auth_challenge);
	PyObject *res = PyString_FromStringAndSize(S(packet));
	if(!res)
		return NULL;
	g_string_free(packet, TRUE);
	return res;
}