]> xenbits.xensource.com Git - people/pauldu/sockpipe.git/commitdiff
Initial Commit
authorPaul Durrant <paul.durrant@citrix.com>
Fri, 31 Mar 2017 13:20:10 +0000 (14:20 +0100)
committerPaul Durrant <paul.durrant@citrix.com>
Fri, 31 Mar 2017 13:20:10 +0000 (14:20 +0100)
Extract sockpipe from xs-windows.hg and wrap in suitable visual studio
magic.

Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
36 files changed:
build.py [new file with mode: 0644]
clean.py [new file with mode: 0644]
msbuild.bat [new file with mode: 0644]
src/sockpipe/Circle.cpp [new file with mode: 0644]
src/sockpipe/circle.h [new file with mode: 0644]
src/sockpipe/connectoid.cpp [new file with mode: 0644]
src/sockpipe/connectoid.h [new file with mode: 0644]
src/sockpipe/logger.cpp [new file with mode: 0644]
src/sockpipe/logger.h [new file with mode: 0644]
src/sockpipe/pipereader.cpp [new file with mode: 0644]
src/sockpipe/pipereader.h [new file with mode: 0644]
src/sockpipe/plj_utils.h [new file with mode: 0644]
src/sockpipe/sockpipe.cpp [new file with mode: 0644]
src/sockpipe/sockreader.cpp [new file with mode: 0644]
src/sockpipe/sockreader.h [new file with mode: 0644]
src/sockpipe/spinlock.cpp [new file with mode: 0644]
src/sockpipe/spinlock.h [new file with mode: 0644]
src/sockpipe/stdafx.cpp [new file with mode: 0644]
src/sockpipe/stdafx.h [new file with mode: 0644]
src/sockpipe/threadcontrol.cpp [new file with mode: 0644]
src/sockpipe/threadcontrol.h [new file with mode: 0644]
vs2012/configs.props [new file with mode: 0644]
vs2012/sockpipe.sln [new file with mode: 0644]
vs2012/sockpipe/sockpipe.vcxproj [new file with mode: 0644]
vs2012/sockpipe/sockpipe.vcxproj.user [new file with mode: 0644]
vs2012/targets.props [new file with mode: 0644]
vs2013/configs.props [new file with mode: 0644]
vs2013/sockpipe.sln [new file with mode: 0644]
vs2013/sockpipe/sockpipe.vcxproj [new file with mode: 0644]
vs2013/sockpipe/sockpipe.vcxproj.user [new file with mode: 0644]
vs2013/targets.props [new file with mode: 0644]
vs2015/configs.props [new file with mode: 0644]
vs2015/sockpipe.sln [new file with mode: 0644]
vs2015/sockpipe/sockpipe.vcxproj [new file with mode: 0644]
vs2015/sockpipe/sockpipe.vcxproj.user [new file with mode: 0644]
vs2015/targets.props [new file with mode: 0644]

diff --git a/build.py b/build.py
new file mode 100644 (file)
index 0000000..6146c10
--- /dev/null
+++ b/build.py
@@ -0,0 +1,147 @@
+#!python -u
+
+import os, sys
+import datetime
+import re
+import glob
+import tarfile
+import subprocess
+import shutil
+import time
+
+def get_configuration(release, debug):
+    configuration = release
+
+    if debug:
+        configuration += ' Debug'
+    else:
+        configuration += ' Release'
+
+    return configuration
+
+
+def get_target_path(release, arch, debug, vs):
+    configuration = get_configuration(release, debug)
+    name = ''.join(configuration.split(' '))
+    target = { 'x86': os.sep.join([name, 'Win32']), 'x64': os.sep.join([name, 'x64']) }
+    target_path = os.sep.join([vs, target[arch]])
+
+    return target_path
+
+
+def shell(command, dir):
+    print(dir)
+    print(command)
+    sys.stdout.flush()
+    
+    sub = subprocess.Popen(' '.join(command), cwd=dir,
+                           stdout=subprocess.PIPE,
+                           stderr=subprocess.STDOUT)
+
+    for line in sub.stdout:
+        print(line.decode(sys.getdefaultencoding()).rstrip())
+
+    sub.wait()
+
+    return sub.returncode
+
+
+class msbuild_failure(Exception):
+    def __init__(self, value):
+        self.value = value
+    def __str__(self):
+        return repr(self.value)
+
+def msbuild(platform, configuration, target, file, args, dir):
+    os.environ['PLATFORM'] = platform
+    os.environ['CONFIGURATION'] = configuration
+    os.environ['TARGET'] = target
+    os.environ['FILE'] = file
+    os.environ['EXTRA'] = args
+
+    bin = os.path.join(os.getcwd(), 'msbuild.bat')
+
+    status = shell([bin], dir)
+
+    if (status != 0):
+        raise msbuild_failure(configuration)
+
+
+def build_sln(name, release, arch, debug, vs):
+    configuration = get_configuration(release, debug)
+
+    if arch == 'x86':
+        platform = 'Win32'
+    elif arch == 'x64':
+        platform = 'x64'
+
+    cwd = os.getcwd()
+
+    msbuild(platform, configuration, 'Build', name + '.sln', '', vs)
+
+
+def copy_output(name, release, arch, debug, vs):
+    configuration = get_configuration(release, debug)
+    dst = os.path.join(name, arch)
+
+    if arch == 'x86':
+        src = vs
+    elif arch == 'x64':
+        src = os.path.join(vs, arch)
+
+    src = os.path.join(src, ''.join(configuration.split(' ')))
+
+    os.makedirs(dst, exist_ok=True)
+
+    files = glob.glob(os.path.join(src, '*.exe'))
+    files += glob.glob(os.path.join(src, '*.pdb'))
+
+    for file in files:
+        shutil.copy(file, dst)
+
+
+def archive(filename, files, tgz=False):
+    print(filename)
+    access='w'
+    if tgz:
+        access='w:gz'
+    tar = tarfile.open(filename, access)
+    for name in files :
+        try:
+            tar.add(name)
+        except:
+            pass
+    tar.close()
+
+
+def getVsVersion():
+    vsenv ={} 
+    vars = subprocess.check_output([os.environ['VS']+'\\VC\\vcvarsall.bat', '&&', 'set'], shell=True)
+    for var in vars.splitlines():
+        k, _, v = map(str.strip, var.strip().decode('utf-8').partition('='))
+        if k.startswith('?'):
+            continue
+        vsenv[k] = v
+
+    mapping = { '11.0':'vs2012',
+                '12.0':'vs2013',
+                '14.0':'vs2015' }
+
+    return mapping[vsenv['VisualStudioVersion']]
+
+
+if __name__ == '__main__':
+    debug = { 'checked': True, 'free': False }
+    util = 'sockpipe'
+    vs = getVsVersion()
+    release = { 'vs2012':'Windows Vista',
+                'vs2013':'Windows 7',
+                'vs2015':'Windows 8' }
+
+    build_sln(util, release[vs], 'x86', debug[sys.argv[1]], vs)
+    build_sln(util, release[vs], 'x64', debug[sys.argv[1]], vs)
+
+    copy_output(util, release[vs], 'x86', debug[sys.argv[1]], vs)
+    copy_output(util, release[vs], 'x64', debug[sys.argv[1]], vs)
+
+    archive(util + '.tar', [util])
diff --git a/clean.py b/clean.py
new file mode 100644 (file)
index 0000000..88d6ed6
--- /dev/null
+++ b/clean.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+
+import os, sys, shutil
+
+if __name__ == '__main__':
+    file = os.popen('git status -u --porcelain')
+
+    for line in file:
+        item = line.split(' ')
+        if item[0] == '??':
+            path = ' '.join(item[1:]).rstrip()
+            print(path)
+            try:
+                if os.path.isfile(path):
+                    os.remove(path)
+                if os.path.isdir(path):
+                    shutil.rmtree(path)
+            except OSError:
+                None
+                
+    file.close()
diff --git a/msbuild.bat b/msbuild.bat
new file mode 100644 (file)
index 0000000..1b1fbc8
--- /dev/null
@@ -0,0 +1,8 @@
+call "%VS%\VC\vcvarsall.bat" x86
+@echo on
+msbuild.exe /m:1 /p:Configuration="%CONFIGURATION%" /p:Platform="%PLATFORM%" /t:"%TARGET%" %EXTRA% %FILE%
+if errorlevel 1 goto error
+exit 0
+
+:error
+exit 1
diff --git a/src/sockpipe/Circle.cpp b/src/sockpipe/Circle.cpp
new file mode 100644 (file)
index 0000000..3bdce72
--- /dev/null
@@ -0,0 +1,402 @@
+//
+// Circular buffer.
+//
+// This class implements a circular buffer for data movement.  The buffer
+// utilizes a pair of pointers, in and out, that chase each other.
+//
+// in is the offset of the next byte in the buffer where data can be inserted.
+// out is the offset of the next byte in the buffer to be removed.
+//
+// in == out means the buffer is empty. in one behind out means the buffer is
+// full.
+//
+// in is only ever updated by producers, out is only updated by consumers.  If 
+// there are multiple producers, in must be protected by a lock, if there are
+// multiple consumers, out must be protected by a lock.
+//
+// In the following, in > out, new data can be inserted at in and in can wrap
+// around to but not catch up out.   Data from out to in is available.
+//
+// +------------------------------------------------------------+
+// |    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX                   |
+// +------------------------------------------------------------+
+//      ^out                                 ^in
+//
+// When in < out, the already inserted data wraps around the buffer.
+//
+// +------------------------------------------------------------+
+// |XXXX                                    XXXXXXXXXXXXXXXXXXXX|
+// +------------------------------------------------------------+
+//      ^in                                 ^out
+//
+
+#include "stdafx.h"
+#include <windows.h>
+#include "plj_utils.h"
+#include "circle.h"
+
+Circle::Circle()
+{
+    buffer = NULL;
+    in     = 0;
+    out    = 0;
+    length = 0;
+
+    waitEvent = INVALID_HANDLE_VALUE;
+    waitCount = 0;
+}
+
+Circle::~Circle()
+{
+    if (buffer != NULL)
+    {
+        delete buffer;
+    }
+}
+
+bool Circle::Initialize(int size)
+{
+    buffer = new char[size];
+    if (buffer == NULL)
+    {
+        die("failed to allocate circular buffer of %d bytes.", size);
+    }
+    length = size;
+
+    waitEvent = CreateEvent(NULL, false, false, NULL);
+
+    if (waitEvent == INVALID_HANDLE_VALUE)
+    {
+        // I don't think this can happen, but, ...
+        die("failed to create wait handle for circular buffer.");
+    }
+    return true;
+}
+
+void Circle::WaitUntilNotFull()
+{
+    if (QueryInsertable() == 0)
+    {
+        InterlockedIncrement(&waitCount);
+        WaitForSingleObject(waitEvent, INFINITE);
+    }
+}
+
+int Circle::QueryInsertable()
+{
+    //
+    // Calculate and return the number of bytes that can be inserted into the
+    // buffer.  
+    //
+    // Note: The number of bytes that can be inserted is one less than the
+    // number of free bytes.  This is so the 'in' pointer doesn't colide with 
+    // the 'out' pointer, in == out is buffer empty, not buffer full.
+    //
+
+    int tin = in;
+    int tout = out;
+
+    if (tin == tout)
+    {
+        //
+        // buffer is empty.
+        //
+
+        return length - 1;
+    }
+    if (tin > tout)
+    {
+        return tout + (length - tin) - 1;
+    }
+
+    // else (in < out)
+
+    return tout - tin - 1;
+}
+
+int Circle::QueryRetrievable()
+{
+    int tin = in;
+    int tout = out;
+
+    if (tin >= tout)
+    {
+        return tin - tout;
+    }
+
+    // else (in < out)
+
+    return tin + (length - tout);
+}
+
+int Circle::Insert(char * data, int len)
+{
+    //
+    // Add data to the circular buffer.  This routine is non-blocking.
+    // The amount of data added to the buffer is returned, that amount
+    // can be less than provided.
+    //
+    // If multiple providers, 'in' must be protected by a lock.
+    //
+
+    int insert = QueryInsertable();
+    int tin = in;
+    char * to = buffer + tin;
+
+    if (len < insert)
+    {
+        insert = len;
+    }
+    int inserted = insert;
+
+    if (in >= out)
+    {
+        //
+        // Determine if the insertion wraps around the end of the buffer in
+        // which case we'll need to do two copies.
+        //
+    
+        int here = length - tin;
+
+        if (here < insert)
+        {
+            //
+            // Need to split the insertion into two parts, the copy to the
+            // top part of the buffer and the copy to the low.  Do the top
+            // copy here and set things up to fall thru and do the bottom
+            // part.
+            //
+
+            RtlCopyMemory(to, data, here);
+            insert -= here;
+            data += here;
+            tin = 0;
+            to = buffer;
+        }
+        else if (here == insert)
+        {
+            //
+            // This insertion fits in the top of the buffer .. exactly ..
+            // need to wrap the in pointer as the next time the insertion
+            // will go to the start of the buffer.  Fall thru and do the
+            // single copy below.
+            //
+
+            tin = -insert;
+        }
+    }
+    tin += insert;
+    ASSERT(tin < length);
+    RtlCopyMemory(to, data, insert);
+    in = tin;
+    return inserted;
+}
+
+int Circle::Retrieve(char * bp, int len)
+{
+    int tin = in;
+    int tout = out;
+    int tlen;
+
+    if (tin == tout)
+    {
+        return 0;
+    }
+
+    if (tin > tout)
+    {
+        //
+        // +------------------------------------------------------------+
+        // |    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX                   |
+        // +------------------------------------------------------------+
+        //      ^out                                 ^in
+        //
+
+        tlen = tin - out;
+
+        if (tlen > len)
+        {
+            tlen = len;
+        }
+
+        RtlCopyMemory(bp, buffer + tout, tlen);
+
+        tout += tlen;
+        if (tout == length) // can't happen
+        {
+            // N.B. This can't actually happen unless we change the algorithm
+            // to allow in == length, currently that will always wrap to 0.
+            // I want to actually check and see if the algorithm becomes cleaner
+            // if we do that.
+            tout = 0;
+        }
+    }
+    else
+    {
+        //
+        // +------------------------------------------------------------+
+        // |XXXX                                    XXXXXXXXXXXXXXXXXXXX|
+        // +------------------------------------------------------------+
+        //      ^in                                 ^out
+        //
+
+        tlen = length - tout + tin;
+        if (tlen > len)
+        {
+            tlen = len;
+        }
+        tout += tlen;
+        
+        if (tout > length)
+        {
+            tout -= length;
+        }
+    }
+    out = tout;
+    if ((tlen != 0) && (waitCount != 0))
+    {
+        InterlockedDecrement(&waitCount);
+        SetEvent(waitEvent);
+    }
+    return tlen;
+}
+
+int Circle::QueryContiguousRetrievable(char ** datap)
+{
+    //
+    // Non-copy optimization, return the number of bytes we can retrieve in a
+    // straight line.  If the available buffer wraps, return from the current
+    // position to the buffer end, the caller will call again for the stuff
+    // at the front.
+    //
+
+    int        tout = out;
+    int        tin  = in;
+    int        len  = 0;
+
+    if (tout <= tin)
+    {
+        len = tin - tout;
+    }
+    else
+    {
+        len = length - tout;
+    }
+    *datap = buffer + tout;
+    return len;
+}
+
+int Circle::CommitRetrieved(int len)
+{
+    int        tout = out;
+    int        tin  = in;
+
+    // Make sure out won't overtake in.
+    ASSERT((tin < tout) || ((tout + len) <= tin));
+
+    tout += len;
+
+    ASSERT(tout <= length);
+
+    if (tout == length)
+    {
+        tout = 0;
+    }
+    out = tout;
+
+    if ((len != 0) && (waitCount != 0))
+    {
+        InterlockedDecrement(&waitCount);
+        SetEvent(waitEvent);
+    }
+
+    return len;
+}
+
+void Circle::Drain()
+{
+    //
+    // Discard any data already in the buffer.
+    //
+    // Note: This is a Consumer function, that is, we pretend to have retrieved
+    // all the data in the buffer.
+    //
+
+    int tout = out;
+    int tin  = in;
+
+    if (tin != tout)
+    {
+        in = tout;
+
+        if (waitCount != 0)
+        {
+            InterlockedDecrement(&waitCount);
+            SetEvent(waitEvent);
+        }
+    }
+}
+
+void Circle::TestPattern(HANDLE Writer)
+{
+    char    pattern[80];
+
+    for (int i = 0; i < sizeof(pattern); i++)
+    {
+        pattern[i] = 0x30 + (i % 10);
+    }
+
+    for (;;)
+    {
+        for (int i = 0; i < sizeof(pattern); i++)
+        {
+            int j = i + 1;
+            char old = pattern[i];
+            pattern[i] = '\n';
+            char * s = pattern;
+            for (int n = 0; n < j; )
+            {
+                int d = Insert(s, i - n + 1);
+                n += d;
+                s += d;
+                if (n < j)
+                {
+                    SetEvent(Writer);
+                    WaitUntilNotFull();
+                    continue;
+                }
+                ASSERT(n == j);
+            }
+            pattern[i] = old;
+            if (QueryRetrievable() == j)
+            {
+                SetEvent(Writer);
+            }
+        }
+        for (int i = sizeof(pattern) - 2; i > 0; i--)
+        {
+            int j = i + 1;
+            char old = pattern[i];
+            pattern[i] = '\n';
+            char * s = pattern;
+            for (int n = 0; n < j; )
+            {
+                int d = Insert(s, i - n + 1);
+                n += d;
+                s += d;
+                if (n < j)
+                {
+                    SetEvent(Writer);
+                    WaitUntilNotFull();
+                    continue;
+                }
+                ASSERT(n == j);
+            }
+            pattern[i] = old;
+            if (QueryRetrievable() == j)
+            {
+                SetEvent(Writer);
+            }
+        }
+    }
+}
diff --git a/src/sockpipe/circle.h b/src/sockpipe/circle.h
new file mode 100644 (file)
index 0000000..24ba3ef
--- /dev/null
@@ -0,0 +1,29 @@
+#if !defined(CIRCLE_H)
+#define CIRCLE_H
+
+class Circle
+{
+public:
+                    Circle();
+                    ~Circle();
+    bool            Initialize(int size);
+    int             Insert(char * data, int len);
+    int             Retrieve(char *, int len);
+    int             QueryRetrievable();
+    int             QueryInsertable();
+    void            WaitUntilNotFull();
+    int             QueryContiguousRetrievable(char ** datap);
+    int             CommitRetrieved(int len);
+    void            Drain();
+    void            TestPattern(HANDLE);
+    
+private:
+    char          * buffer;
+    volatile int    in;
+    volatile int    out;
+    int             length;
+    HANDLE          waitEvent;
+    volatile LONG   waitCount;
+};
+
+#endif
diff --git a/src/sockpipe/connectoid.cpp b/src/sockpipe/connectoid.cpp
new file mode 100644 (file)
index 0000000..f032188
--- /dev/null
@@ -0,0 +1,221 @@
+#include "stdafx.h"
+#include <windows.h>
+#include "plj_utils.h"
+#include "spinlock.h"
+#include "circle.h"
+#include "threadcontrol.h"
+#include "logger.h"
+#include "connectoid.h"
+
+#define MANUAL_RESET_EVENT  1
+
+Channel::Channel()
+{
+    pended = false;
+
+    RtlZeroMemory(Overlapped(), sizeof(overlap));
+    overlap.hEvent = CreateEvent(NULL, MANUAL_RESET_EVENT, false, NULL);
+    if (overlap.hEvent == INVALID_HANDLE_VALUE)
+    {
+        // Really, this can't possibly have happened.
+        die("CreateEvent failed for OVERLAPPED structure for Channel constructor.");
+    }
+}
+
+Channel::~Channel()
+{
+}
+
+void Channel::SetOverlappedEvent()
+{
+    SetEvent(overlap.hEvent);
+}
+
+Connectoid::Connectoid()
+{
+    sender = NULL;
+    log = NULL;
+    tag[0] = tag[1] = tag[2] = 0;
+    resetPacketIndex = 0;
+
+#ifdef OUTBOUND_DROP_UNTIL_RESET_ONLY
+    // N.B. resetAckExpected true will cause data from either end to be ignored.
+    // We use this to silence the debugger until we've seen something from the
+    // target.
+    resetAckExpected = true;
+#else
+    // resetAckExpected starts false but will be set true by the first outbound
+    // data seen on the pipe (from the debugger).  At that point, all data in
+    // either direction will be dropped until a reset ack is seen from the
+    // target.
+    resetAckExpected = false;
+#endif
+    receiveDataSeen = false;
+    connected = false;
+}
+
+Connectoid::~Connectoid()
+{
+}
+
+bool Connectoid::Initialize(Logger * Logger, class Connectoid * Sender, char * Tag)
+{
+    log = Logger;
+    sender = Sender;
+
+    // Grr!  I'd have used strncpy to copy my 3 bytes here and allowing for
+    // the possibility that the source string might be short ... but strncpy
+    // is considered dangerous and strncpy_s whines if it can't fit the trailing
+    // null.
+    //
+
+    for (int i = 0; i < sizeof(tag); i++)
+    {
+        if ((tag[i] = Tag[i]) == 0)
+        {
+            break;
+        }
+    }
+
+    //
+    // Copy this, er, pipe's read handle and the other one's write handle
+    // into the array used by WaitForMultipleObjects for this thread.
+    //
+
+    waitHandles[0] = read.GetHandle();
+    waitHandles[1] = sender->write.GetHandle();
+    blocked[0] = blocked[1] = 0;
+
+    return true;
+}
+
+void Connectoid::Wait()
+{
+    int wake;
+
+    // The following need to be done directly when Pending is set.
+    //blocked[0] = read.Pending();
+    //blocked[1] = sender->write.Pending();
+
+    if (blocked[0] == blocked[1])
+    {
+        //
+        // we have zero or two waiters.
+        //
+
+        if (blocked[0])
+        {
+            //
+            // two waiters.
+            //
+
+            log->Log(0, tag, "Wait multiple");
+            wake = WaitForMultipleObjects(2, waitHandles, false, INFINITE);
+            wake -= WAIT_OBJECT_0;
+
+            ASSERT((wake >= 0) && (wake < 2));
+            log->Log(0, tag, "Wait multiple woke %d (%s) %x", wake, wake ? "sender" : "reader", waitHandles[wake]);
+            blocked[wake] = false;
+#if MANUAL_RESET_EVENT
+            ResetEvent(waitHandles[wake]);
+#endif
+        }
+    }
+    else
+    {
+        //
+        // blocked[0] != blocked[1]
+        //
+        // One waiter.  This (should) mean the other side has nothing to do.
+        // for example, we're waiting on a read and all writes have completed.
+        //
+
+        int which = blocked[1]; // if blocked[1] = 0 then blocked[0] must be 1.
+                                // (overloading true/false as an index)
+        HANDLE handle = waitHandles[which];
+        log->Log(0, tag, "Wait single %d (%s) %x", which, which ? "sender" : "reader", waitHandles[which]);
+        WaitForSingleObject(handle, INFINITE);
+        log->Log(0, tag, "Wait single woke %d (%s) %x", which, which ? "sender" : "reader", waitHandles[which]);
+#if MANUAL_RESET_EVENT
+        ResetEvent(handle);
+#endif
+        blocked[which] = false;
+
+#if 0
+        if (blocked[0])
+        {
+            WaitForSingleObject(waitHandles[0], INFINITE);
+            blocked[0] = false;
+        }
+        else
+        {
+            //
+            // Reader has nothing to do but write side is blocked? This seems
+            // odd.
+            //
+
+            fprintf(stderr, "%.3s write side (alone) blocked .. seems odd.\n");
+            WaitForSingleObject(waitHandles[1], INFINITE);
+            blocked[1] = false;
+        }
+#endif
+    }
+}
+
+int Connectoid::Send(Circle *)
+{
+    die("default Connectoid::Send called.  This should be overridden.");
+}
+
+//
+// This really doesn't have anything to do with the communications but,
+// we need to do a little bit of stateful control when reset (aka resync)
+// packets are being sent.  Specifically, we need to notice them outbound
+// then discard anything inbound until we see the ack inbound.
+//
+// We *could* also ignore inbound acks if we haven't seen an outbound one
+// because there's a bug in the protocol which makes an unexpected inbound
+// ack send us into a reset loop forever.
+//
+// Note: This will fail to catch a reset packet that's preceeded by some random
+// number of leader bytes 0x69.  So far that hasn't been a problem.  We could
+// fix it by keeping a sliding window of the last 8 bytes received.
+//
+// This function returns the number of bytes consumed on this call before the
+// packet was complete, zero otherwise.
+//
+
+char ResetPacket[8] = 
+{
+    0x69, 0x69, 0x69, 0x69, 0x06, 0x00, 0x00, 0x00
+};
+
+int Connectoid::CheckForResetPacket(char * Buffer, int Length)
+{
+    for (int count = 1; Length; count++, Length--)
+    {
+        if (*Buffer++ != ResetPacket[resetPacketIndex++])
+        {
+            resetPacketIndex = 0;
+        }
+        if (resetPacketIndex == sizeof(ResetPacket))
+        {
+            resetPacketIndex = 0;
+            return count;
+        }
+    }
+    return 0;
+}
+
+#if 0
+int Connectoid::FetchResetPacket(char * Buffer)
+{
+    RtlCopyMemory(Buffer, ResetPacket, sizeof(ResetPacket));
+    return sizeof(ResetPacket);
+}
+#endif
+
+void Connectoid::InsertResetPacket(Circle * Buffer)
+{
+    Buffer->Insert(ResetPacket, sizeof(ResetPacket));
+}
diff --git a/src/sockpipe/connectoid.h b/src/sockpipe/connectoid.h
new file mode 100644 (file)
index 0000000..d6abeb9
--- /dev/null
@@ -0,0 +1,132 @@
+#if !defined(CONNECTOID_H)
+#define CONNECTOID_H
+
+extern char resetPacket[8];
+
+class Channel
+{
+public:
+                        Channel();
+                        ~Channel();
+    void                Wait();
+    LPOVERLAPPED        Overlapped();
+//  LPWSAOVERLAPPED     WSAOverlapped();
+    bool                Pending();
+    void                SetPending(bool);
+    void                SetOverlappedEvent();
+    HANDLE              GetHandle();
+private:
+
+    //
+    // Currently OVERLAPPED and WSAOVERLAPPED are the same structure, what a
+    // pity they're different types.
+    //
+    OVERLAPPED          overlap;
+//  WSAOVERLAPPED       wsaoverlap;
+    bool                pended;
+};
+
+inline void Channel::Wait()
+{
+    DWORD result = WaitForSingleObject(overlap.hEvent, INFINITE);
+    ASSERT(result != WAIT_FAILED);
+    return;
+}
+
+inline LPOVERLAPPED Channel::Overlapped()
+{
+    return &overlap;
+}
+
+#if 0
+inline LPWSAOVERLAPPED Channel::WSAOverlapped()
+{
+    return &wsaoverlap;
+}
+#endif
+
+inline bool Channel::Pending()
+{
+    return pended;
+}
+
+inline void Channel::SetPending(bool Pend)
+{
+    pended = Pend;
+}
+
+inline HANDLE Channel::GetHandle()
+{
+    return overlap.hEvent;
+}
+
+
+class Connectoid
+{
+public:
+                        Connectoid();
+                        ~Connectoid();
+    bool                Initialize(Logger * Logger, class Connectoid * Connector, char * Tag);
+//  virtual void        Send(char * buffer, int length);
+    virtual int         Send(Circle *);
+//  void                Receive(char * buffer, int length);
+    void                Wait();
+    void                SetReadWait(bool);
+    void                SetWriteWait(bool);
+    void                SetResetAckExpected(bool);
+    bool                Connected();
+
+protected:
+    class Connectoid  * sender;
+    class Logger      * log;
+    Channel             read;
+    Channel             write;
+    HANDLE              waitHandles[2];
+    union
+    {
+        char            blocked[2];
+        struct
+        {
+            char        read;
+            char        write;
+        } wait;
+    };
+    char                tag[3];
+    Circle              receiveBuffer;
+    int                 resetPacketIndex;
+    bool                resetAckExpected;
+    bool                receiveDataSeen;
+    bool                connected;
+    int                 CheckForResetPacket(char *, int);
+    void                ClearResetPacketIndex();
+    void                InsertResetPacket(Circle *);
+};
+
+inline void Connectoid::SetReadWait(bool value)
+{
+    wait.read = value;
+}
+
+inline void Connectoid::SetWriteWait(bool value)
+{
+    wait.write = value;
+}
+
+inline void Connectoid::ClearResetPacketIndex()
+{
+    resetPacketIndex = 0;
+}
+
+inline void Connectoid::SetResetAckExpected(bool value)
+{
+    resetAckExpected = value;
+    sender->resetAckExpected = value;
+}
+
+inline bool Connectoid::Connected()
+{
+    return connected;
+}
+
+#endif
+
diff --git a/src/sockpipe/logger.cpp b/src/sockpipe/logger.cpp
new file mode 100644 (file)
index 0000000..07f024f
--- /dev/null
@@ -0,0 +1,385 @@
+#include "stdafx.h"
+#include <windows.h>
+#include "plj_utils.h"
+#include "spinlock.h"
+#include "circle.h"
+#include "threadcontrol.h"
+#include "logger.h"
+
+#if 0
+static char * asciiTable[0x20] =
+{
+    "<NUL>",
+    "<SOH>",
+    "<STX>",
+    "<ETX>",
+    "<EOT>",
+    "<ENQ>",
+    "<ACK>",
+    "<BEL>",
+    "<BS>",
+    "<TAB>",
+    "<LF>",
+    "<VT>",
+    "<FF>",
+    "<CR>",
+    "<SO>",
+    "<SI>",
+    "<DLE>",
+    "<DC1>",
+    "<DC2>",
+    "<DC3>",
+    "<DC4>",
+    "<NAK>",
+    "<SYN>",
+    "<ETB>",
+    "<CAN>",
+    "<EM>",
+    "<SUB>",
+    "<ESC>",
+    "<FS>",
+    "<GS>",
+    "<RS>",
+    "<US>"
+}
+
+void
+ToAcsii(char c, char * buf)
+{
+    if ((c & 0x80) != 0)
+    {
+        buf[0] = 0;
+    }
+    else if (c < 0x20)
+    {
+        strcpy(buf, asciiTable[c]);
+    }
+    else if (c < 0x7f)
+    {
+        buf[0] = c;
+        buf[1] = 0;
+    }
+    else
+    {
+        strcpy(buf, "<DEL>");
+    }
+}
+#endif
+
+Logger::Logger()
+{
+    fileHandle = INVALID_HANDLE_VALUE;
+#pragma prefast(suppress:28159)
+    originalTime = GetTickCount();
+}
+
+Logger::~Logger()
+{
+
+#if LOGGING_ENABLED
+
+    if (fileHandle != INVALID_HANDLE_VALUE)
+    {
+        int retries = 0;
+        while (buffer.QueryRetrievable() != 0)
+        {
+            if (++retries > 10)
+            {
+                break;
+            }
+            SetEvent(writerEvent);
+            Sleep(100);
+        }
+        CloseHandle(fileHandle);
+        fileHandle = INVALID_HANDLE_VALUE;
+    }
+
+#endif
+
+}
+
+void Logger::ThreadEntry(void * inContext)
+{
+    UNREFERENCED_PARAMETER(inContext);
+
+    printf("hello from Logger's thread entry!\n");
+
+#if defined(SOCKPIPE_LOGGING)
+
+    for (;;)
+    {
+        int     bytes;
+        char  * data;
+        DWORD   written;
+
+        while ((bytes = buffer.QueryContiguousRetrievable(&data)) != 0)
+        {
+            WriteFile(fileHandle, data, bytes, &written, NULL);
+            //
+            // Error handling? What error handling?
+            //
+
+            buffer.CommitRetrieved(bytes);
+        }
+        WaitForSingleObject(writerEvent, INFINITE);
+    }
+
+#endif
+
+}
+
+bool Logger::Initialize()
+{
+
+#if LOGGING_ENABLED
+    
+    fileHandle = CreateFile(_T("sockpipe.log"), GENERIC_WRITE, FILE_SHARE_READ,
+                            NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
+                            NULL);
+    if (fileHandle == INVALID_HANDLE_VALUE)
+    {
+        die("failed to open log file \"sockpipe.log\".");
+    }
+
+    writerEvent = CreateEvent(NULL, false, false, NULL);
+
+    if (writerEvent == INVALID_HANDLE_VALUE)
+    {
+        // I don't think this can happen, but, ...
+        die("failed to create a writerEvent handle for the logger.");
+    }
+
+    threadHandle = CreateEvent(NULL, false, false, NULL);
+
+    if (threadHandle == INVALID_HANDLE_VALUE)
+    {
+        die("failed to create threadHandle for the logger thread.");
+    }
+
+    lock.Initialize();
+
+    if (!buffer.Initialize(4096))
+    {
+        die("failed to initialize circular buffer for logging.");
+    }
+
+    if (!Start())
+    {
+        die("failed to initialize/start log writer thread.");
+    }
+
+#if 0
+    //
+    // Unit test the Circular Buffer code.  Never returns.
+    //
+
+    buffer.TestPattern(writerEvent);
+#endif
+#endif
+
+    return true;
+}
+
+char LogTags[] = 
+{
+    '.',
+    'R',
+    'X',
+    'S',
+    'r',
+    'x',
+    'u'
+};
+
+void Logger::htoa(char * in, char * out, int lengthIn)
+{
+    char * t = out;
+
+    for (int i = 0; i < lengthIn; i++)
+    {
+        char c = ((in[i] >> 4) & 0xf) + '0';
+        if (c > '9') c += ('a' - '0') - 10;
+        *t = c;
+
+        c = (in[i] & 0xf) + '0';
+        if (c > '9') c += ('a' - '0')- 10;
+        *(t + 1) = c;
+        t += 2;
+    }
+}
+
+
+void Logger::InsertToLogBuffer(char * buff, int len)
+{
+
+#if defined(SOCKPIPE_LOGGING)
+
+    //
+    // Log activity.  Could be receive of either type, or other 
+    // interesting things (like a close).
+    //
+
+    for (int remaining = len; remaining; )
+    {
+        lock.Acquire();
+
+        int done = buffer.Insert(buff, remaining);
+
+        lock.Release();
+
+        remaining -= done;
+
+        if (remaining)
+        {
+            SetEvent(writerEvent);
+            buffer.WaitUntilNotFull();
+        }
+    }
+
+    //
+    // Kick off the writer thread.  If there are more bytes in the buffer than
+    // we just inserted, the thread will have been kicked already, less than or
+    // equal and we can't tell.
+    //
+
+    if (buffer.QueryRetrievable() <= len)
+    {
+        SetEvent(writerEvent);
+    }
+
+#endif
+
+}
+
+void Logger::Flush()
+{
+    if (fileHandle == INVALID_HANDLE_VALUE)
+    {
+        return;
+    }
+
+    if (buffer.QueryRetrievable())
+    {
+        SetEvent(writerEvent);
+    }
+
+    //
+    // Wait up to 3 seconds for the flush to complete.
+    //
+
+    for (int i = 0; (buffer.QueryRetrievable()) && (i < 30); i++)
+    {
+        Sleep(100);
+    }
+}
+
+
+void Logger::Log(int direction, char * tag, int len, char * buff)
+{
+    ASSERT(len < (PUMP_BUFFER_SIZE * 2));
+    ASSERT(direction < TAG_COUNT);
+
+#if LOGGING_ENABLED
+
+    if (fileHandle == INVALID_HANDLE_VALUE)
+    {
+        return;
+    }
+
+    char tmpbuf[PUMP_BUFFER_SIZE * 4];
+    char * t = tmpbuf;
+
+#if defined(SAFESTR)
+    t += sprintf_s(tmpbuf, sizeof(tmpbuf), "%08x %05d %c%.3s ", logTime(), len, LogTags[direction], tag);
+#else
+    t += sprintf(tmpbuf, "%08x %05d %c%.3s ", logTime(), len, LogTags[direction], tag);
+#endif
+
+//  if (buff && (direction <= TAG_READ)) // only dump buffer on read side (for the moment)
+    if (buff && ((direction <= TAG_READ) || ((direction == TAG_SENT) && !strncmp(tag, "pip", 3))))
+    {
+        htoa(buff, t, len);
+    }
+    else
+    {
+        len = 0;
+    }
+    t += len * 2;
+    *t = '\n';
+    *(t + 1) = 0;
+//  printf(tmpbuf);
+    InsertToLogBuffer(tmpbuf, (int)(t - tmpbuf) + 1);
+
+#endif
+
+}
+
+
+void Logger::Log(int direction, char * tag, char * buff, ...)
+{
+    ASSERT(direction < TAG_COUNT);
+
+#if LOGGING_ENABLED
+
+    if (fileHandle == INVALID_HANDLE_VALUE)
+    {
+        return;
+    }
+
+    char tmpbuf[1024];
+    va_list args;
+    int l;
+    int n;
+
+    va_start(args, buff);
+#if defined(SAFESTR)
+    l = sprintf_s(tmpbuf, sizeof(tmpbuf), "%08x       %c%.3s ", logTime(), LogTags[direction], tag);
+    n = vsnprintf_s(tmpbuf + l, sizeof(tmpbuf) - l - 1, sizeof(tmpbuf) - 1 - 2, buff, args);
+#else
+    l = sprintf(tmpbuf, "%08x       %c%.3s ", logTime(), LogTags[direction], tag);
+    n = _vsnprintf(tmpbuf + l, sizeof(tmpbuf) - l - 1, buff, args);
+#endif
+    l += n;
+    if (n < 0)
+    {
+        l = sizeof(tmpbuf) - 1;
+    }
+    
+    tmpbuf[l] = '\n';
+    InsertToLogBuffer(tmpbuf, l + 1);
+
+#endif
+
+}
+
+void Logger::LogPrint(char * format, ...)
+{
+
+#if LOGGING_ENABLED
+
+    if (fileHandle == INVALID_HANDLE_VALUE)
+    {
+        return;
+    }
+
+    char tmpbuf[1024];
+    va_list args;
+    int l;
+
+    va_start(args, format);
+#if defined(SAFESTR)
+    l = vsnprintf_s(tmpbuf, sizeof(tmpbuf), sizeof(tmpbuf) - 1, format, args);
+#else
+    l = _vsnprintf(tmpbuf, sizeof(tmpbuf), format, args);
+#endif
+
+    if (l < 0)
+    {
+        tmpbuf[sizeof(tmpbuf)-1] = '\n';
+        l = sizeof(tmpbuf);
+    }
+    InsertToLogBuffer(tmpbuf, l);
+
+#endif
+
+}
diff --git a/src/sockpipe/logger.h b/src/sockpipe/logger.h
new file mode 100644 (file)
index 0000000..b075aec
--- /dev/null
@@ -0,0 +1,54 @@
+#if !defined(LOGGER_H)
+#define LOGGER_H
+
+#if !defined LOGGING_ENABLED
+#define LOGGING_ENABLED 0
+#endif
+
+typedef enum
+{
+    TAG_INVALID,
+    TAG_READ,
+    TAG_SEND,
+    TAG_SENT,
+    TAG_READ_DBG,
+    TAG_XMIT_DBG,
+    TAG_COUNT
+} TAG_TYPE;
+
+#define SOCKPIPE_LOGGING    1
+#define PUMP_BUFFER_SIZE    2048
+
+class Logger : ThreadControl
+{
+public:
+    Logger();
+    ~Logger();
+    bool Initialize();
+    void Log(int direction, char * tag, int len, char * buff);
+    void Log(int direction, char * tag, char * buff, ...);
+    void LogPrint(char * format, ...);
+    void Flush();
+
+protected:
+    virtual void ThreadEntry(void * inContext);
+
+private:
+    void        InsertToLogBuffer(char * buff, int len);
+    void        htoa(char * in, char * out, int lengthIn);
+    DWORD       logTime();
+    HANDLE      fileHandle;
+    SpinLock    lock;
+    Circle      buffer;
+    HANDLE      writerEvent;
+    HANDLE      threadHandle;
+    DWORD       originalTime;
+};
+
+inline DWORD Logger::logTime()
+{
+#pragma prefast(suppress:28159)
+    return GetTickCount() - originalTime;
+}
+
+#endif
diff --git a/src/sockpipe/pipereader.cpp b/src/sockpipe/pipereader.cpp
new file mode 100644 (file)
index 0000000..62c2d40
--- /dev/null
@@ -0,0 +1,402 @@
+#include "stdafx.h"
+#include <winsock2.h>
+#include <windows.h>
+#include "plj_utils.h"
+#include "spinlock.h"
+#include "circle.h"
+#include "threadcontrol.h"
+#include "logger.h"
+#include "pipereader.h"
+
+
+PipeReader::PipeReader()
+{
+    pipe = INVALID_HANDLE_VALUE;
+}
+
+PipeReader::~PipeReader()
+{
+    if (pipe != INVALID_HANDLE_VALUE)
+    {
+        CloseHandle(pipe);
+        pipe = INVALID_HANDLE_VALUE;
+    }
+}
+
+bool PipeReader::Initialize(char * PipeName, Logger * Logger, class Connectoid * Sock, bool StartThread, bool Client, char * Tag)
+{
+    Connectoid::Initialize(Logger, Sock, Tag);
+    client = Client;
+    pipeName = PipeName;
+
+    receiveBuffer.Initialize(PUMP_BUFFER_SIZE);
+
+    //
+    // If we are spinning a thread for this pipe, spin it.
+    //
+
+    if (StartThread != false)
+    {
+        if (!Start())
+        {
+            die("failed to initialize/start pipe reader thread.");
+        }
+    }
+    return true;
+}
+
+int PipeReader::Send(Circle * buffer)
+{
+    BOOL    success;
+    DWORD   written;
+    DWORD   previouslyWritten = 0;
+
+    if (!receiveDataSeen)
+    {
+        //
+        // Drop incoming data on floor.
+        //
+
+        buffer->Drain();
+        return 0;
+    }
+
+    int lastError = 0;
+
+    if (write.Pending())
+    {
+        //
+        // Check result from previous write.
+        //
+
+        success = GetOverlappedResult(pipe, write.Overlapped(), &previouslyWritten, false);
+        log->Log(TAG_XMIT_DBG, tag, "write: GetOverlapResult returned %d, oh = %p", success, write.GetHandle());
+
+        if (!success)
+        {
+            lastError = GetLastError();
+
+            if (lastError == ERROR_IO_PENDING)
+            {
+                //
+                // The previous write is not yet complete.  We can't
+                // initiate another until it is.
+                //
+
+                log->Log(TAG_XMIT_DBG, tag, "write: GetOverlapResult returned ERROR_IO_PENDING, we shouldn't have come here!!!");
+                return 0;
+            }
+            else
+            {
+                die("pipe write failed, error %d\n", lastError);
+            }
+        }
+        write.SetPending(false);
+//      log->Log(TAG_SENT, tag, previouslyWritten, NULL);
+        {
+            char * bufftmp;
+            DWORD  lentmp;
+            lentmp = buffer->QueryContiguousRetrievable(&bufftmp);
+            ASSERT(lentmp >= previouslyWritten);
+            log->Log(TAG_SENT, tag, previouslyWritten, bufftmp);
+        }
+        buffer->CommitRetrieved(previouslyWritten);
+    }
+
+    //
+    // Initiate a write.
+    //
+
+    char * buff;
+    int length = buffer->QueryContiguousRetrievable(&buff);
+
+    if (length == 0)
+    {
+        //
+        // Nothing available to be written just yet.
+        //
+
+        log->Log(TAG_XMIT_DBG, tag, "write: nothing to write");
+        return 0;
+    }
+
+    log->Log(TAG_SEND, tag, length, NULL);
+    log->Log(TAG_XMIT_DBG, tag, "initiate %d byte write oh = %p", length, write.GetHandle());
+
+    success = WriteFile(pipe, buff, length, &written, write.Overlapped());
+    if (success)
+    {
+//      log->Log(TAG_SENT, tag, written, NULL);
+        log->Log(TAG_SENT, tag, written, buff);
+        log->Log(TAG_XMIT_DBG, tag, "write: instant gratification %d bytes on oh = %p", written, write.GetHandle());
+        return buffer->CommitRetrieved(written) + previouslyWritten;
+    }
+
+    lastError = GetLastError();
+
+    if (lastError == ERROR_IO_PENDING)
+    {
+        write.SetPending(true);
+        sender->SetWriteWait(true);
+        log->Log(TAG_XMIT_DBG, tag, "write: initiated send %d bytes, new state == pending, oh = %p", length, write.GetHandle());
+        return previouslyWritten;
+    }
+    g_shutdown = true;
+    die("pipe write failed, error %d\n", lastError);
+}
+
+int PipeReader::Receive(char * buffer, int length)
+{
+    BOOL    success;
+    DWORD   received = 0;
+
+    if (read.Pending())
+    {
+        //
+        // Check result from previous read.
+        //
+
+        success = GetOverlappedResult(pipe, read.Overlapped(), &received, false);
+        log->Log(TAG_READ_DBG, tag, "read: GetOverlappedResult status %d, count %d, oh = %p", success, received, read.GetHandle());
+        if (!success)
+        {
+            int lastError = GetLastError();
+
+            if (lastError == ERROR_IO_PENDING)
+            {
+                //
+                // The previous read is not yet complete.  We can't
+                // initiate another until it is.
+                //
+
+                log->Log(TAG_READ_DBG, tag, "read: still pending, this shouldn't have happpened *****************");
+                return 0;
+            }
+            if (lastError == ERROR_IO_INCOMPLETE)
+            {
+                log->Log(TAG_READ_DBG, tag, "read: ERROR_IO_INCOMPLETE, this shouldn't have happened ***************");
+                fprintf(stderr, "E_IO_INCOMPLETE read from %.3s -- this shouldn't happen, ignoring.\n", tag);
+                return 0;
+            }
+            else
+            {
+                die("pipe read failed, error %d\n", lastError);
+            }
+        }
+        read.SetPending(false);
+        log->Log(TAG_READ_DBG, tag, "read: delayed read complete, received %d bytes.", received);
+        return received;
+    }
+
+    log->Log(TAG_READ_DBG, tag, "read: initiating read %d bytes (max) oh %p", length, read.GetHandle());
+    success = ReadFile(pipe, buffer, length, &received, read.Overlapped());
+    if (!success)
+    {
+        int lastError = GetLastError();
+
+        if (lastError == ERROR_IO_PENDING)
+        {
+            log->Log(TAG_READ_DBG, tag, 0, "read: pending.");
+            read.SetPending(true);
+            SetReadWait(true); // ick, needs cleaning.
+        }
+        else if (lastError == ERROR_PIPE_LISTENING)
+        {
+            Sleep(500);
+            log->Log(TAG_READ_DBG, tag, "read: nobody is listening.");
+            read.SetOverlappedEvent();  // make sure the big wait will not wait for ever
+        }
+        else
+        {
+            fprintf(stderr, "read pipe failed %d\n", lastError);
+            // For now, get us out of here.
+            g_shutdown = true;
+            my_exit(0);
+        }
+        return 0;
+    }
+    log->Log(TAG_READ_DBG, tag, "read: instantly returning %d bytes", received);
+    return received;
+}
+
+void PipeReader::Pump()
+{
+    char    buf[PUMP_BUFFER_SIZE];
+
+    connected = true;
+
+    while (g_shutdown == false)
+    {
+        int received = 0;
+        int sent = 0;
+
+        if (!wait.read)
+        {
+            //
+            // If there's room in the recieve buffer, attempt to receive
+            // some.
+
+            int receivable = receiveBuffer.QueryInsertable();
+
+            if (receivable != 0)
+            {
+                if ((received = Receive(buf, receivable)) != 0)
+                {
+                    if (receiveDataSeen == false)
+                    {
+                        printf("pipe connected.\n");
+                        log->Log(TAG_READ_DBG, tag, "Recieve data from debugger.\n");
+                        receiveDataSeen = true;
+                    }
+                    log->Log(TAG_READ, tag, received, buf);
+                    if (sender->Connected() == false)
+                    {
+                        // Ignore all incoming data until there is something
+                        // connected to send it to.
+                        printf("pipereader: dropping %d bytes because socket is not connected.\n",
+                                received);
+                        log->Log(TAG_READ_DBG, tag,
+                                "dropping %d bytes because socket is not connected.\n",
+                                received);
+                        received = 0;
+                    }
+                    if (resetAckExpected)
+                    {
+                        // Ignore all incoming data until the other side tells
+                        // us a reset ack has been seen.
+                        log->Log(TAG_READ_DBG, tag,
+                                "dropping %d bytes, waiting for reset ack from target.\n",
+                                received);
+                        received = 0;
+                    }
+
+                    int count = CheckForResetPacket(buf, received);
+                    if (count != 0)
+                    {
+                        log->Log(TAG_READ_DBG, tag, "RESET packet received.\n");
+                        if (!resetAckExpected)
+                        {
+                            printf("debugger sent RESET.\n");
+                        }
+                        // Truncate received data to end of reset packet.  We
+                        // discard all remaining data until we see a reset ack
+                        // from the other end.  Note: On send the reset packet
+                        // is usually followed by 8 bytes of zero, the target
+                        // seems to depend on it ... and being as we truncated
+                        // and we don't know we got them all yet anyway and we
+                        // will drop all further data until we see something,
+                        // better send the zeros along.
+                        receiveBuffer.Insert(buf, count);
+                        int z = 0;
+                        receiveBuffer.Insert((char *)&z, sizeof(z));
+                        receiveBuffer.Insert((char *)&z, sizeof(z));
+                        received = 0;
+                        SetResetAckExpected(true);
+                    }
+                    receiveBuffer.Insert(buf, received);
+                }
+            }
+        }
+
+        if (!wait.write)
+        {
+            //
+            // Attempt to send. 
+            //
+            // Note: The Send routine will take care of the no data case.
+            //
+
+            sent = sender->Send(&receiveBuffer);
+        }
+
+        if (!(sent | received))
+        {
+            //
+            // Nothing sent, nothing received, wait until something happens
+            // on one end or the other.
+            //
+
+            Wait();
+        }
+    }
+    connected = false;
+}
+
+void PipeReader::ThreadEntry(void * inContext)
+{
+    UNREFERENCED_PARAMETER(inContext);
+
+    if (client == false)
+    {
+        //
+        // Create pipe for server (that other end will connect to).
+        //
+
+        pipe = CreateNamedPipe(pipeName,
+                               PIPE_ACCESS_DUPLEX 
+//                             | FILE_FLAG_FIRST_PIPE_INSTANCE
+//                             | FILE_FLAG_WRITE_THROUGH 
+                               | FILE_FLAG_OVERLAPPED
+                               ,
+                               PIPE_TYPE_BYTE
+//                             | PIPE_WAIT
+                               ,
+                               1,
+                               4096,
+                               4096,
+                               INFINITE,
+                               NULL);
+        if (pipe == INVALID_HANDLE_VALUE)
+        {
+            die("failed to open pipe, err = %d.", GetLastError());
+        }
+    }
+    else
+    {
+        //
+        // Create pipe for client.  Use CreateFile because, oddly, CreateNamedPipe 
+        // seems to fail if you use the \\servername\pipe\pipename format.  Sadly,
+        // this too will fail if the other end doesn't exist so we need to do it
+        // in the spun thread.  We did spin a thread right?
+        //
+
+        bool first = TRUE;
+
+        do
+        {
+            pipe = CreateFile(pipeName,                     // pipe name
+                              GENERIC_READ | GENERIC_WRITE, // read and write access
+                              0,                            // no sharing
+                              NULL,                         // default security
+                              OPEN_ALWAYS,                  // sample says open existing
+                              FILE_FLAG_WRITE_THROUGH       // push the data to the other end
+                              | FILE_FLAG_OVERLAPPED        // don't wait
+                              ,
+                              NULL);                        // why would i want a template?
+            if (pipe == INVALID_HANDLE_VALUE)
+            {
+                DWORD err = GetLastError();
+
+                if (err != ERROR_FILE_NOT_FOUND)
+                {
+                    die("failed to open pipe, err = %d.", err);
+                }
+
+                if (first)
+                {
+                    printf("pipe client waiting for remote pipe to become available.\n");
+                    first = false;
+                }
+                Sleep(1700);
+            }
+        } while (pipe == INVALID_HANDLE_VALUE);
+    }
+
+    printf("hello from the pipe reader.\n");
+
+    //
+    // Now pass data back and forth across the connections.
+    //
+
+    Pump();
+}
diff --git a/src/sockpipe/pipereader.h b/src/sockpipe/pipereader.h
new file mode 100644 (file)
index 0000000..aa2c8ba
--- /dev/null
@@ -0,0 +1,27 @@
+#if !defined(PIPEREADER_H)
+#define PIPEREADER_H
+
+#include "connectoid.h"
+
+class PipeReader : public ThreadControl, public Connectoid
+{
+public:
+                        PipeReader();
+                        ~PipeReader();
+    bool                Initialize(char * PipeName,
+                                   Logger * Logger,
+                                   class Connectoid * Sock,
+                                   bool StartThread,
+                                   bool Client,
+                                   char * Tag);
+    void                ThreadEntry(void * inContext);
+//  void                Send(char * buffer, int length);
+    int                 Send(Circle *);
+    int                 Receive(char * buffer, int length);
+private:
+    void                Pump();
+    bool                client;
+    HANDLE              pipe;
+    char              * pipeName;
+};
+#endif
diff --git a/src/sockpipe/plj_utils.h b/src/sockpipe/plj_utils.h
new file mode 100644 (file)
index 0000000..7c7c8b2
--- /dev/null
@@ -0,0 +1,11 @@
+#if !defined(PLJ_UTILS_H)
+#define PLJ_UTILS_H
+
+#define ASSERT(x)   if (!(x)){fprintf(stderr, "assert failed %s %d:%s", __FILE__, __LINE__, #x);__debugbreak();}
+
+__declspec(noreturn) void die(char *,...);
+__declspec(noreturn) void my_exit(int code);
+
+extern bool g_shutdown;
+
+#endif
diff --git a/src/sockpipe/sockpipe.cpp b/src/sockpipe/sockpipe.cpp
new file mode 100644 (file)
index 0000000..0c94b65
--- /dev/null
@@ -0,0 +1,262 @@
+
+#include "stdafx.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <winsock2.h>
+#include <windows.h>
+
+// plj specials
+
+#include "plj_utils.h"
+#include "spinlock.h"
+#include "threadcontrol.h"
+#include "circle.h"
+#include "logger.h"
+#include "connectoid.h"
+#include "pipereader.h"
+#include "sockreader.h"
+
+//
+// Globals.
+//
+
+bool g_shutdown = false;
+class Logger * g_log = NULL;
+_TCHAR g_progname[MAX_PATH];
+
+//
+// Define TWO_PIPE if you want to go pipe to pipe instead of pipe to
+// socket.  This is useful for debugging (this proxy) against a known
+// working debuggee (eg a virtual machine under VPC).
+//
+//#define TWO_PIPE
+
+//
+// Generic (C style) support routines.
+//
+
+void my_exit(int code)
+{
+    if (g_log)
+    {
+        g_log->Flush();
+    }
+    exit(code);
+}
+
+void die(char * message,...)
+{
+    char    buf[1024];
+    va_list args;
+
+    va_start(args, message);
+#if defined(SAFESTR)
+    vsnprintf_s(buf, sizeof(buf), sizeof(buf) - 1, message, args);
+#else
+    _vsnprintf(buf, sizeof(buf), message, args);
+#endif
+    fprintf(stderr, "%s\n", buf);
+    if (g_log)
+    {
+        g_log->Log(0, "die", buf);
+    }
+    my_exit(1);
+}
+
+void usage()
+{
+    _TCHAR * progname = g_progname;
+    _TCHAR * endName = _tcsrchr(g_progname, TCHAR('\\'));
+
+    if (endName)
+    {
+        progname = endName + 1;
+    }
+
+#if !defined(TWO_PIPE)
+    fprintf(stderr, "usage: %s [-l] pipe [address] port\n\n", progname);
+    fprintf(stderr, "where -  pipe is the name of the local pipe which the\n"
+                    "         Microsoft Windows Debugger will try to connect to.\n"
+                    "         address [optional] is the address of the target\n"
+                    "         to connect to if Xen is listening.\n"
+                    "         port is the (decimal) number of the TCP port Xen\n"
+                    "         is configured to listen on or to connect to on\n"
+                    "         this machine.\n\n"
+                    "         Note: If sockpipe is listening then the port must\n"
+                    "               be open through this machine's firewall.\n\n"
+                    "         -l [optional] if specified, enable logging.  N.B.\n"
+                    "         the log file can become quite large very quickly.\n"
+                    "example: %s my_pipe 7001\n",
+                    progname);
+#else
+    fprintf(stderr, "usage:   %s [-l] pipe1 pipe2\n\n", progname);
+    fprintf(stderr, "where -  pipe1 is the name of the local pipe which the\n"
+                    "         Microsoft Windows Debugger will try to connect to.\n"
+                    "         pipe2 is the full path pipe name to the pipe being\n"
+                    "         offered by a machine to be debugged.\n\n"
+                    "         -l [optional] if specified, enable logging.  N.B.\n"
+                    "         the log file can become quite large very quickly.\n"
+                    "example: %s my_pipe \\remotemachine\pipe\debugee_name\n",
+                    progname);
+#endif
+    fprintf(stderr, "\n"
+                    "This program (%s) needs to be started BEFORE either the\n"
+                    "kernel debugger or the system to be debugged.\n"
+                    "To configure the serial ports of a Xen guest to connect,\n"
+                    "add a line to the guest configuration file of the form-\n\n"
+                    "serial='tcp:proxy-machine:port_number'\n\n"
+                    "where proxy-machine is the IP address or name of the machine where\n"
+                    "this program is running and port_number is the TCP port number it\n"
+                    "is listening on.\n\n"
+                    "To configure the serial ports of a Xen guest to listen,\n"
+                    "add a line to the guest configuration file of the form-\n\n"
+                    "serial='tcp::port_number,server,nodelay'\n\n"
+                    "where port_number is the TCP port number the program should\n"
+                    "connect to.\n",
+                    progname);
+    my_exit(1);
+}
+
+int __cdecl _tmain(int argc, _TCHAR* argv[])
+{
+
+#if defined(TWO_PIPE)
+    //
+    // Experiment with pipe to pipe so we can debug using VPC and capture
+    // a log of a working debug session.
+    //
+
+    PipeReader  sock;
+
+#else
+
+    SockReader  sock;
+
+#endif
+
+    PipeReader  pipe;
+    Logger      log;
+
+    //
+    // Save the name of the current running program. This is not presented
+    // in argv[0] as you might expect... but hey, this is Windows.
+    //
+
+    GetModuleFileName(NULL, g_progname, sizeof (g_progname));
+    g_progname[sizeof(g_progname) - 1] = _T('\0');
+    argv++;
+    --argc;
+
+    if (argc == 0)
+        usage();
+
+    //
+    // Three arguments if you count the program name, the pipe name and
+    // the port (or 2nd pipe).
+    //
+
+    if (_tcsncmp(*argv, _T("-l"), 2) == 0)
+    {
+        if (!log.Initialize())
+        {
+            die("couldn't initialize logger");
+        }
+        argv++;
+        --argc;
+
+        if (argc == 0)
+            usage();
+    }
+
+
+    bool passive = true;
+
+    if (argc == 3)
+    {
+        passive = false;
+    }
+    else if (argc < 2)
+    {
+        usage();
+    }
+
+    g_log = &log;
+
+    //
+    // Note: sock.Initialize will fire up the socket pump thread,
+    // pipe initialization needs to be completed before that.
+    //
+
+    _TCHAR * lpipename = *argv;
+
+#define whack_pipe _T("\\\\.\\pipe\\")
+
+    size_t whackPipeLen =  (sizeof(whack_pipe) / sizeof(_TCHAR)) - 1;
+    if (_tcsnccmp(lpipename, whack_pipe, whackPipeLen) != 0)
+    {
+        size_t originalNameLen = _tcslen(lpipename);
+        size_t nameLen = whackPipeLen + originalNameLen + 1;
+        if (nameLen > 1024) // arbitary
+        {
+            die("pipe name is too long.");
+        }
+        lpipename = (_TCHAR *)malloc(nameLen * sizeof(_TCHAR));
+        if (lpipename == NULL)
+        {
+            die("failed to malloc space for local pipe name.");
+        }
+
+#pragma warning(push)
+#pragma warning(disable:6386)
+
+        memcpy(&lpipename[0], whack_pipe, whackPipeLen * sizeof(_TCHAR));
+        memcpy(&lpipename[whackPipeLen],
+               *argv,
+               originalNameLen * sizeof(_TCHAR));
+        lpipename[nameLen - 1] = 0;
+
+#pragma warning(pop)
+
+    }
+    argv++;
+
+    printf("gonna try pipe '%s'\n", lpipename);
+    if (!pipe.Initialize(lpipename, &log, &sock, false, false, "pip"))
+    {
+        die("couldn't open local named pipe, err %d", GetLastError());
+    }
+
+#if !defined(TWO_PIPE)
+    _TCHAR * address;
+    _TCHAR * portnumber;
+
+    if (passive) {
+        address = NULL;
+        portnumber = *argv;
+    } else {
+        address = *argv++;
+        portnumber = *argv;
+    }
+
+    if (!sock.Initialize(address, portnumber, &log, &pipe, true, "win"))
+    {
+        die("couldn't open socket.");
+    }
+#else
+    _TCHAR * rpipename = *argv;
+
+    if (!sock.Initialize(rpipename, &log, &pipe, true, true, "sok"))
+    {
+        die("couldn't open remote pipe.");
+    }
+#endif
+
+    // 
+    // We run the pipe reader directly on this thread.
+    //
+
+    pipe.ThreadEntry(&pipe);
+
+    return 0;
+}
+
diff --git a/src/sockpipe/sockreader.cpp b/src/sockpipe/sockreader.cpp
new file mode 100644 (file)
index 0000000..b76d755
--- /dev/null
@@ -0,0 +1,596 @@
+#include "stdafx.h"
+#include <winsock2.h>
+#include <windows.h>
+#include <stdlib.h>
+#include "plj_utils.h"
+#include "spinlock.h"
+#include "circle.h"
+#include "threadcontrol.h"
+#include "logger.h"
+#include "sockreader.h"
+
+
+bool
+Printable(char c)
+{
+    if ((c >= 0x20) && (c <= 0x7e))
+    {
+        return true;
+    }
+
+    switch (c)
+    {
+        case 0x09:  // tab
+        case 0x0a:  // line feed
+        case 0x0d:  // carriage return
+            return true;
+        default:
+            return false;
+    }
+}
+
+
+SockReader::SockReader()
+{
+    listenSocket    = INVALID_SOCKET;
+    connection      = INVALID_SOCKET;
+    doCleanup       = false;
+    initialPacketHeaderIndex = 0;
+}
+
+SockReader::~SockReader()
+{
+    if (listenSocket != INVALID_SOCKET)
+    {
+        closesocket(listenSocket);
+        listenSocket = INVALID_SOCKET;
+    }
+    Close();
+    if (doCleanup)
+    {
+        WSACleanup();
+    }
+}
+
+void SockReader::Close()
+{
+    if (connection != INVALID_SOCKET)
+    {
+        closesocket(connection);
+        connection = INVALID_SOCKET;
+    }
+}
+
+
+bool SockReader::Initialize(_TCHAR * Address, _TCHAR * PortNumber, Logger * Logger, class Connectoid * Pipe, bool StartThread, char * Tag)
+{
+    u_long addr;
+    u_short port = htons((u_short)_tstol(PortNumber));
+
+    if (Address)
+    {
+        passive = false;
+
+        addr = inet_addr(Address);
+        if (addr == INADDR_ANY || addr == INADDR_NONE)
+        {
+            die("TCP: invalid address.");
+        }
+    }
+    else
+    {
+        addr = INADDR_ANY;
+        passive = true;
+    }
+
+    if (port == 0)
+    {
+        die("TCP: invalid port number.");
+    }
+
+    //
+    // The sockaddr_in structure specifies the address family, IP address and
+    // port number that will be bound.
+    //
+
+    RtlZeroMemory(&service, sizeof(service));
+    service.sin_family      = AF_INET;
+    service.sin_port        = port;
+    service.sin_addr.s_addr = addr;
+
+    Connectoid::Initialize(Logger, Pipe, Tag);
+    receiveBuffer.Initialize(PUMP_BUFFER_SIZE);
+
+    if (StartThread != false)
+    {
+        if (!Start())
+        {
+            die("failed to initialize/start socket reader thread.");
+        }
+    }
+
+    return true;
+}
+
+void SockReader::ThreadEntry(void * inContext)
+{
+    UNREFERENCED_PARAMETER(inContext);
+
+    while (g_shutdown == false)
+    {
+        //
+        // Initialize Winsock.
+        //
+        // Note; We could set this puppy up to handle multiple sessions, probably
+        // something we will want to do in the future.
+        //
+
+        printf("hello from the socket reader.\n");
+
+        if (WSAStartup(MAKEWORD(2,2), &wsaData) != NO_ERROR)
+        {
+            die("WINSOCK2: Winsock startup failed.");
+        }
+        doCleanup = true;
+
+        if (passive)
+        {
+            listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+            if (listenSocket == INVALID_SOCKET)
+            {
+                // GetLastError would be useful here!
+                die("TCP: Socket creation error.");
+            }
+
+            //
+            // Bind it.  The main loop will listen, accept and process it.
+            //
+
+            if (bind(listenSocket, (SOCKADDR *)&service, sizeof(service)) == SOCKET_ERROR)
+            {
+                die("WINSOCK2: bind failed.");
+            }
+
+            if (listen(listenSocket, 1) == SOCKET_ERROR)
+            {
+                die("WINSOCK2: listen failed.");
+            }
+
+            shutdown = false;
+
+            do
+            {
+                printf("socket accepting connections\n");
+                connection = accept(listenSocket, NULL, NULL);
+                if (connection == SOCKET_ERROR)
+                {
+                    printf("accept failed (SOCKET_ERROR = %d)\n", WSAGetLastError());
+                }
+            } while (connection == SOCKET_ERROR);
+
+            printf("remote com emulator connected...\n");
+
+            closesocket(listenSocket);
+            listenSocket = INVALID_SOCKET;
+        }
+        else
+        {
+            shutdown = false;
+
+            connection = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+            if (connection == INVALID_SOCKET)
+            {
+                // GetLastError would be useful here!
+                die("TCP: Socket creation error.");
+            }
+
+            do
+            {
+                printf("socket connecting...\n");
+                if (connect(connection, (SOCKADDR *)&service, sizeof(service)) == SOCKET_ERROR)
+                {
+                    if (WSAGetLastError() != WSAECONNREFUSED &&
+                        WSAGetLastError() != WSAENETUNREACH &&
+                        WSAGetLastError() != WSAETIMEDOUT)
+                    {
+                        die("WINSOCK2: connect failed (SOCKET_ERROR = %d)\n", WSAGetLastError());
+                    }
+
+                    printf("connect failed (SOCKET_ERROR = %d)\n", WSAGetLastError());
+                }
+                else
+                {
+                    break;
+                }
+            } while (true);
+        }
+
+        //
+        // We have no previously initiated read on this socket, clear up
+        // (potentially left over status).  We should probably tear down
+        // and reestablish the read side of the world but ... I didn't
+        // write it in a way that makes that easy so, rudely, just fix it.
+        //
+
+        read.SetPending(false);
+
+        //
+        // Set TCP_NODELAY on the socket so TCP won't try to build bigger
+        // packets.  On the target end this seems to be critical on this
+        // end it may not be so important but still may help.
+        //
+
+        int opt = 1;
+        setsockopt(connection, IPPROTO_TCP, TCP_NODELAY, (char *)&opt, sizeof(opt));
+
+        Pump();
+
+        Close();
+        WSACleanup();
+        doCleanup = false;
+
+        //
+        // Delay slightly before going around.  This is to give the world
+        // time to clean up and shouldn't be needed at all ... but we'll 
+        // see if it helps.
+        //
+
+        Sleep(314);
+    }
+}
+
+int SockReader::Send(Circle * buffer)
+{
+    int     success;
+    DWORD   sent;
+    DWORD   previouslySent = 0;
+    int     lastError = 0;
+    DWORD   flags = 0;
+
+    if (write.Pending())
+    {
+        //
+        // Check the result from a previous send.
+        //
+
+        success = WSAGetOverlappedResult(connection, write.Overlapped(), &previouslySent, false, &flags);
+        log->Log(TAG_XMIT_DBG, tag, "write: WSAGetOverlappedResult %d, oh = %p", success, write.GetHandle());
+
+        if (!success)
+        {
+            lastError = WSAGetLastError();
+            die("write: WSAGetOverlappedResult failed, error = %d", lastError);
+        }
+        write.SetPending(false);
+        log->Log(TAG_SENT, tag, previouslySent, NULL);
+        buffer->CommitRetrieved(previouslySent);
+    }
+
+    //
+    // Initiate a write.
+    //
+
+    char * buff;
+    int length = buffer->QueryContiguousRetrievable(&buff);
+
+    if (length == 0)
+    {
+        //
+        // Nothing available to send.
+        //
+
+        log->Log(TAG_XMIT_DBG, tag, "write: nothing to write");
+        return 0;
+    }
+
+    log->Log(TAG_SEND, tag, length, NULL);
+    log->Log(TAG_XMIT_DBG, tag, "initiate %d write on socket oh = %p", length, write.GetHandle());
+
+    sent = 0;
+    WSABUF  wsabuf;
+    wsabuf.buf = buff;
+    wsabuf.len = length;
+
+    success = WSASend(connection, &wsabuf, 1, &sent, flags, write.Overlapped(), NULL);
+
+    if (success == SOCKET_ERROR)
+    {
+        lastError = WSAGetLastError();
+
+        if (lastError == WSA_IO_PENDING)
+        {
+            write.SetPending(true);
+            sender->SetWriteWait(true);
+            log->Log(TAG_XMIT_DBG, tag, "write: initiated send on socket %d bytes, pending oh = %p.", length, write.GetHandle());
+            return previouslySent;
+        }
+
+        //
+        // Um ... Write failed, we don't know why.  Assume the connection is probably
+        // gone and return to caller ... it should all come tumbling down shortly.
+        //
+
+        shutdown = true;
+        fprintf(stderr, "write socket failed %d\n", lastError);
+        return previouslySent;
+    }
+
+    log->Log(TAG_SENT, tag, sent, NULL);
+    buffer->CommitRetrieved(sent);
+
+    return previouslySent + sent;
+}
+
+
+int SockReader::Receive(char * buffer, int length)
+{
+
+    BOOL    success;
+    DWORD   received = 0;
+
+    if (read.Pending())
+    {
+        //
+        // Check result from previous read.
+        //
+
+        DWORD flags;
+        
+        success = WSAGetOverlappedResult(connection, read.Overlapped(), &received, false, &flags);
+        log->Log(TAG_READ_DBG, tag, "read: WSAGetOverlappedResult returned %d for %d bytes\n", success, received);
+
+        if (!success)
+        {
+            int lastError = WSAGetLastError();
+
+            if (lastError == WSA_IO_INCOMPLETE)
+            {
+                log->Log(TAG_READ_DBG, tag, "read: WSA_IO_INCOMPLETE, this shouldn't happen, ignored.");
+                return 0;
+            }
+            //
+            // I've seen us die here with WSAECONNRESET when the socket goes away.  
+            // Treat any unknown error here the same as if a read failed and cause
+            // socket closure and possible reset.
+            //
+            
+            fprintf(stderr, "WSAGetOverlappedResult failed, err %d, closing pipe.\n", lastError);
+            shutdown = true;
+            return 0;
+        }
+        read.SetPending(false);
+        log->Log(TAG_READ_DBG, tag, "read: delayed read complete, received %d bytes.", received);
+        return received;
+    }
+
+    DWORD flags = 0;
+    WSABUF  wsabuf;
+    wsabuf.buf = buffer;
+    wsabuf.len = length;
+    ASSERT(length);
+
+    log->Log(TAG_READ_DBG, tag, "read: initiating socket receive %d bytes (max) oh = %p", length, read.GetHandle());
+    success = WSARecv(connection, &wsabuf, 1, &received, &flags, read.Overlapped(), NULL);
+    if (success == SOCKET_ERROR)
+    {
+        int lastError = WSAGetLastError();
+
+        if (lastError == WSA_IO_PENDING)
+        {
+            log->Log(TAG_READ_DBG, tag, "read: pending.");
+            read.SetPending(true);
+            SetReadWait(true); // bleh
+        }
+        else
+        {
+            log->Log(TAG_READ, tag, "read failed, WSALastError == %d\n", lastError);
+            fprintf(stderr, "read socket failed %d\n", lastError);
+            shutdown = true;
+        }
+        return 0;
+    }
+    log->Log(TAG_READ_DBG, tag, "read: socket recv returned %d bytes immediately.", received);
+
+    if (!received)
+    {
+        log->Log(TAG_READ_DBG, tag, "read: successful read of 0 bytes, graceful shutdown.");
+        shutdown = true;
+    }
+    return received;
+}
+
+static char InitialPacketHeader[6] =
+{
+    0x30, 0x30, 0x30, 0x30, 0x07, 0x00
+};
+
+int SockReader::CheckForInitialPacketHeader(char * Buffer, int Length)
+{
+    for (int count = 1; Length; count++, Length--)
+    {
+        if (*Buffer++ != InitialPacketHeader[initialPacketHeaderIndex++])
+        {
+            initialPacketHeaderIndex = 0;
+        }
+        if (initialPacketHeaderIndex == sizeof(InitialPacketHeader))
+        {
+            initialPacketHeaderIndex = 0;
+            return count;
+        }
+    }
+    return 0;
+}
+
+
+void SockReader::Pump()
+{
+    //
+    // We have a connection, pass data back and forth.
+    //
+
+    char    buf[PUMP_BUFFER_SIZE];
+
+    log->Log(TAG_READ_DBG, tag, "Socket is up, beginning socket pump.");
+
+    //
+    // Crude.  Push a reset packet onto the socket.  Only the other side is
+    // supposed to write to the socket but until he sees the connected flag
+    // he isn't going to do any such thing, so, do it.  Because we inserted
+    // this packet we need to stop the reset ack from getting thru to the
+    // debugger or it'll ack it and the loop is on forever.
+    //
+    // Trouble is, the easiest way to send something is to stick it in the
+    // send buffer and we're really not supposed to mess with the other side's
+    // buffer ... so ... really really gross, put it in our buffer!
+    //
+
+    receiveBuffer.Drain();
+    InsertResetPacket(&receiveBuffer);
+    int z = 0;
+    receiveBuffer.Insert((char *)&z, sizeof(z));
+    receiveBuffer.Insert((char *)&z, sizeof(z));
+    Send(&receiveBuffer);
+    receiveBuffer.Drain();
+    SetResetAckExpected(true);
+    bool killResetAck = true;
+
+    connected = true;
+    while (Shutdown() == false)
+    {
+        int received = 0;
+        int sent = 0;
+
+        if (!wait.read)
+        {
+            int receivable = receiveBuffer.QueryInsertable();
+            
+            if (receivable != 0)
+            {
+                if ((received = Receive(buf, receivable)) != 0)
+                {
+                    log->Log(TAG_READ, tag, received, buf);
+                    if (receiveDataSeen == false)
+                    {
+                        //
+                        // If some noisy piece of software (eg PXE) spews lots
+                        // of data down the serial port we might think the
+                        // target is talking to the debugger.  Debugger packets
+                        // always contain some unprintable characters soooooo ..
+                        // use that and the probability that anything spewed by
+                        // something verbose is all printable as a heuristic to
+                        // indicate whether or not we think we're hearing from
+                        // the debugger.
+                        //
+
+                        for (int i = 0; i < received; i++)
+                        {
+                            if (!Printable(buf[i]))
+                            {
+                                receiveDataSeen = true;
+                                printf("receiving data from debug target.\n");
+                                log->Log(TAG_READ_DBG, tag, "Receive data from debug target.");
+                                break;
+                            }
+#if 1
+                            else
+                            {
+                                printf("%c", buf[i]);
+                            }
+#endif
+                        }
+                    }
+                    if (sender->Connected() == false)
+                    {
+                        // Ignore all incoming data until there is something
+                        // connected to send it to.
+                        printf("sockreader: dropping %d bytes because pipe is not connected (ERROR)\n",
+                                received);
+                        log->Log(TAG_READ_DBG, tag,
+                                "dropping %d bytes because pipe is not connected.\n",
+                                received);
+                        received = 0;
+                    }
+                    
+                    int count;
+                    
+                    if (resetAckExpected)
+                    {
+                        count = CheckForInitialPacketHeader(buf, received);
+
+                        if (count != 0)
+                        {
+                            // Initial packet seen.   This is as good as a reset.
+
+                            log->Log(TAG_READ_DBG, tag, "Initial packet received from target.\n");
+                            SetResetAckExpected(false);
+                            receiveBuffer.Insert(InitialPacketHeader, sizeof(InitialPacketHeader));
+                            receiveBuffer.Insert(buf + count, received - count);
+                            received = 0;
+                        }
+                    }
+
+                    count = CheckForResetPacket(buf, received);
+
+                    if (count != 0)
+                    {
+                        // Reset packet seen, which is really a reset ack.
+                        // Were we expecting one?
+
+                        if (resetAckExpected)
+                        {
+                            log->Log(TAG_READ_DBG, tag, "Reset ACK received from target.\n");
+                            printf("Reset ACK received from target.\n");
+                            if (killResetAck == false)
+                            {
+                                InsertResetPacket(&receiveBuffer);
+                            }
+                            else
+                            {
+                                killResetAck = false;
+                            }
+                            SetResetAckExpected(false);
+                            receiveBuffer.Insert(buf + count, received - count);
+                            received = 0;
+                        }
+                        else
+                        {
+                            printf("unexpected reset-ack from debug target, probably a bad thing.\n");
+                            log->Log(TAG_READ_DBG, tag, "unexpected reset ACK received from target, PROBABLY A BAD THING.\n");
+                        }
+                    }
+                    else
+                    {
+                        if (resetAckExpected)
+                        {
+                            // Waiting for a reset packet, ignore (ie drop)
+                            // anything else.
+                            log->Log(TAG_READ_DBG, tag,
+                                    "dropping %d bytes, waiting for reset ack.\n",
+                                    received);
+                            received = 0;
+                        }
+                    }
+                    receiveBuffer.Insert(buf, received);
+                }
+            }
+        }
+
+        //
+        // We received some data, yay.  Pass it along.
+        //
+
+        if (!wait.write)
+        {
+            sent = sender->Send(&receiveBuffer);
+        }
+
+        if (!(sent | received))
+        {
+            Wait();
+        }
+    }
+    log->Log(TAG_READ_DBG, tag, "Socket is down.");
+    receiveDataSeen = false;
+    connected = false;
+}
+
diff --git a/src/sockpipe/sockreader.h b/src/sockpipe/sockreader.h
new file mode 100644 (file)
index 0000000..adcdcd5
--- /dev/null
@@ -0,0 +1,46 @@
+#if !defined(SOCKREADER_H)
+#define SOCKREADER_H
+
+#include "connectoid.h"
+
+class SockReader : public ThreadControl, public Connectoid
+{
+public:
+                        SockReader();
+                        ~SockReader();
+    bool                Initialize(_TCHAR * Address,
+                                   _TCHAR * PortNumber,
+                                   Logger * Logger,
+                                   class Connectoid * Pipe,
+                                   bool StartThread,
+                                   char * Tag);
+    void                ThreadEntry(void * inContext);
+    int                 Send(Circle * buffer);
+    int                 Receive(char * buffer, int length);
+
+private:
+    void                Close();
+    void                Pump();
+    bool                Shutdown();
+    int                 CheckForInitialPacketHeader(char *, int);
+    bool                shutdown;
+    bool                doCleanup;
+    int                 initialPacketHeaderIndex;
+    bool                passive;
+
+    // winsock2 fields
+
+    WSADATA             wsaData; 
+    SOCKET              listenSocket;
+    SOCKET              connection;
+    sockaddr_in         service;
+};
+
+inline
+bool
+SockReader::Shutdown()
+{
+    return shutdown || g_shutdown;
+}
+
+#endif
diff --git a/src/sockpipe/spinlock.cpp b/src/sockpipe/spinlock.cpp
new file mode 100644 (file)
index 0000000..f660d3c
--- /dev/null
@@ -0,0 +1,58 @@
+//
+// SpinLock.  Generic procedural.
+//
+
+#include "stdafx.h"
+#include <windows.h>
+#include "plj_utils.h"
+#include "spinlock.h"
+
+
+void SpinLock::Acquire()
+{
+    for(;;)
+    {
+        while (value != 0)
+        {
+            //
+            // Move to the back of the ready queue.  If this process had more
+            // than two threads we might want to do something more interesting
+            // but with only two, if the lock is held the other guy has it,
+            // give him a turn on the processor.
+            //
+
+            Sleep(0);
+        }
+
+        //
+        // Might want to use something more interesting than 1 for the lock value.
+        // for example, the current thread id, or simply whether it's the reader
+        // or writer.
+        //
+
+        if (InterlockedExchange(&value, 1) == 0)
+        {
+            return;
+        }
+    }
+}
+
+void SpinLock::Release()
+{
+    ASSERT(value != 0);
+    value = 0;
+}
+
+bool SpinLock::TryToAcquire()
+{
+    if (value != 0)
+    {
+        return false;
+    }
+
+    if (InterlockedExchange(&value, 1) != 0)
+    {
+        return false;
+    }
+    return true;
+}
diff --git a/src/sockpipe/spinlock.h b/src/sockpipe/spinlock.h
new file mode 100644 (file)
index 0000000..98b3bc1
--- /dev/null
@@ -0,0 +1,37 @@
+#if !defined(SPINLOCK_H)
+#define SPINLOCK_H
+
+class SpinLock
+{
+public:
+    SpinLock();
+    ~SpinLock();
+    bool Initialize();
+
+    void Acquire();
+    void Release();
+    bool TryToAcquire();
+
+private:
+    volatile LONG value;
+};
+
+inline
+SpinLock::SpinLock()
+{
+    value = 0;
+}
+
+inline
+SpinLock::~SpinLock()
+{
+}
+
+inline
+bool SpinLock::Initialize()
+{
+    value = 0;
+    return true;
+}
+
+#endif
diff --git a/src/sockpipe/stdafx.cpp b/src/sockpipe/stdafx.cpp
new file mode 100644 (file)
index 0000000..aac98e1
--- /dev/null
@@ -0,0 +1,8 @@
+// stdafx.cpp : source file that includes just the standard includes
+// sockpipe.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
+// TODO: reference any additional headers you need in STDAFX.H
+// and not in this file
diff --git a/src/sockpipe/stdafx.h b/src/sockpipe/stdafx.h
new file mode 100644 (file)
index 0000000..a019373
--- /dev/null
@@ -0,0 +1,16 @@
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+#pragma once
+
+
+#if !defined(WIN32_LEAN_AND_MEAN)
+#define WIN32_LEAN_AND_MEAN     // Exclude rarely-used stuff from Windows headers
+#endif
+
+#include <stdio.h>
+#include <tchar.h>
+
+
diff --git a/src/sockpipe/threadcontrol.cpp b/src/sockpipe/threadcontrol.cpp
new file mode 100644 (file)
index 0000000..840e72a
--- /dev/null
@@ -0,0 +1,45 @@
+#include "stdafx.h"
+#include <windows.h>
+#include "plj_utils.h"
+#include "spinlock.h"
+#include "threadcontrol.h"
+
+DWORD WINAPI ThreadStart(void * inContext)
+{
+    UNREFERENCED_PARAMETER(inContext);
+
+    //
+    // Thunk from win32 C style entry to the containing C++ object's
+    // ThreadEntry routine.
+    //
+
+    ((class ThreadControl *)inContext)->ThreadEntry(inContext);
+    return 0;
+}
+
+bool ThreadControl::Start()
+{
+    //
+    // Create thread and let it run.
+    //
+    // Note: Anything that needs to be done for this thread before it starts
+    // needs to have been done before we get here.  This includes things like
+    // initializing any events it might be supposed to wait on.
+    //
+
+    handle = CreateThread(NULL, 0, ThreadStart, this, 0, &id);
+    if (handle == INVALID_HANDLE_VALUE)
+    {
+        return false;
+    }
+    return true;
+}
+
+
+void ThreadControl::ThreadEntry(void * inContext)
+{
+    UNREFERENCED_PARAMETER(inContext);
+
+    die("default ThreadEntry called.  This should be overridden.");
+}
+
diff --git a/src/sockpipe/threadcontrol.h b/src/sockpipe/threadcontrol.h
new file mode 100644 (file)
index 0000000..f36b09f
--- /dev/null
@@ -0,0 +1,15 @@
+#if !defined(THREADCONTROL_H)
+#define THREADCONTROL_H
+
+class ThreadControl
+{
+public:
+    bool            Start();
+    virtual void    ThreadEntry(void * inContext);
+
+private:
+    HANDLE          handle;
+    DWORD           id;
+};
+
+#endif
diff --git a/vs2012/configs.props b/vs2012/configs.props
new file mode 100644 (file)
index 0000000..43987fb
--- /dev/null
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 
+       <ItemGroup Label="ProjectConfigurations"> 
+               <ProjectConfiguration Include="Windows 8 Debug|Win32"> 
+                       <Configuration>Windows 8 Debug</Configuration> 
+                       <Platform>Win32</Platform> 
+               </ProjectConfiguration> 
+               <ProjectConfiguration Include="Windows 7 Debug|Win32"> 
+                       <Configuration>Windows 7 Debug</Configuration> 
+                       <Platform>Win32</Platform> 
+               </ProjectConfiguration> 
+               <ProjectConfiguration Include="Windows Vista Debug|Win32"> 
+                       <Configuration>Windows Vista Debug</Configuration> 
+                       <Platform>Win32</Platform> 
+               </ProjectConfiguration> 
+               <ProjectConfiguration Include="Windows 8 Release|Win32"> 
+                       <Configuration>Windows 8 Release</Configuration> 
+                       <Platform>Win32</Platform> 
+               </ProjectConfiguration> 
+               <ProjectConfiguration Include="Windows 7 Release|Win32"> 
+                       <Configuration>Windows 7 Release</Configuration> 
+                       <Platform>Win32</Platform> 
+               </ProjectConfiguration> 
+               <ProjectConfiguration Include="Windows Vista Release|Win32"> 
+                       <Configuration>Windows Vista Release</Configuration> 
+                       <Platform>Win32</Platform> 
+               </ProjectConfiguration> 
+               <ProjectConfiguration Include="Windows 8 Debug|x64"> 
+                       <Configuration>Windows 8 Debug</Configuration> 
+                       <Platform>x64</Platform> 
+               </ProjectConfiguration> 
+               <ProjectConfiguration Include="Windows 7 Debug|x64"> 
+                       <Configuration>Windows 7 Debug</Configuration> 
+                       <Platform>x64</Platform> 
+               </ProjectConfiguration> 
+               <ProjectConfiguration Include="Windows Vista Debug|x64"> 
+                       <Configuration>Windows Vista Debug</Configuration> 
+                       <Platform>x64</Platform> 
+               </ProjectConfiguration> 
+               <ProjectConfiguration Include="Windows 8 Release|x64"> 
+                       <Configuration>Windows 8 Release</Configuration> 
+                       <Platform>x64</Platform> 
+               </ProjectConfiguration> 
+               <ProjectConfiguration Include="Windows 7 Release|x64"> 
+                       <Configuration>Windows 7 Release</Configuration> 
+                       <Platform>x64</Platform> 
+               </ProjectConfiguration> 
+               <ProjectConfiguration Include="Windows Vista Release|x64"> 
+                       <Configuration>Windows Vista Release</Configuration> 
+                       <Platform>x64</Platform> 
+               </ProjectConfiguration> 
+       </ItemGroup> 
+</Project>
diff --git a/vs2012/sockpipe.sln b/vs2012/sockpipe.sln
new file mode 100644 (file)
index 0000000..5d7bc5a
--- /dev/null
@@ -0,0 +1,62 @@
+\r
+Microsoft Visual Studio Solution File, Format Version 12.00\r
+# Visual Studio 2012\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sockpipe", "sockpipe\sockpipe.vcxproj", "{C7C6DFE5-847D-467B-AA0B-86770B042667}"\r
+EndProject\r
+Global\r
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution\r
+               Windows 7 Debug|Win32 = Windows 7 Debug|Win32\r
+               Windows 7 Debug|x64 = Windows 7 Debug|x64\r
+               Windows 7 Release|Win32 = Windows 7 Release|Win32\r
+               Windows 7 Release|x64 = Windows 7 Release|x64\r
+               Windows 8 Debug|Win32 = Windows 8 Debug|Win32\r
+               Windows 8 Debug|x64 = Windows 8 Debug|x64\r
+               Windows 8 Release|Win32 = Windows 8 Release|Win32\r
+               Windows 8 Release|x64 = Windows 8 Release|x64\r
+               Windows Vista Debug|Win32 = Windows Vista Debug|Win32\r
+               Windows Vista Debug|x64 = Windows Vista Debug|x64\r
+               Windows Vista Release|Win32 = Windows Vista Release|Win32\r
+               Windows Vista Release|x64 = Windows Vista Release|x64\r
+       EndGlobalSection\r
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 7 Debug|Win32.ActiveCfg = Windows 7 Debug|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 7 Debug|Win32.Build.0 = Windows 7 Debug|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 7 Debug|Win32.Deploy.0 = Windows 7 Debug|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 7 Debug|x64.ActiveCfg = Windows 7 Debug|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 7 Debug|x64.Build.0 = Windows 7 Debug|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 7 Debug|x64.Deploy.0 = Windows 7 Debug|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 7 Release|Win32.ActiveCfg = Windows 7 Release|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 7 Release|Win32.Build.0 = Windows 7 Release|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 7 Release|Win32.Deploy.0 = Windows 7 Release|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 7 Release|x64.ActiveCfg = Windows 7 Release|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 7 Release|x64.Build.0 = Windows 7 Release|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 7 Release|x64.Deploy.0 = Windows 7 Release|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 8 Debug|Win32.ActiveCfg = Windows 8 Debug|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 8 Debug|Win32.Build.0 = Windows 8 Debug|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 8 Debug|Win32.Deploy.0 = Windows 8 Debug|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 8 Debug|x64.ActiveCfg = Windows 8 Debug|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 8 Debug|x64.Build.0 = Windows 8 Debug|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 8 Debug|x64.Deploy.0 = Windows 8 Debug|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 8 Release|Win32.ActiveCfg = Windows 8 Release|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 8 Release|Win32.Build.0 = Windows 8 Release|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 8 Release|Win32.Deploy.0 = Windows 8 Release|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 8 Release|x64.ActiveCfg = Windows 8 Release|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 8 Release|x64.Build.0 = Windows 8 Release|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 8 Release|x64.Deploy.0 = Windows 8 Release|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows Vista Debug|Win32.ActiveCfg = Windows Vista Debug|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows Vista Debug|Win32.Build.0 = Windows Vista Debug|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows Vista Debug|Win32.Deploy.0 = Windows Vista Debug|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows Vista Debug|x64.ActiveCfg = Windows Vista Debug|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows Vista Debug|x64.Build.0 = Windows Vista Debug|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows Vista Debug|x64.Deploy.0 = Windows Vista Debug|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows Vista Release|Win32.ActiveCfg = Windows Vista Release|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows Vista Release|Win32.Build.0 = Windows Vista Release|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows Vista Release|Win32.Deploy.0 = Windows Vista Release|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows Vista Release|x64.ActiveCfg = Windows Vista Release|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows Vista Release|x64.Build.0 = Windows Vista Release|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows Vista Release|x64.Deploy.0 = Windows Vista Release|x64\r
+       EndGlobalSection\r
+       GlobalSection(SolutionProperties) = preSolution\r
+               HideSolutionNode = FALSE\r
+       EndGlobalSection\r
+EndGlobal\r
diff --git a/vs2012/sockpipe/sockpipe.vcxproj b/vs2012/sockpipe/sockpipe.vcxproj
new file mode 100644 (file)
index 0000000..f1c4fba
--- /dev/null
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="..\configs.props" />
+  <PropertyGroup Label="PropertySheets">
+    <CharacterSet>MultiByte</CharacterSet>
+    <PlatformToolset>WindowsApplicationForDrivers8.0</PlatformToolset>
+    <ConfigurationType>Application</ConfigurationType>
+  </PropertyGroup>
+  <PropertyGroup Label="Globals">
+    <Configuration>Windows Vista Debug</Configuration>
+    <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+    <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{c7c6dfe5-847d-467b-aa0b-86770b042667}</ProjectGuid>
+  </PropertyGroup>
+  <Import Project="..\targets.props" />
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <PropertyGroup>
+    <IncludePath>$(IncludePath)</IncludePath>
+    <RunCodeAnalysis>true</RunCodeAnalysis>
+    <EnableInf2cat>false</EnableInf2cat>
+  </PropertyGroup>
+  <PropertyGroup>
+    <CustomBuildAfterTargets>Link</CustomBuildAfterTargets>
+  </PropertyGroup>
+  <ItemDefinitionGroup>
+    <ClCompile>
+      <AdditionalIncludeDirectories>$(SolutionDir)..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>WIN32;_WINDOWS;_CRT_SECURE_NO_WARNINGS;LOGGING_ENABLED=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <WarningLevel>EnableAllWarnings</WarningLevel>
+      <DisableSpecificWarnings>4127;4265;4365;4711;4548;4820;4668;4255;6001;6054;28196;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <EnablePREfast>true</EnablePREfast>
+      <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='true'">MultiThreadedDebug</RuntimeLibrary>
+      <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='false'">MultiThreaded</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <AdditionalDependencies>kernel32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Platform)'=='Win32'">
+    <ClCompile>
+      <PreprocessorDefinitions>__i386__;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ClCompile>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Platform)'=='x64'">
+    <ClCompile>
+      <PreprocessorDefinitions>__x86_64__;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ClCompile>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <FilesToPackage Include="$(TargetPath)" />
+    <FilesToPackage Include="$(OutDir)$(TargetName).pdb" />
+    <FilesToPackage Include="$(OutDir)$(TargetName).dll" />
+    <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+  </ItemGroup>
+  <ItemGroup> 
+    <ClCompile Include="..\..\src\sockpipe\sockpipe.cpp" />
+    <ClCompile Include="..\..\src\sockpipe\Circle.cpp" />
+    <ClCompile Include="..\..\src\sockpipe\connectoid.cpp" />
+    <ClCompile Include="..\..\src\sockpipe\logger.cpp" />
+    <ClCompile Include="..\..\src\sockpipe\pipereader.cpp" />
+    <ClCompile Include="..\..\src\sockpipe\sockreader.cpp" />
+    <ClCompile Include="..\..\src\sockpipe\spinlock.cpp" />
+    <ClCompile Include="..\..\src\sockpipe\stdafx.cpp" />
+    <ClCompile Include="..\..\src\sockpipe\threadcontrol.cpp" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project>
diff --git a/vs2012/sockpipe/sockpipe.vcxproj.user b/vs2012/sockpipe/sockpipe.vcxproj.user
new file mode 100644 (file)
index 0000000..af0bff3
--- /dev/null
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+</Project>
diff --git a/vs2012/targets.props b/vs2012/targets.props
new file mode 100644 (file)
index 0000000..c8aba92
--- /dev/null
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+       <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 8 Debug|Win32'"> 
+               <TargetVersion>Windows8</TargetVersion> 
+               <UseDebugLibraries>true</UseDebugLibraries> 
+       </PropertyGroup> 
+       <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 8 Release|Win32'"> 
+               <TargetVersion>Windows8</TargetVersion> 
+               <UseDebugLibraries>false</UseDebugLibraries> 
+       </PropertyGroup> 
+       <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 8 Debug|x64'"> 
+               <TargetVersion>Windows8</TargetVersion> 
+               <UseDebugLibraries>true</UseDebugLibraries> 
+       </PropertyGroup> 
+       <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 8 Release|x64'"> 
+               <TargetVersion>Windows8</TargetVersion> 
+               <UseDebugLibraries>false</UseDebugLibraries> 
+       </PropertyGroup>
+       <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 7 Debug|Win32'"> 
+               <TargetVersion>Windows7</TargetVersion> 
+               <UseDebugLibraries>true</UseDebugLibraries> 
+       </PropertyGroup> 
+       <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 7 Release|Win32'"> 
+               <TargetVersion>Windows7</TargetVersion> 
+               <UseDebugLibraries>false</UseDebugLibraries> 
+       </PropertyGroup> 
+       <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 7 Debug|x64'"> 
+               <TargetVersion>Windows7</TargetVersion> 
+               <UseDebugLibraries>true</UseDebugLibraries> 
+       </PropertyGroup> 
+       <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 7 Release|x64'"> 
+               <TargetVersion>Windows7</TargetVersion> 
+               <UseDebugLibraries>false</UseDebugLibraries> 
+       </PropertyGroup>
+       <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows Vista Debug|Win32'"> 
+               <TargetVersion>Vista</TargetVersion> 
+               <UseDebugLibraries>true</UseDebugLibraries> 
+       </PropertyGroup> 
+       <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows Vista Release|Win32'"> 
+               <TargetVersion>Vista</TargetVersion> 
+               <UseDebugLibraries>false</UseDebugLibraries> 
+       </PropertyGroup> 
+       <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows Vista Debug|x64'"> 
+               <TargetVersion>Vista</TargetVersion> 
+               <UseDebugLibraries>true</UseDebugLibraries> 
+       </PropertyGroup> 
+       <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows Vista Release|x64'"> 
+               <TargetVersion>Vista</TargetVersion> 
+               <UseDebugLibraries>false</UseDebugLibraries> 
+       </PropertyGroup>
+</Project>
diff --git a/vs2013/configs.props b/vs2013/configs.props
new file mode 100644 (file)
index 0000000..43987fb
--- /dev/null
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 
+       <ItemGroup Label="ProjectConfigurations"> 
+               <ProjectConfiguration Include="Windows 8 Debug|Win32"> 
+                       <Configuration>Windows 8 Debug</Configuration> 
+                       <Platform>Win32</Platform> 
+               </ProjectConfiguration> 
+               <ProjectConfiguration Include="Windows 7 Debug|Win32"> 
+                       <Configuration>Windows 7 Debug</Configuration> 
+                       <Platform>Win32</Platform> 
+               </ProjectConfiguration> 
+               <ProjectConfiguration Include="Windows Vista Debug|Win32"> 
+                       <Configuration>Windows Vista Debug</Configuration> 
+                       <Platform>Win32</Platform> 
+               </ProjectConfiguration> 
+               <ProjectConfiguration Include="Windows 8 Release|Win32"> 
+                       <Configuration>Windows 8 Release</Configuration> 
+                       <Platform>Win32</Platform> 
+               </ProjectConfiguration> 
+               <ProjectConfiguration Include="Windows 7 Release|Win32"> 
+                       <Configuration>Windows 7 Release</Configuration> 
+                       <Platform>Win32</Platform> 
+               </ProjectConfiguration> 
+               <ProjectConfiguration Include="Windows Vista Release|Win32"> 
+                       <Configuration>Windows Vista Release</Configuration> 
+                       <Platform>Win32</Platform> 
+               </ProjectConfiguration> 
+               <ProjectConfiguration Include="Windows 8 Debug|x64"> 
+                       <Configuration>Windows 8 Debug</Configuration> 
+                       <Platform>x64</Platform> 
+               </ProjectConfiguration> 
+               <ProjectConfiguration Include="Windows 7 Debug|x64"> 
+                       <Configuration>Windows 7 Debug</Configuration> 
+                       <Platform>x64</Platform> 
+               </ProjectConfiguration> 
+               <ProjectConfiguration Include="Windows Vista Debug|x64"> 
+                       <Configuration>Windows Vista Debug</Configuration> 
+                       <Platform>x64</Platform> 
+               </ProjectConfiguration> 
+               <ProjectConfiguration Include="Windows 8 Release|x64"> 
+                       <Configuration>Windows 8 Release</Configuration> 
+                       <Platform>x64</Platform> 
+               </ProjectConfiguration> 
+               <ProjectConfiguration Include="Windows 7 Release|x64"> 
+                       <Configuration>Windows 7 Release</Configuration> 
+                       <Platform>x64</Platform> 
+               </ProjectConfiguration> 
+               <ProjectConfiguration Include="Windows Vista Release|x64"> 
+                       <Configuration>Windows Vista Release</Configuration> 
+                       <Platform>x64</Platform> 
+               </ProjectConfiguration> 
+       </ItemGroup> 
+</Project>
diff --git a/vs2013/sockpipe.sln b/vs2013/sockpipe.sln
new file mode 100644 (file)
index 0000000..9cc739c
--- /dev/null
@@ -0,0 +1,64 @@
+\r
+Microsoft Visual Studio Solution File, Format Version 12.00\r
+# Visual Studio 2013\r
+VisualStudioVersion = 12.0.40629.0\r
+MinimumVisualStudioVersion = 10.0.40219.1\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sockpipe", "sockpipe\sockpipe.vcxproj", "{C7C6DFE5-847D-467B-AA0B-86770B042667}"\r
+EndProject\r
+Global\r
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution\r
+               Windows 7 Debug|Win32 = Windows 7 Debug|Win32\r
+               Windows 7 Debug|x64 = Windows 7 Debug|x64\r
+               Windows 7 Release|Win32 = Windows 7 Release|Win32\r
+               Windows 7 Release|x64 = Windows 7 Release|x64\r
+               Windows 8 Debug|Win32 = Windows 8 Debug|Win32\r
+               Windows 8 Debug|x64 = Windows 8 Debug|x64\r
+               Windows 8 Release|Win32 = Windows 8 Release|Win32\r
+               Windows 8 Release|x64 = Windows 8 Release|x64\r
+               Windows Vista Debug|Win32 = Windows Vista Debug|Win32\r
+               Windows Vista Debug|x64 = Windows Vista Debug|x64\r
+               Windows Vista Release|Win32 = Windows Vista Release|Win32\r
+               Windows Vista Release|x64 = Windows Vista Release|x64\r
+       EndGlobalSection\r
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 7 Debug|Win32.ActiveCfg = Windows 7 Debug|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 7 Debug|Win32.Build.0 = Windows 7 Debug|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 7 Debug|Win32.Deploy.0 = Windows 7 Debug|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 7 Debug|x64.ActiveCfg = Windows 7 Debug|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 7 Debug|x64.Build.0 = Windows 7 Debug|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 7 Debug|x64.Deploy.0 = Windows 7 Debug|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 7 Release|Win32.ActiveCfg = Windows 7 Release|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 7 Release|Win32.Build.0 = Windows 7 Release|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 7 Release|Win32.Deploy.0 = Windows 7 Release|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 7 Release|x64.ActiveCfg = Windows 7 Release|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 7 Release|x64.Build.0 = Windows 7 Release|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 7 Release|x64.Deploy.0 = Windows 7 Release|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 8 Debug|Win32.ActiveCfg = Windows 8 Debug|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 8 Debug|Win32.Build.0 = Windows 8 Debug|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 8 Debug|Win32.Deploy.0 = Windows 8 Debug|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 8 Debug|x64.ActiveCfg = Windows 8 Debug|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 8 Debug|x64.Build.0 = Windows 8 Debug|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 8 Debug|x64.Deploy.0 = Windows 8 Debug|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 8 Release|Win32.ActiveCfg = Windows 8 Release|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 8 Release|Win32.Build.0 = Windows 8 Release|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 8 Release|Win32.Deploy.0 = Windows 8 Release|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 8 Release|x64.ActiveCfg = Windows 8 Release|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 8 Release|x64.Build.0 = Windows 8 Release|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 8 Release|x64.Deploy.0 = Windows 8 Release|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows Vista Debug|Win32.ActiveCfg = Windows Vista Debug|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows Vista Debug|Win32.Build.0 = Windows Vista Debug|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows Vista Debug|Win32.Deploy.0 = Windows Vista Debug|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows Vista Debug|x64.ActiveCfg = Windows Vista Debug|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows Vista Debug|x64.Build.0 = Windows Vista Debug|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows Vista Debug|x64.Deploy.0 = Windows Vista Debug|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows Vista Release|Win32.ActiveCfg = Windows Vista Release|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows Vista Release|Win32.Build.0 = Windows Vista Release|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows Vista Release|Win32.Deploy.0 = Windows Vista Release|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows Vista Release|x64.ActiveCfg = Windows Vista Release|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows Vista Release|x64.Build.0 = Windows Vista Release|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows Vista Release|x64.Deploy.0 = Windows Vista Release|x64\r
+       EndGlobalSection\r
+       GlobalSection(SolutionProperties) = preSolution\r
+               HideSolutionNode = FALSE\r
+       EndGlobalSection\r
+EndGlobal\r
diff --git a/vs2013/sockpipe/sockpipe.vcxproj b/vs2013/sockpipe/sockpipe.vcxproj
new file mode 100644 (file)
index 0000000..b849025
--- /dev/null
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="..\configs.props" />
+  <PropertyGroup Label="Globals">
+    <Configuration>Windows Vista Debug</Configuration>
+    <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+    <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
+  </PropertyGroup>
+  <PropertyGroup Label="PropertySheets">
+    <CharacterSet>MultiByte</CharacterSet>
+    <PlatformToolset>WindowsApplicationForDrivers8.1</PlatformToolset>
+    <ConfigurationType>Application</ConfigurationType>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{c7c6dfe5-847d-467b-aa0b-86770b042667}</ProjectGuid>
+  </PropertyGroup>
+  <Import Project="..\targets.props" />
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <PropertyGroup>
+    <IncludePath>$(IncludePath)</IncludePath>
+    <RunCodeAnalysis>true</RunCodeAnalysis>
+    <EnableInf2cat>false</EnableInf2cat>
+  </PropertyGroup>
+  <PropertyGroup>
+    <CustomBuildAfterTargets>Link</CustomBuildAfterTargets>
+  </PropertyGroup>
+  <ItemDefinitionGroup>
+    <ClCompile>
+      <AdditionalIncludeDirectories>$(SolutionDir)..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>WIN32;_WINDOWS;_CRT_SECURE_NO_WARNINGS;LOGGING_ENABLED=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <WarningLevel>EnableAllWarnings</WarningLevel>
+      <DisableSpecificWarnings>4127;4265;4365;4711;4548;4820;4668;4255;6001;6054;28196;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <EnablePREfast>true</EnablePREfast>
+      <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='true'">MultiThreadedDebug</RuntimeLibrary>
+      <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='false'">MultiThreaded</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <AdditionalDependencies>kernel32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Platform)'=='Win32'">
+    <ClCompile>
+      <PreprocessorDefinitions>__i386__;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ClCompile>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Platform)'=='x64'">
+    <ClCompile>
+      <PreprocessorDefinitions>__x86_64__;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ClCompile>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <FilesToPackage Include="$(TargetPath)" />
+    <FilesToPackage Include="$(OutDir)$(TargetName).pdb" />
+    <FilesToPackage Include="$(OutDir)$(TargetName).dll" />
+    <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\src\sockpipe\sockpipe.cpp" />
+    <ClCompile Include="..\..\src\sockpipe\Circle.cpp" />
+    <ClCompile Include="..\..\src\sockpipe\connectoid.cpp" />
+    <ClCompile Include="..\..\src\sockpipe\logger.cpp" />
+    <ClCompile Include="..\..\src\sockpipe\pipereader.cpp" />
+    <ClCompile Include="..\..\src\sockpipe\sockreader.cpp" />
+    <ClCompile Include="..\..\src\sockpipe\spinlock.cpp" />
+    <ClCompile Include="..\..\src\sockpipe\stdafx.cpp" />
+    <ClCompile Include="..\..\src\sockpipe\threadcontrol.cpp" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project>
diff --git a/vs2013/sockpipe/sockpipe.vcxproj.user b/vs2013/sockpipe/sockpipe.vcxproj.user
new file mode 100644 (file)
index 0000000..af0bff3
--- /dev/null
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+</Project>
diff --git a/vs2013/targets.props b/vs2013/targets.props
new file mode 100644 (file)
index 0000000..c8aba92
--- /dev/null
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+       <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 8 Debug|Win32'"> 
+               <TargetVersion>Windows8</TargetVersion> 
+               <UseDebugLibraries>true</UseDebugLibraries> 
+       </PropertyGroup> 
+       <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 8 Release|Win32'"> 
+               <TargetVersion>Windows8</TargetVersion> 
+               <UseDebugLibraries>false</UseDebugLibraries> 
+       </PropertyGroup> 
+       <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 8 Debug|x64'"> 
+               <TargetVersion>Windows8</TargetVersion> 
+               <UseDebugLibraries>true</UseDebugLibraries> 
+       </PropertyGroup> 
+       <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 8 Release|x64'"> 
+               <TargetVersion>Windows8</TargetVersion> 
+               <UseDebugLibraries>false</UseDebugLibraries> 
+       </PropertyGroup>
+       <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 7 Debug|Win32'"> 
+               <TargetVersion>Windows7</TargetVersion> 
+               <UseDebugLibraries>true</UseDebugLibraries> 
+       </PropertyGroup> 
+       <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 7 Release|Win32'"> 
+               <TargetVersion>Windows7</TargetVersion> 
+               <UseDebugLibraries>false</UseDebugLibraries> 
+       </PropertyGroup> 
+       <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 7 Debug|x64'"> 
+               <TargetVersion>Windows7</TargetVersion> 
+               <UseDebugLibraries>true</UseDebugLibraries> 
+       </PropertyGroup> 
+       <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 7 Release|x64'"> 
+               <TargetVersion>Windows7</TargetVersion> 
+               <UseDebugLibraries>false</UseDebugLibraries> 
+       </PropertyGroup>
+       <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows Vista Debug|Win32'"> 
+               <TargetVersion>Vista</TargetVersion> 
+               <UseDebugLibraries>true</UseDebugLibraries> 
+       </PropertyGroup> 
+       <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows Vista Release|Win32'"> 
+               <TargetVersion>Vista</TargetVersion> 
+               <UseDebugLibraries>false</UseDebugLibraries> 
+       </PropertyGroup> 
+       <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows Vista Debug|x64'"> 
+               <TargetVersion>Vista</TargetVersion> 
+               <UseDebugLibraries>true</UseDebugLibraries> 
+       </PropertyGroup> 
+       <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows Vista Release|x64'"> 
+               <TargetVersion>Vista</TargetVersion> 
+               <UseDebugLibraries>false</UseDebugLibraries> 
+       </PropertyGroup>
+</Project>
diff --git a/vs2015/configs.props b/vs2015/configs.props
new file mode 100644 (file)
index 0000000..cdbb3c8
--- /dev/null
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+       <ItemGroup Label="ProjectConfigurations">
+               <ProjectConfiguration Include="Windows 10 Debug|Win32">
+                       <Configuration>Windows 10 Debug</Configuration>
+                       <Platform>Win32</Platform>
+                       <WindowsTargetPlatformVersion>10</WindowsTargetPlatformVersion>
+               </ProjectConfiguration>
+               <ProjectConfiguration Include="Windows 10 Release|Win32">
+                       <Configuration>Windows 10 Release</Configuration>
+                       <Platform>Win32</Platform>
+                       <WindowsTargetPlatformVersion>10</WindowsTargetPlatformVersion>
+               </ProjectConfiguration>
+               <ProjectConfiguration Include="Windows 10 Debug|x64">
+                       <Configuration>Windows 10 Debug</Configuration>
+                       <Platform>x64</Platform>
+                       <WindowsTargetPlatformVersion>10</WindowsTargetPlatformVersion>
+               </ProjectConfiguration>
+               <ProjectConfiguration Include="Windows 10 Release|x64">
+                       <Configuration>Windows 10 Release</Configuration>
+                       <Platform>x64</Platform>
+                       <WindowsTargetPlatformVersion>10</WindowsTargetPlatformVersion>
+               </ProjectConfiguration>
+               <ProjectConfiguration Include="Windows 8 Debug|Win32">
+                       <Configuration>Windows 8 Debug</Configuration>
+                       <Platform>Win32</Platform>
+                       <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
+               </ProjectConfiguration>
+               <ProjectConfiguration Include="Windows 8 Release|Win32">
+                       <Configuration>Windows 8 Release</Configuration>
+                       <Platform>Win32</Platform>
+                       <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
+               </ProjectConfiguration>
+               <ProjectConfiguration Include="Windows 8 Debug|x64">
+                       <Configuration>Windows 8 Debug</Configuration>
+                       <Platform>x64</Platform>
+                       <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
+               </ProjectConfiguration>
+               <ProjectConfiguration Include="Windows 8 Release|x64">
+                       <Configuration>Windows 8 Release</Configuration>
+                       <Platform>x64</Platform>
+                       <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
+               </ProjectConfiguration>
+       </ItemGroup>
+</Project>
diff --git a/vs2015/sockpipe.sln b/vs2015/sockpipe.sln
new file mode 100644 (file)
index 0000000..66aedb3
--- /dev/null
@@ -0,0 +1,40 @@
+\r
+Microsoft Visual Studio Solution File, Format Version 12.00\r
+# Visual Studio 14\r
+VisualStudioVersion = 14.0.25420.1\r
+MinimumVisualStudioVersion = 10.0.40219.1\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sockpipe", "sockpipe\sockpipe.vcxproj", "{C7C6DFE5-847D-467B-AA0B-86770B042667}"\r
+EndProject\r
+Global\r
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution\r
+               Windows 10 Debug|Win32 = Windows 10 Debug|Win32\r
+               Windows 10 Debug|x64 = Windows 10 Debug|x64\r
+               Windows 10 Release|Win32 = Windows 10 Release|Win32\r
+               Windows 10 Release|x64 = Windows 10 Release|x64\r
+               Windows 8 Debug|Win32 = Windows 8 Debug|Win32\r
+               Windows 8 Debug|x64 = Windows 8 Debug|x64\r
+               Windows 8 Release|Win32 = Windows 8 Release|Win32\r
+               Windows 8 Release|x64 = Windows 8 Release|x64\r
+       EndGlobalSection\r
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 10 Debug|Win32.ActiveCfg = Windows 10 Debug|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 10 Debug|Win32.Build.0 = Windows 10 Debug|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 10 Debug|x64.ActiveCfg = Windows 10 Debug|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 10 Debug|x64.Build.0 = Windows 10 Debug|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 10 Release|Win32.ActiveCfg = Windows 10 Release|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 10 Release|Win32.Build.0 = Windows 10 Release|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 10 Release|x64.ActiveCfg = Windows 10 Release|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 10 Release|x64.Build.0 = Windows 10 Release|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 8 Debug|Win32.ActiveCfg = Windows 8 Debug|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 8 Debug|Win32.Build.0 = Windows 8 Debug|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 8 Debug|x64.ActiveCfg = Windows 8 Debug|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 8 Debug|x64.Build.0 = Windows 8 Debug|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 8 Release|Win32.ActiveCfg = Windows 8 Release|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 8 Release|Win32.Build.0 = Windows 8 Release|Win32\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 8 Release|x64.ActiveCfg = Windows 8 Release|x64\r
+               {C7C6DFE5-847D-467B-AA0B-86770B042667}.Windows 8 Release|x64.Build.0 = Windows 8 Release|x64\r
+       EndGlobalSection\r
+       GlobalSection(SolutionProperties) = preSolution\r
+               HideSolutionNode = FALSE\r
+       EndGlobalSection\r
+EndGlobal\r
diff --git a/vs2015/sockpipe/sockpipe.vcxproj b/vs2015/sockpipe/sockpipe.vcxproj
new file mode 100644 (file)
index 0000000..c319a8d
--- /dev/null
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="..\configs.props" />
+  <PropertyGroup Label="PropertySheets">
+    <CharacterSet>MultiByte</CharacterSet>
+    <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+    <ConfigurationType>Application</ConfigurationType>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{c7c6dfe5-847d-467b-aa0b-86770b042667}</ProjectGuid>
+  </PropertyGroup>
+  <Import Project="..\targets.props" />
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <PropertyGroup>
+    <IncludePath>$(IncludePath)</IncludePath>
+    <RunCodeAnalysis>true</RunCodeAnalysis>
+    <EnableInf2cat>false</EnableInf2cat>
+  </PropertyGroup>
+  <PropertyGroup>
+    <CustomBuildAfterTargets>Link</CustomBuildAfterTargets>
+  </PropertyGroup>
+  <ItemDefinitionGroup>
+    <ClCompile>
+      <AdditionalIncludeDirectories>$(SolutionDir)..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>WIN32;_WINDOWS;_CRT_SECURE_NO_WARNINGS;LOGGING_ENABLED=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <WarningLevel>EnableAllWarnings</WarningLevel>
+      <DisableSpecificWarnings>4127;4265;4365;4548;4711;4777;4820;4668;4255;4996;6001;6054;28196;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <EnablePREfast>true</EnablePREfast>
+      <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='true'">MultiThreadedDebug</RuntimeLibrary>
+      <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='false'">MultiThreaded</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <AdditionalDependencies>kernel32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Platform)'=='Win32'">
+    <ClCompile>
+      <PreprocessorDefinitions>__i386__;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ClCompile>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Platform)'=='x64'">
+    <ClCompile>
+      <PreprocessorDefinitions>__x86_64__;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ClCompile>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <FilesToPackage Include="$(TargetPath)" />
+    <FilesToPackage Include="$(OutDir)$(TargetName).pdb" />
+    <FilesToPackage Include="$(OutDir)$(TargetName).dll" />
+    <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\src\sockpipe\sockpipe.cpp" />
+    <ClCompile Include="..\..\src\sockpipe\Circle.cpp" />
+    <ClCompile Include="..\..\src\sockpipe\connectoid.cpp" />
+    <ClCompile Include="..\..\src\sockpipe\logger.cpp" />
+    <ClCompile Include="..\..\src\sockpipe\pipereader.cpp" />
+    <ClCompile Include="..\..\src\sockpipe\sockreader.cpp" />
+    <ClCompile Include="..\..\src\sockpipe\spinlock.cpp" />
+    <ClCompile Include="..\..\src\sockpipe\stdafx.cpp" />
+    <ClCompile Include="..\..\src\sockpipe\threadcontrol.cpp" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project>
diff --git a/vs2015/sockpipe/sockpipe.vcxproj.user b/vs2015/sockpipe/sockpipe.vcxproj.user
new file mode 100644 (file)
index 0000000..af0bff3
--- /dev/null
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+</Project>
diff --git a/vs2015/targets.props b/vs2015/targets.props
new file mode 100644 (file)
index 0000000..64598fc
--- /dev/null
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+       <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 10 Debug|Win32'">
+               <TargetVersion>Windows10</TargetVersion>
+               <UseDebugLibraries>true</UseDebugLibraries>
+       </PropertyGroup>
+       <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 10 Release|Win32'">
+               <TargetVersion>Windows10</TargetVersion>
+               <UseDebugLibraries>false</UseDebugLibraries>
+       </PropertyGroup>
+       <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 10 Debug|x64'">
+               <TargetVersion>Windows10</TargetVersion>
+               <UseDebugLibraries>true</UseDebugLibraries>
+       </PropertyGroup>
+       <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 10 Release|x64'">
+               <TargetVersion>Windows10</TargetVersion>
+               <UseDebugLibraries>false</UseDebugLibraries>
+       </PropertyGroup>
+       <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 8 Debug|Win32'">
+               <TargetVersion>Windows8</TargetVersion>
+               <UseDebugLibraries>true</UseDebugLibraries>
+       </PropertyGroup>
+       <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 8 Release|Win32'">
+               <TargetVersion>Windows8</TargetVersion>
+               <UseDebugLibraries>false</UseDebugLibraries>
+       </PropertyGroup>
+       <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 8 Debug|x64'">
+               <TargetVersion>Windows8</TargetVersion>
+               <UseDebugLibraries>true</UseDebugLibraries>
+       </PropertyGroup>
+       <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Windows 8 Release|x64'">
+               <TargetVersion>Windows8</TargetVersion>
+               <UseDebugLibraries>false</UseDebugLibraries>
+       </PropertyGroup>
+</Project>