1 /* $Id$ */
2 /*
3  * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4  * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 #ifndef __OS_SYMBIAN_H__
21 #define __OS_SYMBIAN_H__
22 
23 #include <pj/assert.h>
24 #include <pj/errno.h>
25 #include <pj/sock.h>
26 #include <pj/os.h>
27 #include <pj/string.h>
28 
29 #include <e32base.h>
30 #include <e32cmn.h>
31 #include <e32std.h>
32 #include <es_sock.h>
33 #include <in_sock.h>
34 #include <charconv.h>
35 #include <utf.h>
36 #include <e32cons.h>
37 
38 // Forward declarations
39 class CPjSocketReader;
40 
41 #ifndef PJ_SYMBIAN_TIMER_PRIORITY
42 #    define PJ_SYMBIAN_TIMER_PRIORITY	EPriorityNormal
43 #endif
44 
45 //
46 // PJLIB Symbian's Socket
47 //
48 class CPjSocket
49 {
50 public:
51     enum
52     {
53 	MAX_LEN = 1500,
54     };
55 
56     // Construct CPjSocket
CPjSocket(int af,int sock_type,RSocket & sock)57     CPjSocket(int af, int sock_type, RSocket &sock)
58 	: af_(af), sock_(sock), sock_type_(sock_type), connected_(false),
59 	  sockReader_(NULL)
60     {
61     }
62 
63     // Destroy CPjSocket
64     ~CPjSocket();
65 
66     // Get address family
GetAf()67     int GetAf() const
68     {
69     	return af_;
70     }
71 
72     // Get the internal RSocket
Socket()73     RSocket& Socket()
74     {
75 	return sock_;
76     }
77 
78     // Get socket connected flag.
IsConnected()79     bool IsConnected() const
80     {
81 	return connected_;
82     }
83 
84     // Set socket connected flag.
SetConnected(bool connected)85     void SetConnected(bool connected)
86     {
87 	connected_ = connected;
88     }
89 
90     // Get socket type
GetSockType()91     int GetSockType() const
92     {
93 	return sock_type_;
94     }
95 
96     // Returns true if socket is a datagram
IsDatagram()97     bool IsDatagram() const
98     {
99 	return sock_type_ == KSockDatagram;
100     }
101 
102     // Get socket reader, if any.
103     // May return NULL.
Reader()104     CPjSocketReader *Reader()
105     {
106 	return sockReader_;
107     }
108 
109     // Create socket reader.
110     CPjSocketReader *CreateReader(unsigned max_len=CPjSocket::MAX_LEN);
111 
112     // Delete socket reader when it's not wanted.
113     void DestroyReader();
114 
115 private:
116     int		     af_;
117     RSocket	     sock_;	    // Must not be reference, or otherwise
118 				    // it may point to local variable!
119     unsigned   	     sock_type_;
120 
121     bool	     connected_;
122     CPjSocketReader *sockReader_;
123 };
124 
125 
126 //
127 // Socket reader, used by select() and ioqueue abstraction
128 //
129 class CPjSocketReader : public CActive
130 {
131 public:
132     // Construct.
133     static CPjSocketReader *NewL(CPjSocket &sock, unsigned max_len=CPjSocket::MAX_LEN);
134 
135     // Destroy;
136     ~CPjSocketReader();
137 
138     // Start asynchronous read from the socket.
139     void StartRecv(void (*cb)(void *key)=NULL,
140 		   void *key=NULL,
141 		   TDes8 *aDesc = NULL,
142 		   TUint flags = 0);
143 
144     // Start asynchronous read from the socket.
145     void StartRecvFrom(void (*cb)(void *key)=NULL,
146 		       void *key=NULL,
147 		       TDes8 *aDesc = NULL,
148 		       TUint flags = 0,
149 		       TSockAddr *fromAddr = NULL);
150 
151     // Cancel asynchronous read.
152     void DoCancel();
153 
154     // Implementation: called when read has completed.
155     void RunL();
156 
157     // Check if there's pending data.
HasData()158     bool HasData() const
159     {
160 	return buffer_.Length() != 0;
161     }
162 
163     // Append data to aDesc, up to aDesc's maximum size.
164     // If socket is datagram based, buffer_ will be clared.
165     void ReadData(TDes8 &aDesc, TInetAddr *addr=NULL);
166 
167 private:
168     CPjSocket	   &sock_;
169     bool	    isDatagram_;
170     TPtr8	    buffer_;
171     TInetAddr	    recvAddr_;
172 
173     void	   (*readCb_)(void *key);
174     void	    *key_;
175 
176     //
177     // Constructor
178     //
179     CPjSocketReader(CPjSocket &sock);
180     void ConstructL(unsigned max_len);
181 };
182 
183 
184 
185 //
186 // Time-out Timer Active Object
187 //
188 class CPjTimeoutTimer : public CActive
189 {
190 public:
191     static CPjTimeoutTimer *NewL();
192     ~CPjTimeoutTimer();
193 
194     void StartTimer(TUint miliSeconds);
195     bool HasTimedOut() const;
196 
197 protected:
198     virtual void RunL();
199     virtual void DoCancel();
200     virtual TInt RunError(TInt aError);
201 
202 private:
203     RTimer	timer_;
204     pj_bool_t	hasTimedOut_;
205 
206     CPjTimeoutTimer();
207     void ConstructL();
208 };
209 
210 
211 
212 //
213 // Symbian OS helper for PJLIB
214 //
215 class PjSymbianOS
216 {
217 public:
218     //
219     // Get the singleton instance of PjSymbianOS
220     //
221     static PjSymbianOS *Instance();
222 
223     //
224     // Set parameters
225     //
226     void SetParameters(pj_symbianos_params *params);
227 
228     //
229     // Initialize.
230     //
231     TInt Initialize();
232 
233     //
234     // Shutdown.
235     //
236     void Shutdown();
237 
238 
239     //
240     // Socket helper.
241     //
242 
243     // Get RSocketServ instance to be used by all sockets.
SocketServ()244     RSocketServ &SocketServ()
245     {
246 	return appSocketServ_ ? *appSocketServ_ : socketServ_;
247     }
248 
249     // Get RConnection instance, if any.
Connection()250     RConnection *Connection()
251     {
252     	return appConnection_;
253     }
254 
255     // Convert TInetAddr to pj_sockaddr_in
256     static inline pj_status_t Addr2pj(const TInetAddr & sym_addr,
257 			       	      pj_sockaddr &pj_addr,
258 			       	      int *addr_len,
259 			       	      pj_bool_t convert_ipv4_mapped_addr = PJ_FALSE)
260     {
261     TUint fam = sym_addr.Family();
262 	pj_bzero(&pj_addr, *addr_len);
263 	if (fam == PJ_AF_INET ||
264 			(convert_ipv4_mapped_addr &&
265 			 fam == PJ_AF_INET6 &&
266 			 sym_addr.IsV4Mapped()))
267 	{
268 		pj_addr.addr.sa_family = PJ_AF_INET;
269 	    PJ_ASSERT_RETURN(*addr_len>=(int)sizeof(pj_sockaddr_in), PJ_ETOOSMALL);
270 	    pj_addr.ipv4.sin_addr.s_addr = pj_htonl(sym_addr.Address());
271 	    pj_addr.ipv4.sin_port = pj_htons((pj_uint16_t) sym_addr.Port());
272 	    *addr_len = sizeof(pj_sockaddr_in);
273 	} else if (fam == PJ_AF_INET6) {
274 	    PJ_ASSERT_RETURN(*addr_len>=(int)sizeof(pj_sockaddr_in6), PJ_ETOOSMALL);
275 	    const TIp6Addr & ip6 = sym_addr.Ip6Address();
276 	    pj_addr.addr.sa_family = PJ_AF_INET6;
277 	    pj_memcpy(&pj_addr.ipv6.sin6_addr, ip6.u.iAddr8, 16);
278 	    pj_addr.ipv6.sin6_port = pj_htons((pj_uint16_t) sym_addr.Port());
279 	    pj_addr.ipv6.sin6_scope_id = pj_htonl(sym_addr.Scope());
280 	    pj_addr.ipv6.sin6_flowinfo = pj_htonl(sym_addr.FlowLabel());
281 	    *addr_len = sizeof(pj_sockaddr_in6);
282 	} else {
283 	    pj_assert(!"Unsupported address family");
284 	    return PJ_EAFNOTSUP;
285 	}
286 
287 	return PJ_SUCCESS;
288     }
289 
290 
291     // Convert pj_sockaddr_in to TInetAddr
pj2Addr(const pj_sockaddr & pj_addr,int addrlen,TInetAddr & sym_addr)292     static inline pj_status_t pj2Addr(const pj_sockaddr &pj_addr,
293     				      int addrlen,
294 			       	      TInetAddr & sym_addr)
295     {
296     	if (pj_addr.addr.sa_family == PJ_AF_INET) {
297     	    PJ_ASSERT_RETURN(addrlen >= (int)sizeof(pj_sockaddr_in), PJ_EINVAL);
298 	    sym_addr.Init(KAfInet);
299     	    sym_addr.SetAddress((TUint32)pj_ntohl(pj_addr.ipv4.sin_addr.s_addr));
300     	    sym_addr.SetPort(pj_ntohs(pj_addr.ipv4.sin_port));
301     	} else if (pj_addr.addr.sa_family == PJ_AF_INET6) {
302     	    TIp6Addr ip6;
303 
304     	    PJ_ASSERT_RETURN(addrlen>=(int)sizeof(pj_sockaddr_in6), PJ_EINVAL);
305     	    pj_memcpy(ip6.u.iAddr8, &pj_addr.ipv6.sin6_addr, 16);
306     	    sym_addr.Init(KAfInet6);
307     	    sym_addr.SetAddress(ip6);
308     	    sym_addr.SetScope(pj_ntohl(pj_addr.ipv6.sin6_scope_id));
309     	    sym_addr.SetFlowLabel(pj_ntohl(pj_addr.ipv6.sin6_flowinfo));
310     	} else {
311     	    pj_assert(!"Unsupported address family");
312     	}
313     	return PJ_SUCCESS;
314     }
315 
316 
317     //
318     // Resolver helper
319     //
320 
321     // Get RHostResolver instance
GetResolver(int af)322     RHostResolver & GetResolver(int af)
323     {
324     	if (af==PJ_AF_INET6) {
325     	    return appHostResolver6_ ? *appHostResolver6_ : hostResolver6_;
326     	} else {
327     	    return appHostResolver_ ? *appHostResolver_ : hostResolver_;
328     	}
329     }
330 
331     //
332     // Return true if the access point connection is up
333     //
IsConnectionUp()334     bool IsConnectionUp() const
335     {
336 	return isConnectionUp_;
337     }
338 
339     //
340     // Set access point connection status
341     //
SetConnectionStatus(bool up)342     void SetConnectionStatus(bool up)
343     {
344 	isConnectionUp_ = up;
345     }
346 
347     //
348     // Unicode Converter
349     //
350 
351     // Convert to Unicode
352     TInt ConvertToUnicode(TDes16 &aUnicode, const TDesC8 &aForeign);
353 
354     // Convert from Unicode
355     TInt ConvertFromUnicode(TDes8 &aForeign, const TDesC16 &aUnicode);
356 
357     //
358     // Get console
359     //
360 
361     // Get console
Console()362     CConsoleBase *Console()
363     {
364 	return console_;
365     }
366 
367     //
368     // Get select() timeout timer.
369     //
SelectTimeoutTimer()370     CPjTimeoutTimer *SelectTimeoutTimer()
371     {
372 	return selectTimeoutTimer_;
373     }
374 
375     //
376     // Wait for any active objects to run.
377     //
378     void WaitForActiveObjects(TInt aPriority = CActive::EPriorityStandard)
379     {
380 	TInt aError;
381 	CActiveScheduler::Current()->WaitForAnyRequest();
382 	CActiveScheduler::RunIfReady(aError, aPriority);
383     }
384 
385 private:
386     bool isConnectionUp_;
387 
388     bool isSocketServInitialized_;
389     RSocketServ socketServ_;
390 
391     bool isResolverInitialized_;
392     RHostResolver hostResolver_;
393     RHostResolver hostResolver6_;
394 
395     CConsoleBase* console_;
396 
397     CPjTimeoutTimer *selectTimeoutTimer_;
398 
399     // App parameters
400     RSocketServ *appSocketServ_;
401     RConnection *appConnection_;
402     RHostResolver *appHostResolver_;
403     RHostResolver *appHostResolver6_;
404 
405 private:
406     PjSymbianOS();
407 };
408 
409 // This macro is used to check the access point connection status and return
410 // failure if the AP connection is down or unusable. See the documentation
411 // of pj_symbianos_set_connection_status() for more info
412 #define PJ_SYMBIAN_CHECK_CONNECTION() \
413     PJ_SYMBIAN_CHECK_CONNECTION2(PJ_ECANCELLED)
414 
415 #define PJ_SYMBIAN_CHECK_CONNECTION2(retval) \
416     do { \
417 	if (!PjSymbianOS::Instance()->IsConnectionUp()) \
418 	    return retval; \
419     } while (0);
420 
421 #endif	/* __OS_SYMBIAN_H__ */
422 
423