|
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 * Switches |
|
16 * |
|
17 */ |
|
18 |
|
19 |
|
20 |
|
21 //#define SYSTEM_TEST_MP5 |
|
22 |
|
23 |
|
24 /******************************************************************************* |
|
25 * |
|
26 * System Includes |
|
27 * |
|
28 ******************************************************************************/ |
|
29 #include <stdio.h> |
|
30 #include <stdlib.h> |
|
31 #include <pthread.h> |
|
32 #include <unistd.h> |
|
33 #include <assert.h> |
|
34 #include <errno.h> |
|
35 #include <sys/types.h> |
|
36 #include <sys/socket.h> |
|
37 #include <netinet/in.h> |
|
38 #include <signal.h> |
|
39 #include <string.h> |
|
40 |
|
41 /******************************************************************************* |
|
42 * |
|
43 * Local Includes |
|
44 * |
|
45 ******************************************************************************/ |
|
46 #include "socket_helper.h" |
|
47 |
|
48 |
|
49 /******************************************************************************* |
|
50 * |
|
51 * Definitions |
|
52 * |
|
53 ******************************************************************************/ |
|
54 #define RECVBUFFSIZE (4096*4) |
|
55 #define MAXIDSTR 64 |
|
56 |
|
57 |
|
58 /******************************************************************************* |
|
59 * |
|
60 * Prototypes |
|
61 * |
|
62 ******************************************************************************/ |
|
63 void *receive_ppp_frames( void *x ); |
|
64 void *send_ppp_frames( void * ); |
|
65 void closesocket( int sockfd ); |
|
66 int do_client_server_protocol( int aMobsterDeviceID ); |
|
67 |
|
68 |
|
69 /******************************************************************************* |
|
70 * |
|
71 * File-scope |
|
72 * |
|
73 ******************************************************************************/ |
|
74 int sockfd; |
|
75 |
|
76 |
|
77 /******************************************************************************* |
|
78 * |
|
79 * Signal Handler |
|
80 * |
|
81 ******************************************************************************/ |
|
82 void sigterm( int signum ) |
|
83 { |
|
84 pid_t mp = getpid(); |
|
85 fprintf( stderr, "PG: pppdgateway(%d) received a SIGTERM -- ignoring\n", mp ); |
|
86 } |
|
87 |
|
88 |
|
89 /******************************************************************************* |
|
90 * |
|
91 * Main() |
|
92 * |
|
93 ******************************************************************************/ |
|
94 int main( int argc, char *argv[] ) |
|
95 { |
|
96 int err; |
|
97 int mobster_device_id = 0; |
|
98 pthread_t threadhandle_send, threadhandle_recv; |
|
99 struct sockaddr_in mobster_addr; |
|
100 __sighandler_t oh; |
|
101 |
|
102 // check args |
|
103 if( argc != 4 ) { |
|
104 fprintf( stderr, "usage: %s mobster_address mobster_port mobster_device_id\n", argv[0] ); |
|
105 return -1; |
|
106 } |
|
107 mobster_device_id = atoi(argv[3]); |
|
108 fprintf( stderr, "PG: pppdgateway starting\n" ); |
|
109 |
|
110 // setup the signal handler -- note that we ignore SIGTERM! This is because if we shutdown on a SIGTERM we don't |
|
111 // output the TERMREQ -- or receive the TERMACK. Therefore, we rely on the fact that when pppd wants to stop |
|
112 // it will close stdin -- this will cause the output thread to stop -- it will also close the socket which |
|
113 // will cause the input thread to stop -- then the main thread will exit |
|
114 oh = signal( SIGTERM, sigterm ); |
|
115 if( oh == SIG_ERR ) { |
|
116 fprintf( stderr, "PG: error registering signal handler (SIGTERM)\n" ); |
|
117 return -1; |
|
118 } |
|
119 oh = signal( SIGHUP, sigterm ); |
|
120 if( oh == SIG_ERR ) { |
|
121 fprintf( stderr, "PG: error registering signal handler (SIGHUP)\n" ); |
|
122 return -1; |
|
123 } |
|
124 |
|
125 // create a TCP socket |
|
126 sockfd = socket( AF_INET, SOCK_STREAM, 0 ); |
|
127 if( sockfd == -1 ) { |
|
128 fprintf( stderr, "PG: failed to create socket, exiting.\n" ); |
|
129 return -1; |
|
130 } |
|
131 |
|
132 // create the address |
|
133 mobster_addr = getsockaddr( argv[1], argv[2] ); |
|
134 if( mobster_addr.sin_addr.s_addr == 0 ) { |
|
135 fprintf( stderr, "PG: invalid address (zero or couldn't resolve hostname), exiting.\n" ); |
|
136 closesocket( sockfd ); |
|
137 return -1; |
|
138 } |
|
139 |
|
140 // connect to mobster |
|
141 err = connect( sockfd, (struct sockaddr*)&mobster_addr, sizeof(mobster_addr) ); |
|
142 if( err != 0 ) { |
|
143 perror( "PG: connect() to server failed\n" ); |
|
144 closesocket( sockfd ); |
|
145 return -1; |
|
146 } |
|
147 |
|
148 // do the client server protocol - if there is an error the exit |
|
149 err = do_client_server_protocol( mobster_device_id ); |
|
150 if( err != 0 ) { |
|
151 fprintf( stderr, "PG: client/server protocol failed.\n" ); |
|
152 closesocket( sockfd ); |
|
153 return -1; |
|
154 } |
|
155 |
|
156 // change the streams to unbuffered so that this exe doesn't add latency |
|
157 err = setvbuf( stdout, NULL, _IONBF, 0 ); |
|
158 if( err != 0 ) { |
|
159 fprintf( stderr, "PG: failed to set buffering on stdout (%d)\n", err ); |
|
160 closesocket( sockfd ); |
|
161 return -1; |
|
162 } |
|
163 err = setvbuf( stdin, NULL, _IONBF, 0 ); |
|
164 if( err != 0 ) { |
|
165 fprintf( stderr, "PG: failed to set buffering on stdout (%d)\n", err ); |
|
166 closesocket( sockfd ); |
|
167 return -1; |
|
168 } |
|
169 err = setvbuf( stderr, NULL, _IONBF, 0 ); |
|
170 if( err != 0 ) { |
|
171 fprintf( stderr, "PG: failed to set buffering on stdout (%d)\n", err ); |
|
172 closesocket( sockfd ); |
|
173 return -1; |
|
174 } |
|
175 |
|
176 // all the setup is done -- create the threads and let them do their stuff |
|
177 err = pthread_create( &threadhandle_send, NULL, send_ppp_frames, 0 ); |
|
178 assert( err == 0 ); |
|
179 err = pthread_create( &threadhandle_recv, NULL, receive_ppp_frames, 0 ); |
|
180 assert( err == 0 ); |
|
181 |
|
182 |
|
183 // wait for them to exit |
|
184 pthread_join( threadhandle_send, NULL ); |
|
185 pthread_join( threadhandle_recv, NULL ); |
|
186 |
|
187 |
|
188 // return |
|
189 fprintf( stderr, "PG: pppdgateway has completed.\n" ); |
|
190 return 0; |
|
191 } |
|
192 |
|
193 |
|
194 /******************************************************************************* |
|
195 * |
|
196 * receive_ppp_frames |
|
197 * |
|
198 ******************************************************************************/ |
|
199 void *receive_ppp_frames( void *x ) |
|
200 { |
|
201 int recvcount, writecount; |
|
202 char recvbuff[RECVBUFFSIZE]; |
|
203 |
|
204 // listen on the udp socket and send anything received to stdout -- no framing is ever done on the input channel |
|
205 while( 1 ) { |
|
206 |
|
207 // wait for some data -- on error print error, close the socket, and exit. Closing the socket means that the other thread will clean up and exit |
|
208 recvcount = recv( sockfd, recvbuff, RECVBUFFSIZE, 0 ); |
|
209 if( recvcount == -1 ) { |
|
210 fprintf( stderr, "PG: error occured while reading socket.\n" ); |
|
211 closesocket( sockfd ); |
|
212 pthread_exit( NULL ); |
|
213 } |
|
214 // fprintf( stderr, "PG: %d bytes incoming\n", recvcount ); |
|
215 |
|
216 // send the data to the pppd server |
|
217 writecount = fwrite( recvbuff, 1, recvcount, stdout ); |
|
218 if( writecount != recvcount ) { |
|
219 fprintf( stderr, "PG: error occured while writing to stdout.\n" ); |
|
220 closesocket( sockfd ); |
|
221 pthread_exit( NULL ); |
|
222 } |
|
223 } |
|
224 |
|
225 // done |
|
226 return NULL; |
|
227 } |
|
228 |
|
229 |
|
230 /******************************************************************************* |
|
231 * |
|
232 * send_ppp_frames |
|
233 * |
|
234 ******************************************************************************/ |
|
235 void *send_ppp_frames( void *x ) |
|
236 { |
|
237 int err; |
|
238 int sendcount; |
|
239 int c = 0; |
|
240 |
|
241 // listen on stdin for data and write it to the socket -- on error print an error, closesocket, and exit. |
|
242 while( 1 ) { |
|
243 |
|
244 // read the next char |
|
245 err = fread( &c, 1, 1, stdin ); |
|
246 if( err != 1 ) { |
|
247 fprintf( stderr, "PG: error occured while reading from stdin.\n" ); |
|
248 closesocket( sockfd ); |
|
249 pthread_exit( NULL ); |
|
250 } |
|
251 // fprintf( stderr, "PG: %d bytes outgoing\n", err ); |
|
252 |
|
253 // write it to the socket |
|
254 sendcount = send( sockfd, &c, 1, 0 ); |
|
255 if( sendcount != 1 ) { |
|
256 fprintf( stderr, "PG: error occured while writing to the socket.\n" ); |
|
257 closesocket( sockfd ); |
|
258 pthread_exit( NULL ); |
|
259 } |
|
260 } |
|
261 |
|
262 // done |
|
263 return NULL; |
|
264 } |
|
265 |
|
266 |
|
267 /******************************************************************************* |
|
268 * |
|
269 * closesocket |
|
270 * |
|
271 ******************************************************************************/ |
|
272 void closesocket( int sockfd ) |
|
273 { |
|
274 shutdown( sockfd, SHUT_RDWR ); |
|
275 close( sockfd ); |
|
276 } |
|
277 |
|
278 |
|
279 /******************************************************************************* |
|
280 * |
|
281 * do_client_server_protocol() |
|
282 * |
|
283 ******************************************************************************/ |
|
284 int do_client_server_protocol( int aMobsterDeviceID ) |
|
285 { |
|
286 char c; |
|
287 int len, expected_length, i, err; |
|
288 char idstr[MAXIDSTR]; |
|
289 char rpstr[MAXIDSTR]; |
|
290 |
|
291 // construct the client string for the csprotocol |
|
292 snprintf( idstr, MAXIDSTR, "ID=%d", aMobsterDeviceID ); |
|
293 len = strlen(idstr); |
|
294 idstr[len] = 0x0d; |
|
295 idstr[len+1] = 0; |
|
296 |
|
297 #ifdef SYSTEM_TEST_MP5 |
|
298 assert( !"TEST" ); |
|
299 #endif |
|
300 |
|
301 // send the string |
|
302 err = send( sockfd, idstr, len+1, 0 ); |
|
303 if( err != (len+1) ) { |
|
304 fprintf( stderr, "PG: failed to write id string, exiting.\n" ); |
|
305 return -1; |
|
306 } |
|
307 |
|
308 // construct the expected reply string to get the expected length |
|
309 snprintf( rpstr, MAXIDSTR, "SERVER(%d)", aMobsterDeviceID ); |
|
310 expected_length = strlen(rpstr); |
|
311 |
|
312 // now read until there |
|
313 for( i = 0; ; i++ ) { |
|
314 |
|
315 // read a byte |
|
316 err = recv( sockfd, &c, 1, 0 ); |
|
317 if( err == -1 ) { |
|
318 fprintf( stderr, "PG: failed to read reply string (%d, %d).\n", err, errno ); |
|
319 return -1; |
|
320 } |
|
321 |
|
322 // check for a mismatch |
|
323 if( c != rpstr[i] ) { |
|
324 fprintf( stderr, "PG: unexpected character from server.\n" ); |
|
325 return -1; |
|
326 } |
|
327 |
|
328 // see if we've matched all chars |
|
329 if( (i+1) == expected_length ) { |
|
330 break; |
|
331 } |
|
332 } |
|
333 |
|
334 // done - success |
|
335 return 0; |
|
336 } |