|
1 /* |
|
2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include "fdesc.h" |
|
20 |
|
21 TInt CSockDescBase::Socket(RSocketServ& /*aSs*/, int /*family*/, int /*style*/, int /*protocol*/) |
|
22 { |
|
23 return KErrNotSupported; |
|
24 } |
|
25 TInt CSockDescBase::Fcntl(TUint anArg, TUint aCmd) |
|
26 { |
|
27 //fcntl supports only F_SETFL and F_GETFL for Non-Blocking I/O |
|
28 //If aCmd and anArg does not match these, return with Error |
|
29 TInt retVal = KErrNone; |
|
30 |
|
31 switch( aCmd ) |
|
32 { |
|
33 case F_SETFL: |
|
34 { |
|
35 |
|
36 //Send the equivalent Flags of Symbian to RSocket |
|
37 TUint flags = iFcntlFlag; |
|
38 if( anArg & O_NONBLOCK ) |
|
39 { |
|
40 retVal = iSocket.SetOpt(KSONonBlockingIO, KSOLSocket); |
|
41 flags |= O_NONBLOCK; |
|
42 } |
|
43 else |
|
44 { |
|
45 retVal = iSocket.SetOpt(KSOBlockingIO, KSOLSocket); |
|
46 flags &= ~O_NONBLOCK; |
|
47 } |
|
48 if (retVal == KErrNone) |
|
49 { |
|
50 retVal = iFcntlFlag = flags; |
|
51 } |
|
52 break; |
|
53 } |
|
54 case F_GETFL: |
|
55 { |
|
56 // Socket descriptors are always read/write |
|
57 iFcntlFlag |= O_RDWR; |
|
58 //Return fcntl flag |
|
59 retVal = iFcntlFlag; |
|
60 break; |
|
61 } |
|
62 default: |
|
63 retVal = KErrNotSupported; |
|
64 } |
|
65 return retVal; |
|
66 |
|
67 |
|
68 } |
|
69 |
|
70 TInt CSockDescBase::FStat(struct stat *st) |
|
71 { |
|
72 |
|
73 // I am a socket about which little is known |
|
74 st->st_mode = S_IFSOCK; |
|
75 st->st_blksize=0; |
|
76 return KErrNone; |
|
77 |
|
78 } |
|
79 |
|
80 TInt CSockDescBase::FinalClose() |
|
81 { |
|
82 iSocket.Close(); |
|
83 iReadLock.Close(); |
|
84 iWriteLock.Close(); |
|
85 iIoctlLock.Close(); |
|
86 return KErrNone; |
|
87 } |
|
88 |
|
89 void CSockDescBase::Read(TDes8& aBuf, TRequestStatus& aStatus) |
|
90 { |
|
91 TSockXfrLength len; |
|
92 TRequestStatus tempStatus; |
|
93 |
|
94 iSocket.RecvOneOrMore(aBuf, 0, tempStatus, len); // needs a completion which returns the length |
|
95 User::WaitForRequest(tempStatus); |
|
96 if (tempStatus.Int() != KErrNone) |
|
97 { |
|
98 Complete(aStatus, tempStatus.Int()); |
|
99 } |
|
100 else |
|
101 { |
|
102 Complete(aStatus, len()); |
|
103 } |
|
104 } |
|
105 |
|
106 void CSockDescBase::Write(TDes8& aBuf, TRequestStatus& aStatus) |
|
107 { |
|
108 TRequestStatus tempStatus; |
|
109 TInt bytesWritten = 0; |
|
110 TInt bufLength = aBuf.Length(); |
|
111 TSockXfrLength len; |
|
112 do |
|
113 { |
|
114 iSocket.Send(aBuf.Mid(bytesWritten), 0, tempStatus, len); |
|
115 User::WaitForRequest(tempStatus); |
|
116 if (len() == 0) |
|
117 { |
|
118 break; |
|
119 } |
|
120 bytesWritten += len(); |
|
121 } while (bytesWritten < bufLength); |
|
122 if (tempStatus.Int() != KErrNone) |
|
123 { |
|
124 Complete(aStatus, tempStatus.Int()); |
|
125 } |
|
126 else if ((len() == 0) && (bytesWritten == 0)) |
|
127 { |
|
128 Complete(aStatus, KErrWouldBlock); |
|
129 } |
|
130 else |
|
131 { |
|
132 //to do change request complete with actual length written when defect |
|
133 //is fixed |
|
134 Complete(aStatus, bytesWritten); |
|
135 } |
|
136 |
|
137 } |
|
138 |
|
139 void CSockDescBase::RecvFrom(TDes8& aDesc, TSockAddr& from, int flags, TRequestStatus& aStatus) |
|
140 { |
|
141 |
|
142 //Map the flags to the RSocket flags |
|
143 TUint rSockFlags = 0; |
|
144 if( flags & MSG_PEEK ) //Peek at incoming data |
|
145 rSockFlags |= KSockReadPeek; |
|
146 /* No equivalent flags avaialble in RSocket for |
|
147 MSG_OOB and MSG_WAITALL */ |
|
148 |
|
149 TSockXfrLength len; |
|
150 TRequestStatus tempStatus; |
|
151 |
|
152 switch (iStyle) |
|
153 { |
|
154 case SOCK_STREAM: |
|
155 // recvfrom on a stream ignores the from address - get the peername |
|
156 if (from.Length()) |
|
157 SockName(1,from); |
|
158 |
|
159 iSocket.RecvOneOrMore(aDesc,rSockFlags,tempStatus,len); |
|
160 break; |
|
161 |
|
162 case SOCK_SEQPACKET: |
|
163 // get the peername (as above) |
|
164 if (from.Length()) |
|
165 SockName(1,from); |
|
166 iSocket.Recv(aDesc, rSockFlags, tempStatus); |
|
167 break; |
|
168 |
|
169 default: // including SOCK_RAW, SOCK_DGRAM |
|
170 // assume datagram, as per behavior of original stdlib code: |
|
171 iSocket.RecvFrom(aDesc,from,rSockFlags,tempStatus,len); |
|
172 } |
|
173 |
|
174 User::WaitForRequest(tempStatus); |
|
175 len = aDesc.Length(); |
|
176 if (tempStatus.Int() != KErrNone) |
|
177 { |
|
178 if (tempStatus.Int() == KErrEof || tempStatus.Int() == KErrDisconnected) |
|
179 Complete(aStatus, len()); |
|
180 else |
|
181 Complete(aStatus, tempStatus.Int()); |
|
182 } |
|
183 else |
|
184 { |
|
185 Complete(aStatus, len()); |
|
186 } |
|
187 |
|
188 } |
|
189 |
|
190 void CSockDescBase::SendTo(TDes8& aDesc, TSockAddr& to, int flags, TRequestStatus& aStatus) |
|
191 { |
|
192 |
|
193 TRequestStatus tempStatus; |
|
194 TSockXfrLength len; |
|
195 TBool sendflg = EFalse; |
|
196 |
|
197 if (to.Length()==0) |
|
198 { |
|
199 iSocket.Send(aDesc,flags,tempStatus,len); |
|
200 sendflg = ETrue; |
|
201 } |
|
202 else |
|
203 { |
|
204 if (isStream()) |
|
205 Complete(aStatus,KErrNotSupported); // can't sendto a stream |
|
206 else |
|
207 { |
|
208 iSocket.SendTo(aDesc,to,flags,tempStatus,len); |
|
209 sendflg = ETrue; |
|
210 } |
|
211 } |
|
212 |
|
213 if(sendflg) |
|
214 { |
|
215 User::WaitForRequest(tempStatus); |
|
216 if (tempStatus.Int() != KErrNone) |
|
217 { |
|
218 if (tempStatus.Int() == KErrEof ) |
|
219 Complete(aStatus, len()); |
|
220 else |
|
221 Complete(aStatus, tempStatus.Int()); |
|
222 } |
|
223 else |
|
224 { |
|
225 Complete(aStatus, len()); |
|
226 } |
|
227 } |
|
228 |
|
229 |
|
230 } |
|
231 |
|
232 TInt CSockDescBase::CompletionStatus(TInt& aLength, TInt aStatus) |
|
233 { |
|
234 aLength = aStatus; |
|
235 if (aStatus >= 0) |
|
236 { |
|
237 return 0; |
|
238 } |
|
239 return aStatus; |
|
240 } |
|
241 |
|
242 TInt CSockDescBase::Poll(TUint aEvents) |
|
243 { |
|
244 TInt status = 0; |
|
245 TInt err = 0; |
|
246 TInt readyEvents = 0; |
|
247 err = iSocket.GetOpt(KSOSelectPoll, KSOLSocket, status); |
|
248 |
|
249 if (err != KErrNone) |
|
250 { |
|
251 // Poll should return any of the requested events. |
|
252 // In case of any error, the error will be set, and can be later checked by the descriptor. |
|
253 |
|
254 iPollErr = err; |
|
255 // For non-blocking socket, ensure to reset "iConnectInProgress" flag for a non-connected |
|
256 // socket on which a connection is pending. |
|
257 if(GetConnectionProgress()) |
|
258 { |
|
259 SetConnectionProgress(EFalse); |
|
260 } |
|
261 |
|
262 // set all the events that has been requested for |
|
263 // This handles a scenario where connect fails( in loopback ) |
|
264 // here poll should return all the events requested as ready |
|
265 // not KErrNone or failure value as returning KErrNone will indicate |
|
266 // no events are ready and notifyactivity will be used though the event has |
|
267 // completed |
|
268 if( aEvents & EReadyForReading ) |
|
269 { |
|
270 readyEvents |= EReadyForReading; |
|
271 } |
|
272 if( aEvents & EReadyForWriting ) |
|
273 { |
|
274 readyEvents |= EReadyForWriting; |
|
275 } |
|
276 if( aEvents & EAnyException ) |
|
277 { |
|
278 readyEvents |= EAnyException; |
|
279 } |
|
280 return readyEvents; |
|
281 } |
|
282 |
|
283 if ((status & KSockSelectRead) && (aEvents & EReadyForReading)) |
|
284 { |
|
285 readyEvents |= EReadyForReading; |
|
286 } |
|
287 |
|
288 if ((status & KSockSelectWrite) && (aEvents & EReadyForWriting)) |
|
289 { |
|
290 readyEvents |= EReadyForWriting; |
|
291 } |
|
292 |
|
293 if (status & KSockSelectExcept) |
|
294 { |
|
295 if(GetConnectionProgress()) |
|
296 { |
|
297 TBool setExceptFd = ETrue; |
|
298 // Some special checks for non-blocking sockets. |
|
299 if(aEvents & EReadyForWriting) |
|
300 { |
|
301 readyEvents |= EReadyForWriting; |
|
302 setExceptFd = EFalse; |
|
303 } |
|
304 |
|
305 if(aEvents & EReadyForReading) |
|
306 { |
|
307 readyEvents |= EReadyForReading; |
|
308 setExceptFd = EFalse; |
|
309 } |
|
310 |
|
311 if(setExceptFd && (aEvents & EAnyException)) |
|
312 { |
|
313 readyEvents |= EAnyException; |
|
314 } |
|
315 } |
|
316 else |
|
317 { |
|
318 if(aEvents & EAnyException) |
|
319 { |
|
320 readyEvents |= EAnyException; |
|
321 } |
|
322 } |
|
323 } |
|
324 |
|
325 if(GetConnectionProgress() && readyEvents) |
|
326 { |
|
327 SetConnectionProgress(EFalse); |
|
328 } |
|
329 |
|
330 return readyEvents; |
|
331 } |
|
332 |
|
333 /* Register for notification of activity */ |
|
334 TInt CSockDescBase::NotifyActivity(TUint aEvents, TRequestStatus& aRequest, TTimeIntervalMicroSeconds32 timeout) |
|
335 { |
|
336 if (timeout.Int()) |
|
337 { |
|
338 TInt ret = iIoctlLock.Wait(timeout.Int()); |
|
339 if (ret != KErrNone) |
|
340 { |
|
341 return KErrCompletion; |
|
342 } |
|
343 } |
|
344 else |
|
345 { |
|
346 iIoctlLock.Wait(); |
|
347 } |
|
348 |
|
349 iSelectEvents() = 0; |
|
350 |
|
351 if (aEvents & EReadyForReading) |
|
352 { |
|
353 iSelectEvents() = KSockSelectRead; |
|
354 } |
|
355 if (aEvents & EReadyForWriting) |
|
356 { |
|
357 iSelectEvents() |= KSockSelectWrite; |
|
358 } |
|
359 if (aEvents & EAnyException) |
|
360 { |
|
361 iSelectEvents() |= KSockSelectExcept; |
|
362 } |
|
363 |
|
364 iSocket.Ioctl(KIOctlSelect, aRequest, &iSelectEvents, KSOLSocket); |
|
365 return KErrNone; |
|
366 } |
|
367 |
|
368 // ----------------------------------------------------------------------------- |
|
369 // CSockDescBase::TweakWatchedEvents |
|
370 // Requests for socket behaviour specific additional events |
|
371 // ----------------------------------------------------------------------------- |
|
372 // |
|
373 void CSockDescBase::TweakWatchedEvents(TUint& events) |
|
374 { |
|
375 if((events & EReadyForReading) || (events & EReadyForWriting)) |
|
376 { |
|
377 // Handles scenario of select called with writefds, after a non blocking connect on a socket |
|
378 // as per connect specification, select with the writefds after connect should |
|
379 // set writefds, irrespective of if the connection is successful or failure |
|
380 // We request for an exception event, as in Symbian connect failure is |
|
381 // an exception |
|
382 if(GetConnectionProgress()) |
|
383 { |
|
384 events |= EAnyException; |
|
385 } |
|
386 } |
|
387 } |
|
388 // ----------------------------------------------------------------------------- |
|
389 // CSockDescBase::TweakReadyEvents |
|
390 // Prepares the socket behaviours specific output events |
|
391 // ----------------------------------------------------------------------------- |
|
392 // |
|
393 TInt CSockDescBase::TweakReadyEvents(TInt errval) |
|
394 { |
|
395 TInt returnEvents = 0; |
|
396 if( errval >= KErrNone ) |
|
397 { |
|
398 // This file descriptor is socket-like |
|
399 // SelectEvents will also signal ioctlLock. |
|
400 // This hack allows other threads to issue an ioctl on this socket now rather than later. |
|
401 const TUint events = GetSelectEvents(); |
|
402 if (events & KSockSelectRead) |
|
403 { |
|
404 returnEvents |= EReadyForReading; |
|
405 } |
|
406 if (events & KSockSelectWrite) |
|
407 { |
|
408 returnEvents |= EReadyForWriting; |
|
409 } |
|
410 if (events & KSockSelectExcept) |
|
411 { |
|
412 // if it is a case of non blocking connect check for the flag |
|
413 // though the flag indicates connection is in progress, we come out of |
|
414 // waitforNrequest only after a event |
|
415 if(GetConnectionProgress()) |
|
416 { |
|
417 returnEvents |= EReadyForReading; |
|
418 returnEvents |= EReadyForWriting; |
|
419 } |
|
420 else |
|
421 { |
|
422 returnEvents |= EAnyException; |
|
423 } |
|
424 } |
|
425 } |
|
426 else |
|
427 { |
|
428 if( GetConnectionProgress() ) |
|
429 { |
|
430 // Dummy call to retrieve select events also unlocks the socket |
|
431 const TUint events = GetSelectEvents(); |
|
432 // set all the events that has been requested for |
|
433 // This handles a scenario where connect fails( in loopback ) |
|
434 // here all the events requested should be ready ready |
|
435 // Since PrepareOutputEvents is not aware of the events requested, all are |
|
436 // set as ready and it will be filteret in select |
|
437 returnEvents |= EReadyForWriting; |
|
438 returnEvents |= EReadyForReading; |
|
439 returnEvents |= EAnyException; |
|
440 } |
|
441 else |
|
442 { |
|
443 returnEvents |= EAnyException; |
|
444 } |
|
445 } |
|
446 return returnEvents; |
|
447 } |
|
448 |
|
449 void CSockDescBase::CancelNotify() |
|
450 { |
|
451 iSocket.CancelIoctl(); |
|
452 iIoctlLock.Signal(); |
|
453 } |
|
454 |
|
455 TInt CSockDescBase::Listen(TUint qSize) |
|
456 { |
|
457 return iSocket.Listen(qSize); |
|
458 } |
|
459 |
|
460 void CSockDescBase::ReadCancel() |
|
461 { |
|
462 iSocket.CancelRecv(); |
|
463 } |
|
464 |
|
465 TInt CSockDescBase::ReadCompletion(TDes8& /*aBuf*/, TInt aStatus) |
|
466 { |
|
467 if(KErrNone == aStatus) |
|
468 { |
|
469 return iLength(); |
|
470 } |
|
471 return aStatus; |
|
472 } |
|
473 |
|
474 void CSockDescBase::RecvFromCancel() |
|
475 { |
|
476 iSocket.CancelRecv(); |
|
477 } |
|
478 |
|
479 void CSockDescBase::SendToCancel() |
|
480 { |
|
481 iSocket.CancelSend(); |
|
482 } |
|
483 |
|
484 void CSockDescBase::WriteCancel() |
|
485 { |
|
486 iSocket.CancelWrite(); |
|
487 } |
|
488 |
|
489 TInt CSockDescBase::SockName(int anEnd, TSockAddr& anAddr) |
|
490 { |
|
491 const TUint KBadFamily = 0xFF000000; |
|
492 |
|
493 TUSockAddr *addr; |
|
494 |
|
495 addr = (TUSockAddr*)&anAddr; |
|
496 if (addr->iError != 0) |
|
497 { |
|
498 return addr->iError; |
|
499 } |
|
500 |
|
501 anAddr.SetFamily(KBadFamily); |
|
502 if (anEnd==0) |
|
503 iSocket.LocalName(anAddr); |
|
504 else |
|
505 iSocket.RemoteName(anAddr); |
|
506 if (anAddr.Family()==KBadFamily) |
|
507 return ENOTCONN; // assume that the call failed, but there is no way to find out why |
|
508 return KErrNone; |
|
509 } |
|
510 |
|
511 void CSockDescBase::Shutdown(TUint aHow,TRequestStatus& aStatus) |
|
512 { |
|
513 RSocket::TShutdown how; |
|
514 |
|
515 switch (aHow) |
|
516 { |
|
517 case SHUT_RD: |
|
518 how = RSocket::EStopInput; |
|
519 break; |
|
520 case SHUT_WR: |
|
521 how = RSocket::EStopOutput; |
|
522 break; |
|
523 case SHUT_RDWR: |
|
524 how = RSocket::EImmediate; |
|
525 break; |
|
526 default: |
|
527 Complete(aStatus,KErrArgument); // Invalid argument |
|
528 return; |
|
529 } |
|
530 iSocket.Shutdown(how,aStatus); |
|
531 return; |
|
532 } |