Submit Hint Search The Forums LinksStatsPollsHeadlinesRSS
14,000 hints and counting!


Click here to return to the 'A new workaround for dial-up disconnects and fax receive' hint
The following comments are owned by whoever posted them. This site is not responsible for what they say.
A new workaround for dial-up disconnects and fax receive
Authored by: kwindrem on Dec 27, '04 08:58:06PM
My original scipt helped, but there were still holes. I've tried a couple of different versions of the original idea, but the problem still occurs occationally. Here's a totally different approach:

To prevent pppd from hanging, it's execution is delayed after boot, wake from sleep or a disconnect (for any reason). I found no clean ways to hook pppd, but did manage to wrap a shell script around it where the delay can be inserted.

It installs and uninstalls itself with shell command line calls:


sudo PPPfix install
sudo PPPfix uninstall
and will repair the the pppd hook automatically should an OS update overwrite it.

The script requires SleepWatcher (http://home.t-online.de/home/bernhard.baehr/).

Here's the script (hopefully well enough documented for others to use):


#!/bin/sh -
# PPPfix -- works around pppd Disconnecting... hang

# pppd may fail if a dial-up attempt is made within ~20 seconds of waking/startup
# and also if a reconnect attempt occurs too soon after a disconnect
# with efax running, pppd will also hang in the Disconnecting... state if these failures occur
# the workaround is to hold off pppd's launch until the critical periods have passed

# holding off pppd startup is done by wrapping a shell script around the standard pppd executable
# the real pppd executable is renamed and a symbolic link to PPPfix
# named "pppd" is placed in pppd's original location so that configd will call it instead of the real pppd
# the script then checks to see if a dial attempt was made during the critical period
# and if so sleeps for the necessary time if necessary before launching the real pppd
# when the real pppd finishes, a new unsafe zone is computed

# this script has four distinct behaviors depending on how it is called
# they are grouped together in a common script to make it easier
# to synchronize operations and maintain changes

# 1) when called without any parameters,
# it checks and repairs the wrapper if it has been disturbed
# (e.g., an OS update might overwrite the shell with a new executable)
# then it sets up the initial unsafe zone and exits

# Sleepwatcher provides an excellent place for this call
# since it runs every time the system wakes up or boots.
# Sleepwatcher must be installed to use this script as is
# it can be dounloaded at http://www.bernhard-baehr.de/sleepwatcher_1.0.1.dmg

# 2) when called with install as the first parameter,
# the wrapper is installed and a symbolic link to PPPfix is created in /var/.wakeup
# so that sleepwatcher will execute it during the next boot/wakeup

# 3) when called with uninstall as the first parameter
# the pppd wrapper is uninstalled and normal pppd behavior is restored
# the /var/.wakup link is removed to prevent sleepwatcher from calling PPPfix

# the install and uninstall calls should be made manually
# this should be done manually but must be run with root privlidges:
# sudo /Applications/Utilities/PPPfix install
# sudo /Applications/Utilities/PPPfix uninstall

# 4) in all other cases, this script functions as the wrapper for the real pppd
# so that it's execution can be held off during unsafe periods
# all parameters passed to PPPfix are forwarded to the real pppd
# the assumption is that it's called by configd
# if not, behavior is not defined

# names of related files -- CHANGE these if locations or names vary
pppFix="/Applications/Utilities/PPPfix"
origPPPD="/usr/sbin/pppd"		# the location/name of the normal pppd execitable
renamedPPPD="${origPPPD}Real"		# the renamed location/name for the ppp executable
rootWakeup="/var/root/.wakeup"		# location of root's sleepwatcher wakup script

pppTimeFile="/tmp/pppSafeTime"		# used to store earliest "safe" time for pppd launch


# to ease calculations, times used in this script are seconds past the Epoch
# the following macro is used to get the system time

getTime="date +%s"


# calculate the earliest "safe" PPP startup time
# based on current time and delay time passed to function as 1st arguement
# safe time is stored in a file so multiple instances of PPPfix can access it

function setPPPsafeTime ()
{
	# compute and store earliest safe run time for pppd
	goTime=`$getTime`
	(( goTime=$goTime+$1 ))

	echo $goTime > $pppTimeFile
}


# this function is used to hook pppd if it has not been already
# tests prevent hooking the hook overwriting the pppd executable
# original pppd must NOT be a symbolic link
# PPPfix (this script) must exist and be executable

function hookPPPD ()
{
	if [[ ! -h $origPPPD && -x $pppFix ]]; then
	{
		# remove any existing renamed pppd
		rm -f $renamedPPPD

		# rename real pppd
		mv $origPPPD $renamedPPPD

		# setup PPPfix as the wrapper for pppd
		ln -s $pppFix $origPPPD

		logger fixed PPPD hook to holdoff execution during critical times
	}
	fi
}

# this function unhooks pppd and restores the pppd executable to its normal location/name
# original pppd must be a symbolic link
# tests prevent deleting the real executable
# the renamed real pppd must exist
# pppd must be a symbolic link to PPPfix

function unhookPPPD ()
{
	if [[ $origPPPD -ef $pppFix && -a $renamedPPPD ]]; then
	{
		rm -f $origPPPD
		mv $renamedPPPD $origPPPD

		logger PPPD hook uninstalled
	}
	fi
}


# delay times for unsafe zones
wakeupDelay=25		# time to disable PPP after wakeup/boot
reconnectDelay=15	# time to delay pppd after a disconnec



# this is the section executed at wake/boot
# called from sleepwatcher (no parameters) (root privileges)
if [[ $# == 0 ]]; then
{
	# check pppd hook and repair if necessary
	hookPPPD

	# set boot/wakeup unsafe zone
	setPPPsafeTime $wakeupDelay
}

# installer -- called from command line with root privileges 
elif [[ $1 == "install" ]]; then
{
	hookPPPD

	# install root's .wakeup file executed by Sleepwatcher
	if [[ ! -a $rootWakeup ]]; then
	{
		ln -s $pppFix $rootWakeup
	}
	else
	{
		echo $rootWakeup already exists -- install wakeup call manually
	}
	fi

}

# uninstaller -- called from command line with root privileges
elif [[ $1 == "uninstall" ]]; then
{
	unhookPPPD

	# uninstall root's .wakeup file executed by Sleepwatcher
	# .wakeup must be a symbolic link to PPPfix
	if [[ $rootWakeup -ef $pppFix ]]; then
	{
		rm -f $pppFix $rootWakeup
	}
	else
	{
		echo $rootWakeup is not a link to $pppFix -- uninstall wakeup call manually
	}
	fi
}

# this is the pppd wrapper -- called by configd (lots of parameters)
else
{
	# delay only needed if safe time file exists
	# and current time is before the safe time in the file
	if [ -s $pppTimeFile ]; then
	{
		safeTime=$(< $pppTimeFile)
		nowTime=`$getTime`

		if [ $nowTime -lt $safeTime ]; then
		{
			(( delayTime=$safeTime-$nowTime ))
			logger delaying pppd startup $delayTime seconds

			sleep $delayTime
		}
		fi
	}
	fi


	# run real pppd executable -- forward all parameters passed to PPPfix
	`$renamedPPPD "$@"`

	# save status so this script can emulate exit status of real pppd
	pppdStatus=$?

	# compute and store earliest safe run time for pppd
	setPPPsafeTime $reconnectDelay

	exit $pppdStatus
}
fi


[ Reply to This | # ]