EDIT : Scroll down to see the updated code.
I would like to build a fake player for Minecraft, in the C language.
My Minecraft server (bukkit) is listening on the port 25565, on my local IP 192.168.1.141
When I launch my application, (when it send data trough the socket) the bukkit server says : "192.168.1.141:xxxxx lost connection", and
My application tell me :
socked created
socked connected
to send data = (smilie)kekos91;192.168.1.141:25565
to send length = 27
send !
response data = (a strange symbol)
response length = 1
socket disconnected
Maybe is this because of the char-set ?
Does someone know why ? Here is my code :
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <winsock2.h>
int main()
{
char pseudo[] = "kekos91;192.168.1.141:25565";
int pseudoLen = strlen(pseudo);
char *packet = NULL;
packet = (char*)malloc(3 + ((pseudoLen)*sizeof(char)*2));
if(packet == NULL)
{
return -1;
}
memset(packet, '\0', sizeof(packet));
packet[0] = (char)0x02;
strcat(packet, pseudo);
int pLenght = strlen(packet);
char handshake[200];
HANDLE hConsole;
WSADATA wsaData;
int iResult = 0;
SOCKET serverSocket;
sockaddr_in serverInfos;
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != NO_ERROR) {
printf("WSAStartup() failed with error: %d\n", iResult);
return -1;
}
serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serverSocket == INVALID_SOCKET) {
printf("socket function failed with error: %i\n", WSAGetLastError());
WSACleanup();
return -1;
}
printf("socket created\n");
serverInfos.sin_family = AF_INET;
serverInfos.sin_addr.s_addr = inet_addr("192.168.1.141");
serverInfos.sin_port = htons(25565);
iResult = connect(serverSocket, (SOCKADDR *)&serverInfos, sizeof(serverInfos));
if (iResult == SOCKET_ERROR)
{
printf("connect function failed with error: %i\n", WSAGetLastError());
iResult = closesocket(serverSocket);
if (iResult == SOCKET_ERROR)
{
printf("closesocket function failed with error: %i\n", WSAGetLastError());
}
WSACleanup();
return -1;
}
printf("socket connected\n");
printf("to send data = %s\n", packet);
printf("to send length = %i\n", pseudoLen);
Sleep(500); // after this point, the connection is loose :(
if(send(serverSocket, (char*)packet , pLenght, 0) == SOCKET_ERROR)
{
printf("send function failed with error: %i\n", WSAGetLastError());
iResult = closesocket(serverSocket);
if (iResult == SOCKET_ERROR)
{
printf("closesocket function failed with error: %i\n", WSAGetLastError());
}
WSACleanup();
return -1;
}
free(packet);
printf("send !\n");
if(recv(serverSocket, (char*)&handshake, 200, 0) == SOCKET_ERROR)
{
printf("recv function failed with error: %i\n", WSAGetLastError());
iResult = closesocket(serverSocket);
if (iResult == SOCKET_ERROR)
{
printf("closesocket function failed with error: %i\n", WSAGetLastError());
}
WSACleanup();
return -1;
}
printf("response data = %s\n", handshake);
printf("response length = %i\n", strlen(handshake));
iResult = closesocket(serverSocket);
if (iResult == SOCKET_ERROR) {
printf("closesocket function failed with error %i\n", WSAGetLastError());
WSACleanup();
return -1;
}
printf("socket disconnected.\n");
WSACleanup();
Sleep(5000);
return 0;
}
Thanks in advance, and please excuse my bad English 🙂
UPDATE :
Thanks to constructive comments, everything works perfectly now.
Here is the working code for you to see what was going on my old code.
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <winsock2.h>
int main()
{
int iSocketResult = 0; // it will retrieve sockets return functions, like send / recv / errors
wchar_t wcPseudo[] = L"kekos91;192.168.1.141:25565";
int iPseudoLen = wcslen(wcPseudo);
char *pPacket = NULL;
pPacket = (char*)malloc(3 + ((iPseudoLen)*sizeof(char)*2));
if(pPacket == NULL)
{
return -1;
}
pPacket[0] = 0x02;
*(short*)( pPacket + 1 ) = htons( iPseudoLen );
memcpy( pPacket + 3, wcPseudo, iPseudoLen * sizeof( wchar_t ));
int iPacketLen = 3 + iPseudoLen*sizeof(wchar_t) ;
char *handshake = NULL;
handshake = (char*)malloc(sizeof(char)*200);
if(handshake == NULL)
{
return -1;
}
HANDLE hConsole;
WSADATA wsaData;
SOCKET serverSocket;
sockaddr_in serverInfos;
iSocketResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iSocketResult != NO_ERROR) {
printf("WSAStartup() failed with error: %d\n", iSocketResult);
return -1;
}
serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serverSocket == INVALID_SOCKET) {
printf("socket function failed with error: %i\n", WSAGetLastError());
WSACleanup();
return -1;
}
printf("socket created\n");
serverInfos.sin_family = AF_INET;
serverInfos.sin_addr.s_addr = inet_addr("192.168.1.141");
serverInfos.sin_port = htons(25565);
iSocketResult = connect(serverSocket, (SOCKADDR *)&serverInfos, sizeof(serverInfos));
if (iSocketResult == SOCKET_ERROR)
{
printf("connect function failed with error: %i\n", WSAGetLastError());
iSocketResult = closesocket(serverSocket);
if (iSocketResult == SOCKET_ERROR)
{
printf("closesocket function failed with error: %i\n", WSAGetLastError());
}
WSACleanup();
return -1;
}
printf("socket connected\n\n");
printf("to send protocol = %#1.2x \nlenght = %i\n", pPacket[0], iPseudoLen);
iSocketResult = send(serverSocket, pPacket , iPacketLen, 0);
if(iSocketResult == SOCKET_ERROR)
{
printf("send function failed with error: %i\n", WSAGetLastError());
iSocketResult = closesocket(serverSocket);
if (iSocketResult == SOCKET_ERROR)
{
printf("closesocket function failed with error: %i\n", WSAGetLastError());
}
WSACleanup();
return -1;
}
free(pPacket);
printf("send %i (bytes) !\n\n",iSocketResult);
iSocketResult = recv(serverSocket, handshake, 50, 0);
if( iSocketResult == SOCKET_ERROR)
{
printf("recv function failed with error: %i\n", WSAGetLastError());
iSocketResult = closesocket(serverSocket);
if (iSocketResult == SOCKET_ERROR)
{
printf("closesocket function failed with error: %i\n", WSAGetLastError());
}
WSACleanup();
return -1;
}
printf("response protocol = %#1.2x\nresponse lenght = %i (bytes)\n\n", handshake[0], iSocketResult);
free(handshake);
iSocketResult = closesocket(serverSocket);
if (iSocketResult == SOCKET_ERROR)
{
printf("closesocket function failed with error %i\n", WSAGetLastError());
WSACleanup();
return -1;
}
printf("socket disconnected.\n");
WSACleanup();
Sleep(7000);
return 0;
}
The output console now prints :
socket created
socket connected
to send protocol = 0x02
lenght = 27
send 57 (bytes) !
response protocol = 0x02
response lenght = 37 (bytes)
socket disconnected.
Thanks to you all !
In general, what you are doing appears to be correct. I would imagine that the “connection lost” message from the server happens when your test code closes its own socket. However, it looks like you are not handling the string data type correctly. The string needs to be sent as Unicode, and it appears that you are sending it as single-byte characters. Also, string needs to be preceded by the length represented as a 2 byte integer.
The handshake string should maybe instead be specified as follows with wchar_t (or your favorite wide character data type). And use an
Lon the literal to specify a wide string. The actual send length in bytes needs to be sure to multiply the string length by 2.wchar_t pseudo[] = L”kekos91;192.168.1.141:25565″;
int pseudoLen = wcslen(pseudo);
Then, likewise, use a wide string function to copy the string (strcat won’t work).
To put the string length in the two bytes after the 0x02 protocol code, you might do this:
To copy the string into the packet, maybe this (I’m writing this on the fly without compiling:
The actual send length in bytes would be:
3 + pseudoLen * sizeof( wchar_t )When printing the resulting response, something like this might be what you want:
And then extract the string (the two bytes following the protocol byte should be the length of the connection hash string (in network byte order). So you would need to use
ntohsto extract it. And then the following N wide characters would represent the hash.Having written all that, it seems to me that you might want to look for a library to deal with all the protocols. I have not looked, but it seems likely that there is some Minecraft-related sockets library for C available. Just a wild guess. Edit On second thought, it depends on your goals. If you are simply wanting to build a client as fast as possible, then it definitely makes sense to look for a library. If, however, you are wanting to learn the details of the protocol, network programming, etc. then writing it at the level you started with is a good idea and would be a lot of fun since you can make incremental steps that show real results quite often.
One other thing. The
memsetafter allocating the memory might not be doing what you expect. Assuming a 32-bit architecture, thesizeof( packet )will be 4 (it’s a 4 byte pointer). However, since you will be filling the packet in with the data, the memset isn’t really necessary.