|
1 // Copyright (c) 2008-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 // conv.CPP |
|
15 // Descrpition: This file implements the functions for local socket(AF_LOCAL, PF_LOCAL, AF_UNIX) |
|
16 // |
|
17 // |
|
18 |
|
19 #include <fcntl.h> |
|
20 #include <sys/stat.h> |
|
21 #include <sys/socket.h> |
|
22 #include <errno.h> |
|
23 #include <netinet/in.h> |
|
24 #include <sys/un.h> |
|
25 #include <utf.H> |
|
26 #include "fdesc.h" |
|
27 #include "systemspecialfilercg.h" |
|
28 #include "lposix.h" |
|
29 |
|
30 // ----------------------------------------------------------------------------- |
|
31 // CFileSocketDesc::Socket |
|
32 // Creates socket using RSocket::Open |
|
33 // ----------------------------------------------------------------------------- |
|
34 // |
|
35 |
|
36 TInt CFileSocketDesc::Socket(RSocketServ& aSs, int /*aFamily*/, int aStyle, int aProtocol) |
|
37 { |
|
38 if(aProtocol == 0) |
|
39 { |
|
40 switch (aStyle) |
|
41 { |
|
42 case SOCK_STREAM: |
|
43 aProtocol = IPPROTO_TCP; |
|
44 break; |
|
45 |
|
46 case SOCK_DGRAM: |
|
47 aProtocol = IPPROTO_UDP; |
|
48 break; |
|
49 |
|
50 default: |
|
51 aProtocol = KUndefinedProtocol; |
|
52 } |
|
53 } |
|
54 |
|
55 iFcntlFlag = 0; |
|
56 iStyle = aStyle; |
|
57 iProtocol = aProtocol; |
|
58 TInt err = CreateLock(); |
|
59 if (err) |
|
60 { |
|
61 return err; |
|
62 } |
|
63 |
|
64 err = iSocket.Open(aSs, KAfInet, aStyle, aProtocol); |
|
65 return err; |
|
66 |
|
67 } |
|
68 |
|
69 |
|
70 // ----------------------------------------------------------------------------- |
|
71 // CFileSocketDesc::Bind |
|
72 // Binds the socket to path provided in the aAddr |
|
73 // Creates a filesystem entry for the path, binds iSocket to a loopback address and |
|
74 // registers the address with ipc server. |
|
75 // |
|
76 // ----------------------------------------------------------------------------- |
|
77 |
|
78 TInt CFileSocketDesc::Bind(const struct sockaddr* aAddr, unsigned long aSize) |
|
79 { |
|
80 struct SSpecialFileMagicHeader enBuf; |
|
81 int err; |
|
82 const wchar_t* wspath = NULL; |
|
83 if(aSize == NULL) |
|
84 { |
|
85 return EINVAL; |
|
86 } |
|
87 |
|
88 sockaddr_un* addr = (sockaddr_un*)aAddr; |
|
89 if((err=ValidateAddress(addr,&aSize)) != KErrNone) |
|
90 { |
|
91 return err; |
|
92 } |
|
93 if (iPath.Length() != 0) |
|
94 { |
|
95 //Already bound condition |
|
96 return EINVAL; |
|
97 } |
|
98 |
|
99 err = _EncodeSystemSplFileMagicHeader(&enBuf, EFileTypeSocket); |
|
100 if (err != 0) |
|
101 { |
|
102 return err; |
|
103 } |
|
104 |
|
105 TPtrC8 sunpath((TUint8 *)addr->sun_path); |
|
106 TFileName fname16; |
|
107 err = CnvUtfConverter::ConvertToUnicodeFromUtf8(fname16, sunpath); |
|
108 if(err != KErrNone) |
|
109 { |
|
110 return err; |
|
111 } |
|
112 |
|
113 wspath = (const wchar_t*)(fname16.PtrZ()); |
|
114 |
|
115 TInt errorNum; |
|
116 err = _CreateSysSplFile(wspath, (char*)&enBuf, sizeof(struct SSpecialFileMagicHeader), errorNum, Backend()->FileSession()); |
|
117 if (err != KErrNone) |
|
118 { |
|
119 if (errorNum == EEXIST) |
|
120 { |
|
121 err = EADDRINUSE; |
|
122 } |
|
123 return err; |
|
124 } |
|
125 |
|
126 TFileName fullpathName; |
|
127 err=GetFullFile(fullpathName,(const TText16*)wspath,Backend()->FileSession()); |
|
128 if(err != KErrNone) |
|
129 { |
|
130 return err; |
|
131 } |
|
132 |
|
133 err = CnvUtfConverter::ConvertFromUnicodeToUtf8(iPath, fullpathName); |
|
134 if(err != KErrNone) |
|
135 { |
|
136 return err; |
|
137 } |
|
138 |
|
139 TInetAddr inetAddr(KInetAddrLoop,0); |
|
140 err = iSocket.Bind(inetAddr); |
|
141 if(err != KErrNone) |
|
142 { |
|
143 iPath.Zero(); |
|
144 return err; |
|
145 } |
|
146 TUint portNum = iSocket.LocalPort(); |
|
147 if(KErrNone == err) |
|
148 { |
|
149 err = Backend()->iIpcS.RegisterSockAddrWithIPCSvr(iPath,portNum); |
|
150 if(KErrNone != err) |
|
151 { |
|
152 iPath.Zero(); |
|
153 return err; |
|
154 } |
|
155 } |
|
156 |
|
157 return KErrNone; |
|
158 } |
|
159 |
|
160 // ----------------------------------------------------------------------------- |
|
161 // CFileSocketDesc::Accept |
|
162 // Accepts connections from clients |
|
163 // ----------------------------------------------------------------------------- |
|
164 // |
|
165 |
|
166 void CFileSocketDesc::Accept(CFileDescBase*& aNewSocket, TRequestStatus& aStatus, RSocketServ& aSs, TSockAddr *) |
|
167 { |
|
168 TAutoFastLock lock(iReadLock); |
|
169 if (iStyle == SOCK_DGRAM) // Listen on UDP socket, crashing at RSocket::Listen(). |
|
170 { |
|
171 Complete(aStatus,KErrNotSupported); |
|
172 return; |
|
173 } |
|
174 |
|
175 //coverity[alloc_fn] |
|
176 //coverity[assign] |
|
177 CFileSocketDesc *newSocket = new CFileSocketDesc; |
|
178 TInt err=KErrNone; |
|
179 if (newSocket!=0) |
|
180 { |
|
181 err = newSocket->CreateLock(); |
|
182 if (err) |
|
183 { |
|
184 Complete(aStatus, KErrNoMemory); |
|
185 delete newSocket; |
|
186 aNewSocket = NULL; |
|
187 //coverity[memory_leak] |
|
188 return; |
|
189 } |
|
190 |
|
191 err=newSocket->iSocket.Open(aSs); |
|
192 } |
|
193 if (newSocket ==0 || err!=KErrNone) |
|
194 { |
|
195 Complete(aStatus,KErrNoMemory); |
|
196 delete newSocket; |
|
197 aNewSocket = NULL; |
|
198 //coverity[memory_leak] |
|
199 return; |
|
200 } |
|
201 |
|
202 newSocket->iStyle = iStyle; |
|
203 newSocket->iProtocol = iProtocol; |
|
204 iSocket.Accept(newSocket->iSocket,aStatus); |
|
205 aNewSocket = newSocket; |
|
206 } |
|
207 |
|
208 // ----------------------------------------------------------------------------- |
|
209 // CFileSocketDesc::AcceptCancel |
|
210 // Cancels the accept request |
|
211 // ----------------------------------------------------------------------------- |
|
212 // |
|
213 void CFileSocketDesc::AcceptCancel() |
|
214 { |
|
215 iSocket.CancelAccept(); |
|
216 } |
|
217 |
|
218 // ----------------------------------------------------------------------------- |
|
219 // CFileSocketDesc::Connect |
|
220 // Gets the local socket port number from the IPCs and connects to that port |
|
221 // ----------------------------------------------------------------------------- |
|
222 // |
|
223 void CFileSocketDesc::Connect(const struct sockaddr* addr, unsigned long size,TRequestStatus& aStatus) |
|
224 { |
|
225 TUint portNo,ret; |
|
226 |
|
227 if((ret = GetLocalSockPortByPath((sockaddr_un*)addr,size,portNo)) != KErrNone) |
|
228 { |
|
229 aStatus = ret; |
|
230 return; |
|
231 } |
|
232 TInetAddr sAddr(KInetAddrLoop,portNo); |
|
233 iSocket.Connect(sAddr,aStatus); |
|
234 User::WaitForRequest(aStatus); |
|
235 } |
|
236 |
|
237 // ----------------------------------------------------------------------------- |
|
238 // CFileSocketDesc::ConnectCancel |
|
239 // Cancels the connect request |
|
240 // ----------------------------------------------------------------------------- |
|
241 // |
|
242 void CFileSocketDesc::ConnectCancel() |
|
243 { |
|
244 iSocket.CancelConnect(); |
|
245 } |
|
246 |
|
247 // ----------------------------------------------------------------------------- |
|
248 // CFileSocketDesc::Listen |
|
249 // Sets up the listen buffer |
|
250 // ----------------------------------------------------------------------------- |
|
251 // |
|
252 TInt CFileSocketDesc::Listen(TUint qSize) |
|
253 { |
|
254 if (iStyle == SOCK_DGRAM) // Listen on UDP socket, crashing at RSocket::Listen(). |
|
255 { |
|
256 return EOPNOTSUPP; |
|
257 } |
|
258 return CSockDescBase::Listen(qSize); |
|
259 } |
|
260 |
|
261 // ----------------------------------------------------------------------------- |
|
262 // CFileSocketDesc::Write |
|
263 // |
|
264 // ----------------------------------------------------------------------------- |
|
265 |
|
266 void CFileSocketDesc::Write (TDes8& aBuf, TRequestStatus& aStatus) |
|
267 { |
|
268 //Acquire the Lock before write and release it later |
|
269 TAutoFastLock lock(iWriteLock); |
|
270 CSockDescBase::Write(aBuf,aStatus); |
|
271 return; |
|
272 } |
|
273 |
|
274 // ----------------------------------------------------------------------------- |
|
275 // CFileSocketDesc::Read |
|
276 // |
|
277 // ----------------------------------------------------------------------------- |
|
278 |
|
279 void CFileSocketDesc::Read (TDes8& aBuf, TRequestStatus& aStatus) |
|
280 { |
|
281 //Acquire the Lock before read and release it later |
|
282 TAutoFastLock lock(iReadLock); |
|
283 CSockDescBase::Read(aBuf,aStatus); |
|
284 return; |
|
285 } |
|
286 |
|
287 // ----------------------------------------------------------------------------- |
|
288 // CFileSocketDesc::RecvFrom |
|
289 // |
|
290 // ----------------------------------------------------------------------------- |
|
291 |
|
292 void CFileSocketDesc::RecvFrom(TDes8& aDesc, TSockAddr& AFrom, int aFlags, TRequestStatus& aStatus) |
|
293 { |
|
294 TAutoFastLock lock(iReadLock); |
|
295 CSockDescBase::RecvFrom(aDesc, AFrom, aFlags, aStatus); |
|
296 return; |
|
297 } |
|
298 |
|
299 |
|
300 // ----------------------------------------------------------------------------- |
|
301 // CFileSocketDesc::SendTo |
|
302 // |
|
303 // ----------------------------------------------------------------------------- |
|
304 |
|
305 void CFileSocketDesc::SendTo(TDes8& aDesc, const struct sockaddr* aToAddr, unsigned long aAddrLen,int aFlags, TRequestStatus& aStatus) |
|
306 { |
|
307 TAutoFastLock lock(iWriteLock); |
|
308 |
|
309 if(iStyle == SOCK_DGRAM) |
|
310 { |
|
311 TUint portNo; |
|
312 TInt ret; |
|
313 if((ret = GetLocalSockPortByPath((sockaddr_un*)aToAddr,aAddrLen,portNo)) != KErrNone) |
|
314 { |
|
315 Complete(aStatus,ret); |
|
316 return; |
|
317 } |
|
318 TInetAddr sAddr(KInetAddrLoop,portNo); |
|
319 CSockDescBase::SendTo(aDesc, sAddr, aFlags, aStatus); |
|
320 return; |
|
321 } |
|
322 |
|
323 TUSockAddr addr(NULL,0); |
|
324 CSockDescBase::SendTo(aDesc, addr, aFlags, aStatus); |
|
325 return; |
|
326 } |
|
327 |
|
328 |
|
329 // ----------------------------------------------------------------------------- |
|
330 // CFileSocketDesc::Ioctl |
|
331 // Not supported as of now. |
|
332 // ----------------------------------------------------------------------------- |
|
333 |
|
334 void CFileSocketDesc::Ioctl(int /*aCmd*/, void* /*aParam*/, TRequestStatus& aStatus) |
|
335 { |
|
336 Complete(aStatus, KErrNotSupported); |
|
337 return; |
|
338 } |
|
339 |
|
340 // ----------------------------------------------------------------------------- |
|
341 // CFileSocketDesc::FinalClose |
|
342 // |
|
343 // ----------------------------------------------------------------------------- |
|
344 |
|
345 TInt CFileSocketDesc::FinalClose() |
|
346 { |
|
347 RemoveLocalSockAddr(); |
|
348 RHeap* oheap = User::SwitchHeap(Backend()->Heap()); |
|
349 CSockDescBase::FinalClose(); |
|
350 User::SwitchHeap(oheap); |
|
351 return KErrNone; |
|
352 } |
|
353 |
|
354 |
|
355 // ----------------------------------------------------------------------------- |
|
356 // CFileSocketDesc::GetSockOpt |
|
357 // Get the socket option |
|
358 // ----------------------------------------------------------------------------- |
|
359 TInt CFileSocketDesc::GetSockOpt(TInt anOptionName,TInt anOptionLevel,TDes8& anOption) |
|
360 { |
|
361 if (anOption.Ptr() == NULL) |
|
362 { |
|
363 return EFAULT; |
|
364 } |
|
365 if (anOption.Length() == 0) |
|
366 { |
|
367 return EINVAL; |
|
368 } |
|
369 if(anOptionLevel != SOL_SOCKET) |
|
370 { |
|
371 return KErrNotSupported; |
|
372 } |
|
373 switch(anOptionName) |
|
374 { |
|
375 case SO_TYPE: |
|
376 TInt size; |
|
377 size = (anOption.MaxLength() < sizeof(iStyle))? anOption.MaxLength(): sizeof(iStyle); |
|
378 Mem::Copy((unsigned char*)anOption.Ptr(), &iStyle, size); |
|
379 anOption.SetLength(size); |
|
380 return KErrNone; |
|
381 case SO_KEEPALIVE: |
|
382 anOptionLevel=SOL_TCP; |
|
383 break; |
|
384 case SO_SNDBUF: |
|
385 case SO_RCVBUF: |
|
386 break; |
|
387 default: |
|
388 return KErrNotSupported; |
|
389 } |
|
390 |
|
391 return iSocket.GetOpt(anOptionName,anOptionLevel,anOption); |
|
392 |
|
393 } |
|
394 |
|
395 // ----------------------------------------------------------------------------- |
|
396 // CFileSocketDesc::SetSockOpt |
|
397 // Set the socket option |
|
398 // ----------------------------------------------------------------------------- |
|
399 |
|
400 TInt CFileSocketDesc::SetSockOpt(TInt anOptionName,TInt anOptionLevel,TDesC8& anOption) |
|
401 { |
|
402 if (anOption.Ptr() == NULL) |
|
403 { |
|
404 return EFAULT; |
|
405 } |
|
406 if (anOption.Length() == 0) |
|
407 { |
|
408 return EINVAL; |
|
409 } |
|
410 if(anOptionLevel != SOL_SOCKET) |
|
411 { |
|
412 return KErrNotSupported; |
|
413 } |
|
414 switch(anOptionName) |
|
415 { |
|
416 case SO_KEEPALIVE: |
|
417 if(iStyle == SOCK_STREAM) |
|
418 { |
|
419 anOptionLevel=SOL_TCP; |
|
420 } |
|
421 else |
|
422 { |
|
423 return KErrNotSupported; |
|
424 } |
|
425 break; |
|
426 case SO_SNDBUF: |
|
427 case SO_RCVBUF: |
|
428 break; |
|
429 default: |
|
430 return KErrNotSupported; |
|
431 } |
|
432 |
|
433 return iSocket.SetOpt(anOptionName,anOptionLevel,anOption); |
|
434 |
|
435 } |
|
436 |
|
437 // --------------------------------------------------------------------------------- |
|
438 // CFileSocketDesc::SockName |
|
439 // Fetches the local socket address. |
|
440 // --------------------------------------------------------------------------------- |
|
441 // |
|
442 TInt CFileSocketDesc::SockName(int anEnd, struct sockaddr* aAddr,unsigned long* aAddrLen) |
|
443 { |
|
444 TInt ret = KErrNone; |
|
445 TUSockAddr lSockAddr; |
|
446 if(anEnd == 0) |
|
447 { |
|
448 TInt ret; |
|
449 if((ret = ValidateAddress((sockaddr_un*)aAddr,aAddrLen)) != KErrNone) |
|
450 { |
|
451 if ( ( ret == EINVAL ) && (aAddrLen != 0)) |
|
452 { |
|
453 // since the length passed is less than the first field but greater than 0 i.e sun_family we dont need to fill any field into aAddr structure passed. |
|
454 return KErrNone; |
|
455 } |
|
456 return ret; |
|
457 } |
|
458 struct sockaddr_un* addr = (struct sockaddr_un*)aAddr; |
|
459 TInt buflen = *aAddrLen - (sizeof(addr->sun_family) + sizeof(addr->sun_len)); |
|
460 addr->sun_family = AF_UNIX; |
|
461 *aAddrLen = sizeof(addr->sun_family); |
|
462 |
|
463 if(iPath.Length() && buflen > 1) |
|
464 { |
|
465 TPtr8 sockPath((TText8*)(addr->sun_path),buflen); |
|
466 sockPath.Copy(iPath.Left(buflen-1)); |
|
467 sockPath.ZeroTerminate(); |
|
468 *aAddrLen = sizeof(addr->sun_family) + sockPath.Length() + 1; //+1 for NULL character |
|
469 } |
|
470 else if (buflen == 1) |
|
471 { |
|
472 addr->sun_path[0] = '\0'; |
|
473 } |
|
474 return KErrNone; |
|
475 } |
|
476 else |
|
477 { |
|
478 |
|
479 ret = CSockDescBase::SockName(anEnd,lSockAddr); |
|
480 if( ret == EFAULT ) |
|
481 return ret; |
|
482 |
|
483 struct sockaddr_un* addr = (struct sockaddr_un*)aAddr; |
|
484 // If the length passed is greater than or equal to 0 but less than the first field i.e sun_family , return kErrnone and dont fill any field into aAddr structure passed. |
|
485 if( (aAddrLen != 0) && (*aAddrLen < sizeof(addr->sun_family)) ) |
|
486 { |
|
487 return KErrNone; |
|
488 } |
|
489 |
|
490 if(ret == KErrNone) |
|
491 { |
|
492 ret = GetLocalSockAddrByPort((sockaddr_un*)aAddr,aAddrLen,lSockAddr.Port()); |
|
493 } |
|
494 } |
|
495 return ret; |
|
496 } |
|
497 |
|
498 // --------------------------------------------------------------------------------- |
|
499 // CFileSocketDesc::ValidateAddress |
|
500 // Utility function to check the validity of the socket address. |
|
501 // --------------------------------------------------------------------------------- |
|
502 // |
|
503 TInt CFileSocketDesc::ValidateAddress(const struct sockaddr_un* aAddr,unsigned long* aAddrLen) |
|
504 { |
|
505 if (aAddr == NULL) |
|
506 { |
|
507 return EFAULT; |
|
508 } |
|
509 if (aAddrLen == 0) |
|
510 { |
|
511 return EINVAL; |
|
512 } |
|
513 if( *aAddrLen < sizeof(aAddr->sun_family) ) |
|
514 { |
|
515 return EINVAL; |
|
516 } |
|
517 |
|
518 return KErrNone; |
|
519 } |
|
520 |
|
521 // --------------------------------------------------------------------------------- |
|
522 // CFileSocketDesc::GetLocalSockAddrByPort |
|
523 // Gets the file socket address associated with the port by querying the IPC server. |
|
524 // --------------------------------------------------------------------------------- |
|
525 // |
|
526 TInt CFileSocketDesc::GetLocalSockAddrByPort(struct sockaddr_un* aAddr,unsigned long* aAddrLen,TUint aPortNum) |
|
527 { |
|
528 TInt ret; |
|
529 if((ret = ValidateAddress(aAddr,aAddrLen)) != KErrNone) |
|
530 { |
|
531 return ret; |
|
532 } |
|
533 |
|
534 |
|
535 TInt buflen = *aAddrLen - (sizeof(aAddr->sun_family) + sizeof(aAddr->sun_len)); |
|
536 TInt err; |
|
537 |
|
538 aAddr->sun_family = AF_UNIX; |
|
539 *aAddrLen = sizeof(aAddr->sun_family); |
|
540 if(buflen > 1) |
|
541 { |
|
542 TPtr8 sockPath((TText8*)aAddr->sun_path,buflen-1); |
|
543 if((err=Backend()->iIpcS.GetLocalSockAddrByPort(sockPath,aPortNum)) != KErrNone) |
|
544 { |
|
545 sockPath.ZeroTerminate(); |
|
546 *aAddrLen = 0; |
|
547 return err; |
|
548 } |
|
549 |
|
550 aAddr->sun_path[sockPath.Length()] = '\0'; |
|
551 *aAddrLen = sizeof(aAddr->sun_family) + sockPath.Length() + 1; //+1 for NULL character |
|
552 return KErrNone; |
|
553 } |
|
554 else if (buflen == 1) |
|
555 { |
|
556 aAddr->sun_path[0] = '\0'; |
|
557 } |
|
558 |
|
559 return KErrNone; |
|
560 |
|
561 } |
|
562 |
|
563 // ----------------------------------------------------------------------------- |
|
564 // CFileSocketDesc::GetLocalSockPortByPath |
|
565 // Queries the IPC server to get the port associated with the path |
|
566 // ----------------------------------------------------------------------------- |
|
567 |
|
568 TInt CFileSocketDesc::GetLocalSockPortByPath(const struct sockaddr_un* aAddr,unsigned long aAddrLen,TUint& aPortNum) |
|
569 { |
|
570 TInt err; |
|
571 if((err = ValidateAddress(aAddr,&aAddrLen)) != KErrNone) |
|
572 { |
|
573 return err; |
|
574 } |
|
575 |
|
576 TInt buflen = aAddrLen - (sizeof(aAddr->sun_family) + sizeof(aAddr->sun_len)); |
|
577 |
|
578 if(buflen <= 1) |
|
579 { |
|
580 return EINVAL; |
|
581 } |
|
582 |
|
583 TBuf8<KMaxFileName> fullname; |
|
584 err = GetFullFileUtf8(fullname, aAddr->sun_path, Backend()->FileSession()); |
|
585 |
|
586 return Backend()->iIpcS.GetLocalSockPortByPath(fullname, aPortNum); |
|
587 } |
|
588 |
|
589 // ----------------------------------------------------------------------------- |
|
590 // CFileSocketDesc::RemoveLocalSockAddr |
|
591 // Removes the local socket address from the IPCServer |
|
592 // ----------------------------------------------------------------------------- |
|
593 |
|
594 TInt CFileSocketDesc::RemoveLocalSockAddr() |
|
595 { |
|
596 if(iPath.Length()) |
|
597 { |
|
598 return Backend()->iIpcS.RemLocalSockAddr(iPath); |
|
599 } |
|
600 return KErrNone; |
|
601 } |
|
602 |