Jump to content
Excelsior Forums
rms

Using sockets, program dies on 'send' call

Recommended Posts

I'm trying to use 'send' from PMOS.  It fails.  It does not generate any error messages, the program simply terminates prematurely.

The following is it's output:

hep =  10609036

Got socket # 3

Preparing to call connect

Got a connection

Preparing to send

And that is it.  It hits the 'send' call and halts.  It does not write Ending main line of Sock02, or even the value of 'sent'.  Anybody know how to fix it?  Or at lease how to delay termination long enough to get an error message?  Thanks.

The following is the program:

<*+ M2EXTENSIONS *>

<*+ M2ADDTYPES *>

<*+ CSTDLIB *>

MODULE Sock02;

FROM NetDB    IMPORT gethostbyname, HostEntPtr;

FROM Sockets  IMPORT Socket, send, recv;

FROM Strings  IMPORT Assign, Concat;

FROM STextIO  IMPORT WriteString, WriteLn, WriteChar;

FROM SYSTEM  IMPORT CARD16, CARD32, LOC, INT32, TSIZE;

FROM Storage  IMPORT ALLOCATE;

FROM InOut    IMPORT WriteInt, WriteCard;

CONST

  maxChars = 512;

 

TYPE

  AddressFamily = (AF_UNSPEC, AF_UNIX, AF_INET, AF_IMPLINK, AF_PUP,

                  AF_CHAOS, AF_NS, AF_NBS, AF_ECMA, AF_DATAKIT,

  AF_CCITT, AF_SNA, AF_DECnet, AF_DLI, AF_LAT,

  AF_HYLINK, AF_APPLETALK, AF_NETBIOS, AF_MAX);

  Addr = RECORD

          addr : CARD32;

        END; (* RECORD Addr*)

  inAddr = RECORD

            family : CARD16 (*AddressFamily*);

            port : CARD16;

            s_addr : Addr;

          END; (* RECORD inAddr *)

  strType = ARRAY [0..maxChars] OF CHAR;

VAR

  serv      : Socket;

PROCEDURE ["C"] / bind (    socket : Socket;

                        VAR myAddr : inAddr;

    addrlen : CARDINAL ) : BOOLEAN;

PROCEDURE ["C"] / connect (  socket : CARDINAL;

                            servAddr : inAddr;

    addrlen  : CARDINAL ) : BOOLEAN;

PROCEDURE ["C"] / htons ( numb : CARD16 ) : CARD16;

PROCEDURE ["C"] / htonl ( numb : CARD32 ) : CARD32;

PROCEDURE ["C"] / socket(  domain : CARDINAL;

                            type : CARDINAL;

protocol : CARDINAL ) : CARDINAL;

TYPE

  Recv_buf = ARRAY[ 1..1000 ] OF CHAR;

  Recv_buf_ptr = POINTER TO Recv_buf;

  Send_buf = ARRAY[ 1..10 ] OF CHAR;

  Send_buf_ptr = POINTER TO Send_buf;

VAR

  i: INTEGER;

  sock_num: Socket;

  recv_buf_ptr: Recv_buf_ptr;

  send_buf_ptr: Send_buf_ptr;

  hep: HostEntPtr ;

  service_name: ARRAY[ 1..20 ] OF CHAR;

  serv_addr: inAddr;

  connected, sent, received: BOOLEAN;

  port, num_sent, num_received: CARDINAL;

  msg: strType;

BEGIN

  service_name := 'www.yahoo.com';

  hep := gethostbyname( service_name );

  WriteString("hep = ");

  WriteInt( INT32( hep ), 10 );

  WriteLn;

  sock_num := socket( 2, 1, CARD32( AF_NS ) );

  IF sock_num < 1 THEN

    WriteString("Can't get a socket");

    WriteLn;

  ELSE

    WriteString("Got socket #");

    WriteInt( sock_num, 2 );

    WriteLn;

  END; 

  port := 9999;

  serv_addr.s_addr.addr := CARD32( hep^.h_addr_list^[0]^ );

  serv_addr.family := 2 (* AF_INET *);

  serv_addr.port := htons( CARD16(port) ) ;

    WriteString("Preparing to call connect");

    WriteLn;

  connected := connect( sock_num, serv_addr, SIZE( inAddr )  );

  IF connected THEN

    WriteString("Got a connection");

    WriteLn;

  ELSE

    WriteString("Can't get a connection");

    WriteLn;

  END;

  IF connected THEN

    WriteString("Preparing to send");

    WriteLn;

(*

    this send call - instead of using allocate and msg - generates same failure

    msg := "test";

    num_sent := send( sock_num, msg, LENGTH( msg ), 0 );

*)

    ALLOCATE( send_buf_ptr, TSIZE(Send_buf) );

    send_buf_ptr^ := "test";

    num_sent := send( sock_num, send_buf_ptr, LENGTH( send_buf_ptr^ ), 0 );  (**DIES HERE**)

    sent := ( MAX( CARDINAL ) <> num_sent );

    IF sent THEN

      WriteString("Sent data ok");

      WriteLn;

    ELSE

      WriteString("Error when trying to send.  Number sent =");

      WriteCard( num_sent, 10 );

      WriteLn;

    END;

  END;

  IF sent THEN

    ALLOCATE( recv_buf_ptr, TSIZE(Recv_buf) );

    FOR i := 1 TO 100 DO

      recv_buf_ptr^ := 'x';

    END;

    num_received := recv( sock_num, recv_buf_ptr, TSIZE(Recv_buf), 0 );

    received := ( MAX( CARDINAL ) <> num_received );

  END;

  IF received THEN

    FOR i := 1 TO 100 DO

      IF ( ORD( recv_buf_ptr^ ) > ORD('A') ) AND ( ORD( recv_buf_ptr^ ) < ORD('z') ) THEN

        WriteChar ( recv_buf_ptr^ );

      ELSE

        WriteChar ( '.' );

      END;

    END;

    WriteLn;

  ELSE

    WriteString( "Error when receiving " );

    WriteLn;

  END;

  WriteString("Ending main line of Sock02");

  WriteLn;

END Sock02.

Share this post


Link to post
Share on other sites

This works for me:

CR is a CONST of 15C

Concat is being imported from Strings

send and Socket are imported from the PMOS sockets library

[tt]

PROCEDURE DoSend(serv : Socket; msg : ARRAY OF CHAR);

VAR

  sent : CARDINAL;

BEGIN

  Concat(msg,CR,msg);

  WriteString(msg);

  WriteLn;

  sent := send(serv, msg, LENGTH(msg), 0);

  Assign("", msg);

END DoSend;

[/tt]

Try appending a carriage return onto the message string, see if that works.

Share this post


Link to post
Share on other sites

Thanks, but that does not fix it.  I appended the CR, nothing changed.  I even considered the possibility that passing msg as a parameter might 'purify' it, so I rearranged it as follows:

PROCEDURE DoSend ( s_num: Socket; msg: ARRAY OF CHAR );

VAR

  sent: BOOLEAN;

  num_sent: CARDINAL;

BEGIN

    WriteString("Preparing to send");

    WriteLn;

    Concat(msg,CR,msg);

    WriteString( msg );

    WriteLn;

    num_sent := send( s_num, msg, LENGTH( msg ), 0 );

    sent := ( MAX( CARDINAL ) <> num_sent );

    IF sent THEN

      WriteString("Sent data ok");

      WriteLn;

    ELSE

      WriteString("Error when trying to send.  Number sent =");

      WriteCard( num_sent, 10 );

      WriteLn;

    END;

END DoSend;

Nothing changed. 

So I was beginning to suspect that msg is not the problem.  As a test, I tried

sent := send( s_num, 0, 0, 0 );

Still no change.  I don't think that msg is the problem.

Share this post


Link to post
Share on other sites

OK, well, another thing.

I was never able to get this to work:

[tt]connected := connect( sock_num, serv_addr, SIZE( inAddr )  );[/tt]

I had to do this to get connected.  I meant to go back and try to fix it, but I was distracted.  Anyway - while it isn't the way I want to do it, this is what is working for me:

[tt]done := connect(serv, sa,  20    (* SIZE(sa) *)  );

  (* OK, now this is wrong.  I should be using SIZE(sa), but

    I cannot connect if I do.  I will need to look into this

    and correct it. *)[/tt]

Note that IIRC the SIZE(sa) impacted the send and rcv until I changed it to 20 (BTW, sa is inAddr)

Share this post


Link to post
Share on other sites

I used a hard-wired 20 in my first try, lifing it straight from your code at Aliboom.  It caused my program to hang while attempting to connect.  When I substituted SIZE( inAddr ) or a hard-wired 8, it worked. 

(  just so nobody wastes their time on one other possibility: yes I should be using TSIZE(), since inAddr is a TYPE.  But both SIZE() and TSIZE() return a value of 8, and the program still behaves the same.  I guess the ability of SIZE() to handle not only VARs but also TYPEs is an undocumented feature. )

Any value of 0 thru 15 works ( ie: connected = TRUE ).  Any value of 16 through 20 causes my program to hang.

I'm going to try some higher numbers.  It shouldn't work, but, then again, 20 shouldn't work in your program.

I'm also going to look at the flags on the send call.

Share this post


Link to post
Share on other sites

Good luck.  I'm going to try your code tonight.  I was busy on some distro work last night and couldn't, 

By the way, let me know if you get select working :)

Terry

Share this post


Link to post
Share on other sites

You don't get any errors at all?  I get a broken pipe

[tt]terry@timestorm: /home/terry/Sock02

01:24:32 $ ./Sock02

hep = -1208835664

Got socket # 3

Preparing to call connect

Got a connection

Preparing to send

Broken pipe

[/tt]

strace gives me:

[tt]

...snipped...

socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 3

write(1, "Got socket # 3\n", 15Got socket # 3

)        = 15

write(1, "Preparing to call connect\n", 26Preparing to call connect

) = 26

connect(3, {sa_family=AF_INET, sin_port=htons(9999), sin_addr=inet_addr("68.142.226.45")}, B) = -1 EINVAL (Invalid argument)

write(1, "Got a connection\n", 17Got a connection

)      = 17

write(1, "Preparing to send\n", 18Preparing to send

)    = 18

send(3, "test", 4, 0)                  = -1 EPIPE (Broken pipe)

--- SIGPIPE (Broken pipe) @ 0 (0) ---

+++ killed by SIGPIPE +++

[/tt]

Share this post


Link to post
Share on other sites

I used a hard-wired 20 in my first try, lifing it straight from your code at Aliboom.  It caused my program to hang while attempting to connect.  When I substituted SIZE( inAddr ) or a hard-wired 8, it worked. 

(  just so nobody wastes their time on one other possibility: yes I should be using TSIZE(), since inAddr is a TYPE.  But both SIZE() and TSIZE() return a value of 8, and the program still behaves the same.  I guess the ability of SIZE() to handle not only VARs but also TYPEs is an undocumented feature. )

Any value of 0 thru 15 works ( ie: connected = TRUE ).  Any value of 16 through 20 causes my program to hang.

I'm going to try some higher numbers.  It shouldn't work, but, then again, 20 shouldn't work in your program.

I'm also going to look at the flags on the send call.

For info, I have converted the PMOS2 files so that they actually work for me and the TSIZE works.  I'll give you a link to them later.  Not difficult, just a matter of changing all the "SysCall" to "C" and adding other items like htons, htonl, etc.

Share this post


Link to post
Share on other sites

Just for info, running strace and looking at the output shows a lot of wrong information.  When I run it with the direct language specifications, like I do in Connect.mod from my IRC bot, the strace output looks much better.

I think some of us are going to have to work those PMOS2 files for Linux - or start from scratch.

Share this post


Link to post
Share on other sites

Yep, there are some contradictions here: connected is TRUE, yet strace says there are errors.  I didn't know about strace until this thread, so I still don't know enough about it to know what to make of it all.

Even that aside, I can't figure out why your connect works and mine does not, as  I copied much from yours at aliboom.

Anybody else aside from qrn and myself have any ideas here?

Share this post


Link to post
Share on other sites

Well, what I did was make a copy of the output from a C program, and the one I was trying to convert.  It looked ok on the terminal, but major differences in the output.

$ strace -o strace-sserver ./sserver

I have no idea why it doesn't work on yours. 

right now I'm trying to figure out accept.  This code kind of works - and the strace output is close to that found in Beej's Guide to Network Programming at http://beej.us/guide/bgnet/output/html/clientserver.html#simpleserver (although I'm using code from an earlier version of the Guide, that looks a little different).  You test it by doing a telnet localhost 3490.  It works fine with the C version, but I need to touch up the "accept" procedure (I believe that I need to be sending an address for SockAddr).

I get this output from strace - although running it in the terminal, it says the problem is later - it really is due to this:

socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
bind(3, {sa_family=AF_INET, sin_port=htons(3490), sin_addr=inet_addr("0.0.0.0")}, 20) = 0
listen(3, 10)                           = 0
accept(3, 0x805755c, 0x10)              = -1 EFAULT (Bad address)

The equivalent strace output from the C version is:

socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
bind(3, {sa_family=AF_INET, sin_port=htons(3490), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
listen(3, 10)                           = 0
rt_sigaction(SIGCHLD, {0x8048704, [], SA_RESTART}, NULL,  = 0
accept(3, {sa_family=AF_INET, sin_port=htons(62737), sin_addr=inet_addr("69.173.131.225")}, [16]) = 4

This the the whole thing, with direct language specification instead of using any sockets libraries.  It should work for you.

<*+ M2EXTENSIONS *>
<*+ CSTDLIB *>
<*+ NOHEADER *>

MODULE Sock04;

IMPORT stdio, SYSTEM, STextIO, SWholeIO, types, unistd, Strings;

TYPE EightByte = ARRAY [0..7] OF SYSTEM.CARD8;
CONST Zero8 = EightByte {0, 0, 0, 0, 0, 0, 0, 0};

CONST
  CR = 15C;

  MAXALIASES = 35;
  MAXADDRS   = 35;

  PF_INET = 2;
  AF_INET = PF_INET;
  SOCK_STREAM = 1;

  MYPORT = 3940;
  BACKLOG = 10;

TYPE
  Socket = CARDINAL;

  Subscript = [0..511];
  AddressPointerArrayPointer = POINTER TO ARRAY [0..MAXADDRS]
                                           OF POINTER TO CARDINAL;

  HostEntPtr = POINTER TO
                 RECORD
                     h_name: POINTER TO ARRAY Subscript OF CHAR;
                     h_aliases: POINTER TO ARRAY [0..MAXALIASES-1] OF
                                        POINTER TO ARRAY Subscript OF CHAR;
                     h_addrtype: CARDINAL;
                     h_addr_list: AddressPointerArrayPointer;
                 END (*RECORD*);



  Addr = RECORD
           addr : SYSTEM.CARD32;
         END; (* RECORD Addr*)	 

  (* Note that this should be variable, but isn't  (the AF_UNIX/AF_INET bit) *)
  SockAddr = RECORD
             family : SYSTEM.CARD16 (*AddressFamily*);
             port : SYSTEM.CARD16;
             addr : CARDINAL (*Addr *);
             zero : EightByte;
           END; (* RECORD inAddr *)
   
VAR 
  sockFD, newFD, sinSize : INTEGER;
  myAddr, theirAddr : (* Sockets. *) SockAddr;
  hp : HostEntPtr;
  return : INTEGER;
  pidNum : types.pid_t;
  msg : ARRAY [0..511] OF CHAR;

PROCEDURE ["C"] / close ( socket : Socket) : BOOLEAN;

PROCEDURE ["C"] / bind (     socket : Socket;
                         VAR   Addr : SockAddr;
		    addrlen : CARDINAL ) : BOOLEAN;


PROCEDURE ["C"] / socket(  domain : CARDINAL;
                             type : CARDINAL;
		 protocol : CARDINAL ) : CARDINAL;

PROCEDURE ["C"] / htons ( numb : SYSTEM.CARD16 ) : SYSTEM.CARD16;

PROCEDURE ["C"] / listen (  sockfd : Socket;
                           backlog : CARDINAL ) : INTEGER;
		   
PROCEDURE ["C"] / accept (             socket : Socket;
                           VAR (* OUT *) from : SockAddr;
		              addrlen : CARDINAL ) : INTEGER;
		      
(* ssize_t send(int s, const void *buf, size_t len, int flags); *)			      
PROCEDURE ["C"] / send ( sockfd : Socket;
		 buf : ARRAY OF CHAR;
		 len : CARDINAL;
		 flags : CARDINAL ): types.ssize_t;

BEGIN

    
  sockFD := socket(PF_INET, SOCK_STREAM, 0);
  
   myAddr.family :=  SYSTEM.CAST(CARDINAL, AF_INET); 
  myAddr.port := htons(3490);
  myAddr.addr := 0;
  myAddr.zero := Zero8;
  
  (* IF NOT Sockets.bind(sockFD, myAddr, SIZE(Sockets.SockAddr)) THEN *)
  IF bind(sockFD, myAddr, 20 (*SIZE(Sockets.SockAddr)*)) THEN
    stdio.perror("bind");
    HALT; 
  END; 

  return := listen(sockFD, BACKLOG);
  
  IF return = -1 THEN
    stdio.perror("listen");
    HALT; 
  END;  

  LOOP
    sinSize := SIZE(theirAddr); 
    newFD := accept(sockFD, theirAddr, SIZE(SockAddr) );
        IF (newFD = -1) THEN
          stdio.perror("accept");
          EXIT; 
        END;
        
  END; 

  STextIO.WriteString("server: got connection from ");
  SWholeIO.WriteCard(theirAddr.addr,1);
  STextIO.WriteLn;

  pidNum := unistd.fork();
  IF NOT (pidNum = -1) THEN
    msg := "Hello world!";
    Strings.Concat(msg, CR, msg);
    IF (send(newFD, msg, LENGTH(msg), 0) <> MAX(INTEGER)) THEN
      stdio.perror("send");
      close(newFD);
      HALT;
    END;
    close(newFD);
    (* need to convert this:
    while(waitpid(-1,NULL,WNOHANG) > 0); /* clean up child processes */
    *)
  END;
  close(sockFD);
  


  

END Sock04.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×