PDA

View Full Version : Winsock and recvfrom function



Jimmy Valavanis
02-11-2007, 01:39 PM
First of all i'd like to say that I'm tottally unexperienced in network programming, and speaking the truth I do not know almost nothing about networks. (that's why I'm making this post) To give you take a clue I don't really know what UDP means, some kind of protocol I suppose.

Anyway, I use Delphi6(or greater), WinSock.pas unit and SDK functions. I do not work in a form-based enviroment, so usage of components is useless.
Maintaining a game (DelphiDoom, as well as DelphiHeretic http://delphidoom.sitesled.com/downloads.html) I have a big problem in networking:
After a lot of of experiments using 2 computers connected in LAN running simultaneously DelphiHeretic(and DelphiDoom) I'm managed to send packets (PacketSend procedure in i_net.pas works) but could not receive none of them (procedure PacketGet in i_net.pas does not work, recvfrom() function returns error = WSAEWOULDBLOCK) and I don't even know what does that error mean, sorry.

To debug a network game you must run DelphiDoom/DelphiHeretic with these parameters (in 2 seperate computers):

for DelphiDoom
doom32.exe -net 1 addr2 -players 2 (running in computer addr1)
doom32.exe -net 2 addr1 -players 2 (running in computer addr1)

for DelphiHeretic
heretic32.exe -net 1 addr2 -players 2 (running in computer addr1)
heretic32.exe -net 2 addr1 -players 2 (running in computer addr1)

where addr1/addr2 is the computer name or IP address of the computer you want to comunicate.

As I'm totally unexperienced in networking I have the feeling that only if someone take a look in i_net.pas and make the apropriate changes the network code is going to work. Of cource I will be glad to credit anyone that will solve my problem (sorry guys, no money )

To avoid downloading the source code, the unit i_net.pas is here:
(even that I doubt that if someone looking only to the source code will find the error, but how knows).

Thanks in advance and sorry for being so lengthy.



unit i_net;

interface

{
i_net.h, i_net.c
}

// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// DESCRIPTION:
// System specific network interface stuff.
//
//-----------------------------------------------------------------------------

{ Called by D_DoomMain. }

procedure I_InitNetwork;

procedure I_ShutDownNetwork;

procedure I_NetCmd;

implementation

uses
WinSock,
d_delphi,
doomtype,
d_event, d_net, d_net_h, d_player, d_ticcmd,
g_game,
i_system,
m_argv,
r_main,
tables,
doomstat;

const
MAPPED_PACKETS_PER_NODE = 32;
NUM_MAPPED_PACKETS = (MAPPED_PACKETS_PER_NODE * MAXNETNODES);

IPPORT_USERRESERVED = 5000;

var
DOOMPORT: word = (IPPORT_USERRESERVED + 29);

sendsocket: TSocket;
insocket: TSocket;

sendaddress: array[0..MAXNETNODES - 1] of TSockAddrIn;

MappedNode: integer = -1;

type
packetpacket_t = record
from: integer;
_to: integer;
dd: doomdata_t;
end;

socklen_t = integer;

const
NO_PACKET = -1;

type
mapfileheader_t = record
numnodes: integer;
packets: array[0..MAXNETNODES - 1] of integer;
numpackets: array[0..MAXNETNODES - 1] of integer;
free: integer;
end;
Pmapfileheader_t = ^mapfileheader_t;

mapfilepacket_t = record
next: integer;
from: integer;
length: integer;
data: doomdata_t;
end;
Pmapfilepacket_t = ^mapfilepacket_t;

{var
hMemoryMap: integer = 0;
pSharedMemory: PByteArray = nil;
pSharedHeader: Pmapfileheader_t;
SharedPackets: Pmapfilepacket_t;
hNetMutex: integer = 0;}

var
netget: PProcedure;
netsend: PProcedure;

const
NDF_DRONE = $01;
NDF_LEFT = $02;
NDF_RIGHT = $04;
NDF_BACK = $08;
NDF_DEATHMATCH = $10;
NDF_DEATH2 = $20;
NDF_SPLITONLY = $40;

procedure I_CheckIfDrone(const flags: integer);
begin
if (M_CheckParm('-left') > 0) or (flags and NDF_LEFT <0> 0) or (flags and NDF_RIGHT <0> 0) or (flags and NDF_BACK <0> 0) or (flags and NDF_DRONE <> 0) then
doomcom.drone := 1;
end;

//
// UDPsocket
//
function UDPsocket: TSocket;
begin
// allocate a socket
result := socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if result = INVALID_SOCKET then
I_Error('UDPsocket(): Can''t create socket.');
end;

//
// BindToLocalPort
//
procedure BindToLocalPort(s: TSocket; port: integer);
var
v: integer;
address: TSockAddrIn;
begin
ZeroMemory(@address, SizeOf(TSockAddrIn));
address.sin_family := AF_INET;
address.sin_addr.s_addr := INADDR_ANY;
address.sin_port := port;

v := bind(s, address, SizeOf(TSockAddrIn));
if v = SOCKET_ERROR then
I_Error('BindToLocalPort(): Failed.');
end;

//
// PacketSend
//
procedure PacketSend;
var
c: integer;
begin
c := sendto(sendsocket, netbuffer, doomcom.datalength, 0,
sendaddress[doomcom.remotenode], SizeOf(sendaddress[doomcom.remotenode]));

if c = SOCKET_ERROR then
I_Error('PacketSend(): sendto() failed.');
end;

function FindNode(const address: TSockAddrIn): integer;
var
i: integer;
begin
// find remote node number
i := 0;
while i <doomcom>= 0) then
begin
// The remote node aborted unexpectedly, so pretend it sent an exit packet
printf('The connection from node %d was dropped'#13#10, [node]);

c := 1;
end
else if err <> WSAEWOULDBLOCK then
begin
I_Error('PacketGet() failed.');
end
else
begin
doomcom.remotenode := -1; // no packet
exit;
end;
end;

i := 0;
while i <doomcom> 0 then
begin
portpart := Copy(remotename, p + 1, Length(remotename) - p);
port := atoi(portpart);
if port = 0 then
begin
printf('AddNodeAddress(%s): Weird port: %s (using %d)'#13#10, [remotename, portpart, DOOMPORT]);
port := DOOMPORT;
end
end
else
port := DOOMPORT;

addr.sin_port := htons(port);

if remotename[1] = '.' then
addr.sin_addr.s_addr := inet_addr(PChar(Copy(remotename, 2, Length(remotename) - 1)))
else
begin
isnamed := false;
for i := 1 to Length(remotename) do
begin
if not (remotename[i] in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.']) then
begin
isnamed := true;
break;
end;
end;

if not isnamed then
begin
addr.sin_addr.s_addr := inet_addr(PChar(remotename));
printf('Node number %d address %s'#13#10, [doomcom.numnodes, remotename]);
end
else
begin
hostentry := gethostbyname(PChar(remotename));
if hostentry = nil then
I_Error('gethostbyname(): Could not find %s'#13#10, [remotename]);
addr.sin_addr.s_addr := PInteger(hostentry.h_addr_list)^;
printf('Node number %d hostname %s'#13#10,
[doomcom.numnodes, StringVal(hostentry.h_name)]);
end;
end;

if addr.sin_addr.s_addr = u_long(INADDR_NONE) then
I_Error('AddNodeAddress(): Unknown Host (%s)', [remotename]);
end;

procedure I_InitPacketNetworkStart;
var
wsad: WSADATA;
begin
printf(' Multiplayer'#13#10);

netgame := true;

if WSAStartup($0101, wsad) <0> 0 then
while (i < myargc) and (myargv[i][1] <do> 0) and (p < myargc - 1) then
begin
DOOMPORT := atoi(myargv[p + 1]);
printf('Using Port %d'#13#10, [DOOMPORT]);
end;

inc(i);

if i <myargc> 0) and (p <myargc> 0) and (p < myargc - 1) then
begin
doomcom.ticdup := Ord(myargv[p + 1][1]) - Ord('0');
if doomcom.ticdup <1> 9 then
doomcom.ticdup := 9;
end
else
doomcom.ticdup := 1;

if M_CheckParm('-extratic') <0> 0 then
begin
I_InitCLNetwork(p);
exit;
end;

printf(' Single Player'#13#10);
// single player game
netgame := false;
doomcom.id := DOOMCOM_ID;
doomcom.numplayers := 1;
doomcom.numnodes := 1;
doomcom.deathmatch := 0;
doomcom.consoleplayer := 0;
end;

procedure I_ShutDownNetwork;
begin
memfree(pointer(doomcom), SizeOf(doomcom_t));
end;

procedure I_NetCmd;
begin
if doomcom.command = CMD_SEND then
netsend
else if doomcom.command = CMD_GET then
netget
else
I_Error('I_NetCmd(): Bad net cmd: %d', [doomcom.command]);
end;

end.

Jimmy Valavanis
04-01-2008, 09:56 AM
Happy new year!

I've fixed it!!!