r93989 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r93988‎ | r93989 | r93990 >
Date:18:29, 5 August 2011
Author:demon
Status:ok (Comments)
Tags:
Comment:
Moving udpmcast back into trunk so mark can find it again. Ping r92262
Modified paths:
  • /trunk/ATTIC/udpmcast (deleted) (history)
  • /trunk/udpmcast (added) (history)

Diff [purge]

Index: trunk/udpmcast/udpmcast.py
@@ -0,0 +1,215 @@
 2+#!/usr/bin/python
 3+#
 4+# udpcast.py
 5+# application level udp multicaster/multiplexer
 6+# Written on 2005/04/03 by Mark Bergsma <mark@nedworks.org>
 7+#
 8+# $Id$
 9+
 10+import socket, getopt, sys, os, signal, pwd, grp
 11+
 12+debugging = False
 13+
 14+def createDaemon():
 15+ """
 16+ Detach a process from the controlling terminal and run it in the
 17+ background as a daemon.
 18+ """
 19+
 20+ try:
 21+ # Fork a child process so the parent can exit. This will return control
 22+ # to the command line or shell. This is required so that the new process
 23+ # is guaranteed not to be a process group leader. We have this guarantee
 24+ # because the process GID of the parent is inherited by the child, but
 25+ # the child gets a new PID, making it impossible for its PID to equal its
 26+ # PGID.
 27+ pid = os.fork()
 28+ except OSError, e:
 29+ return((e.errno, e.strerror)) # ERROR (return a tuple)
 30+
 31+ if (pid == 0): # The first child.
 32+
 33+ # Next we call os.setsid() to become the session leader of this new
 34+ # session. The process also becomes the process group leader of the
 35+ # new process group. Since a controlling terminal is associated with a
 36+ # session, and this new session has not yet acquired a controlling
 37+ # terminal our process now has no controlling terminal. This shouldn't
 38+ # fail, since we're guaranteed that the child is not a process group
 39+ # leader.
 40+ os.setsid()
 41+
 42+ # When the first child terminates, all processes in the second child
 43+ # are sent a SIGHUP, so it's ignored.
 44+ signal.signal(signal.SIGHUP, signal.SIG_IGN)
 45+
 46+ try:
 47+ # Fork a second child to prevent zombies. Since the first child is
 48+ # a session leader without a controlling terminal, it's possible for
 49+ # it to acquire one by opening a terminal in the future. This second
 50+ # fork guarantees that the child is no longer a session leader, thus
 51+ # preventing the daemon from ever acquiring a controlling terminal.
 52+ pid = os.fork() # Fork a second child.
 53+ except OSError, e:
 54+ return((e.errno, e.strerror)) # ERROR (return a tuple)
 55+
 56+ if (pid == 0): # The second child.
 57+ # Ensure that the daemon doesn't keep any directory in use. Failure
 58+ # to do this could make a filesystem unmountable.
 59+ os.chdir("/")
 60+ # Give the child complete control over permissions.
 61+ os.umask(0)
 62+ else:
 63+ os._exit(0) # Exit parent (the first child) of the second child.
 64+ else:
 65+ os._exit(0) # Exit parent of the first child.
 66+
 67+ # Close all open files. Try the system configuration variable, SC_OPEN_MAX,
 68+ # for the maximum number of open files to close. If it doesn't exist, use
 69+ # the default value (configurable).
 70+ try:
 71+ maxfd = os.sysconf("SC_OPEN_MAX")
 72+ except (AttributeError, ValueError):
 73+ maxfd = 256 # default maximum
 74+
 75+ for fd in range(0, maxfd):
 76+ try:
 77+ os.close(fd)
 78+ except OSError: # ERROR (ignore)
 79+ pass
 80+
 81+ # Redirect the standard file descriptors to /dev/null.
 82+ os.open("/dev/null", os.O_RDONLY) # standard input (0)
 83+ os.open("/dev/null", os.O_RDWR) # standard output (1)
 84+ os.open("/dev/null", os.O_RDWR) # standard error (2)
 85+
 86+ return(0)
 87+
 88+def debug(msg):
 89+ global debugging
 90+ if debugging:
 91+ print msg;
 92+
 93+def multicast_diagrams(sock, addrrules):
 94+ portnr = sock.getsockname()[1];
 95+
 96+ while 1:
 97+ diagram, srcaddr = sock.recvfrom(2**14)
 98+ if not diagram: break
 99+
 100+ try:
 101+ addresses = addrrules[srcaddr[0]]
 102+ except KeyError:
 103+ addresses = addrrules[0]
 104+
 105+ for addr in addresses:
 106+ try:
 107+ sock.sendto(diagram, 0, (addr, portnr))
 108+ debug('Sent diagram to '+addr+' port '+str(portnr))
 109+ except socket.error:
 110+ debug('Error while sending diagram to '+addr)
 111+ pass
 112+
 113+def join_multicast_group(sock, multicast_group):
 114+ import struct
 115+
 116+ ip_mreq = struct.pack('!4sl', socket.inet_aton(multicast_group),
 117+ socket.INADDR_ANY)
 118+ sock.setsockopt(socket.IPPROTO_IP,
 119+ socket.IP_ADD_MEMBERSHIP,
 120+ ip_mreq)
 121+
 122+ # We do not want to see our own messages back
 123+ sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP, 0)
 124+
 125+def print_help():
 126+ print 'Usage:\n\tudpmcast [ options ] { addresses | forward rules }\n'
 127+ print 'Options:'
 128+ print '\t-d\t\tFork into the background (become a daemon)'
 129+ print '\t-p {portnr}\tUDP port number to listen on (default is 4827)'
 130+ print '\t-j {mcast addr}\tMulticast group to join on startup'
 131+ print '\t-u {username}\tChange uid'
 132+ print '\t-g {group}\tChange group'
 133+ print '\t-t {ttl}\tSet multicast TTL for outgoing multicast packets'
 134+ print '\t-v\t\tBe more verbose'
 135+
 136+if __name__ == '__main__':
 137+ host = ''
 138+ portnr = 4827
 139+ multicast_group = None
 140+ multicast_ttl = None
 141+ daemon = False
 142+ user = group = None
 143+ opts = 'dhj:p:vu:g:t:'
 144+
 145+ # Parse options
 146+ options, arguments = getopt.getopt(sys.argv[1:], opts)
 147+ if len(arguments) == 0:
 148+ print_help()
 149+ sys.exit()
 150+ else:
 151+ for option, value in options:
 152+ if option == '-j':
 153+ multicast_group = value
 154+ elif option == '-p':
 155+ portnr = int(value)
 156+ elif option == '-h':
 157+ print_help()
 158+ sys.exit()
 159+ elif option == '-d':
 160+ daemon = True
 161+ elif option == '-u':
 162+ user = value
 163+ elif option == '-g':
 164+ group = value
 165+ elif option == '-v':
 166+ debugging = True
 167+ elif option == '-t':
 168+ multicast_ttl = int(value)
 169+
 170+ try:
 171+ # Change uid and gid
 172+ try:
 173+ if group: os.setgid(grp.getgrnam(group).gr_gid)
 174+ if user: os.setuid(pwd.getpwnam(user).pw_uid)
 175+ except:
 176+ print "Error: Could not change uid or gid."
 177+ sys.exit(-1)
 178+
 179+ # Become a daemon
 180+ if daemon:
 181+ createDaemon()
 182+
 183+ # Open the UDP socket
 184+ sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
 185+ sock.bind((host, portnr))
 186+
 187+ # Set the multicast TTL if requested
 188+ if multicast_ttl is not None:
 189+ sock.setsockopt(socket.IPPROTO_IP,
 190+ socket.IP_MULTICAST_TTL,
 191+ multicast_ttl)
 192+
 193+ # Join a multicast group if requested
 194+ if multicast_group is not None:
 195+ debug('Joining multicast group ' + multicast_group)
 196+ join_multicast_group(sock, multicast_group)
 197+
 198+ # Parse the argument list
 199+ addrrules = { 0: [] }
 200+ for argument in arguments:
 201+ if argument[0] == '{':
 202+ # Forward rule
 203+ addrrules.update(eval(argument))
 204+ else:
 205+ # Default forward
 206+ addrrules[0].append(argument)
 207+
 208+ debug('Forward rules: ' + str(addrrules))
 209+
 210+ # Multiplex everything that comes in
 211+ multicast_diagrams(sock, addrrules)
 212+ except socket.error, msg:
 213+ print msg[1];
 214+ except KeyboardInterrupt:
 215+ pass
 216+
Property changes on: trunk/udpmcast/udpmcast.py
___________________________________________________________________
Added: svn:keywords
1217 + Author Date Id Revision
Added: svn:eol-style
2218 + native
Added: svn:executable
3219 + *

Past revisions this follows-up on

RevisionCommit summaryAuthorDate
r92262Move old projects to the new ATTIC directory....hashar18:13, 15 July 2011

Comments

#Comment by Hashar (talk | contribs)   20:57, 5 August 2011

My apologies to the ops team. Since the script hasn't been updated I thought it was obsolete. Looks like it is just exempt of bugs :-)

#Comment by P858snake (talk | contribs)   01:06, 9 August 2011

perhaps we should move it to /tools/ or something and try to keep trunk cleanish

Status & tagging log