1########################################################################### 2## 3#W xstream.gi The SCSCP package Alexander Konovalov 4#W Steve Linton 5## 6########################################################################### 7 8 9########################################################################### 10## 11## InputOutputTCPStream( <hostname>, <port> ) 12## InputOutputTCPStream( <socket_descriptor> ) 13## 14## The first usage is to be used by client and specifies hostname and port. 15## The second usage is to be used by server and specifies socket descriptor 16## which will be used to accept incoming connections. 17## 18InstallGlobalFunction( InputOutputTCPStream, 19function( arg ) 20# InputOutputLocalProcess has 3 arguments: cdir, exec, argts 21# at least for now, we want to preserve four components of the internal 22# representation of input/output streams, with the following correspondence 23# 1) ptynum --> object in the category IsFile 24# 2) basename --> hostname 25# 3) argts --> ??? arguments to be communicated to the hostname? 26# 4) false --> false # what'is the meaning of this? 27local hostname, port, lookup, sock, res, fio, socket_descriptor, i; 28if Length( arg ) = 2 then # client case 29 hostname := arg[1]; 30 port := arg[2]; 31 if not IsString( hostname ) then 32 Error( "InputOutputTCPStream: <hostname> must be a string! \n"); 33 fi; 34 if not ( IsInt(port) and port >= 0 ) then 35 Error( "InputOutputTCPStream: <port> must be a non-negative integer! \n"); 36 fi; 37 # try to lookup the host for up to ten times 38 for i in [1..10] do 39 lookup := IO_gethostbyname( hostname ); 40 if lookup <> fail then 41 break; 42 fi; 43 od; 44 if lookup = fail then 45 Print( "InputOutputTCPStream: cannot find hostname ", hostname, "\n"); 46 return fail; 47 fi; 48 Info( InfoSCSCP, 1, "Creating a socket ..." ); 49 sock := IO_socket( IO.PF_INET, IO.SOCK_STREAM, "tcp" ); 50 Info( InfoSCSCP, 1, "Connecting to a remote socket via TCP/IP ..." ); 51 res := IO_connect( sock, IO_make_sockaddr_in( lookup.addr[1], port ) ); 52 if res = fail then 53 Print( "Error: ", LastSystemError(), "\n" ); 54 IO_close( sock ); 55 return fail; 56 else 57 fio := IO_WrapFD( sock, IO.DefaultBufSize, IO.DefaultBufSize ); 58 return Objectify( InputOutputTCPStreamDefaultType, 59 [ fio, hostname, [ port ], false ] ); 60 fi; 61elif Length( arg ) = 1 then # server case 62 socket_descriptor := arg[1]; 63 if not ( IsInt(socket_descriptor) and socket_descriptor >= 0 ) then 64 Error( "InputOutputTCPStream: <socket_descriptor> must be a non-negative integer! \n"); 65 fi; 66 fio := IO_WrapFD( socket_descriptor, IO.DefaultBufSize, IO.DefaultBufSize ); 67 return Objectify( InputOutputTCPStreamDefaultType, 68 [ fio, "socket descriptor", [ socket_descriptor ], false ] ); 69else 70 Error( "InputOutputTCPStream: usage \n", 71 "InputOutputTCPStream(<hostname>, <port>) for client, \n", 72 "InputOutputTCPStream(<socket_descriptor>) for server! \n"); 73fi; 74end); 75 76 77########################################################################### 78## 79#M ViewObj( <ioTCPstream> ) 80## 81InstallMethod( ViewObj, "for ioTCPstream", 82[ IsInputOutputTCPStreamRep and IsInputOutputStream ], 83function(stream) 84 Print("< "); 85 if IsClosedStream(stream) then 86 Print("closed "); 87 fi; 88 Print("input/output TCP stream to ",stream![2],":", stream![3][1], " >"); 89end); 90 91 92########################################################################### 93## 94#M PrintObj( <ioTCPstream> ) 95## 96InstallMethod( PrintObj, "for ioTCPstream", 97[ IsInputOutputTCPStreamRep and IsInputOutputStream ], 98function(stream) 99 local i; 100 Print("< "); 101 if IsClosedStream(stream) then 102 Print("closed "); 103 fi; 104 Print("input/output TCP stream to ",stream![2],":", stream![3][1], " >"); 105end); 106 107 108########################################################################### 109## 110#M ReadByte( <ioTCPstream> ) 111## 112InstallMethod( ReadByte, "for ioTCPstream", 113[ IsInputOutputTCPStreamRep and IsInputOutputStream ], 114function(stream) 115local buf; 116 buf := IO_Read( stream![1], 1 ); 117 if buf = fail or Length(buf) = 0 then 118 stream![4] := true; 119 return fail; 120 else 121 stream![4] := true; 122 return INT_CHAR(buf[1]); 123 fi; 124end); 125 126 127########################################################################### 128## 129#M ReadLine( <ioTCPstream> ) 130## 131InstallMethod( ReadLine, "for ioTCPstream", 132[ IsInputOutputTCPStreamRep and IsInputOutputStream ], 133function( stream ) 134 local sofar, chunk; 135 sofar := IO_Read( stream![1], 1 ); 136 if sofar = fail or Length(sofar) = 0 then 137 stream![4] := true; 138 return fail; 139 fi; 140 while sofar[ Length(sofar) ] <> '\n' do 141 chunk := IO_Read( stream![1], 1); 142 if chunk = fail or Length(chunk) = 0 then 143 stream![4] := true; 144 return sofar; 145 fi; 146 Append( sofar, chunk ); 147 od; 148 return sofar; 149end); 150 151 152########################################################################### 153## 154#M ReadAllIoTCPStream( <ioTCPstream> ) 155## 156BindGlobal( "ReadAllIoTCPStream", function(stream, limit) 157 local sofar, chunk, csize; 158 if limit = -1 then 159 csize := 20000; 160 else 161 csize := Minimum(20000,limit); 162 limit := limit - csize; 163 fi; 164 sofar := IO_Read(stream![1], csize); 165 if sofar = fail or Length(sofar) = 0 then 166 stream![4] := true; 167 return fail; 168 fi; 169 while limit <> 0 do 170 if limit = -1 then 171 csize := 20000; 172 else 173 csize := Minimum(20000,limit); 174 limit := limit - csize; 175 fi; 176 chunk := IO_Read( stream![1], csize); 177 if chunk = fail or Length(chunk) = 0 then 178 stream![4] := true; 179 return sofar; 180 fi; 181 Append(sofar,chunk); 182 od; 183 return sofar; 184end); 185 186 187InstallMethod( ReadAll, "for ioTCPstream", 188 [ IsInputOutputTCPStreamRep and IsInputOutputStream ], 189 stream -> ReadAllIoTCPStream(stream, -1) ); 190 191 192InstallMethod( ReadAll, "for ioTCPstream", 193[ IsInputOutputTCPStreamRep and IsInputOutputStream, IsInt ], 194function( stream, limit ) 195 if limit < 0 then 196 Error("ReadAll: negative limit not allowed"); 197 fi; 198 return ReadAllIoTCPStream(stream, limit); 199end); 200 201 202########################################################################### 203## 204#M WriteByte( <ioTCPstream> ) 205## 206InstallMethod( WriteByte, "for ioTCPstream", 207[ IsInputOutputTCPStreamRep and IsInputOutputStream, IsInt ], 208function(stream, byte) 209 local ret,s; 210 if byte < 0 or 255 < byte then 211 Error( "<byte> must an integer between 0 and 255" ); 212 fi; 213 s := [CHAR_INT(byte)]; 214 ConvertToStringRep( s ); 215 ret := IO_Write( stream![1], s ); 216 if ret <> 1 then 217 return fail; 218 else 219 return true; 220 fi; 221end); 222 223 224########################################################################### 225## 226#M WriteLine( <ioTCPstream>, <string> ) . . . write plus newline and flush 227## 228InstallMethod( WriteLine, "for ioTCPstream", 229[ IsInputOutputTCPStreamRep and IsInputOutputStream, IsString ], 230function( stream, string ) 231# local res; 232# res := WriteAll( stream, string ); 233# if res <> true then 234# return res; 235# fi; 236# WriteByte( stream, INT_CHAR('\n') ); 237# return IO_Flush( stream![1] ); 238return IO_WriteLine( stream![1], string ); 239end ); 240 241 242########################################################################### 243## 244#M WriteAll( <ioTCPstream>, <string> ) . . . . . . . . . write all bytes 245## 246InstallMethod( WriteAll, "for ioTCPstream", 247[ IsInputOutputTCPStreamRep and IsInputOutputStream, IsString ], 248function( stream, string ) 249 local byte; 250 for byte in string do 251 if WriteByte( stream, INT_CHAR(byte) ) <> true then 252 return fail; 253 fi; 254 od; 255 return true; 256end ); 257 258 259########################################################################### 260## 261#M IsEndOfStream( <ioTCPstream> ) 262## 263InstallMethod( IsEndOfStream, "iostream", 264 [ IsInputOutputTCPStreamRep and IsInputOutputStream ], 265 stream -> not IO_HasData( stream![1] ) ); 266 # or IS_BLOCKED_IOSTREAM(stream![1]) ); 267 268 269########################################################################### 270## 271#M CloseStream( <ioTCPstream> ) 272## 273InstallMethod( CloseStream, "for ioTCPstream", 274[ IsInputOutputTCPStreamRep and IsInputOutputStream ], 275function(stream) 276 IO_Close( stream![1] ); 277 SetFilterObj( stream, IsClosedStream ); 278end); 279 280 281########################################################################### 282## 283#M FileDescriptorOfStream( <ioTCPstream> ) 284## 285InstallMethod( FileDescriptorOfStream, "for ioTCPstream", 286[ IsInputOutputTCPStreamRep and IsInputOutputStream ], 287stream -> IO_GetFD( stream![1] ) ); 288 289 290########################################################################### 291## 292#F SCSCPwait( <ioTCPstream>, [ <timeout>] ) 293## 294InstallGlobalFunction( SCSCPwait, 295function( arg ) 296if Length(arg) = 2 then 297 IO_Select( [ arg[1]![1] ], [ ], [ ], [ ], arg[2], 0 ); 298elif Length(arg) = 1 then 299 IO_Select( [ arg[1]![1] ], [ ], [ ], [ ], 3600, 0 ); 300fi; 301end); 302 303########################################################################### 304## 305#E 306## 307