1 /*****************************************************************************/
2 /* Software Testing Automation Framework (STAF)                              */
3 /* (C) Copyright IBM Corp. 2001                                              */
4 /*                                                                           */
5 /* This software is licensed under the Eclipse Public License (EPL) V1.0.    */
6 /*****************************************************************************/
7 
8 #include "STAFOSTypes.h"
9 #include "STAFLocalConnection.h"
10 #include "STAFException.h"
11 
12 #ifdef DEBUG_LOCAL_CONNECTION
13 #undef sleep
14 #include "STAF_iostream.h"
15 #include "STAFThread.h"
16 #define MYTID STAFThreadGetCurrentThreadID()
17 #endif
18 
19 #define CHECKCONNECT(string) if (rc) {\
20         STAFConnectionConnectException connectError(string, rc);\
21         THROW_STAF_EXCEPTION(connectError);}
22 
23 #define CHECKIO(string) if (rc) {\
24         STAFConnectionIOException ioError(string, rc);\
25         THROW_STAF_EXCEPTION(ioError);}
26 
create(STAFString localName)27 STAFConnAllocInfo STAFLocalConnection::create(STAFString localName)
28 {
29     return STAFConnAllocInfo(new STAFLocalConnection(localName),
30                              &freeLocalConnection);
31 }
32 
33 
STAFLocalConnection(HPIPE pipeHandle)34 STAFLocalConnection::STAFLocalConnection(HPIPE pipeHandle)
35 {
36     return STAFConnAllocInfo(new STAFLocalConnection(pipeHandle),
37                              &freeLocalConnection);
38 }
39 
40 
STAFLocalConnection(STAFString localName)41 STAFLocalConnection::STAFLocalConnection(STAFString localName)
42     : STAFConnection(kLocal, kClient)
43 {
44     APIRET rc = 0;
45     ULONG openAction;
46     STAFString pipeName(STAFString("\\PIPE\\") + localName);
47     STAFStringBufferPtr pipeNameBuf = pipeName.toCurrentCodePage();
48 
49     rc = DosOpen((PSZ)pipeNameBuf->buffer(), &fPipeHandle, &openAction, 0, 0,
50                  OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS,
51                  OPEN_SHARE_DENYNONE | OPEN_ACCESS_READWRITE, 0);
52 
53     while ((rc == ERROR_PIPE_BUSY) || (rc == ERROR_SEM_TIMEOUT))
54     {
55         rc = DosWaitNPipe((PSZ)pipeNameBuf->buffer(), 100);
56 
57         if (!rc)
58         {
59             rc = DosOpen((PSZ)pipeNameBuf->buffer(), &fPipeHandle, &openAction,
60                          0, 0, OPEN_ACTION_FAIL_IF_NEW |
61                          OPEN_ACTION_OPEN_IF_EXISTS,
62                          OPEN_SHARE_DENYNONE | OPEN_ACCESS_READWRITE, 0);
63         }
64     }
65 
66     CHECKCONNECT("DosOpen");
67 }
68 
69 
STAFLocalConnection(HPIPE pipeHandle)70 STAFLocalConnection::STAFLocalConnection(HPIPE pipeHandle)
71     : STAFConnection(kLocal, kServer), fPipeHandle(pipeHandle)
72 {
73     /* Do Nothing */
74 }
75 
76 
read(void * buffer,unsigned int size)77 void STAFLocalConnection::read(void *buffer, unsigned int size)
78 {
79     APIRET rc = 0;
80     ULONG actual = 0;
81 
82     for(ULONG current = 0; current < size; current += actual)
83     {
84         actual = 0;
85         CHECKIO("DosRead");
86 
87         #ifdef DEBUG_LOCAL_CONNECTION
88         cout << MYTID << ": Reading: " << (ULONG)(size - current) << " @ "
89              << current << " of " << size << endl;
90         #endif
91 
92         rc = DosRead(fPipeHandle, (PVOID)((char *)buffer + current),
93                      (ULONG)(size - current), &actual);
94 
95         #ifdef DEBUG_LOCAL_CONNECTION
96         cout << MYTID << ": Read   : " << actual << " @ " << current
97              << " of " << size << " RC: " << rc << endl;
98         #endif
99 
100         if ((actual == 0) && (size != 0))
101         {
102             STAFConnectionIOException noData("No data available on pipe");
103             THROW_STAF_EXCEPTION(noData);
104         }
105     }
106 
107     #ifdef DEBUG_LOCAL_CONNECTION
108     if (size == 4) cout << MYTID << ": RNum   : " << *((unsigned int *)buffer)
109                         << endl;
110     else if (size) cout << MYTID << ": RData  : "
111                         << IString((char *)buffer, size) << endl;
112     else           cout << MYTID << ": RZero" << endl;
113     #endif
114 }
115 
116 
write(void * buffer,unsigned int size)117 void STAFLocalConnection::write(void *buffer, unsigned int size)
118 {
119     APIRET rc = 0;
120     ULONG actual = 0;
121 
122     for(ULONG current = 0; current < size; current += actual)
123     {
124         actual = 0;
125         #ifdef DEBUG_LOCAL_CONNECTION
126         cout << MYTID << ": Writing: " << (ULONG)(size - current) << " @ "
127              << current << " of " << size << endl;
128         #endif
129 
130         rc = DosWrite(fPipeHandle, (PVOID)((char *)buffer + current),
131                       (ULONG)(size - current), &actual);
132 
133         #ifdef DEBUG_LOCAL_CONNECTION
134         cout << MYTID << ": Wrote  : " << actual << " @ " << current
135              << " of " << size << " RC: " << rc << endl;
136         #endif
137 
138         CHECKIO("DosWrite");
139 
140         rc = DosResetBuffer(fPipeHandle);
141 
142         // This if statement is here due to a bug (?) in Warp V3, where
143         // DosResetBuffer returns ERROR_BROKEN_PIPE or ERROR_PIPE_NOT_CONNECTED
144         // when the other side of the pipe has read the data and closed its end
145         // of the pipe.  Warp V4 does not seem to exhibit this problem.
146         //
147         // This check should be fairly harmless, as, if this is the last
148         // write then it doesn't matter if the pipe is now broken.  If
149         // it isn't the last write then the error will be returned on
150         // the next call, due to a failure on the DosWrite call.
151 
152         if ((rc != ERROR_BROKEN_PIPE) && (rc != ERROR_PIPE_NOT_CONNECTED))
153         {
154             CHECKIO("DosResetBuffer");
155         }
156     }
157 
158     #ifdef DEBUG_LOCAL_CONNECTION
159     if (size == 4) cout << MYTID << ": WNum   : " << *((unsigned int *)buffer)
160                         << " RC: " << rc << endl;
161     else if (size) cout << MYTID << ": WData  : "
162                         << IString((char *)buffer, size) << " RC: " << rc
163                         << endl;
164     else           cout << MYTID << ": WZero RC: " << rc << endl;
165     #endif
166 }
167 
168 
freeLocalConnection(STAFConnection * pConn)169 void STAFLocalConnection::freeLocalConnection(STAFConnection *pConn)
170 {
171     delete pConn;
172 }
173 
174 
~STAFLocalConnection()175 STAFLocalConnection::~STAFLocalConnection()
176 {
177     if (connectionMode() == kServer)
178         DosDisConnectNPipe(fPipeHandle);
179 
180     DosClose(fPipeHandle);
181 }
182