|
1 /* |
|
2 * Copyright (c) 2005-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 * System Includes |
|
16 * |
|
17 */ |
|
18 |
|
19 |
|
20 |
|
21 #include <stdio.h> |
|
22 #include <memory.h> |
|
23 #include <assert.h> |
|
24 #ifndef WIN32 |
|
25 #include <errno.h> |
|
26 #include <unistd.h> |
|
27 #endif |
|
28 |
|
29 |
|
30 /******************************************************************************* |
|
31 * |
|
32 * Local Includes |
|
33 * |
|
34 ******************************************************************************/ |
|
35 #include "CUDPAirInterface.h" |
|
36 |
|
37 |
|
38 /******************************************************************************* |
|
39 * |
|
40 * Definitions |
|
41 * |
|
42 ******************************************************************************/ |
|
43 #ifndef WIN32 |
|
44 #define SOCKET_ERROR (-1) |
|
45 #define INVALID_SOCKET (-1) |
|
46 #define ADDRESS_INTEGER s_addr |
|
47 #define closesocket(x) (shutdown(x,SHUT_RDWR),close(x)) |
|
48 #else |
|
49 typedef int socklen_t; |
|
50 #endif |
|
51 |
|
52 |
|
53 /******************************************************************************* |
|
54 * |
|
55 * Macro Functions |
|
56 * |
|
57 ******************************************************************************/ |
|
58 |
|
59 |
|
60 /******************************************************************************* |
|
61 * |
|
62 * Constructor - sets the passed pointers and sets the state to disabled |
|
63 * |
|
64 ******************************************************************************/ |
|
65 CUDPAirInterface::CUDPAirInterface( TPhoneData *aPhoneData, CLog *aLog ) |
|
66 { |
|
67 // verify parameters |
|
68 assert( aPhoneData != NULL ); |
|
69 assert( aLog != NULL ); |
|
70 |
|
71 // init state |
|
72 iPhoneData = aPhoneData; |
|
73 iProcessData = NULL; |
|
74 iLog = aLog; |
|
75 iFilter = NULL; |
|
76 memset( &iRemoteAddress, 0, sizeof(iRemoteAddress) ); |
|
77 memset( &iLocalAddress, 0, sizeof(iLocalAddress) ); |
|
78 iSockIncoming = INVALID_SOCKET; |
|
79 iSockOutgoing = INVALID_SOCKET; |
|
80 iExitFlag = 0; |
|
81 iRemoteAddressValid = 0; |
|
82 } |
|
83 |
|
84 CUDPAirInterface::~CUDPAirInterface( ) |
|
85 { |
|
86 // check the status of the sockets |
|
87 assert( iSockIncoming == INVALID_SOCKET ); |
|
88 assert( iSockOutgoing == INVALID_SOCKET ); |
|
89 } |
|
90 |
|
91 |
|
92 /******************************************************************************* |
|
93 * |
|
94 * PUBLIC METHOD: LISTEN-THREAD: ListenOnInterface. Binds to local port and |
|
95 * then starts listening on this port for more incoming data. Any incoming data |
|
96 * is then sent to the datalink layer. |
|
97 * |
|
98 ******************************************************************************/ |
|
99 TAirInterfaceError CUDPAirInterface::ListenOnInterface( int *aErrCode ) |
|
100 { |
|
101 TDataPathError derr; |
|
102 int err, errcode; |
|
103 struct sockaddr_in remote_recv_addr; |
|
104 socklen_t addrlen; |
|
105 |
|
106 // verify params |
|
107 assert( aErrCode != NULL ); |
|
108 *aErrCode = 0; |
|
109 |
|
110 // check that the local port is invalid |
|
111 assert( iSockIncoming == INVALID_SOCKET ); |
|
112 |
|
113 // create the listening socket |
|
114 iSockIncoming = socket( AF_INET, SOCK_DGRAM, 0 ); |
|
115 if( iSockIncoming == INVALID_SOCKET ) { |
|
116 *aErrCode = GetSocketError(); |
|
117 return AIE_SOCKET_FAILED; |
|
118 } |
|
119 |
|
120 // if the exit flag is set then exit now |
|
121 if( iExitFlag != 0 ) { |
|
122 closesocket( iSockIncoming ); |
|
123 iSockIncoming = INVALID_SOCKET; |
|
124 return AIE_NONE; |
|
125 } |
|
126 |
|
127 |
|
128 // bind the listening socket -- bind to an ephemeral port |
|
129 iLocalAddress.sin_family = AF_INET; |
|
130 iLocalAddress.sin_port = htons(0); |
|
131 iLocalAddress.sin_addr.ADDRESS_INTEGER = INADDR_ANY; |
|
132 err = bind( iSockIncoming, (struct sockaddr*)&iLocalAddress, sizeof(iLocalAddress) ); |
|
133 |
|
134 // get the allocated port info |
|
135 addrlen = sizeof(iLocalAddress); |
|
136 err = getsockname( iSockIncoming, (sockaddr*)&iLocalAddress, &addrlen ); |
|
137 assert( err == 0 ); |
|
138 |
|
139 // check for errors during the bind |
|
140 if( err != 0 ) { |
|
141 closesocket( iSockIncoming ); |
|
142 iSockIncoming = INVALID_SOCKET; |
|
143 *aErrCode = GetSocketError(); |
|
144 return AIE_BIND_FAILED; |
|
145 } |
|
146 |
|
147 // use the listening socket as the outgoing socket -- no reason we can't do |
|
148 // this. It also means that we know the source port of the outgoing datagrams |
|
149 // and hence we can do some proper NISTNET stuff |
|
150 iSockOutgoing = iSockIncoming; |
|
151 |
|
152 // read from the socket until an error occurs (this may be induced by another |
|
153 // thread closing the socket) |
|
154 while( 1 ) { |
|
155 |
|
156 // now read from the socket |
|
157 memset( &remote_recv_addr, 0, sizeof(remote_recv_addr) ); |
|
158 addrlen = sizeof(remote_recv_addr); |
|
159 err = recvfrom( iSockIncoming, iPacketBuffer, KPCKTBUFFSIZE, 0, (struct sockaddr*)&remote_recv_addr, &addrlen ); |
|
160 |
|
161 // check for errors |
|
162 if( err == SOCKET_ERROR ) { |
|
163 closesocket( iSockIncoming ); |
|
164 iSockIncoming = iSockOutgoing = INVALID_SOCKET; |
|
165 *aErrCode = GetSocketError(); |
|
166 return AIE_RECEIVE_FAILED; |
|
167 } |
|
168 |
|
169 // send the data to the filters |
|
170 if( iFilter != NULL ) { |
|
171 iFilter->ProcessIncomingData( iPacketBuffer, err ); |
|
172 } |
|
173 |
|
174 // otherwise we have data to send to the datalink layer |
|
175 derr = iProcessData->ProcessUUData( iPacketBuffer, err, &errcode ); |
|
176 if( derr != DPE_NONE ) { |
|
177 iLog->WriteLogEntry( SV_WARNING, "CUDPAirInterface::ListenOnInterface", "ProcessUUData returned", derr, errcode ); |
|
178 } |
|
179 } |
|
180 |
|
181 // code should never get here |
|
182 assert( !"INVALID CODE PATH" ); |
|
183 return AIE_NONE; |
|
184 } |
|
185 |
|
186 |
|
187 /******************************************************************************* |
|
188 * |
|
189 * PUBLIC METHOD: MAIN-THREAD: StopInterface. Closes the socket (if it is open) |
|
190 * was called. We can't guarantee when the receiving thread will return. But it |
|
191 * must before any other calls can be made. |
|
192 * |
|
193 ******************************************************************************/ |
|
194 int CUDPAirInterface::StopInterface() |
|
195 { |
|
196 // set the exit flag |
|
197 iExitFlag = 1; |
|
198 |
|
199 // close the socket if it is open |
|
200 if( iSockIncoming != INVALID_SOCKET ) { |
|
201 closesocket( iSockIncoming ); |
|
202 iSockIncoming = iSockOutgoing = INVALID_SOCKET; |
|
203 } |
|
204 |
|
205 // done |
|
206 return 0; |
|
207 } |
|
208 |
|
209 |
|
210 /******************************************************************************* |
|
211 * |
|
212 * PUBLIC METHOD: GetLocalAddress |
|
213 * |
|
214 ******************************************************************************/ |
|
215 void CUDPAirInterface::GetLocalAddress( struct sockaddr_in *aLocalAddress ) |
|
216 { |
|
217 assert( aLocalAddress != NULL ); |
|
218 *aLocalAddress = iLocalAddress; |
|
219 } |
|
220 |
|
221 |
|
222 /******************************************************************************* |
|
223 * |
|
224 * PUBLIC METHOD: SetRemoteAddress |
|
225 * |
|
226 ******************************************************************************/ |
|
227 void CUDPAirInterface::GetRemoteAddress( struct sockaddr_in *aRemoteAddress ) |
|
228 { |
|
229 *aRemoteAddress = iRemoteAddress; |
|
230 } |
|
231 |
|
232 |
|
233 /******************************************************************************* |
|
234 * |
|
235 * PUBLIC METHOD: SetRemoteAddress |
|
236 * |
|
237 ******************************************************************************/ |
|
238 void CUDPAirInterface::SetRemoteAddress( struct sockaddr_in aRemoteAddress ) |
|
239 { |
|
240 iRemoteAddressValid = 1; |
|
241 iRemoteAddress = aRemoteAddress; |
|
242 } |
|
243 |
|
244 |
|
245 /******************************************************************************* |
|
246 * |
|
247 * PUBLIC METHOD: SetDatalink |
|
248 * |
|
249 ******************************************************************************/ |
|
250 void CUDPAirInterface::SetDatalink( IProcessData *aProcessData ) |
|
251 { |
|
252 iProcessData = aProcessData; |
|
253 } |
|
254 |
|
255 |
|
256 /******************************************************************************* |
|
257 * |
|
258 * PUBLIC METHOD: RPC-THREAD. SetFilter, called by the main setup call in |
|
259 * cphone - links up all the bits. |
|
260 * |
|
261 ******************************************************************************/ |
|
262 void CUDPAirInterface::SetFilter( IFilter *aFilter ) |
|
263 { |
|
264 iFilter = aFilter; |
|
265 } |
|
266 |
|
267 |
|
268 /******************************************************************************* |
|
269 * |
|
270 * PUBLIC METHOD: TE-THREAD: SendPacket, when data is received on the te |
|
271 * channel it eventually makes its way here (in its thread) to send the |
|
272 * data out the uu interface. |
|
273 * |
|
274 ******************************************************************************/ |
|
275 TDataPathError CUDPAirInterface::SendPacket( char *data, int len, int *aErrCode ) |
|
276 { |
|
277 int err; |
|
278 |
|
279 //verify the params |
|
280 assert( data != NULL ); |
|
281 assert( aErrCode != NULL ); |
|
282 *aErrCode = 0; |
|
283 |
|
284 // make sure the remote address is set - not an error |
|
285 if( iRemoteAddressValid == 0 ) { |
|
286 return DPE_NONE; |
|
287 } |
|
288 |
|
289 // send the packet - send in 4k chunks to avoid system defined UDP packet size limit |
|
290 err = sendto( iSockOutgoing, data, len, 0, (struct sockaddr*)&iRemoteAddress, sizeof(iRemoteAddress) ); |
|
291 if( err == SOCKET_ERROR ) { |
|
292 *aErrCode = GetSocketError(); |
|
293 return DPE_SEND_FAILED; |
|
294 } |
|
295 |
|
296 // done |
|
297 return DPE_NONE; |
|
298 } |
|
299 |
|
300 |
|
301 /******************************************************************************* |
|
302 * |
|
303 * PRIVATE METHODS: Helper functions |
|
304 * |
|
305 ******************************************************************************/ |
|
306 int CUDPAirInterface::GetSocketError() |
|
307 { |
|
308 #ifdef WIN32 |
|
309 return WSAGetLastError(); |
|
310 #else |
|
311 return errno; |
|
312 #endif |
|
313 } |