Monday, November 08, 2010 at 12:03 AM.
system.verbs.builtins.inetd.supervisor
on supervisor (stream, refcon) {
<<This is the callback that receives incoming requests for all inetd servers.
<<It calls the appropriate daemon script then returns data to the client.
<<Change Notes
<<Saturday, December 20, 1997 at 3:29:57 PM by PBS
<<Modified to work with tcp verbs.
<<Friday, February 27, 1998 at 9:03:42 AM by DW and RAB
<<Major update, added error log, everything within a try.
<<Friday, February 27, 1998 at 12:18:30 PM by RAB
<<Updated read data condensing it into 1 loop and allowing a yield to give time for the winsock buffer to refil
<<It no longer uses bytespending == 0 to terminate the read data loop
<<Updated the write on info from Dave Habermann to allow a yield on the writes to give a chance
<<for the buffers to be cleared before the next write.
<<Monday, March 9, 1998 at 3:15:00 PM by RAB
<<Added a thread sleep so as to yeild some time.
<<Thursday, March 12, 1998 at 9:31:15 PM by WF/RAB
<<Fixed bug where clocks.now was used instead of clock.ticks
<<Thursday, November 11, 1999 at 2:38:45 AM by AR
<<Implemented as a kernel verb in Frontier 6.1.
<<Old code
<<on supervisor (stream, refcon)
<<
<<if stream < 0 //an internal Frontier error, should never happen?
<<return (true) //don't terminate the listener
<<
<<if user.inetd.shutdown //you can turn off inetd by setting this global
<<tcp.closeStream (stream)
<<inetd.stop ()
<<return
<<
<<on addToErrorLog (whatWereWeDoing, errorString)
<<local (adrtable = log.addToGuestDatabase ("inetd", flHourlyRoll:true))
<<adrtable^.stream = stream
<<try {adrtable^.port = paramTable.port}
<<try {adrtable^.client = paramtable.client}
<<adrtable^.whatWentWrong = errorstring
<<adrtable^.whatWereWeDoing = whatWereWeDoing
<<try {tcp.closeStream (stream)}
<<
<<local (paramTable)
<<bundle //initialize paramtable
<<try
<<new (tableType, @paramTable)
<<paramTable.request = ""
<<paramTable.client = tcp.addressDecode (tcp.getPeerAddress (stream))
<<paramTable.ready = true
<<paramTable.refcon = refcon
<<paramTable.stream = stream
<<paramTable.inetdConfigTableAdr = user.inetd.listens.[refcon].adrTable
<<paramTable.port = paramTable.inetdConfigTableAdr^.port
<<else
<<addToErrorLog ("Initializing paramtable", tryError)
<<try {tcp.closeStream (stream)}
<<return (true) //don't terminate the listener
<<
<<local (noWait)
<<try {noWait = paramTable.inetdConfigTableAdr^.noWait} else {noWait = false}
<<
<<local (timeoutSecs)
<<try {timeoutSecs = paramTable.inetdConfigTableAdr^.timeout} else {timeoutSecs = user.inetd.prefs.defaultTimeoutSecs}
<<paramTable.timeout = timeoutSecs
<<local (tcTimeout = clock.ticks () + (60 * timeoutsecs))
<<
<<if not noWait //wait for the whole stream to come in
<<local (bytespending, status)
<<try
<<loop //wait for data to read
<<status = tcp.statusStream (stream, @bytespending)
<<if (bytespending > 0) and (status == "DATA")
<<paramTable.request = paramTable.request + tcp.readStream (stream, bytespending)
<<tcTimeout = clock.ticks () + 30 //Now give only 1/2 second to get more data
<<if status == "CLOSED"
<<break
<<if status == "INACTIVE"
<<break
<<if clock.ticks () > tcTimeout
<<break
<<if status == "OPEN"
<<sys.systemTask () //yield a little within this thread for the system
<<thread.sleepfor (1) //yield this thread for a second to allow normal Frontier processing
<<else
<<addToErrorLog ("Waiting for data", tryError)
<<return (true) //don't terminate the listener
<<
<<bundle //call the daemon
<<try
<<local (adrScript = @paramTable.inetdConfigTableAdr^.daemon)
<<if typeOf (adrScript^) == addressType //allow for indirect daemon scripts
<<adrScript = adrScript^
<<local (returnData = string (adrScript^ (@paramTable)))
<<if sizeof (returnData) > 0 //there is data to return
<<local (chunksize = user.inetd.prefs.returnChunkSize)
<<local (tcLastWrite = clock.ticks ())
<<loop //return data to the client
<<try
<<if sizeof (returnData) <= chunksize
<<tcp.writeStream (stream, returnData)
<<break
<<tcp.writeStream (stream, string.mid (returnData, 1, chunkSize))
<<tcLastWrite = clock.ticks ()
<<returnData = string.delete (returnData, 1, chunkSize)
<<else
<<if (tryerror contains "10035") && (clock.ticks () < (tcLastWrite + (60*5))) //10035 means the socket buffers are not ready, give them upto 5 second
<<sys.systemTask() //yield a little within this thread for the system
<<thread.sleepfor (1) //yield this thread for a second to allow normal frontier processing
<<else
<<addToErrorLog ("Returning data", tryError)
<<return (true) //don't terminate the listener
<<if sizeof (returnData) > 0 //there is data to return
<<tcp.writeStringToStream (stream, returnData, user.inetd.prefs.returnChunkSize, 10)
<<else
<<addToErrorLog ("Calling the daemon", tryError)
<<return (true) //don't terminate the listener
<<
<<try {tcp.closeStream (stream)}
<<return (true)
kernel (inetd.supervisor)}
This listing is for code that runs in the OPML Editor environment. I created these listings because I wanted the search engines to index it, so that when I want to look up something in my codebase I don't have to use the much slower search functionality in my object database. Dave Winer.