The online racing simulator
Problem getting InSim TCP+UDP to work [solved]
I've come to a wall that I don't understand

This morning I tried using full UDP InSim just changing the "stream socket" I was using to a "datagram socket". It worked (surprisingly).

Now I'm preparing my library to work with a main TCP connection and UDP connection for NLP & MCI packets.

This is the construction of the IS_ISI packet:
struct IS_ISI isi_p;
memset(&isi_p, 0, sizeof(struct IS_ISI));
isi_p.Size = sizeof(struct IS_ISI);
isi_p.Type = ISP_ISI;

if (pack_ver != NULL) // We request an ISP_VER if the caller asks for it
isi_p.ReqI = 1;

isi_p.Prefix = prefix;
isi_p.UDPPort = udpport; // <-- 29999
isi_p.Flags = flags; // <-- ISF_MCI
isi_p.Interval = interval; // <-- 1000
memcpy(isi_p.IName, product, sizeof(isi_p.IName)-1);
memcpy(isi_p.Admin, admin, 16);

And this is a summary of the server log (only the interesting part):
A new guest is connecting
Sent guest list to new guest
Sent new user packet
[Q3] makakazo^L connected (makakazo^L)
InSim - TCP : X-Y-Z Pos (UDP port 29999)
InSim : packet received before ISI packet
InSim : packet received before ISI packet
InSim : packet received before ISI packet
InSim : packet received before ISI packet
[Q3] makakazo^L joined the spectators
[Q3] makakazo : ^L!exit
InSim guest closed : X-Y-Z Pos

The thing is... the IS_ISI packet HAS been sent and the application is connected to InSim: " InSim - TCP : X-Y-Z Pos (UDP port 29999)". I even have some buttons in screen.

When I get to the track I'm supposed to receive MCI packets every one second, but what I get instead is that " InSim : packet received before ISI packet" in the dedi server console (every one second). What does this mean? I'm not sending any packet, but I'm just trying to receive the MCI ones. Do anyone know what is happening?
More data:

I had something wrong with the ports. I was using the same port for sending and receiving UDP packets. As the dedicated server is in the same machine than the client I'm testing this was causing conflicts.

Anyway, after selecting different ports I still don't get the UDP packets.

I'm connecting to:
localhost
29999

I use that port to create both TCP and UDP sockets, as the server uses the same port for receiving/sending all data.

Now, I've chosen port 60000 as "udpport" to which insim will be sending UDP packets. I define this in the IS_ISI packet.

After sending the IS_ISI packet the application connects to InSim. Message by server when connecting:
"InSim - TCP : X-Y-Z Pos (UDP port 60000)"

But when I enter the track and MCI packets are supposed to start being sent the dedi server console says "InSim - UDP : no slots available". This is different from the previous message "InSim : packet received before ISI packet", but still I get the same result. I got rid of the old "InSim : packet received before ISI packet" message when I picked different ports for UDP sending and receiving.

Aside from creating the UDP socket, connecting it (I use a connected datagram socket, but connecting this socket only stores adrress and port info, it performs no sending/receiving) and sending the IS_ISI packet I do nothing at all with UDP, just watch the dedi server console throwing errors.

Plesae I really need help on this
I think you have to send the ISI packet to the UDP port for LFS to accept it as an open connection. It's not as simple as simply setting it up in the TCP side, the LFS host also needs to know the UDP port is active.


Start LFS Server & allow InSim connections.
Start InSim program.
Set TCP listen & send port.
Set UDP listen & send port.
Send TCP ISI to establish connection with UDP Port information.
Send UDP ISI to establish connection with this port for MCI & NPL packets.

Quote from Dygear :I think you have to send the ISI packet to the UDP port for LFS to accept it as an open connection. It's not as simple as simply setting it up in the TCP side, the LFS host also needs to know the UDP port is active.


Start LFS Server & allow InSim connections.
Start InSim program.
Set TCP listen & send port.
Set UDP listen & send port.
Send TCP ISI to establish connection with UDP Port information.
Send UDP ISI to establish connection with this port for MCI & NPL packets.


I already tried that when I was getting the "packet received before ISI" message, and what it did was generate double messages "packet received before ISI". I think my application opened a TCP+UDP connection and a pure UDP connection, so all the messages generated by UDP errors were generated twice.

Anyway, that was when I was using the same port for sending and receiving, so I'll try that again now that I use different ports and we'll see what happens

Thanks for the help


EDIT: Thinking about it, it doesn't make sense to do what you have suggested. Let's check the workings of all this!
  • LFS servers use the same port for receiving and sending both TCP and UDP packets. Let's say we set in the server config "/insim 29999". That is the only port that will be used in the server side (along with the port for player connections, let's say 63395 for example).
  • The client application can use TCP, UDP or TCP&UDP. For the TCP or UDP full connections we don't choose any port, it will be assigned randomly when we start the communication to the server by sending the IS_ISI packet (it doesn't matter if we are using TCP or UDP).
  • When we use TCP&UDP (TCP for all but NLP and MCI, and UDP for just NLP and MCI), we don't have to choose a TCP port because we are the ones that start the communication, BUT we have to tell the server what UDP port it has to use when sending us NLP and MCI packets. Why? Because we are not going to start any UDP communication, we are just going to listen on that specific port for incoming UDP packets. So, we must make sure that UDP port is reachable from the server.
So, it doesn't make sense to try and open an UDP connection when you are specifying a listening port.

Anyway, I tried it again and as I expected got double the "InSim - UDP : no slots available" messages as before
Quote from MaKaKaZo :So, it doesn't make sense to try and open an UDP connection when you are specifying a listening port.

What packets are you sending down the pipe then for the UDP and TCP packet types? Could you also provide time stamps for these packets ...


TCP:
ISI, 0.0001, Sent
VER, 0.0010, Sent
VER, 0.0250, Recv
STA, 0.0267, Sent
STA, 0.0326, Recv

UDP:
ISI, 0.0005, Sent
MCI, 0.0100, Recv
MCI, 0.0200, Recv
MCI, 0.0300, Recv
MCI, 0.0400, Recv
MCI, 0.0500, Recv

Ok, here are some logs. I'll tell first the procedure I'm following:
  • Start the dedicated server.
  • Start the insim application (this starts the connection to insim).
  • Connect a player to the server.
  • Add the player to the grid and the race starts.
  • MCI packets should start arriving by now.
  • Vote race to end.
  • After voting is complete type "!exit" to quit the insim application.
  • Close the dedicated server.
I hace repeated this procedure using:


FULL TCP
(MCI packets requested every one second via TCP)

Application log:
TCP, ISP_ISI, 0.046, send <-- InSim Initialization (ReqI != 0)
TCP, ISP_VER, 0.093, recv <-- IS_VER requested within IS_ISI
TCP, ISP_TINY, 0.109, send <-- TINY_NCN, asking for all connections
TCP, ISP_TINY, 0.109, send <-- TINY_NPL, asking for all players in grid
TCP, ISP_NCN, 0.125, recv <-- Reply to previous TINY_NCN (host is connected)
TCP, ISP_MSO, 8.578, recv <-- Text ("new guest connecting")
TCP, ISP_MSO, 9.062, recv <-- Text ("makakazo connected")
TCP, ISP_NCN, 9.062, recv <-- New player connected
TCP, ISP_MTC, 9.062, send <-- Welcome message to new player
TCP, ISP_BTN, 9.062, send <-- Buttons for X, Y, Z coordinates (this is the purpose of this example application)
TCP, ISP_BTN, 9.062, send
TCP, ISP_BTN, 9.062, send
TCP, ISP_STA, 9.109, recv <-- Race state
TCP, ISP_STA, 13.25, recv
TCP, ISP_NPL, 13.625, recv <-- Player added to grid
TCP, ISP_REO, 14.765, recv <-- Race restarting
TCP, ISP_RST, 14.765, recv <-- Race restarting
TCP, ISP_STA, 14.781, recv <-- Race state
TCP, ISP_MCI, 15.984, recv <-- MCI packets every one second
TCP, ISP_MCI, 16.984, recv
TCP, ISP_MCI, 17.984, recv
TCP, ISP_MCI, 18.984, recv
TCP, ISP_MCI, 19.984, recv
TCP, ISP_MCI, 20.984, recv
TCP, ISP_VTN, 21.89, recv <-- Player votes to end race
TCP, ISP_MSO, 21.906, recv
TCP, ISP_SMALL, 21.906, recv
TCP, ISP_MCI, 21.984, recv
TCP, ISP_MCI, 22.984, recv
TCP, ISP_MCI, 23.968, recv
TCP, ISP_TINY, 24.875, recv
TCP, ISP_TINY, 24.89, recv
TCP, ISP_STA, 24.921, recv
TCP, ISP_TINY, 30.093, recv
TCP, ISP_TINY, 30.093, send <-- Probably keepalive packet
TCP, ISP_MSO, 34.234, recv
TCP, ISP_MST, 34.234, send <-- "!exit"

Dedicated server log:
LFS DEDICATED HOST : 0.5Z
?
?
?
?
?
?
?
?
?
?
?
?
load bans
load font
-----
create english file
initialisations
tables
load objects
start intro
Aston
end of initialisation
Track loaded
Handicaps :
InSim - TCP : X-Y-Z Pos
Host Auth : 10.0.0.8
Send Track : 10.0.0.8
Alive : 10.0.0.8
Connecting guest still alive
Send Track : 10.0.0.8
Connect : 10.0.0.8
Sent OK to new guest
Sent scrutineering packet
Told guests about new guest
A new guest is connecting
Sent guest list to new guest
Sent new user packet
[Q3] makakazo^L connected (makakazo^L)
[Q3] makakazo^L voted to END RACE
Exit : clean up
Exit : delete
[Q3] makakazo : ^L!exit
InSim guest closed : X-Y-Z Pos
shutting down
free objects
free languages
free humans
free font
free host list
kill graphics
save config
free mouse
EXIT

FULL UDP
(MCI packets requested every one second via UDP using the same port as the rest of the packets)

Application log:
UDP, ISP_ISI, 0.015, send
UDP, ISP_VER, 0.046, recv
UDP, ISP_TINY, 0.046, send
UDP, ISP_TINY, 0.046, send
UDP, ISP_NCN, 0.078, recv
UDP, ISP_MSO, 6.671, recv
UDP, ISP_MSO, 7.203, recv
UDP, ISP_NCN, 7.203, recv
UDP, ISP_MTC, 7.218, send
UDP, ISP_BTN, 7.218, send
UDP, ISP_BTN, 7.218, send
UDP, ISP_BTN, 7.218, send
UDP, ISP_STA, 7.265, recv
UDP, ISP_STA, 9.312, recv
UDP, ISP_NPL, 9.343, recv
UDP, ISP_REO, 11.375, recv
UDP, ISP_RST, 11.375, recv
UDP, ISP_STA, 11.375, recv
UDP, ISP_MCI, 12.578, recv
UDP, ISP_MCI, 13.578, recv
UDP, ISP_MCI, 14.593, recv
UDP, ISP_MCI, 15.593, recv
UDP, ISP_VTN, 15.75, recv
UDP, ISP_MSO, 15.75, recv
UDP, ISP_SMALL, 15.75, recv
UDP, ISP_MCI, 16.593, recv
UDP, ISP_MCI, 17.578, recv
UDP, ISP_MCI, 18.593, recv
UDP, ISP_TINY, 18.734, recv
UDP, ISP_TINY, 18.765, recv
UDP, ISP_STA, 18.781, recv
UDP, ISP_MSO, 22.718, recv
UDP, ISP_MST, 22.734, send

Dedicated server log:
LFS DEDICATED HOST : 0.5Z
?
?
?
?
?
?
?
?
?
?
?
?
load bans
load font
-----
create english file
initialisations
tables
load objects
start intro
Aston
end of initialisation
Track loaded
Handicaps :
InSim - UDP : X-Y-Z Pos
Host Auth : 10.0.0.8
Send Track : 10.0.0.8
Connect : 10.0.0.8
Sent OK to new guest
Sent scrutineering packet
Told guests about new guest
A new guest is connecting
Sent guest list to new guest
Sent new user packet
[Q3] makakazo^L connected (makakazo^L)
[Q3] makakazo^L voted to END RACE
Exit : clean up
Exit : delete
[Q3] makakazo : ^L!exit
host : ^L* Closing application (requested by admin) *
InSim : unknown packet (80 bytes) - X-Y-Z Pos
InSim - UDP : no slots available
InSim - UDP : no slots available
InSim - UDP : no slots available
InSim - UDP : no slots available
InSim timeout : X-Y-Z Pos
shutting down
free objects
free languages
free humans
free font
free host list
kill graphics
save config
free mouse
EXIT

TCP+UDP
(Main connections uses TCP, but MCI packets are requested every one second via UDP using a specific port)

Application log:
TCP, ISP_ISI, 0.031, send
TCP, ISP_VER, 0.031, recv
TCP, ISP_TINY, 0.031, send
TCP, ISP_TINY, 0.031, send
TCP, ISP_NCN, 0.062, recv
TCP, ISP_MSO, 4.484, recv
TCP, ISP_MSO, 4.984, recv
TCP, ISP_NCN, 4.984, recv
TCP, ISP_MTC, 4.984, send
TCP, ISP_BTN, 4.984, send
TCP, ISP_BTN, 4.984, send
TCP, ISP_BTN, 4.984, send
TCP, ISP_STA, 5.046, recv
TCP, ISP_STA, 6.593, recv
TCP, ISP_NPL, 6.64, recv
TCP, ISP_REO, 9.171, recv <-- Race restarting
TCP, ISP_RST, 9.171, recv <-- Race restarting
TCP, ISP_STA, 9.187, recv <-- Race state
TCP, ISP_VTN, 14.953, recv <-- Player votes to end race
TCP, ISP_MSO, 14.968, recv
TCP, ISP_SMALL, 14.968, recv
TCP, ISP_TINY, 17.937, recv
TCP, ISP_TINY, 17.968, recv
TCP, ISP_STA, 18, recv
TCP, ISP_MSO, 21.125, recv
TCP, ISP_MST, 21.125, send

Dedicated server log:
LFS DEDICATED HOST : 0.5Z
?
?
?
?
?
?
?
?
?
?
?
?
load bans
load font
-----
create english file
initialisations
tables
load objects
start intro
Aston
end of initialisation
Track loaded
Handicaps :
InSim - TCP : X-Y-Z Pos (UDP port 60000)
Host Auth : 10.0.0.8
Send Track : 10.0.0.8
Connect : 10.0.0.8
Sent OK to new guest
Sent scrutineering packet
Told guests about new guest
A new guest is connecting
Sent guest list to new guest
Sent new user packet
[Q3] makakazo^L connected (makakazo^L)
InSim - UDP : no slots available
InSim - UDP : no slots available
InSim - UDP : no slots available
InSim - UDP : no slots available
InSim - UDP : no slots available
[Q3] makakazo^L voted to END RACE
InSim - UDP : no slots available
InSim - UDP : no slots available
InSim - UDP : no slots available
Exit : clean up
Exit : delete
[Q3] makakazo : ^L!exit
InSim guest closed : X-Y-Z Pos
shutting down
free objects
free languages
free humans
free font
free host list
kill graphics
save config
free mouse
EXIT

As you can see, when I'm using full TCP or full UDP the MCI packets are sent.

When using UDP I get a final last message "InSim : unknown packet (80 bytes) - X-Y-Z Pos" that I'm not sure what is causing it. The rest of "InSim - UDP : no slots available" arrive when I have already closed the application, they last for a while until LFS decides that it's been too long not receiving any UDP pakcet and closes the UDP connection due to a timeout.

When using TCP+UDP the main packets all arrive, but when MCI should start arriving the server says that "InSim - UDP : no slots available". This message stops when the vote to end race finishes and the player goes back to the main race config screen. In this screen no MCI packets are sent so there's no problem. With this method it looks like the server tries to send the MCI packets but for some reason it can't and delivers that message "no slots available".

I really don't know what is going on!
Now that I'm not getting any help I'm wondering if anyone is currently using this TCP+UDP feature in InSim4 or everyone is just using full TCP for main and NLP/MCI packets in their applications.

Based on all the tests I've done I've come to the conclussion that the problem is in the InSim interface/reference or the server code, but not in my code. Let aside grabbing the UDP packets, it just seems like the server won't send the packets at all.

So, is someone currently using TCP+UDP???
The current version of LFS External works with TCP and UDP. The source code is not yet available though.
After some more testing, sniffing and stuff I've checked that the UDP packets are actually being sent, at least when I connect to a remote server.

My problem right now looks evident: the "select()" call for the UDP socket is not working. It times out and does not receive anything at all as it should (as I've checked that the info is being sent).


If I use only ony socket everything goes fine, but when I set up a second socket (in this case for the UDP packets) it won't receive anything.

I'm using two independent select() calls, one for each socket, and I don't know if that may be causing all the trouble. I'll post some code now.


This is the class delcaration:

#define PACKET_BUFFER_SIZE 512
#define PACKET_MAX_SIZE 512
#define IS_TIMEOUT 5

// Definition for our buffer datatype
struct buffer
{
char buffer[PACKET_BUFFER_SIZE]; // Packet buffer - 512 should be more than enough
unsigned int bytes; // Number of bytes currently in buffer
};

/**
* CInsim class to manage the Insim connection and processing of the packets
*/
class CInsim
{
private:
SOCKET sock; // TCP Socket (most packets)
SOCKET sockudp; // UDP Socket (if requested, for NLP and MCI)
byte using_udp; // 1 if we are using UDP for NLP or MCI packets
struct buffer gbuf; // Our global buffer
struct buffer lbuf; // Our local buffer
char packet[PACKET_MAX_SIZE]; // A buffer where the current packet is stored
fd_set readfd, exceptfd; // File descriptor watches
struct timeval select_timeout; // timeval struct for the select() call
struct buffer udp_gbuf; // (for NLP and MCI packets via UDP) Our global buffer
struct buffer udp_lbuf; // (for NLP and MCI packets via UDP) Our local buffer
char udp_packet[PACKET_MAX_SIZE]; // (for NLP and MCI packets via UDP) A buffer where the current packet is stored
fd_set udp_readfd, udp_exceptfd; // (for NLP and MCI packets via UDP) File descriptor watches
struct timeval udp_select_timeout; // (for NLP and MCI packets via UDP) timeval struct for the select() call
ofstream logfile;

public:
CInsim::CInsim(); // Constructor
// "int init(...)" Establishes connection with the socket and insim.
//+ The last argument ch_ver is a pointer to a IS_VER struct. If it's used an IS_VER packet
//+ will be returned. If ch_ver is not used in the call no IS_VER will be requested/returned.
int init (char *addr, word port, char *product, char *admin, struct IS_VER *pack_ver = NULL, byte prefix = 0, word flags = 0, word interval = 0, word udpport = 0);
int isclose(); // Closes connection from insim and from the socket
int next_packet(); // Gets next packet ready into "char packet[]"
char peek_packet(); // Returns the type of the current packet
void* get_packet(); // Returns a pointer to the current packet. Must be casted
int send_packet(void* packet); // Sends a packet to the host
int udp_next_packet(); // (UDP) Gets next packet ready into "char udp_packet[]"
char udp_peek_packet(); // (UDP) Returns the type of the current packet
void* udp_get_packet(); // (UDP) Returns a pointer to the current packet. Must be casted
int udp_send_packet(void* packet); // (UDP) Sends a packet to the host
};

This is the code used for establishing/connecting the two sockets and the connection to InSim:
(any var used not defined here is because it's a private member)

/**
* Initialize the socket and the Insim connection
* If "struct IS_VER *pack_ver" is set it will contain an IS_VER packet after returning. It's an optional argument
*/
int CInsim::init (char *addr, word port, char *product, char *admin, struct IS_VER *pack_ver, byte prefix, word flags, word interval, word udpport)
{
// Initialise WinSock
// Only required on Windows
WSADATA wsadata;

if (WSAStartup(0x202, &wsadata) == SOCKET_ERROR)
{
WSACleanup();
return -1;
}

// Create the TCP socket - this defines the type of socket
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

// Could we get the socket handle? If not the OS might be too busy or have run out of available socket descriptors
if (sock == INVALID_SOCKET)
{
closesocket(sock);
WSACleanup();
return -1;
}

// Resolve the IP address
struct sockaddr_in saddr;
memset(&saddr, 0, sizeof(saddr));

saddr.sin_family = AF_INET;

struct hostent *hp;
hp = gethostbyname(addr);

if (hp != NULL)
saddr.sin_addr.s_addr = *((unsigned long*)hp->h_addr);
else
saddr.sin_addr.s_addr = inet_addr(addr);

// Set the port number in the socket structure - we convert it from host byte order, to network
saddr.sin_port = htons(port);

// Now the socket address structure is full, lets try to connect
if (connect(sock, (struct sockaddr *) &saddr, sizeof(saddr)) < 0)
{
closesocket(sock);
WSACleanup();
return -1;
}

// If the user asked for NLP or MCI packets and defined an udpport
if ((udpport) && (flags >= ISF_NLP))
{
// Create the UDP socket - this defines the type of socket
sockudp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

// Could we get the socket handle? If not the OS might be too busy or have run out of available socket descriptors
if (sockudp == INVALID_SOCKET)
{
closesocket(sock);
closesocket(sockudp);
WSACleanup();
return -1;
}

// Resolve the IP address
struct sockaddr_in udp_saddr;
memset(&udp_saddr, 0, sizeof(udp_saddr));

udp_saddr.sin_family = AF_INET;

struct hostent *udp_hp;
udp_hp = gethostbyname(addr);

if (udp_hp != NULL)
udp_saddr.sin_addr.s_addr = *((unsigned long*)udp_hp->h_addr);
else
udp_saddr.sin_addr.s_addr = inet_addr(addr);

// Set the UDP port number in the UDP socket structure - we convert it from host byte order, to network
udp_saddr.sin_port = htons(port);

// Connect the UDP using the same address as in the TCP socket
if (connect(sockudp, (struct sockaddr *) &udp_saddr, sizeof(udp_saddr)) < 0)
{
closesocket(sock);
closesocket(sockudp);
WSACleanup();
return -1;
}

// We are using UDP!
using_udp = 1;
}

// Ok, so we're connected. First we need to let LFS know we're here by sending the IS_ISI packet
struct IS_ISI isi_p;
memset(&isi_p, 0, sizeof(struct IS_ISI));
isi_p.Size = sizeof(struct IS_ISI);
isi_p.Type = ISP_ISI;

if (pack_ver != NULL) // We request an ISP_VER if the caller asks for it
isi_p.ReqI = 1;

isi_p.Prefix = prefix;
isi_p.UDPPort = udpport;
isi_p.Flags = flags;
isi_p.Interval = interval;
memcpy(isi_p.IName, product, sizeof(isi_p.IName)-1);
memcpy(isi_p.Admin, admin, 16);

// Send the initialization packet
if(send_packet(&isi_p) < 0)
{
if (using_udp)
closesocket(sockudp);

closesocket(sock);
WSACleanup();
return -1;
}

// If an IS_VER packet was requested
if (pack_ver != NULL)
{
if (next_packet() < 0) // Get next packet, supposed to be an IS_VER
{
if (isclose() < 0)
{
if (using_udp)
closesocket(sockudp);

closesocket(sock);
WSACleanup();
return -1;
}
return -1;
}

switch (peek_packet()) // Check if the packet returned was an IS_VER
{
case ISP_VER: // It was, get it!
memcpy(pack_ver, (struct IS_VER*)get_packet(), sizeof(struct IS_VER));
break;
default: // It wasn't, something went wrong. Quit
if (isclose() < 0)
{
if (using_udp)
closesocket(sockudp);

closesocket(sock);
WSACleanup();
}
return -1;
}
}

return 0;
}

Here's the code for retrieving TCP packets. This seems to work fine in all cases:

/**
* Get next packet ready
* This function also keeps the connection alive as long as you keep calling it
*/
int CInsim::next_packet()
{
unsigned char oldp_size, p_size;
bool alive = true;

while (alive) // Keep the connection alive!
{
alive = false;
oldp_size = (unsigned char)*lbuf.buffer;

if ((lbuf.bytes > 0) && (lbuf.bytes >= oldp_size)) // There's an old packet in the local buffer, skip it
{
// Copy the leftovers from local buffer to global buffer
memcpy(gbuf.buffer, lbuf.buffer+oldp_size, lbuf.bytes-oldp_size);
gbuf.bytes = lbuf.bytes - oldp_size;

// Copy from global buffer back to the beginning of local buffer
memset(lbuf.buffer, 0, PACKET_BUFFER_SIZE);
memcpy(lbuf.buffer, gbuf.buffer, gbuf.bytes);
lbuf.bytes = gbuf.bytes;
}

p_size = (unsigned char)*lbuf.buffer;

while ((lbuf.bytes < p_size) || (lbuf.bytes < 1)) // Read until we have a full packet
{
// Set the timeout period
select_timeout.tv_sec = IS_TIMEOUT;
select_timeout.tv_usec = 0;

// Clear them
FD_ZERO(&readfd);
FD_ZERO(&exceptfd);

// Set them to watch our socket for data to read and exceptions that maybe thrown
FD_SET(sock, &readfd);
FD_SET(sock, &exceptfd);

int rc = select(sock + 1, &readfd, NULL, &exceptfd, &select_timeout);

if (rc == 0) // Timeout
continue;

if (rc < 0) // An error occured
return -1;

if (FD_ISSET(sock, &readfd)) // We got data!
{
// Recieve any waiting bytes
int retval = recv(sock, lbuf.buffer + lbuf.bytes, PACKET_BUFFER_SIZE - lbuf.bytes, 0);

// Deal with the results
if (retval == 0) // Connection has been closed at the other end
return -2;

if (retval < 0) // An error ocurred
return -1;

p_size = *lbuf.buffer;
lbuf.bytes += retval;
}
else if (FD_ISSET(sock, &exceptfd)) // An exception occured - we want to quit
return -1;
}

memset(packet, 0, PACKET_MAX_SIZE);
memcpy(packet, lbuf.buffer, p_size);

logfile << "UDP, ISP_" << (int)peek_packet() << ", " << (float)clock()/CLOCKS_PER_SEC << ", recv" << endl;

if ((peek_packet() == ISP_TINY) && (*(packet+3) == TINY_NONE))
{
alive = true;

struct IS_TINY keepalive;
keepalive.Size = sizeof(struct IS_TINY);
keepalive.Type = ISP_TINY;
keepalive.ReqI = 0;
keepalive.SubT = TINY_NONE;

// Send it back
if (send_packet(&keepalive) < 0)
return -1;
}
}

return 0;
}

And here's the code for retrieving UDP packets. This is the function that is giving me problems:

/**
* Get next UDP packet ready
*/
int CInsim::udp_next_packet()
{
unsigned char oldp_size, p_size;

oldp_size = (unsigned char)*udp_lbuf.buffer;

if ((udp_lbuf.bytes > 0) && (udp_lbuf.bytes >= oldp_size)) // There's an old packet in the local buffer, skip it
{
// Copy the leftovers from local buffer to global buffer
memcpy(udp_gbuf.buffer, udp_lbuf.buffer+oldp_size, udp_lbuf.bytes-oldp_size);
udp_gbuf.bytes = udp_lbuf.bytes - oldp_size;

// Copy from global buffer back to the beginning of local buffer
memset(udp_lbuf.buffer, 0, PACKET_BUFFER_SIZE);
memcpy(udp_lbuf.buffer, udp_gbuf.buffer, udp_gbuf.bytes);
udp_lbuf.bytes = udp_gbuf.bytes;
}

p_size = (unsigned char)*udp_lbuf.buffer;

while ((udp_lbuf.bytes == 0) || (udp_lbuf.bytes < p_size)) // Read until we have a full packet
{
// Set the timeout period
udp_select_timeout.tv_sec = IS_TIMEOUT;
udp_select_timeout.tv_usec = 0;

// Clear them
FD_ZERO(&udp_readfd);
FD_ZERO(&udp_exceptfd);

// Set them to watch our socket for data to read and exceptions that maybe thrown
FD_SET(sockudp, &udp_readfd);
FD_SET(sockudp, &udp_exceptfd);

int rc = select(sockudp + 1, &udp_readfd, NULL, &udp_exceptfd, &udp_select_timeout);

if (rc == 0) // Timeout
continue;

if (rc < 0) // An error occured
return -1;

if (FD_ISSET(sockudp, &udp_readfd)) // We got data!
{
// Recieve any waiting bytes
int retval = recv(sockudp, udp_lbuf.buffer + udp_lbuf.bytes, PACKET_BUFFER_SIZE - udp_lbuf.bytes, 0);

// Deal with the results
if (retval < 0) // An error ocurred
{
return -1;
}

p_size = *udp_lbuf.buffer;
udp_lbuf.bytes += retval;
}
else if (FD_ISSET(sockudp, &udp_exceptfd)) // An exception occured - we want to quit
return -1;
}

memset(udp_packet, 0, PACKET_MAX_SIZE);
memcpy(udp_packet, udp_lbuf.buffer, p_size);

logfile << "UDP, ISP_" << (int)udp_peek_packet() << ", " << (float)clock()/CLOCKS_PER_SEC << ", recv" << endl;

return 0;
}

I'm not sure if I'm doing something wrong with the sockets. If anyone is willing to check the code to help me I can provide tha full example and library code, executables, dlls and whatever you might want to give it a try.
UDP is sent a packet at a time, so unlike TCP (which is a stream) you don't have to worry about having partial packets, and having to have a global buffer, etc.
Quote from the_angry_angel :UDP is sent a packet at a time, so unlike TCP (which is a stream) you don't have to worry about having partial packets, and having to have a global buffer, etc.

Totally right, hadn't thought about that. BUT, now that I think about it... if there's more than 8 people driving then multiple IS_MCI packets are sent "at the same time". That would cause problems, wouldn't it?
Each time you call recv, under UDP, you will only get a single packet, so if you get 8 at once it'll take 8 recv calls before you get them all - depending on how you process them will depend on what consequences that has, obviously
InSim.txt Patch Z
struct IS_MCI // Multi Car Info - if more than 8 in race then more than one of these is sent
{
byte Size; // [b]4 + [u]NumP[/u] * 28[/b]
byte Type; // ISP_MCI
byte ReqI; // 0 unless this is a reply to an TINY_MCI request
byte NumC; // number of valid CompCar structs in this packet

CompCar Info[8]; // car info for each player, 1 to 8 of these (NumC)
};

I am guessing that's an error, meant to say NumC. But, with the MCI packets by them selves there is no way to find the amount of players in the race just by using the MCI packet. The only information it will give is the number of CompCar structs in the packet. So you will not know if you still have more coming. (Unless the number is less then eight of course, then that's the last packet, for the sequence.)
Quote from Dygear :InSim.txt Patch Z
struct IS_MCI // Multi Car Info - if more than 8 in race then more than one of these is sent
{
byte Size; // [B]4 + [U]NumP[/U] * 28[/B]
byte Type; // ISP_MCI
byte ReqI; // 0 unless this is a reply to an TINY_MCI request
byte NumC; // number of valid CompCar structs in this packet

CompCar Info[8]; // car info for each player, 1 to 8 of these (NumC)
};

I am guessing that's an error, meant to say NumC. But, with the MCI packets by them selves there is no way to find the amount of players in the race just by using the MCI packet. The only information it will give is the number of CompCar structs in the packet. So you will not know if you still have more coming. (Unless the number is less then eight of course, then that's the last packet, for the sequence.)

That's an interesting point. I haven't checked, but if it's really NumP as in all the players, then you don't know the size of that packet if there are more than 8 players. If it's to mean NumC then there's the possibility that the number of players is a multiple of 8 and you won't know which packet is the last of the sequence.

Anyway, you can always track the number of players connected at any given time so you wouldn't have problems. But that's right, you'd have to use more logic than just the info provided in the MCI packets.

Subliminal PS: Someone help me with the UDP stuff XDDD
Quote from MaKaKaZo :Subliminal PS: Someone help me with the UDP stuff XDDD

The problem now is that your problem is language specific. I would love to help, but I don't do ANY packet stream programming for C, C++, or C#. So your very much out of my area. I'd be more then happy to discuss the issue it's self in Pseudocode, but nothing as language specific as to what function calls to use, or the issues you might encounter with said functions.
I'm trying now in a whats looks to be a nice forum for coders. If I get to solve it I'll post what was failing so people can laugh at my *probably* stupid mistake
Quote from Dygear :InSim.txt Patch Z
struct IS_MCI // Multi Car Info - if more than 8 in race then more than one of these is sent
{
byte Size; // [B]4 + [U]NumP[/U] * 28[/B]
byte Type; // ISP_MCI
byte ReqI; // 0 unless this is a reply to an TINY_MCI request
byte NumC; // number of valid CompCar structs in this packet

CompCar Info[8]; // car info for each player, 1 to 8 of these (NumC)
};

I am guessing that's an error, meant to say NumC. But, with the MCI packets by them selves there is no way to find the amount of players in the race just by using the MCI packet. The only information it will give is the number of CompCar structs in the packet. So you will not know if you still have more coming. (Unless the number is less then eight of course, then that's the last packet, for the sequence.)

You use the CCI_FIRST and CCI_LAST-flags to determine the amount of MCI-packets/CompCar-structs.

struct CompCar // Car info in 28 bytes - there is an array of these in the MCI (below)
{
word Node; // current path node
word Lap; // current lap
byte PLID; // player's unique id
byte Position; // current race position : 0 = unknown, 1 = leader, etc...
byte Info; // flags and other info - see below
byte Sp3;
int X; // X map (65536 = 1 metre)
int Y; // Y map (65536 = 1 metre)
int Z; // Z alt (65536 = 1 metre)
word Speed; // speed (32768 = 100 m/s)
word Direction; // direction of car's motion : 0 = world y direction, 32768 = 180 deg
word Heading; // direction of forward axis : 0 = world y direction, 32768 = 180 deg
short AngVel; // signed, rate of change of heading : (16384 = 360 deg/s)
};

// NOTE 1) Info byte - the bits in this byte have the following meanings :

#define CCI_BLUE 1 // this car is in the way of a driver who is a lap ahead
#define CCI_YELLOW 2 // this car is slow or stopped and in a dangerous place

#define CCI_LAG 32 // this car is lagging (missing or delayed position packets)

[B] #define CCI_FIRST 64 // this is the first compcar in this set of MCI packets
#define CCI_LAST 128 // this is the last compcar in this set of MCI packets[/B]

Quote from nikka :You use the CCI_FIRST and CCI_LAST-flags to determine the amount of MCI-packets/CompCar-structs.

Learn something new everyday Thanks for that . So I take it that if there was only one car on track, then you would get one MCI packet, with the info value of 192? And while this information will give the ammout of players in the MCI packet, it will not give you the overall players. (Correct?)


<?php 
if ($MCI[0]->ComCar[0]->Info CCI_FIRST CCI_LAST AND $MCI[0]->ComCar[0]->Position != 1) {
    
# There is only one player in the race, and that driver is not first!
    # EPIC ERROR: PACKET ERROR, InSim ERROR, OR PROGRAM ERROR!
}
?>

Quote from Dygear :Learn something new everyday Thanks for that . So I take it that if there was only one car on track, then you would get one MCI packet, with the info value of 192? And while this information will give the ammout of players in the MCI packet, it will not give you the overall players. (Correct?)


<?php 
if ($MCI[0]->ComCar[0]->Info CCI_FIRST CCI_LAST AND $MCI[0]->ComCar[0]->Position != 1) {
    
# There is only one player in the race, and that driver is not first!
    # EPIC ERROR: PACKET ERROR, InSim ERROR, OR PROGRAM ERROR!
}
?>


Well, it gives enough info to know when a sequence starts and ends I didn't know about that either.


Good news guys: I managed to solve the UDP problem. As I thought it was a newbie mistake and some nice guy at www.codeguru.com helped me out checking my code.

The problem was that I wasn't binding the UDP socket to my local port. I mean, I specified that I wanted to use udpport 60000 and the server was sending packets to that port, but I never told my socket to listen on THAT port. I only told it to listen for incoming packets from IP x.x.x.x and port yyyy (the server's insim port).

So, when I use connect on the UDP socket without binding it previously to any specific port, it prepares a random port assuming that I'm going to start the communication (which I'm not). So, if I want to listen on a specific port I have to bind the socket first to my IP and port 60000 (the one I selected), and then use "connect()". That way my socket is prepared to listen on the desired port and not a random one.

I know most of you don't give a damn, but maybe someone that reads this will find it useful in the future. I'll be posting some example on car coordinates via UDP probably next week.
Freaking awesome man!
Quote from Dygear :InSim.txt Patch Z
struct IS_MCI // Multi Car Info - if more than 8 in race then more than one of these is sent
{
byte Size; // [b]4 + [u]NumP[/u] * 28[/b]
byte Type; // ISP_MCI
byte ReqI; // 0 unless this is a reply to an TINY_MCI request
byte NumC; // number of valid CompCar structs in this packet

CompCar Info[8]; // car info for each player, 1 to 8 of these (NumC)
};

I am guessing that's an error, meant to say NumC.

Yes, I've fixed this now in my version of the documentation.

FGED GREDG RDFGDR GSFDG