[39514] branches/gsoc08-framework/MacPorts_Framework_Release

armahg at macports.org armahg at macports.org
Fri Aug 22 10:56:12 PDT 2008


Revision: 39514
          http://trac.macosforge.org/projects/macports/changeset/39514
Author:   armahg at macports.org
Date:     2008-08-22 10:56:11 -0700 (Fri, 22 Aug 2008)
Log Message:
-----------
Added MPNotifications* files for asynchronous notifications between MacPorts.Framework and MPHelperTool. This code only covers the MPHelperTool side of things. It currently compiles and runs fine with the Test bundle even though there is no indication that DoShout() command is being called

Modified Paths:
--------------
    branches/gsoc08-framework/MacPorts_Framework_Release/MPHelperTool.m
    branches/gsoc08-framework/MacPorts_Framework_Release/MacPorts.Framework.xcodeproj/project.pbxproj

Added Paths:
-----------
    branches/gsoc08-framework/MacPorts_Framework_Release/MPHelperNotificationsCommon.c
    branches/gsoc08-framework/MacPorts_Framework_Release/MPHelperNotificationsCommon.h
    branches/gsoc08-framework/MacPorts_Framework_Release/MPHelperNotificationsProtocol.h

Added: branches/gsoc08-framework/MacPorts_Framework_Release/MPHelperNotificationsCommon.c
===================================================================
--- branches/gsoc08-framework/MacPorts_Framework_Release/MPHelperNotificationsCommon.c	                        (rev 0)
+++ branches/gsoc08-framework/MacPorts_Framework_Release/MPHelperNotificationsCommon.c	2008-08-22 17:56:11 UTC (rev 39514)
@@ -0,0 +1,574 @@
+/*
+    File:       MPHelperNotificationsCommon.c
+
+    Contains:   Common code between client and server.
+
+    Written by: DTS
+
+    Copyright:  Copyright (c) 2005 by Apple Computer, Inc., All Rights Reserved.
+
+    Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
+                ("Apple") in consideration of your agreement to the following terms, and your
+                use, installation, modification or redistribution of this Apple software
+                constitutes acceptance of these terms.  If you do not agree with these terms,
+                please do not use, install, modify or redistribute this Apple software.
+
+                In consideration of your agreement to abide by the following terms, and subject
+                to these terms, Apple grants you a personal, non-exclusive license, under Apple's
+                copyrights in this original Apple software (the "Apple Software"), to use,
+                reproduce, modify and redistribute the Apple Software, with or without
+                modifications, in source and/or binary forms; provided that if you redistribute
+                the Apple Software in its entirety and without modifications, you must retain
+                this notice and the following text and disclaimers in all such redistributions of
+                the Apple Software.  Neither the name, trademarks, service marks or logos of
+                Apple Computer, Inc. may be used to endorse or promote products derived from the
+                Apple Software without specific prior written permission from Apple.  Except as
+                expressly stated in this notice, no other rights or licenses, express or implied,
+                are granted by Apple herein, including but not limited to any patent rights that
+                may be infringed by your derivative works or by other works in which the Apple
+                Software may be incorporated.
+
+                The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
+                WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+                WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+                PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+                COMBINATION WITH YOUR PRODUCTS.
+
+                IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+                CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+                GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+                ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+                OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+                (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+                ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+    Change History (most recent first):
+
+$Log: MPHelperNotificationsCommon.c,v $
+Revision 1.2  2005/06/30 20:22:25         
+Corrected a bug that would causing the packet's fID field to not be initialised in the RPC case.
+
+Revision 1.1  2005/05/17 12:19:17         
+First checked in.
+
+
+*/
+
+/////////////////////////////////////////////////////////////////
+
+// System interfaces
+
+#include <assert.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/fcntl.h>
+#include <sys/param.h>
+#include <sys/un.h>
+#include <netdb.h>
+
+// Our prototypes
+
+#include "MPHelperNotificationsCommon.h"
+
+/////////////////////////////////////////////////////////////////
+
+extern int MoreUNIXErrno(int result)
+    // See comment in header.
+{
+    int err;
+    
+    err = 0;
+    if (result < 0) {
+        err = errno;
+        assert(err != 0);
+    }
+    return err;
+}
+
+extern int MoreUNIXIgnoreSIGPIPE(void)
+    // See comment in header.
+{
+	int err;
+	struct sigaction signalState;
+	
+	err = sigaction(SIGPIPE, NULL, &signalState);
+	err = MoreUNIXErrno(err);
+	if (err == 0) {
+		signalState.sa_handler = SIG_IGN;
+		
+		err = sigaction(SIGPIPE, &signalState, NULL);
+		err = MoreUNIXErrno(err);
+	}
+	
+	return err;
+}
+
+extern int MoreUNIXRead( int fd,       void *buf, size_t bufSize, size_t *bytesRead   )
+    // See comment in header.
+{
+	int 	err;
+	char *	cursor;
+	size_t	bytesLeft;
+	ssize_t bytesThisTime;
+
+	assert(fd >= 0);
+	assert(buf != NULL);
+	
+	err = 0;
+	bytesLeft = bufSize;
+	cursor = (char *) buf;
+	while ( (err == 0) && (bytesLeft != 0) ) {
+		bytesThisTime = read(fd, cursor, bytesLeft);
+		if (bytesThisTime > 0) {
+			cursor    += bytesThisTime;
+			bytesLeft -= bytesThisTime;
+		} else if (bytesThisTime == 0) {
+			err = EPIPE;
+		} else {
+			assert(bytesThisTime == -1);
+			
+			err = errno;
+			assert(err != 0);
+			if (err == EINTR) {
+				err = 0;		// let's loop again
+			}
+		}
+	}
+	if (bytesRead != NULL) {
+		*bytesRead = bufSize - bytesLeft;
+	}
+	
+	return err;
+}
+
+extern int MoreUNIXWrite(int fd, const void *buf, size_t bufSize, size_t *bytesWritten)
+    // See comment in header.
+{
+	int 	err;
+	char *	cursor;
+	size_t	bytesLeft;
+	ssize_t bytesThisTime;
+	
+	assert(fd >= 0);
+	assert(buf != NULL);
+
+	err = 0;
+	bytesLeft = bufSize;
+	cursor = (char *) buf;
+	while ( (err == 0) && (bytesLeft != 0) ) {
+		bytesThisTime = write(fd, cursor, bytesLeft);
+		if (bytesThisTime > 0) {
+			cursor    += bytesThisTime;
+			bytesLeft -= bytesThisTime;
+		} else if (bytesThisTime == 0) {
+			assert(false);
+			err = EPIPE;
+		} else {
+			assert(bytesThisTime == -1);
+			
+			err = errno;
+			assert(err != 0);
+			if (err == EINTR) {
+				err = 0;		// let's loop again
+			}
+		}
+	}
+	if (bytesWritten != NULL) {
+		*bytesWritten = bufSize - bytesLeft;
+	}
+	
+	return err;
+}
+
+extern int MoreUNIXSetNonBlocking(int fd)
+{
+    int err;
+    int flags;
+ 
+    // According to the man page, F_GETFL can't error!
+    
+    flags = fcntl(fd, F_GETFL, NULL);
+    
+    err = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+    err = MoreUNIXErrno(err);
+    
+    return err;
+}
+
+static int					gSignalSinkFD   = -1;
+static CFSocketRef			gSignalSourceCF = NULL;
+static SignalSocketCallback	gClientCallback = NULL;
+static void *				gClientCallbackRefCon = NULL;
+
+static void SignalToSocketHandler(int sig, siginfo_t *sigInfo, void *uap)
+    // A signal handler that catches the signal and forwards it 
+    // to the runloop via gSignalSinkFD.  This code is careful to 
+    // only use signal safe routines (except for the asserts, 
+    // of course, but they're compiled out on production builds).
+{
+	#pragma unused(uap)
+	ssize_t		junk;
+	
+	assert(gSignalSinkFD != -1);
+	
+	assert(sig == sigInfo->si_signo);
+
+	junk = write(gSignalSinkFD, sigInfo, sizeof(*sigInfo));
+	
+	// There's not much I can do if this fails.  Missing a signal 
+	// isn't such a big deal, but writing only a partial siginfo_t 
+	// to the socket would be bad.
+	
+	assert(junk == sizeof(*sigInfo));
+}
+
+static void SignalCFSocketCallback(
+	CFSocketRef				s, 
+	CFSocketCallBackType	type, 
+	CFDataRef				address, 
+	const void *			data, 
+	void *					info
+)
+    // Call in the context of the runloop when data arrives on the 
+    // UNIX domain socket shared with the signal handler.  This 
+    // reads the information about the signal and passes to the client's 
+    // callback.
+{
+	#pragma unused(info)
+	int			err;
+	siginfo_t	sigInfo;
+
+	assert(gSignalSourceCF != NULL);
+	assert(gClientCallback != NULL);
+	
+	assert(s == gSignalSourceCF);
+	assert(type == kCFSocketReadCallBack);
+	assert(address == NULL);
+	assert(data == NULL);
+
+	err = MoreUNIXRead( CFSocketGetNative(gSignalSourceCF), &sigInfo, sizeof(sigInfo), NULL);
+	if (err == 0) {
+		gClientCallback(&sigInfo, gClientCallbackRefCon);
+	}
+	assert(err == 0);
+}
+
+extern int InstallSignalToSocket(
+	const sigset_t *		sigSet, 
+	CFRunLoopRef			runLoop,
+	CFStringRef				runLoopMode,
+	SignalSocketCallback	callback, 
+	void *					refCon
+)
+    // See comment in header.
+{
+	int		err;
+	int		junk;
+	int		sockets[2];
+	int		signalSourceFD;
+	
+	assert(sigSet != NULL);
+	assert(runLoop != NULL);
+	assert(runLoopMode != NULL);
+	assert(callback != NULL);
+	
+	assert(gSignalSinkFD   == -1);              // don't call me twice
+	assert(gSignalSourceCF == NULL);
+	assert(gClientCallback == NULL);
+	
+	signalSourceFD = -1;
+	
+    // Create a UNIX domain socket pair and assign them to the 
+    // sink (where the signal handler writes the information) and 
+    // source variables (where the runloop callback reads it).  
+    
+	err = socketpair(AF_UNIX, SOCK_STREAM, 0, sockets);
+	err = MoreUNIXErrno(err);
+	if (err == 0) {
+		gSignalSinkFD  = sockets[0];
+		signalSourceFD = sockets[1];
+	}
+    
+    // We set the signal sink socket to non-blocking because, if the 
+    // socket fills up, there's a possibility we might deadlock with 
+    // ourselves (the signal handler blocks trying to write data to 
+    // a full socket, but the runloop thread can't read data from the 
+    // socket because it has been interrupted by the signal handler).
+    
+    if (err == 0) {
+        err = MoreUNIXSetNonBlocking(gSignalSinkFD);
+    }
+
+    // Wrap the destination socket in a CFSocket, and create a 
+    // runloop source for it.  The associated callback (SignalCFSocketCallback) 
+    // receives information about the signal from the signal handler 
+    // and passes it along to the client's callback, but it's now in the context 
+    // of the runloop.
+    
+	if (err == 0) {
+		gSignalSourceCF = CFSocketCreateWithNative(
+			NULL,
+			signalSourceFD, 
+			kCFSocketCloseOnInvalidate | kCFSocketReadCallBack, 
+			SignalCFSocketCallback, 
+			NULL
+		);
+        if (gSignalSourceCF == NULL) {
+            err = EINVAL;
+        }
+	}
+	if (err == 0) {
+		CFRunLoopSourceRef	rls;
+		int					thisSigNum;
+
+		gClientCallback = callback;
+        gClientCallbackRefCon = refCon;
+		
+		rls = CFSocketCreateRunLoopSource(NULL, gSignalSourceCF, 0);
+        if (rls == NULL) {
+            err = EINVAL;
+        }
+
+		if (err == 0) {
+			CFRunLoopAddSource(runLoop, rls, runLoopMode);
+
+            // For each signal in the set, register our signal handler 
+            // (SignalToSocketHandler).  Specificy SA_SIGINFO so that 
+            // the handler gets lots of yummy signal information.
+            
+			for (thisSigNum = 0; thisSigNum < NSIG; thisSigNum++) {
+				if ( sigismember(sigSet, thisSigNum) ) {
+					struct sigaction newSignalAction;
+					
+					newSignalAction.sa_sigaction = SignalToSocketHandler;
+					newSignalAction.sa_flags = SA_SIGINFO;
+					sigemptyset(&newSignalAction.sa_mask);
+
+					junk = sigaction(thisSigNum, &newSignalAction, NULL);
+					assert(junk == 0);
+					
+					// Error recovery here would be hard.  We'd have to undo 
+					// any previous signal handlers that were installed 
+					// (requiring us to get the previous value and remembering 
+					// it) and then it would also require us to remove the 
+					// run loop source.  All-in-all, not worth the effort 
+					// given the very small chance of an error from sigaction.
+				}
+			}
+		}
+		
+        // We don't need the runloop source from here on, so release our 
+        // reference to it.  It still exists because the runloop knows about it.
+        
+        if (rls != NULL) {
+            CFRelease(rls);
+        }
+	}
+	
+	// Clean up.
+
+	if (err != 0) {
+		gClientCallback = NULL;
+		
+		if (gSignalSourceCF != NULL) {
+			CFSocketInvalidate(gSignalSourceCF);
+			CFRelease(gSignalSourceCF);
+			gSignalSourceCF = NULL;
+		}
+		
+		if (signalSourceFD != -1) {
+			junk = close(signalSourceFD);
+			assert(junk == 0);
+		}
+        
+        if (gSignalSinkFD != -1) {
+            junk = close(gSignalSinkFD);
+            assert(junk == 0);
+            
+            gSignalSinkFD = -1;
+        }
+	}
+	
+	return err;
+}
+
+static char * SockAddrToString(int fd, Boolean peer)
+    // Gets either the socket name or the peer name from the socket 
+    // (depending on the peer parameter) and converts it to a human 
+    // readable string.  The caller is responsible for freeing the 
+    // memory.
+{
+    int			err;
+    char *		result;
+    size_t		resultLen;
+    union {
+        struct sockaddr addr;
+        char            pad[SOCK_MAXADDRLEN];
+    } paddedAddr;
+    socklen_t	addrLen;
+    
+    addrLen = sizeof(paddedAddr);
+    assert(addrLen == SOCK_MAXADDRLEN);
+    
+    // Socket name, or peer name?
+    
+    if (peer) {
+        err = getpeername(fd, &paddedAddr.addr, &addrLen);
+    } else {
+        err = getsockname(fd, &paddedAddr.addr, &addrLen);
+    }
+    
+    // Convert the result to a string.
+    
+    if ( (err == -1) || (addrLen < offsetof(struct sockaddr, sa_data))) {
+        result = strdup("?");
+    } else {
+        char hostStr[NI_MAXHOST];
+        char servStr[NI_MAXSERV];
+        
+        assert(addrLen >= offsetof(struct sockaddr, sa_data));
+        assert(addrLen == paddedAddr.addr.sa_len);
+
+        err = getnameinfo(
+            &paddedAddr.addr, 
+            addrLen, 
+            hostStr, 
+            sizeof(hostStr), 
+            servStr, 
+            sizeof(servStr), 
+            NI_NUMERICHOST | NI_NUMERICSERV
+        );
+        if (err == 0) {
+            // Cool.  getnameinfo did all the heavy lifting, so we just return the results.
+            
+            resultLen = strlen(hostStr) + 1 + strlen(servStr) + 1;
+            result = malloc(resultLen);
+            if (result != NULL) {
+                snprintf(result, resultLen, "%s %s", hostStr, servStr);
+            }
+        } else {
+            // Drat.  getnameinfo isn't helping out with this address, so we have to do it 
+            // all by hand.
+            
+            switch (paddedAddr.addr.sa_family) {
+                case AF_UNIX:
+                    {
+                        struct sockaddr_un * unAddr;
+                        
+                        assert(addrLen < SOCK_MAXADDRLEN);
+                        paddedAddr.pad[addrLen] = 0;
+                        unAddr = (struct sockaddr_un *) &paddedAddr.addr;
+                        result = strdup( unAddr->sun_path );
+                    }
+                    break;
+                default:
+                    assert(false);
+                    result = strdup("unrecognised address");
+                    break;
+            };
+        }
+    }
+                
+    return result;
+}
+
+extern void DebugPrintDescriptorTable(void)
+    // See comment in header.
+{
+    int			err;
+    int			descCount;
+    int			descIndex;
+    char		pathBuf[MAXPATHLEN];
+    int			sockType;
+    socklen_t	sockTypeLen;
+    static const char * kSockTypeToStr[] = {
+        "unknown    ",
+        "SOCK_STREAM",
+        "SOCK_DGRAM ",
+        "SOCK_RAW   ",
+        "SOCK_RDM   ",
+        "SOCK_SEQPACKET"            // not going to see this anyway, so don't need to pad everything else to this long length
+    };
+
+    fprintf(stderr, "Descriptors:\n");
+
+    descCount = getdtablesize();
+    for (descIndex = 0; descIndex < descCount; descIndex++) {
+        if ( fcntl(descIndex, F_GETFD, NULL) != -1 ) {
+
+            // Descriptor is active, let's try to find out what it is.
+
+            // See if we can get a file path from it.
+            
+            err = fcntl(descIndex, F_GETPATH, pathBuf);
+            if (err != -1) {
+            
+                // If it's a file, print its path.
+                
+                fprintf(stderr, "  %2d file    '%s'\n", descIndex, pathBuf);
+            } else {
+            
+                // See if it's a socket.
+                
+                sockTypeLen = sizeof(sockType);
+                err = getsockopt(descIndex, SOL_SOCKET, SO_TYPE, &sockType, &sockTypeLen);
+                if (err != -1) {
+                    char *  localStr;
+                    char *  peerStr;
+                    const char *  sockTypeStr;
+
+                    // If it's a socket, print the local and remote address.
+                    
+                    localStr = NULL;
+                    peerStr  = NULL;
+                    
+                    localStr = SockAddrToString(descIndex, false);
+                    peerStr  = SockAddrToString(descIndex, true);
+
+                    if ( (sockType < 0) || (sockType > (sizeof(kSockTypeToStr) / sizeof(kSockTypeToStr[0]))) ) {
+                        sockTypeStr = kSockTypeToStr[0];
+                    } else {
+                        sockTypeStr = kSockTypeToStr[sockType];
+                    }
+                    if (sockTypeStr == kSockTypeToStr[0]) {
+                        fprintf(stderr, "  %2d socket  %s (%d) %s -> %s\n", descIndex, sockTypeStr, sockType, localStr, peerStr);
+                    } else {
+                        fprintf(stderr, "  %2d socket  %s %s -> %s\n", descIndex, sockTypeStr, localStr, peerStr);
+                    }
+                    
+                    free(localStr);
+                    free(peerStr);
+                } else {
+
+                    // No idea.
+
+                    fprintf(stderr, "  %2d unknown\n", descIndex);
+                }
+            }
+        }
+    }
+}
+
+extern void InitPacketHeader(PacketHeader *packet, OSType packetType, size_t packetSize, Boolean rpc)
+    // See comment in header.
+{
+    static int sNextID = kPacketIDFirst;
+    
+    assert(packet != NULL);
+    assert(packetSize >= sizeof(PacketHeader));
+    
+    packet->fMagic = kPacketMagic;
+    packet->fType  = packetType;
+    if (rpc) {
+        // Increment to the next ID, skipping 0.
+        
+		packet->fID = sNextID;
+        sNextID += 1;
+        if (sNextID == kPacketIDNone) {
+            sNextID = kPacketIDFirst;
+        }
+    } else {
+        packet->fID = kPacketIDNone;
+    }
+    packet->fSize = packetSize;
+}


Property changes on: branches/gsoc08-framework/MacPorts_Framework_Release/MPHelperNotificationsCommon.c
___________________________________________________________________
Name: svn:executable
   + *

Added: branches/gsoc08-framework/MacPorts_Framework_Release/MPHelperNotificationsCommon.h
===================================================================
--- branches/gsoc08-framework/MacPorts_Framework_Release/MPHelperNotificationsCommon.h	                        (rev 0)
+++ branches/gsoc08-framework/MacPorts_Framework_Release/MPHelperNotificationsCommon.h	2008-08-22 17:56:11 UTC (rev 39514)
@@ -0,0 +1,119 @@
+/*
+    File:       MPHelperNotificationsCommon.h
+
+    Contains:   Common code between client and server.
+
+    Written by: DTS
+
+    Copyright:  Copyright (c) 2005 by Apple Computer, Inc., All Rights Reserved.
+
+    Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
+                ("Apple") in consideration of your agreement to the following terms, and your
+                use, installation, modification or redistribution of this Apple software
+                constitutes acceptance of these terms.  If you do not agree with these terms,
+                please do not use, install, modify or redistribute this Apple software.
+
+                In consideration of your agreement to abide by the following terms, and subject
+                to these terms, Apple grants you a personal, non-exclusive license, under Apple's
+                copyrights in this original Apple software (the "Apple Software"), to use,
+                reproduce, modify and redistribute the Apple Software, with or without
+                modifications, in source and/or binary forms; provided that if you redistribute
+                the Apple Software in its entirety and without modifications, you must retain
+                this notice and the following text and disclaimers in all such redistributions of
+                the Apple Software.  Neither the name, trademarks, service marks or logos of
+                Apple Computer, Inc. may be used to endorse or promote products derived from the
+                Apple Software without specific prior written permission from Apple.  Except as
+                expressly stated in this notice, no other rights or licenses, express or implied,
+                are granted by Apple herein, including but not limited to any patent rights that
+                may be infringed by your derivative works or by other works in which the Apple
+                Software may be incorporated.
+
+                The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
+                WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+                WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+                PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+                COMBINATION WITH YOUR PRODUCTS.
+
+                IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+                CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+                GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+                ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+                OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+                (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+                ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+    Change History (most recent first):
+
+$Log: MPHelperNotificationsCommon.h,v $
+Revision 1.1  2005/05/17 12:19:20         
+First checked in.
+
+
+*/
+
+#ifndef _COMMON_H
+#define _COMMON_H
+
+/////////////////////////////////////////////////////////////////
+
+// System interfaces
+
+#include <CoreServices/CoreServices.h>
+
+// Project interfaces
+
+#include "MPHelperNotificationsProtocol.h"
+
+/////////////////////////////////////////////////////////////////
+
+extern int MoreUNIXErrno(int result);
+extern int MoreUNIXIgnoreSIGPIPE(void);
+extern int MoreUNIXRead( int fd,       void *buf, size_t bufSize, size_t *bytesRead   );
+extern int MoreUNIXWrite(int fd, const void *buf, size_t bufSize, size_t *bytesWritten);
+    // The above routines are taken from the MoreIsBetter library.
+
+extern int MoreUNIXSetNonBlocking(int fd);
+    
+typedef void (*SignalSocketCallback)(const siginfo_t *sigInfo, void *refCon);
+    // This callback is called when a signal occurs.  It's called in the 
+    // context of the runloop specified when you registered the callback.  
+    // sigInfo describes the signal and refCon is the value you supplied 
+    // when you registered the callback.
+
+extern int InstallSignalToSocket(
+	const sigset_t *		sigSet, 
+	CFRunLoopRef			runLoop,
+	CFStringRef				runLoopMode,
+	SignalSocketCallback	callback, 
+	void *					refCon
+);
+    // A method for routing signals to a runloop-based program. 
+    //
+    // sigSet is the set of signals that you're interested in. 
+    // Use the routines documented in <x-man-page://3/sigsetopts> 
+    // to construct this.
+    //
+    // runLoop and runLoopMode specify how you want the callback 
+    // to be run.  You typically pass CFRunLoopGetCurrent and 
+    // kCFRunLoopDefaultMode.
+    //
+    // callback is the routine you want called, and refCon is an 
+    // uninterpreted value that's passed to that callback.
+    //
+    // The function result is an errno-style error code.
+    //
+    // IMPORTANT:
+    // You can only call this routine once for any given application; 
+    // you must register all of the signals you're interested in at that 
+    // time.  There is no way to deregister.
+
+#endif
+
+extern void DebugPrintDescriptorTable(void);
+    // Prints a nice dump of the file descriptor table to stdout.
+
+extern void InitPacketHeader(PacketHeader *packet, OSType packetType, size_t packetSize, Boolean rpc);
+    // Initialises the PacketHeader structure with the values specified 
+    // in the parameters.  The rpc parameter controls whether the fID 
+    // field is set to kPacketIDNone (rpc false, hence no ID) or an 
+    // incrementing sequence number (rpc true).


Property changes on: branches/gsoc08-framework/MacPorts_Framework_Release/MPHelperNotificationsCommon.h
___________________________________________________________________
Name: svn:executable
   + *
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Added: branches/gsoc08-framework/MacPorts_Framework_Release/MPHelperNotificationsProtocol.h
===================================================================
--- branches/gsoc08-framework/MacPorts_Framework_Release/MPHelperNotificationsProtocol.h	                        (rev 0)
+++ branches/gsoc08-framework/MacPorts_Framework_Release/MPHelperNotificationsProtocol.h	2008-08-22 17:56:11 UTC (rev 39514)
@@ -0,0 +1,182 @@
+/*
+    File:       MPHelperNotificationsProtocol.h
+
+    Contains:   Definition of the communication protocol between client and server.
+
+    Written by: DTS
+
+    Copyright:  Copyright (c) 2005 by Apple Computer, Inc., All Rights Reserved.
+
+    Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
+                ("Apple") in consideration of your agreement to the following terms, and your
+                use, installation, modification or redistribution of this Apple software
+                constitutes acceptance of these terms.  If you do not agree with these terms,
+                please do not use, install, modify or redistribute this Apple software.
+
+                In consideration of your agreement to abide by the following terms, and subject
+                to these terms, Apple grants you a personal, non-exclusive license, under Apple's
+                copyrights in this original Apple software (the "Apple Software"), to use,
+                reproduce, modify and redistribute the Apple Software, with or without
+                modifications, in source and/or binary forms; provided that if you redistribute
+                the Apple Software in its entirety and without modifications, you must retain
+                this notice and the following text and disclaimers in all such redistributions of
+                the Apple Software.  Neither the name, trademarks, service marks or logos of
+                Apple Computer, Inc. may be used to endorse or promote products derived from the
+                Apple Software without specific prior written permission from Apple.  Except as
+                expressly stated in this notice, no other rights or licenses, express or implied,
+                are granted by Apple herein, including but not limited to any patent rights that
+                may be infringed by your derivative works or by other works in which the Apple
+                Software may be incorporated.
+
+                The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
+                WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+                WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+                PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+                COMBINATION WITH YOUR PRODUCTS.
+
+                IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+                CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+                GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+                ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+                OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+                (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+                ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+    Change History (most recent first):
+
+$Log: MPHelperNotificationsProtocol.h,v $
+Revision 1.1  2005/05/17 12:19:23         
+First checked in.
+
+
+*/
+
+#ifndef _PROTOCOL_H
+#define _PROTOCOL_H
+
+/////////////////////////////////////////////////////////////////
+
+// System interfaces
+
+#include <CoreServices/CoreServices.h>
+
+#include <inttypes.h>
+
+/////////////////////////////////////////////////////////////////
+
+// Packet types
+
+enum {
+    kPacketTypeGoodbye = 'GDBY',            // sent by client to server before signing off
+    kPacketTypeNOP     = 'NOOP',            // no operation, test for client/server RPC
+    kPacketTypeReply   = 'RPLY',            // all RPC replies are of this type
+    kPacketTypeWhisper = 'WSPR',            // client/server RPC to print message on server
+    kPacketTypeShout   = 'SHOU',            // sent by client to server, which echoes it to all listening clients
+    kPacketTypeListen  = 'LSTN',            // client/server RPC to register for shouts
+    kPacketTypeQuit    = 'QUIT'             // client/server RPC to tell server to quit
+};
+
+// Well known packet IDs (for the fID field of the packet header).
+// kPacketIDFirst is just a suggestion.  The server doesn't require 
+// that the client use sequential IDs starting from 1; the IDs are 
+// for the client to choose.  However, the use of kPacketIDNone for 
+// some packets (those that don't have a reply) is a hard requirement 
+// in the server.  
+
+enum {
+    kPacketIDNone  = 0,
+    kPacketIDFirst = 1
+};
+
+// kPacketMagic is first four bytes of every packet.  If the packet stream 
+// gets out of sync, this will quickly detect the problem.
+
+enum {
+    kPacketMagic = 'LSPM'               // for Local Server Packet Magic
+};
+
+// kPacketMaximumSize is an arbitrary limit, chosen so that we can detect 
+// if the packet streams get out of sync or if a client goes mad.
+
+enum {  
+    kPacketMaximumSize = 100 * 1024     // just basic sanity checks
+};
+
+// IMPORTANT:
+// The following structures define the packets sent between the client and 
+// the server.  For a network protocol you'd need to worry about byte ordering, 
+// but this isn't a network protocol (it always stays on the same machine) so 
+// I don't have to worry.  However, I do need to worry about having 
+// size invariant types (so that 32- and 64-bit clients and servers are 
+// all compatible) and structure alignment (so that code compiled by different 
+// compilers is compatible).  Size invariant types is easy, and represented 
+// by the structures below.  Alignment is trickier, and I'm mostly just 
+// glossing over the issue right now.
+
+// PacketHeader is the header at the front of every packet.
+
+struct PacketHeader {
+    OSType          fMagic;             // must be kPacketMagic
+    OSType          fType;              // kPacketTypeGoodbye etc 
+    int32_t         fID;                // kPacketIDNone or some other value
+    uint32_t        fSize;              // includes size of header itself
+};
+typedef struct PacketHeader PacketHeader;
+
+struct PacketGoodbye {                  // reply: n/a
+    PacketHeader    fHeader;            // fType is kPacketTypeGoodbye, fID must be kPacketIDNone
+    char            fMessage[32];       // Just for fun.
+};
+typedef struct PacketGoodbye PacketGoodbye;
+
+struct PacketNOP {                      // reply: PacketReply
+    PacketHeader    fHeader;            // fType is kPacketTypeNOP, fID echoed
+};
+typedef struct PacketNOP PacketNOP;
+
+struct PacketReply {                    // reply: n/a
+    PacketHeader    fHeader;            // fType is kPacketTypeReply, fID is ID of request
+    int32_t         fErr;               // result of operation, errno-style
+};
+typedef struct PacketReply PacketReply;
+
+struct PacketWhisper {                  // reply: PacketReply
+    PacketHeader    fHeader;            // fType is kPacketTypeWhisper, fID echoed
+    char            fMessage[32];       // message to print
+};
+typedef struct PacketWhisper PacketWhisper;
+
+struct PacketShout {                    // reply: none
+    PacketHeader    fHeader;            // fType is kPacketTypeShout, fID must be kPacketIDNone
+    char            fMessage[32];       // message for each of the clients
+};
+typedef struct PacketShout PacketShout;
+
+// Shouts are echoed to anyone who listens, including sender.
+
+struct PacketListen {                   // reply: PacketReply
+    PacketHeader    fHeader;            // fType is kPacketTypeListen, fID echoed
+};
+typedef struct PacketListen PacketListen;
+
+struct PacketQuit {                     // reply: PacketReply
+    PacketHeader    fHeader;            // fType is kPacketTypeQuit, fID echoed
+};
+typedef struct PacketQuit PacketQuit;
+
+// IMPORTANT:
+// The location of the kServerAddress socket file is intimately tied to the 
+// security of the server.  The file should be placed in a directory that's 
+// read access to everyone who needs access to the service, but only write 
+// accessible to the UID that's running the server.  Failure to follow this  
+// guideline may make your server subject to security exploits.
+//
+// To prevent this sort of silliness I require that the socket be created 
+// in a directory owned by the server's user ("com.apple.dts.CFLocalServer") 
+// within a directory that's sticky ("/var/tmp", not "/tmp" because that's 
+// periodically cleaned up). See SafeBindUnixDomainSocket (in "Server.c") for 
+// the details about how I achieve this.
+
+#define kServerSocketPath "/var/run/org.macports.MacPorts.Framework.MPHelperToolIPC.socket"
+
+#endif


Property changes on: branches/gsoc08-framework/MacPorts_Framework_Release/MPHelperNotificationsProtocol.h
___________________________________________________________________
Name: svn:executable
   + *
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Modified: branches/gsoc08-framework/MacPorts_Framework_Release/MPHelperTool.m
===================================================================
--- branches/gsoc08-framework/MacPorts_Framework_Release/MPHelperTool.m	2008-08-22 17:39:56 UTC (rev 39513)
+++ branches/gsoc08-framework/MacPorts_Framework_Release/MPHelperTool.m	2008-08-22 17:56:11 UTC (rev 39514)
@@ -41,8 +41,18 @@
 #include <tcl.h>
 #include "MPHelperCommon.h"
 
+#include "MPHelperNotificationsProtocol.h"
+#include "MPHelperNotificationsCommon.h"
 
+#include <stdlib.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <signal.h>
 
+
+
 //According to the docs all I need is
 //the file descriptor that MPNotifications
 //obtained when creating the server socket
@@ -52,6 +62,355 @@
 BOOL hasSetFileDescriptor = NO;
 
 
+
+#pragma mark -
+/////////////////////////////////////////////////////////////////
+#pragma mark ***** Notifications Connection Abstraction
+
+// A ConnectionRef represents a connection from the client to the server. 
+// The internals of this are opaque to external callers.  All operations on 
+// a connection are done via the routines in this section.
+
+enum {
+    kConnectionStateMagic = 'LCCM'           // Local Client Connection Magic
+};
+
+typedef struct ConnectionState *  ConnectionRef;
+// Pseudo-opaque reference to the connection.
+
+typedef Boolean (*ConnectionCallbackProcPtr)(
+											 ConnectionRef           conn, 
+											 const PacketHeader *    packet, 
+											 void *                  refCon
+											 );
+// When the client enables listening on a connection, it supplies a 
+// function of this type as a callback.  We call this function in 
+// the context of the runloop specified by the client when they enable 
+// listening.
+//
+// conn is a reference to the connection.  It will not be NULL.
+//
+// packet is a pointer to the packet that arrived, or NULL if we've 
+// detected that the connection to the server is broken.
+//
+// refCon is a value that the client specified when it registered this 
+// callback.
+//
+// If the server sends you a bad packet, you can return false to 
+// tell the connection management system to shut down the connection.
+
+// ConnectionState is the structure used to track a single connection to 
+// the server.  All fields after fSockFD are only relevant if the client 
+// has enabled listening.
+
+struct ConnectionState {
+    OSType                      fMagic;             // kConnectionStateMagic
+    int                         fSockFD;            // UNIX domain socket to server
+    CFSocketRef                 fSockCF;            // CFSocket wrapper for the above
+    CFRunLoopSourceRef          fRunLoopSource;     // runloop source for the above
+    CFMutableDataRef            fBufferedPackets;   // buffer for incomplete packet data
+    ConnectionCallbackProcPtr   fCallback;          // client's packet callback
+    void *                      fCallbackRefCon;    // refCon for the above.
+};
+
+// Forward declarations.  See the comments associated with the function definition.
+
+static void ConnectionShutdown(ConnectionRef conn);
+static void ConnectionCloseInternal(ConnectionRef conn, Boolean sayGoodbye);
+
+enum {
+    kResultColumnWidth = 10
+};
+
+static int ConnectionSend(ConnectionRef conn, const PacketHeader *packet)
+// Send a packet to the server.  Use this when you're not expecting a 
+// reply.
+//
+// conn must be a valid connection
+// packet must be a valid, ready-to-send, packet
+// Returns an errno-style error code
+{
+    int     err;
+    
+    assert(conn != NULL);
+    assert(conn->fSockFD != -1);            // connection must not be shut down
+    // conn->fSockCF may or may not be NULL; it's OK to send a packet when listening 
+    // because there's no reply; OTOH, you can't do an RPC while listening because 
+    // an unsolicited packet might get mixed up with the RPC reply.
+    
+    assert(packet != NULL);
+    assert(packet->fMagic == kPacketMagic);
+    assert(packet->fSize >= sizeof(PacketHeader));
+    
+    // Simply send the packet down the socket.
+    
+    err = MoreUNIXWrite(conn->fSockFD, packet, packet->fSize, NULL);
+    
+    return err;
+}
+
+static int ConnectionOpen(ConnectionRef *connPtr)
+// Opens a connection to the server.
+//
+// On entry, connPtr must not be NULL
+// On entry, *connPtr must be NULL
+// Returns an errno-style error code
+// On success, *connPtr will not be NULL
+// On error, *connPtr will be NULL
+{
+    int                 err;
+    ConnectionRef       conn;
+    Boolean             sayGoodbye;
+    
+    assert( connPtr != NULL);
+    assert(*connPtr == NULL);
+    
+    sayGoodbye = false;
+    
+    // Allocate a ConnectionState structure and fill out some basic fields.
+    
+    err = 0;
+    conn = (ConnectionRef) calloc(1, sizeof(*conn));
+    if (conn == NULL) {
+        err = ENOMEM;
+    }
+    if (err == 0) {
+        conn->fMagic  = kConnectionStateMagic;
+        
+        // For clean up to work properly, we must make sure that, if 
+        // the connection record is allocated successfully, we always 
+        // set fSockFD to -1.  So, while the following line is redundant 
+        // in the current code, it's present to press home this point.
+		
+        conn->fSockFD = -1;
+    }
+    
+    // Create a UNIX domain socket and connect to the server. 
+    
+    if (err == 0) {
+        conn->fSockFD = socket(AF_UNIX, SOCK_STREAM, 0);
+        err = MoreUNIXErrno(conn->fSockFD);
+    }
+    if (err == 0) {
+        struct sockaddr_un connReq;
+		
+        connReq.sun_len    = sizeof(connReq);
+        connReq.sun_family = AF_UNIX;
+        strcpy(connReq.sun_path, kServerSocketPath);
+		
+        err = connect(conn->fSockFD, (struct sockaddr *) &connReq, SUN_LEN(&connReq));
+        err = MoreUNIXErrno(err);
+        
+        sayGoodbye = (err == 0);
+    }
+    
+    // Clean up.
+    
+    if (err != 0) {
+        ConnectionCloseInternal(conn, sayGoodbye);
+        conn = NULL;
+    }
+    *connPtr = conn;
+    
+    assert( (err == 0) == (*connPtr != NULL) );
+    
+    return err;
+}
+
+
+static void ConnectionShutdown(ConnectionRef conn)
+// This routine shuts down down the connection to the server 
+// without saying goodbye; it leaves conn valid.  This routine 
+// is primarily used internally to the connection abstraction 
+// where we notice that the connection has failed for some reason. 
+// It's also called by the client after a successful quit RPC 
+// because we know that the server has closed its end of the 
+// connection.
+//
+// It's important to nil out the fields as we close them because 
+// this routine is called if any messaging routine fails.  If it 
+// doesn't nil out the fields, two bad things might happen:
+//
+// o When the connection is eventually closed, ConnectionCloseInternal 
+//   will try to send a Goodbye, which fails triggering an assert.
+//
+// o If ConnectionShutdown is called twice on a particular connection 
+//   (which happens a lot; this is a belts and braces implementation 
+//   [that's "belts and suspenders" for the Americans reading this; 
+//   ever wonder why Monty Python's lumberjacks sing about "suspenders 
+//   and a bra"?; well look up "suspenders" in a non-American dictionary 
+//   for a quiet chuckle :-] )
+{
+    int     junk;
+    Boolean hadSockCF;
+	
+    assert(conn != NULL);
+    
+    conn->fCallback       = NULL;
+    conn->fCallbackRefCon = NULL;
+	
+    if (conn->fRunLoopSource != NULL) {
+        CFRunLoopSourceInvalidate(conn->fRunLoopSource);
+        
+        CFRelease(conn->fRunLoopSource);
+        
+        conn->fRunLoopSource = NULL;
+    }
+    
+    // CFSocket will close conn->fSockFD when we invalidate conn->fSockCF, 
+    // so we remember whether we did this so that, later on, we know 
+    // whether to close the file descriptor ourselves.  We need an extra 
+    // variable because we NULL out fSockCF as we release it, for the reason 
+    // described above.
+    
+    hadSockCF = (conn->fSockCF != NULL);
+    if (conn->fSockCF != NULL) {
+        CFSocketInvalidate(conn->fSockCF);
+        
+        CFRelease(conn->fSockCF);
+        
+        conn->fSockCF = NULL;
+    }
+	
+    if (conn->fBufferedPackets != NULL) {
+        CFRelease(conn->fBufferedPackets);
+        conn->fBufferedPackets = NULL;
+    }
+	
+    if ( (conn->fSockFD != -1) && ! hadSockCF ) {
+        junk = close(conn->fSockFD);
+        assert(junk == 0);
+    }
+    // We always set fSockFD to -1 because either we've closed it or 
+    // CFSocket has.
+    conn->fSockFD = -1;
+}
+
+
+static void ConnectionCloseInternal(ConnectionRef conn, Boolean sayGoodbye)
+// The core of ConnectionClose.  It's called by ConnectionClose 
+// and by ConnectionOpen, if it fails for some reason.  This exists 
+// as a separate routine so that we can add the sayGoodbye parameter, 
+// which controls whether we send a goodbye packet to the server.  We 
+// need this because we should always try to say goodbye if we're called 
+// from ConnectionClose, but if we're called from ConnectionOpen we 
+// should only try to say goodbye if we successfully connected the 
+// socket.
+//
+// Regardless, the bulk of the work of this routine is done by 
+// ConnectionShutdown.  This routine exists to a) say goodbye, if 
+// necessary, and b) free the memory associated with the connection.
+{
+    int     junk;
+    
+    if (conn != NULL) {
+        assert(conn->fMagic == kConnectionStateMagic);
+		
+        if ( (conn->fSockFD != -1) && sayGoodbye ) {
+            PacketGoodbye   goodbye;
+			
+            InitPacketHeader(&goodbye.fHeader, kPacketTypeGoodbye, sizeof(goodbye), false);
+            snprintf(goodbye.fMessage, sizeof(goodbye.fMessage), "Process %ld signing off", (long) getpid());
+            
+            junk = ConnectionSend(conn, &goodbye.fHeader);
+            assert(junk == 0);
+        }
+        ConnectionShutdown(conn);
+        
+        free(conn);
+    }
+}
+
+static void ConnectionClose(ConnectionRef conn)
+// Closes the connection.  It's legal to pass conn as NULL, in which 
+// case this does nothing (kinda like free'ing NULL).
+{
+    ConnectionCloseInternal(conn, true);
+}
+
+
+
+/////////////////////////////////////////////////////////////////
+#pragma mark ***** Notifications Command Utilities 
+
+static void SIGINTRunLoopCallback(const siginfo_t *sigInfo, void *refCon)
+// This routine is called in response to a SIGINT signal. 
+// It is not, however, a signal handler.  Rather, we 
+// orchestrate to have it called from the runloop (via 
+// the magic of InstallSignalToSocket).  It's purpose 
+// is to stop the runloop when the user types ^C.
+{
+#pragma unused(sigInfo)
+#pragma unused(refCon)
+    
+    // Stop the runloop.  Note that we can get a reference to the runloop by 
+	// calling CFRunLoopGetCurrent because this is called from the runloop.
+    
+    CFRunLoopStop( CFRunLoopGetCurrent() );
+    
+    // Print a bonus newline to ensure that the next command prompt isn't 
+    // printed on the same line as the echoed ^C.
+    
+    fprintf(stderr, "\n");
+}
+
+
+static void PrintResult(const char *command, int errNum, const char *arg)
+// Prints the result of a command.  command is the name of the 
+// command, errNum is the errno-style error number, and arg 
+// (if not NULL) is the command argument.
+{
+    if (errNum == 0) {
+        if (arg == NULL) {
+            fprintf(stderr, "%*s\n", kResultColumnWidth, command);
+        } else {
+            fprintf(stderr, "%*s \"%s\"\n", kResultColumnWidth, command, arg);
+        }
+    } else {
+        fprintf(stderr, "%*s failed with error %d\n", kResultColumnWidth, command, errNum);
+    }
+}
+
+
+
+
+static void DoShout(ConnectionRef conn, const char *message)
+// Implements the "shout" command by sending a shout packet to the server. 
+// Note that this is /not/ an RPC.
+//
+// The server responds to this packet by echoing it to each registered 
+// listener.
+{
+	
+	//asl logging stuff
+	aslmsg logMsg = asl_new(ASL_TYPE_MSG) ;
+	assert(logMsg != NULL);
+	asl_set(logMsg, ASL_KEY_FACILITY, "com.apple.console");
+	asl_set(logMsg, ASL_KEY_SENDER, "MPHelperTool");
+	
+	aslclient logClient = asl_open(NULL , NULL, ASL_OPT_STDERR);
+	assert(logClient != NULL);
+
+	
+    int         err;
+	NSString * shoutString = [NSString stringWithFormat:@"Do Shout is passing %@", 
+							  [NSString stringWithCString:message encoding:NSUTF8StringEncoding]];
+	err = asl_NSLog(logClient , logMsg, ASL_LEVEL_DEBUG, @" %@", shoutString );
+	
+	
+	
+    PacketShout request;    
+    InitPacketHeader(&request.fHeader, kPacketTypeShout, sizeof(request), false);
+    snprintf(request.fMessage, sizeof(request.fMessage), "%s", message);
+    err = ConnectionSend(conn, &request.fHeader);
+    PrintResult("shout", err, message);
+	
+	asl_close(logClient);
+}
+
+# pragma mark -
+
+
 #pragma mark Tcl Commands
 
 //For now we just log to Console ... soon we will be doing fully fledged IPC
@@ -96,8 +455,23 @@
 
 
 
+
 #pragma mark -
 
+
+
+
+
+/////////////////////////////////////////////////////////////////
+#pragma mark ***** Tool Infrastructure
+
+/*
+ IMPORTANT
+ ---------
+ This array must be exactly parallel to the kMPHelperCommandSet array 
+ in "MPHelperCommon.c".
+ */
+
 static OSStatus DoEvaluateTclString 
 (
  AuthorizationRef			auth,
@@ -171,7 +545,7 @@
 	}
 	else
 		CFDictionaryAddValue(response, CFSTR("TclPkgPath"), (CFStringRef)tclPkgPath);
-		
+	
 	//Load macports1.0 package
 	NSString * mport_fastload = [[@"source [file join \"" stringByAppendingString:tclPkgPath]
 								 stringByAppendingString:@"\" macports1.0 macports_fastload.tcl]"];
@@ -187,7 +561,7 @@
 		CFDictionaryAddValue(response, CFSTR("MPFastload"), CFSTR("YES"));
 	}
 	
-
+	
 	//Add simplelog tcl command
 	Tcl_CreateObjCommand(interpreter, "simplelog", SimpleLog_Command, NULL, NULL);
 	if (Tcl_PkgProvide(interpreter, "simplelog", "1.0") != TCL_OK) {
@@ -199,8 +573,8 @@
 	else {
 		CFDictionaryAddValue(response, CFSTR("simplelog"), CFSTR("YES"));
 	}
-		
 	
+	
 	//Get path for and load interpInit.tcl file to Tcl Interpreter
 	NSString * interpInitFilePath = (NSString *) (CFStringRef) CFDictionaryGetValue(request, CFSTR(kInterpInitFilePath));
 	if (interpInitFilePath == nil) {
@@ -250,16 +624,7 @@
 	return retval;
 }
 
-/////////////////////////////////////////////////////////////////
-#pragma mark ***** Tool Infrastructure
 
-/*
- IMPORTANT
- ---------
- This array must be exactly parallel to the kMPHelperCommandSet array 
- in "MPHelperCommon.c".
- */
-
 static const BASCommandProc kMPHelperCommandProcs[] = {
 DoEvaluateTclString,	
 NULL
@@ -268,6 +633,65 @@
 int main(int argc, char const * argv[]) {
 	NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
 	
+	
+	
+	//For Debugging
+	//asl logging stuff
+	aslmsg logMsg = asl_new(ASL_TYPE_MSG) ;
+	assert(logMsg != NULL);
+	asl_set(logMsg, ASL_KEY_FACILITY, "com.apple.console");
+	asl_set(logMsg, ASL_KEY_SENDER, "MPHelperTool");
+	aslclient logClient = asl_open(NULL , NULL, ASL_OPT_STDERR);
+	assert(logClient != NULL);
+	
+	
+	int             err;
+    ConnectionRef   conn;
+    conn = NULL;
+    
+    // SIGPIPE is evil, so tell the system not to send it to us.
+    if (err == 0) {
+        err = MoreUNIXIgnoreSIGPIPE();
+    }
+	
+    // Organise to have SIGINT delivered to a runloop callback.
+    if (err == 0) {
+        sigset_t    justSIGINT;
+        
+        (void) sigemptyset(&justSIGINT);
+        (void) sigaddset(&justSIGINT, SIGINT);
+        
+        err = InstallSignalToSocket(
+									&justSIGINT,
+									CFRunLoopGetCurrent(),
+									kCFRunLoopDefaultMode,
+									SIGINTRunLoopCallback,
+									NULL
+									);
+    }
+    
+    // Connect to the server.
+    if (err == 0) {
+        err = ConnectionOpen(&conn);
+    }
+    
+    // Process the command line arguments.  Basically the arguments are a 
+    // sequence of commands, which we process in order.  The logic is 
+    // a little convoluted because some commands have arguments and because 
+    // the "listen" command must come last.
+    
+    if (err == 0) {
+		asl_NSLog(logClient , logMsg, ASL_LEVEL_DEBUG, @"MPHelperTool: calling DoShout");
+		DoShout(conn, "Testing MPHelperTool IPC");
+	}
+	else
+		asl_NSLog(logClient , logMsg, ASL_LEVEL_DEBUG, @"MPHelperTool: calling DoShout");
+	asl_close(logClient);
+	
+    // Clean up.
+    ConnectionClose(conn);
+	
+	
 	int result = BASHelperToolMain(kMPHelperCommandSet, kMPHelperCommandProcs);
 	
 	[pool release];

Modified: branches/gsoc08-framework/MacPorts_Framework_Release/MacPorts.Framework.xcodeproj/project.pbxproj
===================================================================
--- branches/gsoc08-framework/MacPorts_Framework_Release/MacPorts.Framework.xcodeproj/project.pbxproj	2008-08-22 17:39:56 UTC (rev 39513)
+++ branches/gsoc08-framework/MacPorts_Framework_Release/MacPorts.Framework.xcodeproj/project.pbxproj	2008-08-22 17:56:11 UTC (rev 39514)
@@ -44,6 +44,12 @@
 		6E44A00D0E2DAD66007DE8EC /* ToDo.txt in Resources */ = {isa = PBXBuildFile; fileRef = 6E44A00C0E2DAD66007DE8EC /* ToDo.txt */; };
 		6E49F37B0DFFAB0B0030C3AF /* MPInterpreterTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 489DD92E0C94674B00595506 /* MPInterpreterTest.m */; };
 		6E49F37F0DFFAFF80030C3AF /* MacPorts.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8DC2EF5B0486A6940098B216 /* MacPorts.framework */; };
+		6E8563B80E5DDF7000C1D73C /* MPHelperNotificationsCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = 6E8563B50E5DDF7000C1D73C /* MPHelperNotificationsCommon.c */; };
+		6E8563B90E5DDF7000C1D73C /* MPHelperNotificationsCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = 6E8563B60E5DDF7000C1D73C /* MPHelperNotificationsCommon.h */; };
+		6E8563BA0E5DDF7000C1D73C /* MPHelperNotificationsProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 6E8563B70E5DDF7000C1D73C /* MPHelperNotificationsProtocol.h */; };
+		6E8563BB0E5DDF7000C1D73C /* MPHelperNotificationsCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = 6E8563B50E5DDF7000C1D73C /* MPHelperNotificationsCommon.c */; };
+		6E8563BC0E5DDF7000C1D73C /* MPHelperNotificationsCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = 6E8563B60E5DDF7000C1D73C /* MPHelperNotificationsCommon.h */; };
+		6E8563BD0E5DDF7000C1D73C /* MPHelperNotificationsProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 6E8563B70E5DDF7000C1D73C /* MPHelperNotificationsProtocol.h */; };
 		6EA294590E080DEB00902D12 /* MPMacPortsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 6E88D1CB0DF4B90B00684E9F /* MPMacPortsTest.m */; };
 		6EB6FA420E43ECCE0057962C /* MPHelperTool in Resources */ = {isa = PBXBuildFile; fileRef = 6ED12A4A0E3E552F0026773D /* MPHelperTool */; };
 		6EB6FA460E43ECD60057962C /* MPHelperInstallTool in Resources */ = {isa = PBXBuildFile; fileRef = 6EC260870E426FF10013BC48 /* MPHelperInstallTool */; };
@@ -128,6 +134,9 @@
 		6E3345330E54AF14008A2F6C /* MPPortManipulationTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPortManipulationTest.h; sourceTree = "<group>"; };
 		6E3345340E54AF14008A2F6C /* MPPortManipulationTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPortManipulationTest.m; sourceTree = "<group>"; };
 		6E44A00C0E2DAD66007DE8EC /* ToDo.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ToDo.txt; sourceTree = "<group>"; };
+		6E8563B50E5DDF7000C1D73C /* MPHelperNotificationsCommon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = MPHelperNotificationsCommon.c; sourceTree = "<group>"; };
+		6E8563B60E5DDF7000C1D73C /* MPHelperNotificationsCommon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPHelperNotificationsCommon.h; sourceTree = "<group>"; };
+		6E8563B70E5DDF7000C1D73C /* MPHelperNotificationsProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPHelperNotificationsProtocol.h; sourceTree = "<group>"; };
 		6E88D1CA0DF4B90B00684E9F /* MPMacPortsTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPMacPortsTest.h; sourceTree = "<group>"; };
 		6E88D1CB0DF4B90B00684E9F /* MPMacPortsTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPMacPortsTest.m; sourceTree = "<group>"; };
 		6EA0F56E0DFEB55E00C15082 /* Tcl.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Tcl.framework; path = System/Library/Frameworks/Tcl.framework; sourceTree = SDKROOT; };
@@ -328,6 +337,9 @@
 		6EA293540E05C8C600902D12 /* Tcl Notifications  */ = {
 			isa = PBXGroup;
 			children = (
+				6E8563B50E5DDF7000C1D73C /* MPHelperNotificationsCommon.c */,
+				6E8563B60E5DDF7000C1D73C /* MPHelperNotificationsCommon.h */,
+				6E8563B70E5DDF7000C1D73C /* MPHelperNotificationsProtocol.h */,
 				6E270D070E158CED00BAE687 /* MPNotifications.h */,
 				6E270D080E158CED00BAE687 /* MPNotifications.m */,
 			);
@@ -356,6 +368,8 @@
 			files = (
 				6EC260740E426FC80013BC48 /* BetterAuthorizationSampleLib.h in Headers */,
 				6EC260970E4272D20013BC48 /* MPHelperCommon.h in Headers */,
+				6E8563BC0E5DDF7000C1D73C /* MPHelperNotificationsCommon.h in Headers */,
+				6E8563BD0E5DDF7000C1D73C /* MPHelperNotificationsProtocol.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -374,6 +388,8 @@
 				6E270D090E158CED00BAE687 /* MPNotifications.h in Headers */,
 				6EC260770E426FC80013BC48 /* BetterAuthorizationSampleLib.h in Headers */,
 				6EC260990E4272D20013BC48 /* MPHelperCommon.h in Headers */,
+				6E8563B90E5DDF7000C1D73C /* MPHelperNotificationsCommon.h in Headers */,
+				6E8563BA0E5DDF7000C1D73C /* MPHelperNotificationsProtocol.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -581,6 +597,7 @@
 				6EC260730E426FC80013BC48 /* BetterAuthorizationSampleLib.c in Sources */,
 				6EC260980E4272D20013BC48 /* MPHelperCommon.c in Sources */,
 				6ECD98110E484E8400488335 /* MPHelperTool.m in Sources */,
+				6E8563BB0E5DDF7000C1D73C /* MPHelperNotificationsCommon.c in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -598,6 +615,7 @@
 				6E270D0A0E158CED00BAE687 /* MPNotifications.m in Sources */,
 				6EC260760E426FC80013BC48 /* BetterAuthorizationSampleLib.c in Sources */,
 				6EC2609A0E4272D20013BC48 /* MPHelperCommon.c in Sources */,
+				6E8563B80E5DDF7000C1D73C /* MPHelperNotificationsCommon.c in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/macports-changes/attachments/20080822/bed01711/attachment-0001.html 


More information about the macports-changes mailing list