|
1 // Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // Telnet Protocol API |
|
15 // CIOBufferControl implementation |
|
16 // |
|
17 // |
|
18 |
|
19 /** |
|
20 @file |
|
21 */ |
|
22 |
|
23 #include "IOBUFFER.H" |
|
24 #include "ACTIVEIO.H" |
|
25 #include "TELDEBUG.H" |
|
26 |
|
27 CIOBufferControl::CIOBufferControl() |
|
28 /** |
|
29 Constructor |
|
30 */ |
|
31 { |
|
32 } |
|
33 |
|
34 CIOBufferControl::~CIOBufferControl() |
|
35 /** |
|
36 Destructor |
|
37 */ |
|
38 { |
|
39 Reset(); |
|
40 __FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CIOBufferControl::D'Tor")); |
|
41 } |
|
42 |
|
43 CIOBufferControl* CIOBufferControl::NewL(MIONotifier* aNotifier) |
|
44 { |
|
45 CIOBufferControl* self = new(ELeave) CIOBufferControl; |
|
46 CleanupStack::PushL(self); |
|
47 self->ConstructL(aNotifier); |
|
48 CleanupStack::Pop(); |
|
49 return self; |
|
50 } |
|
51 |
|
52 void CIOBufferControl::ConstructL(MIONotifier* aNotifier) |
|
53 { |
|
54 iNotifier = aNotifier; |
|
55 |
|
56 iWriter = NULL; |
|
57 iReader = NULL; |
|
58 |
|
59 iQueueIndex = 0; |
|
60 iLiveIndex = 0; |
|
61 |
|
62 iUrgent = NULL; |
|
63 iWriteBuffers[0] = NULL; |
|
64 iWriteBuffers[1] = NULL; |
|
65 } |
|
66 |
|
67 TInt CIOBufferControl::WriteUrgent(HBufC8* aBuffer) |
|
68 /** |
|
69 Caller requests to send data as TCP urgent |
|
70 */ |
|
71 { |
|
72 TInt err = KErrNone; |
|
73 // Check to see if write is already outstanding |
|
74 if(iLiveIndex == iQueueIndex) |
|
75 { |
|
76 // No write outstanding |
|
77 // Just set the live index to point to the heap buffer |
|
78 iWriteBuffers[iLiveIndex] = aBuffer; |
|
79 // Make indexes different so if the next write call comes before completion of this one |
|
80 // then it can append to the queue buffer |
|
81 (iLiveIndex == 0) ? (iQueueIndex = 1) : (iQueueIndex = 0); |
|
82 iWriter->IssueUrgentWrite(*(iWriteBuffers[iLiveIndex])); |
|
83 err = KErrNone; |
|
84 } |
|
85 else |
|
86 { |
|
87 // Check for existing queued urgent |
|
88 if(iUrgent) |
|
89 // DON'T permit queued urgents |
|
90 err = KErrInUse; |
|
91 else |
|
92 { |
|
93 // Data will be sent on next write completion |
|
94 iUrgent = aBuffer; |
|
95 err = KErrNone; |
|
96 } |
|
97 } |
|
98 return(err); |
|
99 } |
|
100 |
|
101 TInt CIOBufferControl::Write(HBufC8* aBuffer) |
|
102 /** |
|
103 Writes issued into this object send it to the active writer |
|
104 Ownership of the buffer is transferred |
|
105 */ |
|
106 { |
|
107 TInt ret = KErrNone; |
|
108 |
|
109 TPtr8 ptr = aBuffer->Des(); |
|
110 |
|
111 // iLiveIndex = iQueueIndex means there are no outstanding writes on the socket |
|
112 if(iLiveIndex == iQueueIndex) |
|
113 { |
|
114 iWriteBuffers[iLiveIndex] = aBuffer; |
|
115 // Make indexes different so if the next write call comes before completion of this one |
|
116 // then it can append to the queue buffer |
|
117 (iLiveIndex == 0) ? (iQueueIndex = 1) : (iQueueIndex = 0); |
|
118 iWriter->IssueWrite(*(iWriteBuffers[iLiveIndex])); |
|
119 } |
|
120 else |
|
121 { |
|
122 __FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CIOBufferControl() Write Queue")); |
|
123 // There is already a buffer loaded on the socket |
|
124 if(iWriteBuffers[iQueueIndex]) |
|
125 // Append this data to the iQueueIndex buffer |
|
126 // Overflow check first |
|
127 { |
|
128 HBufC8* qBuf = iWriteBuffers[iQueueIndex]; |
|
129 TPtr8 qPtr = qBuf->Des(); |
|
130 if((qPtr.MaxLength() - qPtr.Length()) < ptr.Length()) |
|
131 // Not enough room to append |
|
132 { |
|
133 qBuf = iWriteBuffers[iQueueIndex]->ReAlloc(qPtr.Length() + ptr.Length()); |
|
134 if(qBuf==NULL) |
|
135 return KErrNoMemory; //Return error and don't take ownership of aBuffer |
|
136 iWriteBuffers[iQueueIndex] = qBuf; |
|
137 qPtr = qBuf->Des(); |
|
138 } |
|
139 qPtr.Append(ptr); |
|
140 delete aBuffer; |
|
141 } |
|
142 else |
|
143 // Nothing queued just assign the pointer |
|
144 // Data will be sent on next write completion |
|
145 { |
|
146 iWriteBuffers[iQueueIndex] = aBuffer; |
|
147 } |
|
148 } |
|
149 return(ret); |
|
150 } |
|
151 |
|
152 |
|
153 TInt CIOBufferControl::Read(TDes8& aBuffer) |
|
154 { |
|
155 return(iReader->IssueRead(aBuffer)); |
|
156 } |
|
157 |
|
158 void CIOBufferControl::SetWriter(CActiveWriter* aWriter) |
|
159 { |
|
160 iWriter = aWriter; |
|
161 } |
|
162 |
|
163 void CIOBufferControl::SetReader(CActiveReader* aReader) |
|
164 { |
|
165 iReader = aReader; |
|
166 } |
|
167 |
|
168 |
|
169 // MIONotifier |
|
170 |
|
171 void CIOBufferControl::Event(TInt aEvent,TInt aEventCode) |
|
172 { |
|
173 iNotifier->Event(aEvent,aEventCode); |
|
174 } |
|
175 |
|
176 void CIOBufferControl::WriteComplete() |
|
177 /** |
|
178 Normal asynchronous completion to a write request to the active writer |
|
179 The data we transmitted will always be pointed to by iLiveIndex |
|
180 On completion there could be Urgent or ordinary data queued |
|
181 Submit any queued urgent first |
|
182 */ |
|
183 { |
|
184 // Free the HBufC8* we loaded for transmit the last time |
|
185 delete iWriteBuffers[iLiveIndex]; |
|
186 iWriteBuffers[iLiveIndex] = NULL; |
|
187 // First check to see if we have any urgent data queued |
|
188 if(iUrgent) |
|
189 { |
|
190 // Urgent data queued, move the urgent pointer to the live index |
|
191 iWriteBuffers[iLiveIndex] = iUrgent; |
|
192 // Free the pointer |
|
193 iUrgent = NULL; |
|
194 // Send the queued urgent data |
|
195 iWriter->IssueUrgentWrite(*(iWriteBuffers[iLiveIndex])); |
|
196 } |
|
197 else if(iWriteBuffers[iQueueIndex]) |
|
198 // Check to see if any data is on the normal queue |
|
199 { |
|
200 // Data queued |
|
201 // Swap the indexes |
|
202 iLiveIndex = iQueueIndex; |
|
203 (iLiveIndex == 0) ? (iQueueIndex = 1) : (iQueueIndex = 0); |
|
204 // Issue the next write |
|
205 __FLOG_STATIC(KTelnetLoggingCompnt(),KTelnetLoggingTag(),_L("CIOBufferControl() WriteComplete() Write Queue Data")); |
|
206 iWriter->IssueWrite(*(iWriteBuffers[iLiveIndex])); |
|
207 // complete the write |
|
208 } |
|
209 else |
|
210 { |
|
211 // No data queued, set the transmitter empty condition |
|
212 iLiveIndex = iQueueIndex; |
|
213 } |
|
214 iNotifier->WriteComplete(); |
|
215 } |
|
216 |
|
217 void CIOBufferControl::WriteError(TInt aError) |
|
218 /** |
|
219 Write completion with an error, just pass the code up in a notification |
|
220 */ |
|
221 { |
|
222 Reset(); |
|
223 iNotifier->WriteError(aError); |
|
224 } |
|
225 |
|
226 void CIOBufferControl::ReadCompleteL() |
|
227 { |
|
228 iNotifier->ReadCompleteL(); |
|
229 } |
|
230 |
|
231 void CIOBufferControl::ReadComplete(TInt aError) |
|
232 { |
|
233 Reset(); |
|
234 iNotifier->ReadComplete(aError); |
|
235 } |
|
236 |
|
237 void CIOBufferControl::Reset() |
|
238 { |
|
239 delete iWriteBuffers[0]; |
|
240 delete iWriteBuffers[1]; |
|
241 delete iUrgent; |
|
242 |
|
243 iUrgent = NULL; |
|
244 iWriteBuffers[0] = NULL; |
|
245 iWriteBuffers[1] = NULL; |
|
246 |
|
247 iQueueIndex = iLiveIndex = 0; |
|
248 iWriter = NULL; |
|
249 iReader = NULL; |
|
250 } |