Mercurial > flash_v2
annotate packages/net/ppp/current/src/chat.c @ 1592:a9676dbe50b5
* src/chat.c: Script now returns success when it runs to completion
| author | nickg |
|---|---|
| date | Thu, 15 Apr 2004 15:51:54 +0000 |
| parents | e0d88dc6a92f |
| children | 5629b7c30ed2 |
| rev | line source |
|---|---|
| 1586 | 1 //========================================================================== |
| 2 // | |
| 3 // src/chat.c | |
| 4 // | |
| 5 // PPP CHAT scripting | |
| 6 // | |
| 7 //========================================================================== | |
| 8 //####ECOSGPLCOPYRIGHTBEGIN#### | |
| 9 // ------------------------------------------- | |
| 10 // This file is part of eCos, the Embedded Configurable Operating System. | |
| 11 // Copyright (C) 2003 eCosCentric Ltd. | |
| 12 // | |
| 13 // eCos is free software; you can redistribute it and/or modify it under | |
| 14 // the terms of the GNU General Public License as published by the Free | |
| 15 // Software Foundation; either version 2 or (at your option) any later version. | |
| 16 // | |
| 17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY | |
| 18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 19 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 20 // for more details. | |
| 21 // | |
| 22 // You should have received a copy of the GNU General Public License along | |
| 23 // with eCos; if not, write to the Free Software Foundation, Inc., | |
| 24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | |
| 25 // | |
| 26 // As a special exception, if other files instantiate templates or use macros | |
| 27 // or inline functions from this file, or you compile this file and link it | |
| 28 // with other works to produce a work based on this file, this file does not | |
| 29 // by itself cause the resulting work to be covered by the GNU General Public | |
| 30 // License. However the source code for this file must still be made available | |
| 31 // in accordance with section (3) of the GNU General Public License. | |
| 32 // | |
| 33 // This exception does not invalidate any other reasons why a work based on | |
| 34 // this file might be covered by the GNU General Public License. | |
| 35 // | |
| 36 // Alternative licenses for eCos may be arranged by contacting the | |
| 37 // copyright holder. | |
| 38 // ------------------------------------------- | |
| 39 //####ECOSGPLCOPYRIGHTEND#### | |
| 40 //========================================================================== | |
| 41 //#####DESCRIPTIONBEGIN#### | |
| 42 // | |
| 43 // Author(s): nickg | |
| 44 // Contributors: nickg | |
| 45 // Date: 2003-06-08 | |
| 46 // Purpose: Chat script handling | |
| 47 // Description: | |
| 48 // | |
| 49 //####DESCRIPTIONEND#### | |
| 50 // | |
| 51 //========================================================================== | |
| 52 | |
| 53 //===================================================================== | |
| 54 | |
| 55 #include <pkgconf/system.h> | |
| 56 #include <pkgconf/net.h> | |
| 57 #include <pkgconf/io_fileio.h> | |
| 58 | |
| 59 | |
| 60 #include <stdio.h> | |
| 61 #include <ctype.h> | |
| 62 #include <stdlib.h> | |
| 63 #include <string.h> | |
| 64 #include <errno.h> | |
| 65 | |
| 66 #include "cyg/ppp/syslog.h" | |
| 67 | |
| 68 #include <cyg/io/io.h> | |
| 69 #include <cyg/io/serial.h> | |
| 70 | |
| 71 #include <cyg/kernel/kapi.h> | |
| 72 | |
| 73 #include <cyg/ppp/ppp.h> | |
| 74 | |
| 75 //===================================================================== | |
| 76 | |
| 77 //#undef db_printf | |
| 78 //#define db_printf diag_printf | |
| 79 | |
| 80 //===================================================================== | |
| 81 // Expect return values | |
| 82 | |
| 83 #define CHAT_MATCH 0 | |
| 84 #define CHAT_ABORT 1 | |
| 85 #define CHAT_TIMEOUT 2 | |
| 86 #define CHAT_FAIL -1 | |
| 87 | |
| 88 //===================================================================== | |
| 89 // Configuration constants | |
| 90 | |
| 91 #define CHAT_MAX_ABORTS CYGNUM_PPP_CHAT_ABORTS_MAX | |
| 92 #define CHAT_ABORT_SIZE CYGNUM_PPP_CHAT_ABORTS_SIZE | |
| 93 | |
| 94 #define CHAT_STRING_LENGTH CYGNUM_PPP_CHAT_STRING_LENGTH | |
| 95 | |
| 96 //===================================================================== | |
| 97 // Local variables | |
| 98 | |
| 99 // Array of ABORT strings | |
| 100 static char cyg_ppp_chat_abort[CHAT_MAX_ABORTS][CHAT_ABORT_SIZE]; | |
| 101 static int cyg_ppp_chat_abort_count; | |
| 102 | |
| 103 // Response timeout | |
| 104 static int cyg_ppp_chat_timeout; | |
| 105 // timeout alarm | |
| 106 static cyg_alarm cyg_ppp_chat_alarm_obj; | |
| 107 static cyg_handle_t cyg_ppp_chat_alarm; | |
| 108 static cyg_handle_t cyg_ppp_chat_thread; | |
| 109 | |
| 110 // Handle on serial device | |
| 111 static cyg_io_handle_t cyg_ppp_chat_handle; | |
| 112 | |
| 113 // String buffers | |
| 114 static char cyg_ppp_chat_buffer[CHAT_STRING_LENGTH]; | |
| 115 static char cyg_ppp_chat_expect_buffer[CHAT_STRING_LENGTH]; | |
| 116 | |
| 117 //===================================================================== | |
| 118 // Timeout alarm function | |
| 119 // | |
| 120 // The alarm is set whenever we start looking for a match, if the alarm | |
| 121 // goes off before we find a match, then it kicks the thread out of any | |
| 122 // wait it is in. | |
| 123 | |
| 124 static void chat_alarm(cyg_handle_t alarm, cyg_addrword_t data) | |
| 125 { | |
| 126 db_printf("%s(%d)\n",__PRETTY_FUNCTION__,__LINE__); | |
| 127 cyg_thread_release( cyg_ppp_chat_thread ); | |
| 128 } | |
| 129 | |
| 130 //===================================================================== | |
| 131 // Match | |
| 132 // | |
| 133 // Looks for the supplied string in the input. Returns zero on timeout | |
| 134 // or other error, 1 if a match is found. | |
| 135 | |
| 136 static int cyg_ppp_chat_match( char *str ) | |
| 137 { | |
| 138 cyg_uint64 trigger = (cyg_ppp_chat_timeout * 100) + cyg_current_time(); | |
| 139 char *s = cyg_ppp_chat_buffer; | |
| 140 int matchlen = strlen(str); | |
| 141 int matched = 0; | |
| 142 int aborted = 0; | |
| 143 | |
| 144 db_printf("%s(%d) timeout %d trigger %d\n",__PRETTY_FUNCTION__,__LINE__, | |
| 145 cyg_ppp_chat_timeout,(long)trigger); | |
| 146 db_printf(" current time %d\n",(long)cyg_current_time()); | |
| 147 | |
| 148 if( matchlen == 0 ) | |
| 149 return 1; | |
| 150 | |
| 151 cyg_alarm_initialize( cyg_ppp_chat_alarm, | |
| 152 trigger, | |
| 153 0 ); | |
| 154 | |
| 155 while(!(matched || aborted)) | |
| 156 { | |
| 157 Cyg_ErrNo err; | |
| 158 char c; | |
| 159 cyg_uint32 len = 1; | |
| 160 int i; | |
| 161 | |
| 162 err = cyg_io_read( cyg_ppp_chat_handle, &c, &len ); | |
| 163 | |
| 164 if( err != 0 ) | |
| 165 { | |
| 166 db_printf("%s(%d) err %d\n",__PRETTY_FUNCTION__,__LINE__,err); | |
| 167 break; | |
| 168 } | |
| 169 | |
| 170 db_printf("%c",c); | |
| 171 | |
| 172 *s++ = c; | |
| 173 | |
| 174 // If we have enough characters to match the expect string, | |
| 175 // and the current character matches the last character of the | |
| 176 // expect string, then it is worth trying to compare the strings. | |
| 177 | |
| 178 if( s - cyg_ppp_chat_buffer >= matchlen && | |
| 179 c == str[matchlen - 1] && | |
| 180 strncmp( s - matchlen, str, matchlen ) == 0 ) | |
| 181 { | |
| 182 matched = 1; | |
| 183 break; | |
| 184 } | |
| 185 | |
| 186 for( i = 0 ; i < cyg_ppp_chat_abort_count; i++ ) | |
| 187 { | |
| 188 int abortlen = strlen( cyg_ppp_chat_abort[i] ); | |
| 189 | |
| 190 if( s - cyg_ppp_chat_buffer >= abortlen && | |
| 191 strncmp( s - abortlen, cyg_ppp_chat_abort[i], abortlen ) == 0 ) | |
| 192 { | |
| 193 syslog(LOG_ERR,"ABORT: %s\n",cyg_ppp_chat_abort[i]); | |
| 194 aborted = 1; | |
| 195 break; | |
| 196 } | |
| 197 } | |
| 198 | |
| 199 // If we have reached the end of the buffer, shuffle it down | |
| 200 // leaving the last matchlen characters in place. | |
| 201 if( s >= &cyg_ppp_chat_buffer[sizeof(cyg_ppp_chat_buffer)-1] ) | |
| 202 { | |
| 203 strncpy( cyg_ppp_chat_buffer, s-matchlen, matchlen ); | |
| 204 s = cyg_ppp_chat_buffer + matchlen; | |
| 205 } | |
| 206 } | |
| 207 | |
| 208 cyg_alarm_disable( cyg_ppp_chat_alarm ); | |
| 209 | |
| 210 return matched; | |
| 211 } | |
| 212 | |
| 213 //===================================================================== | |
| 214 // Send string | |
| 215 // | |
| 216 // Send the string to the remote end, dealing with any escapes or | |
| 217 // special values. We currently implement the "EOT" and "BREAK" | |
| 218 // strings (or would if the device drivers did), and just the \c | |
| 219 // escape sequence. | |
| 220 | |
| 221 static int cyg_ppp_chat_send( const char *s ) | |
| 222 { | |
| 223 cyg_bool crlf = true; | |
| 224 | |
| 225 db_printf("%s(%d) %s\n",__PRETTY_FUNCTION__,__LINE__,s); | |
| 226 | |
| 227 if( strcmp( s, "EOT" ) == 0 ) | |
| 228 { | |
| 229 s = "\x04"; | |
| 230 crlf = false; | |
| 231 } | |
| 232 else if( strcmp( s, "BREAK" ) == 0 ) | |
| 233 { | |
| 234 // cannot do this at present | |
| 235 } | |
| 236 | |
| 237 for( ; *s != 0 ; s++ ) | |
| 238 { | |
| 239 char c = *s; | |
| 240 cyg_uint32 one = 1; | |
| 241 | |
| 242 // Look for escape sequences and process them | |
| 243 if( c == '\\' ) | |
| 244 { | |
| 245 c = *++s; | |
| 246 | |
| 247 if( c == 0 ) | |
| 248 break; | |
| 249 | |
| 250 switch( c ) | |
| 251 { | |
| 252 case 'c': | |
| 253 crlf = false; | |
| 254 continue; | |
| 255 } | |
| 256 } | |
| 257 | |
| 258 cyg_io_write( cyg_ppp_chat_handle, &c, &one ); | |
| 259 } | |
| 260 | |
| 261 if( crlf ) | |
| 262 { | |
| 263 cyg_uint32 len = 2; | |
| 264 s = "\r\n"; | |
| 265 cyg_io_write( cyg_ppp_chat_handle, s, &len ); | |
| 266 } | |
| 267 | |
| 268 return 0; | |
| 269 } | |
| 270 | |
| 271 //===================================================================== | |
| 272 // find_sep | |
| 273 // | |
| 274 // Split the pointed-to string at the next '-' character. | |
| 275 | |
| 276 static char *find_sep( char **str ) | |
| 277 { | |
| 278 char *s = *str; | |
| 279 char *res = s; | |
| 280 | |
| 281 if( *s == 0 ) | |
| 282 return NULL; | |
| 283 | |
| 284 while( *s != 0 && *s != '-' ) | |
| 285 s++; | |
| 286 | |
| 287 if( *s == '-' ) | |
| 288 *s++ = 0; | |
| 289 | |
| 290 *str = s; | |
| 291 return res; | |
| 292 } | |
| 293 | |
| 294 | |
| 295 //===================================================================== | |
| 296 // expect processing | |
| 297 // | |
| 298 // Parse the expect string. The return value indicates what it is: a | |
| 299 // match string, an ABORT, a TIMEOUT or a failure. | |
| 300 | |
| 301 static int cyg_ppp_chat_expect( const char *str ) | |
| 302 { | |
| 303 char *expect; | |
| 304 char *reply; | |
| 305 char *s; | |
| 306 | |
| 307 db_printf("%s(%d) %s\n",__PRETTY_FUNCTION__,__LINE__,str); | |
| 308 | |
| 309 // Look for command strings | |
| 310 if( strcmp( str, "ABORT" ) == 0 ) | |
| 311 return CHAT_ABORT; | |
| 312 | |
| 313 if( strcmp( str, "TIMEOUT" ) == 0 ) | |
| 314 return CHAT_TIMEOUT; | |
| 315 | |
| 316 // Copy the string over to a writable buffer, so we can handle the | |
| 317 // sub-expect strings | |
| 318 strncpy( cyg_ppp_chat_expect_buffer, str, sizeof(cyg_ppp_chat_expect_buffer) ); | |
| 319 s = cyg_ppp_chat_expect_buffer; | |
| 320 | |
| 321 while(1) | |
| 322 { | |
| 323 // Split the string at the next '-' | |
| 324 expect = find_sep( &s ); | |
| 325 | |
| 326 // All done, it looks like we succeeded! | |
| 327 if( expect == NULL ) | |
| 328 return CHAT_MATCH; | |
| 329 | |
| 330 db_printf("%s(%d) expect %s\n",__PRETTY_FUNCTION__,__LINE__,expect); | |
| 331 | |
| 332 // Get and response string in case the match fails. | |
| 333 reply = find_sep( &s ); | |
| 334 | |
| 335 db_printf("%s(%d) reply %s\n",__PRETTY_FUNCTION__,__LINE__,reply); | |
| 336 | |
| 337 // Try a match. | |
| 338 if( cyg_ppp_chat_match( expect ) ) | |
| 339 return CHAT_MATCH; | |
| 340 | |
| 341 // The match failed. If there is no reply string, then the | |
| 342 // whole thing has failed. | |
| 343 if( reply == NULL ) | |
| 344 break; | |
| 345 | |
| 346 // Send the reply string an loop around to pick up the next | |
| 347 // expect string. | |
| 348 cyg_ppp_chat_send( reply ); | |
| 349 } | |
| 350 | |
| 351 return CHAT_FAIL; | |
| 352 } | |
| 353 | |
| 354 //===================================================================== | |
| 355 // Chat entry point | |
| 356 // | |
| 357 // This is the main CHAT entry point. It is given the name of a device | |
| 358 // plus a pointer to the expect script in argv format. The device | |
| 359 // should already have been set up to the correct baud rate, bits, | |
| 360 // parity, flow control etc. | |
| 361 | |
| 362 externC cyg_int32 cyg_ppp_chat( const char *devname, | |
| 363 const char *script[] ) | |
| 364 { | |
| 365 const char *s; | |
| 366 Cyg_ErrNo err; | |
|
1592
a9676dbe50b5
* src/chat.c: Script now returns success when it runs to completion
nickg
parents:
1586
diff
changeset
|
367 cyg_int32 result = 1; |
| 1586 | 368 |
| 369 cyg_ppp_chat_thread = cyg_thread_self(); | |
| 370 cyg_ppp_chat_abort_count = 0; | |
| 371 cyg_ppp_chat_timeout = 45; | |
| 372 | |
| 373 while ((err = cyg_io_lookup(devname, &cyg_ppp_chat_handle)) < 0) { | |
| 374 if (err != 0) | |
| 375 syslog(LOG_ERR, "Failed to open %s: %d", devname,err); | |
| 376 } | |
| 377 | |
| 378 // Set up timeout alarm. | |
| 379 cyg_alarm_create( cyg_real_time_clock(), | |
| 380 chat_alarm, | |
| 381 (cyg_addrword_t)0, | |
| 382 &cyg_ppp_chat_alarm, | |
| 383 &cyg_ppp_chat_alarm_obj); | |
| 384 | |
| 385 | |
| 386 // Now loop over script handling the elements in turn | |
|
1592
a9676dbe50b5
* src/chat.c: Script now returns success when it runs to completion
nickg
parents:
1586
diff
changeset
|
387 while( (s = *script++) != NULL ) |
| 1586 | 388 { |
| 389 int what = cyg_ppp_chat_expect( s ); | |
| 390 | |
| 391 db_printf("%s(%d) what %d\n",__PRETTY_FUNCTION__,__LINE__,what); | |
| 392 | |
| 393 if( what == CHAT_FAIL ) | |
| 394 { | |
|
1592
a9676dbe50b5
* src/chat.c: Script now returns success when it runs to completion
nickg
parents:
1586
diff
changeset
|
395 result = 0; |
| 1586 | 396 break; |
| 397 } | |
| 398 | |
| 399 if( (s = *script++) != NULL ) | |
| 400 { | |
| 401 if( what == CHAT_MATCH ) | |
| 402 cyg_ppp_chat_send( s ); | |
| 403 else switch( what ) | |
| 404 { | |
| 405 case CHAT_ABORT: | |
| 406 // An abort string, add it to the table. | |
| 407 if( cyg_ppp_chat_abort_count >= CHAT_MAX_ABORTS ) | |
| 408 { | |
| 409 syslog(LOG_ERR,"Too many ABORT strings\n"); | |
| 410 } | |
| 411 else if( strlen( s ) >= CHAT_ABORT_SIZE ) | |
| 412 syslog(LOG_ERR,"Abort string too long\n"); | |
| 413 else | |
| 414 { | |
| 415 strncpy( cyg_ppp_chat_abort[cyg_ppp_chat_abort_count++], | |
| 416 s, CHAT_ABORT_SIZE ); | |
| 417 } | |
| 418 break; | |
| 419 | |
| 420 case CHAT_TIMEOUT: | |
| 421 // A new timeout value | |
| 422 cyg_ppp_chat_timeout = atoi( s ); | |
| 423 db_printf("New timeout >%s< %d\n",s,cyg_ppp_chat_timeout); | |
| 424 break; | |
| 425 } | |
| 426 } | |
| 427 } | |
| 428 | |
|
1592
a9676dbe50b5
* src/chat.c: Script now returns success when it runs to completion
nickg
parents:
1586
diff
changeset
|
429 if (s==NULL) |
|
a9676dbe50b5
* src/chat.c: Script now returns success when it runs to completion
nickg
parents:
1586
diff
changeset
|
430 { |
|
a9676dbe50b5
* src/chat.c: Script now returns success when it runs to completion
nickg
parents:
1586
diff
changeset
|
431 // the script ran to completion |
|
a9676dbe50b5
* src/chat.c: Script now returns success when it runs to completion
nickg
parents:
1586
diff
changeset
|
432 result = 1; |
|
a9676dbe50b5
* src/chat.c: Script now returns success when it runs to completion
nickg
parents:
1586
diff
changeset
|
433 } |
|
a9676dbe50b5
* src/chat.c: Script now returns success when it runs to completion
nickg
parents:
1586
diff
changeset
|
434 |
| 1586 | 435 // Finally, wait for the serial device to drain |
| 436 { | |
| 437 cyg_uint32 zero = 0; | |
| 438 cyg_uint32 len = sizeof(zero); | |
| 439 | |
| 440 cyg_io_get_config( cyg_ppp_chat_handle, | |
| 441 CYG_IO_GET_CONFIG_SERIAL_OUTPUT_DRAIN, | |
| 442 &zero, &len); | |
| 443 | |
| 444 } | |
| 445 | |
|
1592
a9676dbe50b5
* src/chat.c: Script now returns success when it runs to completion
nickg
parents:
1586
diff
changeset
|
446 return result; |
| 1586 | 447 } |
| 448 | |
| 449 //===================================================================== | |
| 450 // End of chat.c | |
| 451 |
