├── android-sercd ├── Application.mk └── project │ ├── .classpath │ ├── .project │ ├── AndroidManifest.xml │ ├── jni │ ├── .cproject │ ├── .project │ ├── Android.mk │ ├── COPYING │ ├── android.c │ ├── android.h │ ├── sercd-jni.h │ ├── sercd.c │ ├── sercd.h │ ├── unix.c │ └── unix.h │ ├── res │ ├── drawable │ │ ├── icon.png │ │ ├── notification_icon_connected.png │ │ └── notification_icon_ready.png │ ├── values │ │ └── strings.xml │ └── xml │ │ └── preferences.xml │ └── src │ ├── android │ └── serialport │ │ └── SerialPortFinder.java │ └── gnu │ └── sercd │ ├── Sercd.java │ └── SercdService.java └── android-serialport-api └── project ├── AndroidManifest.xml ├── jni ├── Android.mk ├── Application.mk ├── SerialPort.c ├── SerialPort.h └── gen_SerialPort_h.sh ├── libs ├── armeabi-v7a │ └── libserial_port.so ├── armeabi │ └── libserial_port.so └── x86 │ └── libserial_port.so ├── res ├── drawable │ └── icon.png ├── layout │ ├── console.xml │ ├── loopback.xml │ ├── main.xml │ └── sending01010101.xml ├── values │ ├── baudrates.xml │ └── strings.xml └── xml │ └── serial_port_preferences.xml ├── run_emulator.sh └── src └── android_serialport_api ├── SerialPort.java ├── SerialPortFinder.java └── sample ├── Application.java ├── ConsoleActivity.java ├── LoopbackActivity.java ├── MainMenu.java ├── Sending01010101Activity.java ├── SerialPortActivity.java └── SerialPortPreferences.java /android-sercd/Application.mk: -------------------------------------------------------------------------------- 1 | APP_PROJECT_PATH := $(call my-dir)/project 2 | APP_MODULES := sercd 3 | -------------------------------------------------------------------------------- /android-sercd/project/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android-sercd/project/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | android-sercd 4 | 5 | 6 | 7 | 8 | 9 | com.android.ide.eclipse.adt.ResourceManagerBuilder 10 | 11 | 12 | 13 | 14 | com.android.ide.eclipse.adt.PreCompilerBuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.jdt.core.javabuilder 20 | 21 | 22 | 23 | 24 | com.android.ide.eclipse.adt.ApkBuilder 25 | 26 | 27 | 28 | 29 | 30 | com.android.ide.eclipse.adt.AndroidNature 31 | org.eclipse.jdt.core.javanature 32 | 33 | 34 | -------------------------------------------------------------------------------- /android-sercd/project/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /android-sercd/project/jni/.cproject: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 28 | 31 | 32 | 33 | 34 | 37 | 40 | 41 | 42 | 43 | 46 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 329 | 332 | 333 | 334 | 335 | 338 | 341 | 342 | 343 | 344 | 347 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | -------------------------------------------------------------------------------- /android-sercd/project/jni/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | android-sercd-jni 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.cdt.managedbuilder.core.genmakebuilder 10 | auto,full,incremental, 11 | 12 | 13 | ?name? 14 | 15 | 16 | 17 | org.eclipse.cdt.make.core.append_environment 18 | true 19 | 20 | 21 | org.eclipse.cdt.make.core.autoBuildTarget 22 | APP=android-sercd 23 | 24 | 25 | org.eclipse.cdt.make.core.buildArguments 26 | 27 | 28 | 29 | org.eclipse.cdt.make.core.buildCommand 30 | make 31 | 32 | 33 | org.eclipse.cdt.make.core.buildLocation 34 | ${ANDROID_NDK_ROOT} 35 | 36 | 37 | org.eclipse.cdt.make.core.cleanBuildTarget 38 | clean 39 | 40 | 41 | org.eclipse.cdt.make.core.contents 42 | org.eclipse.cdt.make.core.activeConfigSettings 43 | 44 | 45 | org.eclipse.cdt.make.core.enableAutoBuild 46 | true 47 | 48 | 49 | org.eclipse.cdt.make.core.enableCleanBuild 50 | false 51 | 52 | 53 | org.eclipse.cdt.make.core.enableFullBuild 54 | true 55 | 56 | 57 | org.eclipse.cdt.make.core.fullBuildTarget 58 | APP=android-sercd 59 | 60 | 61 | org.eclipse.cdt.make.core.stopOnError 62 | true 63 | 64 | 65 | org.eclipse.cdt.make.core.useDefaultBuildCmd 66 | true 67 | 68 | 69 | 70 | 71 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder 72 | 73 | 74 | 75 | 76 | 77 | org.eclipse.cdt.core.cnature 78 | org.eclipse.cdt.managedbuilder.core.managedBuildNature 79 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature 80 | 81 | 82 | -------------------------------------------------------------------------------- /android-sercd/project/jni/Android.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2009 Cedric Priscal 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | LOCAL_PATH := $(call my-dir) 18 | 19 | include $(CLEAR_VARS) 20 | 21 | TARGET_PLATFORM := android-3 22 | LOCAL_MODULE := sercd 23 | LOCAL_SRC_FILES := sercd.c android.c unix.c 24 | LOCAL_CFLAGS := -DVERSION=\"3.0.0\" 25 | LOCAL_LDLIBS := -llog 26 | 27 | include $(BUILD_SHARED_LIBRARY) 28 | -------------------------------------------------------------------------------- /android-sercd/project/jni/COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 675 Mass Ave, Cambridge, MA 02139, USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | Appendix: How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 19yy 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) 19yy name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Library General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /android-sercd/project/jni/android.c: -------------------------------------------------------------------------------- 1 | /* 2 | sercd: RFC 2217 compliant serial port redirector 3 | Copyright 2003-2008 Peter Åstrand for Cendio AB 4 | Copyright (C) 1999 - 2003 InfoTecna s.r.l. 5 | Copyright (C) 2001, 2002 Trustees of Columbia University 6 | in the City of New York 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program; if not, write to the Free Software 20 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 | */ 22 | 23 | #ifdef ANDROID 24 | 25 | #include "android.h" 26 | #include 27 | 28 | static jobject ConvertToJava(JNIEnv *env, ProxyState newstate) 29 | { 30 | 31 | jclass class = (*env)->FindClass(env, "gnu.sercd.SercdService$ProxyState"); 32 | 33 | const char *name; 34 | switch(newstate) 35 | { 36 | case STATE_READY: name = "STATE_READY"; break; 37 | case STATE_CONNECTED: name = "STATE_CONNECTED"; break; 38 | case STATE_PORT_OPENED: name = "STATE_PORT_OPENED"; break; 39 | case STATE_STOPPED: name = "STATE_STOPPED"; break; 40 | case STATE_CRASHED: name = "STATE_CRASHED"; break; 41 | } 42 | 43 | jfieldID fieldid = (*env)->GetStaticFieldID( 44 | env, 45 | class, 46 | name, 47 | "Lgnu/sercd/SercdService$ProxyState;"); 48 | 49 | return (*env)->GetStaticObjectField( 50 | env, 51 | class, 52 | fieldid); 53 | } 54 | 55 | void ChangeState(JNIEnv *env, jobject thiz, ProxyState newstate) 56 | { 57 | 58 | jclass class = (*env)->GetObjectClass( 59 | env, 60 | thiz); 61 | 62 | jmethodID methodid = (*env)->GetMethodID( 63 | env, 64 | class, 65 | "ChangeState", 66 | "(Lgnu/sercd/SercdService$ProxyState;)V"); 67 | 68 | jvalue value; 69 | value.l = ConvertToJava( 70 | env, 71 | newstate); 72 | 73 | (*env)->CallVoidMethodA( 74 | env, 75 | thiz, 76 | methodid, 77 | &value); 78 | } 79 | 80 | #endif /* ANDROID */ 81 | -------------------------------------------------------------------------------- /android-sercd/project/jni/android.h: -------------------------------------------------------------------------------- 1 | /* 2 | sercd: RFC 2217 compliant serial port redirector 3 | Copyright 2003-2008 Peter Åstrand for Cendio AB 4 | Copyright (C) 1999 - 2003 InfoTecna s.r.l. 5 | Copyright (C) 2001, 2002 Trustees of Columbia University 6 | in the City of New York 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program; if not, write to the Free Software 20 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 | */ 22 | 23 | #ifndef _ANDROID_H_ 24 | #define _ANDROID_H_ 25 | #ifdef ANDROID 26 | 27 | #include 28 | 29 | #define exit(code) { \ 30 | char msg[64]; \ 31 | sprintf(msg, "Exiting at %d", __LINE__); \ 32 | LogMsg(LOG_ERR, msg); \ 33 | return code; \ 34 | } 35 | 36 | typedef enum { 37 | STATE_READY, STATE_CONNECTED, STATE_PORT_OPENED, STATE_STOPPED, STATE_CRASHED 38 | } ProxyState; 39 | 40 | void ChangeState(JNIEnv *env, jobject thiz, ProxyState newstate); 41 | 42 | #endif /* ANDROID */ 43 | #endif /* _ANDROID_H_ */ 44 | -------------------------------------------------------------------------------- /android-sercd/project/jni/sercd-jni.h: -------------------------------------------------------------------------------- 1 | /* DO NOT EDIT THIS FILE - it is machine generated */ 2 | #include 3 | /* Header for class gnu_sercd_SercdService */ 4 | 5 | #ifndef _Included_gnu_sercd_SercdService 6 | #define _Included_gnu_sercd_SercdService 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | /* 11 | * Class: gnu_sercd_SercdService 12 | * Method: main 13 | * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I 14 | */ 15 | JNIEXPORT jint JNICALL Java_gnu_sercd_SercdService_main 16 | (JNIEnv *, jobject, jstring, jstring, jstring); 17 | 18 | /* 19 | * Class: gnu_sercd_SercdService 20 | * Method: exit 21 | * Signature: ()V 22 | */ 23 | JNIEXPORT void JNICALL Java_gnu_sercd_SercdService_exit 24 | (JNIEnv *, jobject); 25 | 26 | #ifdef __cplusplus 27 | } 28 | #endif 29 | #endif 30 | /* Header for class gnu_sercd_SercdService_ProxyState */ 31 | 32 | #ifndef _Included_gnu_sercd_SercdService_ProxyState 33 | #define _Included_gnu_sercd_SercdService_ProxyState 34 | #ifdef __cplusplus 35 | extern "C" { 36 | #endif 37 | #ifdef __cplusplus 38 | } 39 | #endif 40 | #endif 41 | -------------------------------------------------------------------------------- /android-sercd/project/jni/sercd.c: -------------------------------------------------------------------------------- 1 | /* 2 | sercd: RFC 2217 compliant serial port redirector 3 | Copyright 2003-2008 Peter Åstrand for Cendio AB 4 | Copyright (C) 1999 - 2003 InfoTecna s.r.l. 5 | Copyright (C) 2001, 2002 Trustees of Columbia University 6 | in the City of New York 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program; if not, write to the Free Software 20 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 | 22 | Current design issues: 23 | 24 | . does not properly check implement BREAK handling. Need to figure 25 | out how to turn a BREAK on and then off based upon receipt of 26 | COM-PORT Subnegotiations 27 | 28 | . Lack of login processing 29 | 30 | . Lack of Telnet START_TLS to protect the data stream 31 | 32 | . Lack of Telnet AUTHENTICATION 33 | 34 | . LineState processing is not implemented 35 | 36 | . The code probably won't compile on most versions of Unix due to the 37 | highly platform dependent nature of the serial apis. 38 | 39 | */ 40 | 41 | /* Return NoError, which is 0, on success */ 42 | 43 | /* Standard library includes */ 44 | #include /* snprintf */ 45 | #include /* atoi */ 46 | #include /* strlen */ 47 | #include /* close */ 48 | #include /* errno */ 49 | #include /* CLOCKS_PER_SEC */ 50 | #include /* open */ 51 | #include /* assert */ 52 | #include "sercd.h" 53 | #include "unix.h" 54 | #ifndef ANDROID 55 | #include "win.h" 56 | #endif 57 | #ifdef ANDROID 58 | #include 59 | #include "android.h" 60 | #endif 61 | 62 | /* Buffer size */ 63 | #define BufferSize 2048 64 | 65 | /* Cisco IOS bug compatibility */ 66 | Boolean CiscoIOSCompatible = False; 67 | 68 | /* Log to stderr instead of syslog */ 69 | Boolean StdErrLogging = False; 70 | 71 | /* Buffer structure */ 72 | typedef struct 73 | { 74 | unsigned char Buffer[BufferSize]; 75 | unsigned int RdPos; 76 | unsigned int WrPos; 77 | } 78 | BufferType; 79 | 80 | #ifndef ANDROID 81 | /* Complete lock file pathname */ 82 | static char *LockFileName; 83 | #endif 84 | 85 | /* Complete device file pathname */ 86 | static char *DeviceName; 87 | 88 | /* Device file descriptor */ 89 | static PORTHANDLE *DeviceFd = NULL; 90 | 91 | /* Network sockets */ 92 | static SERCD_SOCKET *InSocketFd = NULL; 93 | static SERCD_SOCKET *OutSocketFd = NULL; 94 | 95 | /* Com Port Control enabled flag */ 96 | Boolean PortControlEnable = True; 97 | 98 | /* Maximum log level to log in the system log */ 99 | int MaxLogLevel = LOG_DEBUG + 1; 100 | 101 | /* Status enumeration for IAC escaping and interpretation */ 102 | typedef enum 103 | { IACNormal, IACReceived, IACComReceiving } 104 | IACState; 105 | 106 | /* Effective status for IAC escaping and interpretation */ 107 | static IACState IACEscape = IACNormal; 108 | 109 | /* Same as above during signature reception */ 110 | static IACState IACSigEscape; 111 | 112 | /* Current IAC command begin received */ 113 | static unsigned char IACCommand[TmpStrLen]; 114 | 115 | /* Position of insertion into IACCommand[] */ 116 | static size_t IACPos; 117 | 118 | /* Modem state mask set by the client */ 119 | static unsigned char ModemStateMask = ((unsigned char) 255); 120 | 121 | /* Line state mask set by the client */ 122 | static unsigned char LineStateMask = ((unsigned char) 0); 123 | 124 | #ifdef COMMENT 125 | /* Current status of the line control lines */ 126 | static unsigned char LineState = ((unsigned char) 0); 127 | #endif 128 | 129 | /* Current status of the modem control lines */ 130 | static unsigned char ModemState = ((unsigned char) 0); 131 | 132 | /* Break state flag */ 133 | Boolean BreakSignaled = False; 134 | 135 | /* Input flow control flag */ 136 | Boolean InputFlow = True; 137 | 138 | /* Telnet State Machine */ 139 | static struct _tnstate 140 | { 141 | int sent_will:1; 142 | int sent_do:1; 143 | int sent_wont:1; 144 | int sent_dont:1; 145 | int is_will:1; 146 | int is_do:1; 147 | } 148 | tnstate[256]; 149 | 150 | /* Function prototypes */ 151 | 152 | /* initialize Telnet State Machine */ 153 | void InitTelnetStateMachine(void); 154 | 155 | /* Initialize a buffer for operation */ 156 | void InitBuffer(BufferType * B); 157 | 158 | /* Check if the buffer is empty */ 159 | Boolean IsBufferEmpty(BufferType * B); 160 | 161 | /* Add a byte to a buffer */ 162 | void AddToBuffer(BufferType * B, unsigned char C); 163 | 164 | /* Get a byte from a buffer */ 165 | unsigned char GetFromBuffer(BufferType * B); 166 | 167 | /* Retrieves the port speed from PortFd */ 168 | unsigned long int GetPortSpeed(PORTHANDLE PortFd); 169 | 170 | /* Retrieves the data size from PortFd */ 171 | unsigned char GetPortDataSize(PORTHANDLE PortFd); 172 | 173 | /* Retrieves the parity settings from PortFd */ 174 | unsigned char GetPortParity(PORTHANDLE PortFd); 175 | 176 | /* Retrieves the stop bits size from PortFd */ 177 | unsigned char GetPortStopSize(PORTHANDLE PortFd); 178 | 179 | /* Retrieves the flow control status, including DTR and RTS status, 180 | from PortFd */ 181 | unsigned char GetPortFlowControl(PORTHANDLE PortFd, unsigned char Which); 182 | 183 | /* Return the status of the modem control lines (DCD, CTS, DSR, RNG) */ 184 | unsigned char GetModemState(PORTHANDLE PortFd, unsigned char PMState); 185 | 186 | /* Set the serial port data size */ 187 | void SetPortDataSize(PORTHANDLE PortFd, unsigned char DataSize); 188 | 189 | /* Set the serial port parity */ 190 | void SetPortParity(PORTHANDLE PortFd, unsigned char Parity); 191 | 192 | /* Set the serial port stop bits size */ 193 | void SetPortStopSize(PORTHANDLE PortFd, unsigned char StopSize); 194 | 195 | /* Set the port flow control and DTR and RTS status */ 196 | void SetPortFlowControl(PORTHANDLE PortFd, unsigned char How); 197 | 198 | /* Set the serial port speed */ 199 | void SetPortSpeed(PORTHANDLE PortFd, unsigned long BaudRate); 200 | 201 | /* Serial port break */ 202 | void SetBreak(PORTHANDLE PortFd, Boolean on); 203 | 204 | /* Flush serial port */ 205 | void SetFlush(PORTHANDLE PortFd, int selector); 206 | 207 | /* Init platform subsystems, such as the syslog */ 208 | void PlatformInit(); 209 | 210 | /* Initialize port */ 211 | #ifndef ANDROID 212 | int OpenPort(const char *DeviceName, const char *LockFileName, PORTHANDLE * PortFd); 213 | #else 214 | int OpenPort(const char *DeviceName, PORTHANDLE * PortFd); 215 | #endif 216 | 217 | /* Close and uninit port */ 218 | #ifndef ANDROID 219 | void ClosePort(PORTHANDLE PortFd, const char *LockFileName); 220 | #else 221 | void ClosePort(PORTHANDLE PortFd); 222 | #endif 223 | 224 | /* Send the signature Sig to the client */ 225 | void SendSignature(BufferType * B, char *Sig); 226 | 227 | /* Write a char to SockFd performing IAC escaping */ 228 | void EscWriteChar(BufferType * B, unsigned char C); 229 | 230 | /* Redirect char C to PortFd checking for IAC escape sequences */ 231 | void EscRedirectChar(BufferType * SockB, BufferType * DevB, PORTHANDLE PortFd, unsigned char C); 232 | 233 | /* Send the specific telnet option to SockFd using Command as command */ 234 | void SendTelnetOption(BufferType * B, unsigned char Command, char Option); 235 | 236 | /* Send a string to SockFd performing IAC escaping */ 237 | void SendStr(BufferType * B, char *Str); 238 | 239 | /* Send the baud rate BR to SockFd */ 240 | void SendBaudRate(BufferType * B, unsigned long int BR); 241 | 242 | /* Send the CPC command Command using Parm as parameter */ 243 | void SendCPCByteCommand(BufferType * B, unsigned char Command, unsigned char Parm); 244 | 245 | /* Handling of COM Port Control specific commands */ 246 | void HandleCPCCommand(BufferType * B, PORTHANDLE PortFd, unsigned char *Command, size_t CSize); 247 | 248 | /* Common telnet IAC commands handling */ 249 | void HandleIACCommand(BufferType * B, PORTHANDLE PortFd, unsigned char *Command, size_t CSize); 250 | 251 | /* Write a buffer to SockFd with IAC escaping */ 252 | void EscWriteBuffer(BufferType * B, unsigned char *Buffer, unsigned int BSize); 253 | 254 | /* initialize Telnet State Machine */ 255 | void 256 | InitTelnetStateMachine(void) 257 | { 258 | int i; 259 | for (i = 0; i < 256; i++) { 260 | tnstate[i].sent_do = 0; 261 | tnstate[i].sent_will = 0; 262 | tnstate[i].sent_wont = 0; 263 | tnstate[i].sent_dont = 0; 264 | tnstate[i].is_do = 0; 265 | tnstate[i].is_will = 0; 266 | } 267 | } 268 | 269 | /* Setup sockets for low latency and automatic keepalive; doesn't 270 | * check if anything fails because failure doesn't prevent correct 271 | * functioning but only provides slightly worse behaviour 272 | */ 273 | void 274 | SetSocketOptions(SERCD_SOCKET insocket, SERCD_SOCKET outsocket) 275 | { 276 | /* Socket setup flag */ 277 | int SockParmEnable = 1; 278 | 279 | setsockopt(insocket, SOL_SOCKET, SO_KEEPALIVE, (char *) &SockParmEnable, 280 | sizeof(SockParmEnable)); 281 | setsockopt(insocket, SOL_SOCKET, SO_OOBINLINE, (char *) &SockParmEnable, 282 | sizeof(SockParmEnable)); 283 | setsockopt(outsocket, SOL_SOCKET, SO_KEEPALIVE, (char *) &SockParmEnable, 284 | sizeof(SockParmEnable)); 285 | #ifndef WIN32 286 | /* Generic socket parameter */ 287 | int SockParm; 288 | 289 | SockParm = IPTOS_LOWDELAY; 290 | setsockopt(insocket, SOL_IP, IP_TOS, &SockParm, sizeof(SockParm)); 291 | setsockopt(outsocket, SOL_IP, IP_TOS, &SockParm, sizeof(SockParm)); 292 | 293 | /* Make reads/writes non-blocking. In principle, non-blocking IO 294 | is not necessary, since we are using select. However, the Linux 295 | select man page BUGS section contains: "Under Linux, select() 296 | may report a socket file descriptor as "ready for reading", 297 | while nevertheless a subsequent read blocks." Besides, we need 298 | to use non-blocking for the serial port anyway, and using 299 | non-blocking means that we don't need to check the send buffer 300 | size. */ 301 | ioctl(outsocket, FIONBIO, &SockParmEnable); 302 | ioctl(insocket, FIONBIO, &SockParmEnable); 303 | #endif 304 | } 305 | 306 | /* Initialize a buffer for operation */ 307 | void 308 | InitBuffer(BufferType * B) 309 | { 310 | /* Set the initial buffer positions */ 311 | B->RdPos = 0; 312 | B->WrPos = 0; 313 | } 314 | 315 | 316 | /* Return the length of the data in the buffer */ 317 | unsigned int 318 | BufferLength(BufferType * B) 319 | { 320 | return (B->WrPos - B->RdPos + BufferSize) % BufferSize; 321 | } 322 | 323 | /* Return how much room is left */ 324 | unsigned int 325 | BufferRoomLeft(BufferType * B) 326 | { 327 | /* -1 is for full/empty distinction */ 328 | return BufferSize - 1 - BufferLength(B); 329 | } 330 | 331 | /* Check if there's room for a number of additional bytes */ 332 | Boolean 333 | BufferHasRoomFor(BufferType * B, unsigned int x) 334 | { 335 | return BufferRoomLeft(B) >= x; 336 | } 337 | 338 | /* Check if the buffer is empty */ 339 | Boolean 340 | IsBufferEmpty(BufferType * B) 341 | { 342 | return BufferLength(B) == 0; 343 | } 344 | 345 | /* Add a byte to a buffer. */ 346 | void 347 | AddToBuffer(BufferType * B, unsigned char C) 348 | { 349 | assert(BufferHasRoomFor(B, 1)); 350 | 351 | B->Buffer[B->WrPos] = C; 352 | B->WrPos = (B->WrPos + 1) % BufferSize; 353 | } 354 | 355 | /* Get a byte from a buffer */ 356 | unsigned char 357 | GetFromBuffer(BufferType * B) 358 | { 359 | unsigned char C = B->Buffer[B->RdPos]; 360 | B->RdPos = (B->RdPos + 1) % BufferSize; 361 | return (C); 362 | } 363 | 364 | /* Get string from buffer, without removing it. Returns the length of 365 | the string. */ 366 | unsigned char * 367 | GetBufferString(BufferType * B, unsigned int *len) 368 | { 369 | if (B->RdPos <= B->WrPos) 370 | *len = B->WrPos - B->RdPos; 371 | else 372 | *len = BufferSize - B->RdPos; 373 | 374 | return &(B->Buffer[B->RdPos]); 375 | } 376 | 377 | /* Remove the number of read bytes specified */ 378 | void 379 | BufferPopBytes(BufferType * B, unsigned int len) 380 | { 381 | B->RdPos += len; 382 | B->RdPos %= BufferSize; 383 | } 384 | 385 | /* Function executed when the program exits */ 386 | void 387 | ExitFunction(void) 388 | { 389 | #ifndef ANDROID 390 | DropConnection(DeviceFd, InSocketFd, OutSocketFd, LockFileName); 391 | #else 392 | DropConnection(DeviceFd, InSocketFd, OutSocketFd); 393 | #endif 394 | 395 | /* Program termination notification */ 396 | LogMsg(LOG_NOTICE, "sercd stopped."); 397 | } 398 | 399 | #ifndef ANDROID 400 | /* Function called on break signal */ 401 | /* Unimplemented yet */ 402 | void 403 | BreakFunction(int unused) 404 | { 405 | #ifndef COMMENT 406 | /* Just to avoid compilation warnings */ 407 | /* There's no performance penalty in doing this 408 | because this function is almost never called */ 409 | unused = unused; 410 | 411 | /* ExitFunction will be called through atexit */ 412 | exit(NoError); 413 | #else /* COMMENT */ 414 | 415 | unsigned char LineState; 416 | 417 | if (BreakSignaled == True) { 418 | BreakSignaled = False; 419 | LineState = 0; 420 | } 421 | else { 422 | BreakSignaled = True; 423 | LineState = 16; 424 | } 425 | 426 | /* Notify client of break change */ 427 | if ((LineStateMask & (unsigned char) 16) != 0) { 428 | LogMsg(LOG_DEBUG, "Notifying break change."); 429 | SendCPCByteCommand(&ToNetBuf, TNASC_NOTIFY_LINESTATE, LineState); 430 | } 431 | #endif /* COMMENT */ 432 | } 433 | #endif 434 | 435 | /* Send the signature Sig to the client. Sig must not be longer than 436 | 255 characters. */ 437 | #define SendSignature_bytes (6 + 2 * 255) 438 | void 439 | SendSignature(BufferType * B, char *Sig) 440 | { 441 | assert(strlen(Sig) <= 255); 442 | AddToBuffer(B, TNIAC); 443 | AddToBuffer(B, TNSB); 444 | AddToBuffer(B, TNCOM_PORT_OPTION); 445 | AddToBuffer(B, TNASC_SIGNATURE); 446 | SendStr(B, Sig); 447 | AddToBuffer(B, TNIAC); 448 | AddToBuffer(B, TNSE); 449 | } 450 | 451 | /* Write a char to socket performing IAC escaping */ 452 | #define EscWriteChar_bytes 2 453 | void 454 | EscWriteChar(BufferType * B, unsigned char C) 455 | { 456 | /* Last received byte */ 457 | static unsigned char Last = 0; 458 | 459 | if (C == TNIAC) 460 | AddToBuffer(B, C); 461 | else if (C != 0x0A && !tnstate[TN_TRANSMIT_BINARY].is_will && Last == 0x0D) 462 | AddToBuffer(B, 0x00); 463 | AddToBuffer(B, C); 464 | 465 | /* Set last received byte */ 466 | Last = C; 467 | } 468 | 469 | /* Redirect char C to Device checking for IAC escape sequences */ 470 | #define EscRedirectChar_bytes_SockB HandleIACCommand_bytes 471 | #define EscRedirectChar_bytes_DevB 1 472 | void 473 | EscRedirectChar(BufferType * SockB, BufferType * DevB, PORTHANDLE PortFd, unsigned char C) 474 | { 475 | /* Last received byte */ 476 | static unsigned char Last = 0; 477 | 478 | /* Check the IAC escape status */ 479 | switch (IACEscape) { 480 | /* Normal status */ 481 | case IACNormal: 482 | if (C == TNIAC) 483 | IACEscape = IACReceived; 484 | else if (!tnstate[TN_TRANSMIT_BINARY].is_do && C == 0x00 && Last == 0x0D) 485 | /* Swallow the NUL after a CR if not receiving BINARY */ 486 | break; 487 | else 488 | AddToBuffer(DevB, C); 489 | break; 490 | 491 | /* IAC previously received */ 492 | case IACReceived: 493 | if (C == TNIAC) { 494 | AddToBuffer(DevB, C); 495 | IACEscape = IACNormal; 496 | } 497 | else { 498 | IACCommand[0] = TNIAC; 499 | IACCommand[1] = C; 500 | IACPos = 2; 501 | IACEscape = IACComReceiving; 502 | IACSigEscape = IACNormal; 503 | } 504 | break; 505 | 506 | /* IAC Command reception */ 507 | case IACComReceiving: 508 | /* Telnet suboption, could be only CPC */ 509 | if (IACCommand[1] == TNSB) { 510 | /* Get the suboption signature */ 511 | if (IACPos < 4) { 512 | IACCommand[IACPos] = C; 513 | IACPos++; 514 | } 515 | else { 516 | /* Check which suboption we are dealing with */ 517 | switch (IACCommand[3]) { 518 | /* Signature, which needs further escaping */ 519 | case TNCAS_SIGNATURE: 520 | switch (IACSigEscape) { 521 | case IACNormal: 522 | if (C == TNIAC) 523 | IACSigEscape = IACReceived; 524 | else if (IACPos < sizeof(IACCommand)) { 525 | IACCommand[IACPos] = C; 526 | IACPos++; 527 | } 528 | break; 529 | 530 | case IACComReceiving: 531 | IACSigEscape = IACNormal; 532 | break; 533 | 534 | case IACReceived: 535 | if (C == TNIAC) { 536 | if (IACPos < sizeof(IACCommand)) { 537 | IACCommand[IACPos] = C; 538 | IACPos++; 539 | } 540 | IACSigEscape = IACNormal; 541 | } 542 | else { 543 | if (IACPos < sizeof(IACCommand)) { 544 | IACCommand[IACPos] = TNIAC; 545 | IACPos++; 546 | } 547 | 548 | if (IACPos < sizeof(IACCommand)) { 549 | IACCommand[IACPos] = C; 550 | IACPos++; 551 | } 552 | 553 | HandleIACCommand(SockB, PortFd, IACCommand, IACPos); 554 | IACEscape = IACNormal; 555 | } 556 | break; 557 | } 558 | break; 559 | 560 | /* Set baudrate */ 561 | case TNCAS_SET_BAUDRATE: 562 | IACCommand[IACPos] = C; 563 | IACPos++; 564 | 565 | if (IACPos == 10) { 566 | HandleIACCommand(SockB, PortFd, IACCommand, IACPos); 567 | IACEscape = IACNormal; 568 | } 569 | break; 570 | 571 | /* Flow control command */ 572 | case TNCAS_FLOWCONTROL_SUSPEND: 573 | case TNCAS_FLOWCONTROL_RESUME: 574 | IACCommand[IACPos] = C; 575 | IACPos++; 576 | 577 | if (IACPos == 6) { 578 | HandleIACCommand(SockB, PortFd, IACCommand, IACPos); 579 | IACEscape = IACNormal; 580 | } 581 | break; 582 | 583 | /* Normal CPC command with single byte parameter */ 584 | default: 585 | IACCommand[IACPos] = C; 586 | IACPos++; 587 | 588 | if (IACPos == 7) { 589 | HandleIACCommand(SockB, PortFd, IACCommand, IACPos); 590 | IACEscape = IACNormal; 591 | } 592 | break; 593 | } 594 | } 595 | } 596 | else { 597 | /* Normal 3 byte IAC option */ 598 | IACCommand[IACPos] = C; 599 | IACPos++; 600 | 601 | if (IACPos == 3) { 602 | HandleIACCommand(SockB, PortFd, IACCommand, IACPos); 603 | IACEscape = IACNormal; 604 | } 605 | } 606 | break; 607 | } 608 | 609 | /* Set last received byte */ 610 | Last = C; 611 | } 612 | 613 | /* Send the specific telnet option to SockFd using Command as command */ 614 | #define SendTelnetOption_bytes 3 615 | void 616 | SendTelnetOption(BufferType * B, unsigned char Command, char Option) 617 | { 618 | unsigned char IAC = TNIAC; 619 | 620 | AddToBuffer(B, IAC); 621 | AddToBuffer(B, Command); 622 | AddToBuffer(B, Option); 623 | } 624 | 625 | /* Send initial Telnet negotiations to the client */ 626 | #define SendTelnetInitialOptions_bytes (SendTelnetOption_bytes*3) 627 | void 628 | SendTelnetInitialOptions(BufferType * B) 629 | { 630 | SendTelnetOption(B, TNWILL, TN_TRANSMIT_BINARY); 631 | tnstate[TN_TRANSMIT_BINARY].sent_will = 1; 632 | SendTelnetOption(B, TNDO, TN_TRANSMIT_BINARY); 633 | tnstate[TN_TRANSMIT_BINARY].sent_do = 1; 634 | SendTelnetOption(B, TNWILL, TN_ECHO); 635 | tnstate[TN_ECHO].sent_will = 1; 636 | SendTelnetOption(B, TNWILL, TN_SUPPRESS_GO_AHEAD); 637 | tnstate[TN_SUPPRESS_GO_AHEAD].sent_will = 1; 638 | SendTelnetOption(B, TNDO, TN_SUPPRESS_GO_AHEAD); 639 | tnstate[TN_SUPPRESS_GO_AHEAD].sent_do = 1; 640 | SendTelnetOption(B, TNDO, TNCOM_PORT_OPTION); 641 | tnstate[TNCOM_PORT_OPTION].sent_do = 1; 642 | } 643 | 644 | /* Send a string to SockFd performing IAC escaping 645 | Max buffer fill: 2*len(Str) */ 646 | void 647 | SendStr(BufferType * B, char *Str) 648 | { 649 | size_t I; 650 | size_t L; 651 | 652 | L = strlen(Str); 653 | 654 | for (I = 0; I < L; I++) 655 | EscWriteChar(B, (unsigned char) Str[I]); 656 | } 657 | 658 | /* Send the baud rate BR to Buffer */ 659 | #define SendBaudRate_bytes (6 + 2*sizeof(unsigned long int)) 660 | void 661 | SendBaudRate(BufferType * B, unsigned long int BR) 662 | { 663 | unsigned char *p; 664 | unsigned long int NBR; 665 | int i; 666 | 667 | NBR = htonl(BR); 668 | 669 | AddToBuffer(B, TNIAC); 670 | AddToBuffer(B, TNSB); 671 | AddToBuffer(B, TNCOM_PORT_OPTION); 672 | AddToBuffer(B, TNASC_SET_BAUDRATE); 673 | p = (unsigned char *) &NBR; 674 | for (i = 0; i < (int) sizeof(NBR); i++) 675 | EscWriteChar(B, p[i]); 676 | AddToBuffer(B, TNIAC); 677 | AddToBuffer(B, TNSE); 678 | } 679 | 680 | /* Send the CPC command Command using Parm as parameter */ 681 | #define SendCPCByteCommand_bytes 8 682 | void 683 | SendCPCByteCommand(BufferType * B, unsigned char Command, unsigned char Parm) 684 | { 685 | AddToBuffer(B, TNIAC); 686 | AddToBuffer(B, TNSB); 687 | AddToBuffer(B, TNCOM_PORT_OPTION); 688 | AddToBuffer(B, Command); 689 | EscWriteChar(B, Parm); 690 | AddToBuffer(B, TNIAC); 691 | AddToBuffer(B, TNSE); 692 | } 693 | 694 | /* Handling of COM Port Control specific commands */ 695 | #define HandleCPCCommand_bytes \ 696 | MAX(SendSignature_bytes, MAX(SendBaudRate_bytes, SendCPCByteCommand_bytes)) 697 | void 698 | HandleCPCCommand(BufferType * SockB, PORTHANDLE PortFd, unsigned char *Command, size_t CSize) 699 | { 700 | char LogStr[TmpStrLen]; 701 | char SigStr[255]; 702 | unsigned long int BaudRate; 703 | unsigned char DataSize; 704 | unsigned char Parity; 705 | unsigned char StopSize; 706 | unsigned char FlowControl; 707 | 708 | /* Check wich command has been requested */ 709 | switch (Command[3]) { 710 | /* Signature */ 711 | case TNCAS_SIGNATURE: 712 | if (CSize == 6) { 713 | /* Void signature, client is asking for our signature */ 714 | snprintf(SigStr, sizeof(SigStr), "sercd %s %s", VERSION, DeviceName); 715 | LogStr[sizeof(SigStr) - 1] = '\0'; 716 | SendSignature(SockB, SigStr); 717 | snprintf(LogStr, sizeof(LogStr), "Sent signature: %s", SigStr); 718 | LogStr[sizeof(LogStr) - 1] = '\0'; 719 | LogMsg(LOG_INFO, LogStr); 720 | } 721 | else { 722 | /* Received client signature */ 723 | strncpy(SigStr, (char *) &Command[4], MAX(CSize - 6, sizeof(SigStr) - 1)); 724 | snprintf(LogStr, sizeof(LogStr) - 1, "Received client signature: %s", SigStr); 725 | LogStr[sizeof(LogStr) - 1] = '\0'; 726 | LogMsg(LOG_INFO, LogStr); 727 | } 728 | break; 729 | 730 | /* Set serial baud rate */ 731 | case TNCAS_SET_BAUDRATE: 732 | /* Retrieve the baud rate which is in network order */ 733 | BaudRate = ntohl(*((unsigned long int *) &Command[4])); 734 | 735 | if (BaudRate == 0) 736 | /* Client is asking for current baud rate */ 737 | LogMsg(LOG_DEBUG, "Baud rate notification received."); 738 | else { 739 | /* Change the baud rate */ 740 | snprintf(LogStr, sizeof(LogStr), "Port baud rate change to %lu requested.", BaudRate); 741 | LogStr[sizeof(LogStr) - 1] = '\0'; 742 | LogMsg(LOG_DEBUG, LogStr); 743 | SetPortSpeed(PortFd, BaudRate); 744 | } 745 | 746 | /* Send confirmation */ 747 | BaudRate = GetPortSpeed(PortFd); 748 | SendBaudRate(SockB, BaudRate); 749 | snprintf(LogStr, sizeof(LogStr), "Port baud rate: %lu", BaudRate); 750 | LogStr[sizeof(LogStr) - 1] = '\0'; 751 | LogMsg(LOG_DEBUG, LogStr); 752 | break; 753 | 754 | /* Set serial data size */ 755 | case TNCAS_SET_DATASIZE: 756 | if (Command[4] == 0) 757 | /* Client is asking for current data size */ 758 | LogMsg(LOG_DEBUG, "Data size notification requested."); 759 | else { 760 | /* Set the data size */ 761 | snprintf(LogStr, sizeof(LogStr), 762 | "Port data size change to %u requested.", (unsigned int) Command[4]); 763 | LogStr[sizeof(LogStr) - 1] = '\0'; 764 | LogMsg(LOG_DEBUG, LogStr); 765 | SetPortDataSize(PortFd, Command[4]); 766 | } 767 | 768 | /* Send confirmation */ 769 | DataSize = GetPortDataSize(PortFd); 770 | SendCPCByteCommand(SockB, TNASC_SET_DATASIZE, DataSize); 771 | snprintf(LogStr, sizeof(LogStr), "Port data size: %u", (unsigned int) DataSize); 772 | LogStr[sizeof(LogStr) - 1] = '\0'; 773 | LogMsg(LOG_DEBUG, LogStr); 774 | break; 775 | 776 | /* Set the serial parity */ 777 | case TNCAS_SET_PARITY: 778 | if (Command[4] == 0) 779 | /* Client is asking for current parity */ 780 | LogMsg(LOG_DEBUG, "Parity notification requested."); 781 | else { 782 | /* Set the parity */ 783 | snprintf(LogStr, sizeof(LogStr), 784 | "Port parity change to %u requested", (unsigned int) Command[4]); 785 | LogStr[sizeof(LogStr) - 1] = '\0'; 786 | LogMsg(LOG_DEBUG, LogStr); 787 | SetPortParity(PortFd, Command[4]); 788 | } 789 | 790 | /* Send confirmation */ 791 | Parity = GetPortParity(PortFd); 792 | SendCPCByteCommand(SockB, TNASC_SET_PARITY, Parity); 793 | snprintf(LogStr, sizeof(LogStr), "Port parity: %u", (unsigned int) Parity); 794 | LogStr[sizeof(LogStr) - 1] = '\0'; 795 | LogMsg(LOG_DEBUG, LogStr); 796 | break; 797 | 798 | /* Set the serial stop size */ 799 | case TNCAS_SET_STOPSIZE: 800 | if (Command[4] == 0) 801 | /* Client is asking for current stop size */ 802 | LogMsg(LOG_DEBUG, "Stop size notification requested."); 803 | else { 804 | /* Set the stop size */ 805 | snprintf(LogStr, sizeof(LogStr), 806 | "Port stop size change to %u requested.", (unsigned int) Command[4]); 807 | LogStr[sizeof(LogStr) - 1] = '\0'; 808 | LogMsg(LOG_DEBUG, LogStr); 809 | SetPortStopSize(PortFd, Command[4]); 810 | } 811 | 812 | /* Send confirmation */ 813 | StopSize = GetPortStopSize(PortFd); 814 | SendCPCByteCommand(SockB, TNASC_SET_STOPSIZE, StopSize); 815 | snprintf(LogStr, sizeof(LogStr), "Port stop size: %u", (unsigned int) StopSize); 816 | LogStr[sizeof(LogStr) - 1] = '\0'; 817 | LogMsg(LOG_DEBUG, LogStr); 818 | break; 819 | 820 | /* Flow control and DTR/RTS handling */ 821 | case TNCAS_SET_CONTROL: 822 | switch (Command[4]) { 823 | case TNCOM_CMD_FLOW_REQ: 824 | case TNCOM_CMD_DTR_REQ: 825 | case TNCOM_CMD_RTS_REQ: 826 | case TNCOM_CMD_INFLOW_REQ: 827 | /* Client is asking for current flow control or DTR/RTS status */ 828 | LogMsg(LOG_DEBUG, "Flow control notification requested."); 829 | FlowControl = GetPortFlowControl(PortFd, Command[4]); 830 | SendCPCByteCommand(SockB, TNASC_SET_CONTROL, FlowControl); 831 | snprintf(LogStr, sizeof(LogStr), "Port flow control: %u", (unsigned int) FlowControl); 832 | LogStr[sizeof(LogStr) - 1] = '\0'; 833 | LogMsg(LOG_DEBUG, LogStr); 834 | break; 835 | 836 | case TNCOM_CMD_BREAK_REQ: 837 | if (BreakSignaled) { 838 | SendCPCByteCommand(SockB, TNASC_SET_CONTROL, TNCOM_CMD_BREAK_ON); 839 | } 840 | else { 841 | SendCPCByteCommand(SockB, TNASC_SET_CONTROL, TNCOM_CMD_BREAK_OFF); 842 | } 843 | break; 844 | 845 | case TNCOM_CMD_BREAK_ON: 846 | /* Break command */ 847 | SetBreak(PortFd, True); 848 | BreakSignaled = True; 849 | LogMsg(LOG_DEBUG, "Break Signal ON."); 850 | SendCPCByteCommand(SockB, TNASC_SET_CONTROL, TNCOM_CMD_BREAK_ON); 851 | break; 852 | 853 | case TNCOM_CMD_BREAK_OFF: 854 | SetBreak(PortFd, False); 855 | BreakSignaled = False; 856 | LogMsg(LOG_DEBUG, "Break Signal OFF."); 857 | SendCPCByteCommand(SockB, TNASC_SET_CONTROL, TNCOM_CMD_BREAK_OFF); 858 | break; 859 | 860 | default: 861 | /* Set the flow control */ 862 | snprintf(LogStr, sizeof(LogStr), 863 | "Port flow control change to %u requested.", (unsigned int) Command[4]); 864 | LogStr[sizeof(LogStr) - 1] = '\0'; 865 | LogMsg(LOG_DEBUG, LogStr); 866 | SetPortFlowControl(PortFd, Command[4]); 867 | 868 | /* Flow control status confirmation */ 869 | if (CiscoIOSCompatible && Command[4] >= TNCOM_CMD_INFLOW_REQ 870 | && Command[4] <= TNCOM_CMD_INFLOW_HARDWARE) 871 | /* INBOUND not supported separately. 872 | Following the behavior of Cisco ISO 11.3 873 | */ 874 | FlowControl = 0; 875 | else 876 | /* Return the actual port flow control settings */ 877 | FlowControl = GetPortFlowControl(PortFd, TNCOM_CMD_FLOW_REQ); 878 | 879 | SendCPCByteCommand(SockB, TNASC_SET_CONTROL, FlowControl); 880 | snprintf(LogStr, sizeof(LogStr), "Port flow control: %u", (unsigned int) FlowControl); 881 | LogStr[sizeof(LogStr) - 1] = '\0'; 882 | LogMsg(LOG_DEBUG, LogStr); 883 | break; 884 | } 885 | break; 886 | 887 | /* Set the line state mask */ 888 | case TNCAS_SET_LINESTATE_MASK: 889 | snprintf(LogStr, sizeof(LogStr), "Line state set to %u", (unsigned int) Command[4]); 890 | LogStr[sizeof(LogStr) - 1] = '\0'; 891 | LogMsg(LOG_DEBUG, LogStr); 892 | 893 | /* Only break notification supported */ 894 | LineStateMask = Command[4] & (unsigned char) 16; 895 | SendCPCByteCommand(SockB, TNASC_SET_LINESTATE_MASK, LineStateMask); 896 | break; 897 | 898 | /* Set the modem state mask */ 899 | case TNCAS_SET_MODEMSTATE_MASK: 900 | snprintf(LogStr, sizeof(LogStr), "Modem state mask set to %u", (unsigned int) Command[4]); 901 | LogStr[sizeof(LogStr) - 1] = '\0'; 902 | LogMsg(LOG_DEBUG, LogStr); 903 | ModemStateMask = Command[4]; 904 | SendCPCByteCommand(SockB, TNASC_SET_MODEMSTATE_MASK, ModemStateMask); 905 | break; 906 | 907 | /* Port flush requested */ 908 | case TNCAS_PURGE_DATA: 909 | snprintf(LogStr, sizeof(LogStr), "Port flush %u requested.", (unsigned int) Command[4]); 910 | LogStr[sizeof(LogStr) - 1] = '\0'; 911 | LogMsg(LOG_DEBUG, LogStr); 912 | SetFlush(PortFd, Command[4]); 913 | SendCPCByteCommand(SockB, TNASC_PURGE_DATA, Command[4]); 914 | break; 915 | 916 | /* Suspend output to the client */ 917 | case TNCAS_FLOWCONTROL_SUSPEND: 918 | LogMsg(LOG_DEBUG, "Flow control suspend requested."); 919 | InputFlow = False; 920 | break; 921 | 922 | /* Resume output to the client */ 923 | case TNCAS_FLOWCONTROL_RESUME: 924 | LogMsg(LOG_DEBUG, "Flow control resume requested."); 925 | InputFlow = True; 926 | break; 927 | 928 | /* Unknown request */ 929 | default: 930 | snprintf(LogStr, sizeof(LogStr), "Unhandled request %u", (unsigned int) Command[3]); 931 | LogStr[sizeof(LogStr) - 1] = '\0'; 932 | LogMsg(LOG_DEBUG, LogStr); 933 | break; 934 | } 935 | } 936 | 937 | /* Common telnet IAC commands handling */ 938 | #define HandleIACCommand_bytes MAX(HandleCPCCommand_bytes, SendTelnetOption_bytes) 939 | void 940 | HandleIACCommand(BufferType * SockB, PORTHANDLE PortFd, unsigned char *Command, size_t CSize) 941 | { 942 | char LogStr[TmpStrLen]; 943 | 944 | /* Check which command */ 945 | switch (Command[1]) { 946 | /* Suboptions */ 947 | case TNSB: 948 | if (!(tnstate[Command[2]].is_will || tnstate[Command[2]].is_do)) 949 | break; 950 | 951 | switch (Command[2]) { 952 | /* RFC 2217 COM Port Control Protocol option */ 953 | case TNCOM_PORT_OPTION: 954 | HandleCPCCommand(SockB, PortFd, Command, CSize); 955 | break; 956 | 957 | default: 958 | snprintf(LogStr, sizeof(LogStr), "Unknown suboption received: %u", 959 | (unsigned int) Command[2]); 960 | LogStr[sizeof(LogStr) - 1] = '\0'; 961 | LogMsg(LOG_DEBUG, LogStr); 962 | break; 963 | } 964 | break; 965 | 966 | /* Requests for options */ 967 | case TNWILL: 968 | switch (Command[2]) { 969 | /* COM Port Control Option */ 970 | case TNCOM_PORT_OPTION: 971 | LogMsg(LOG_INFO, "Telnet COM Port Control Enabled (WILL)."); 972 | PortControlEnable = True; 973 | if (!tnstate[Command[2]].sent_do) { 974 | SendTelnetOption(SockB, TNDO, Command[2]); 975 | } 976 | tnstate[Command[2]].is_do = 1; 977 | break; 978 | 979 | /* Telnet Binary mode */ 980 | case TN_TRANSMIT_BINARY: 981 | LogMsg(LOG_INFO, "Telnet Binary Transfer Enabled (WILL)."); 982 | if (!tnstate[Command[2]].sent_do) 983 | SendTelnetOption(SockB, TNDO, Command[2]); 984 | tnstate[Command[2]].is_do = 1; 985 | break; 986 | 987 | /* Echo request not handled */ 988 | case TN_ECHO: 989 | LogMsg(LOG_INFO, "Rejecting Telnet Echo Option (WILL)."); 990 | if (!tnstate[Command[2]].sent_do) 991 | SendTelnetOption(SockB, TNDO, Command[2]); 992 | tnstate[Command[2]].is_do = 1; 993 | break; 994 | 995 | /* No go ahead needed */ 996 | case TN_SUPPRESS_GO_AHEAD: 997 | LogMsg(LOG_INFO, "Suppressing Go Ahead characters (WILL)."); 998 | if (!tnstate[Command[2]].sent_do) 999 | SendTelnetOption(SockB, TNDO, Command[2]); 1000 | tnstate[Command[2]].is_do = 1; 1001 | break; 1002 | 1003 | /* Reject everything else */ 1004 | default: 1005 | snprintf(LogStr, sizeof(LogStr), "Rejecting option WILL: %u", 1006 | (unsigned int) Command[2]); 1007 | LogStr[sizeof(LogStr) - 1] = '\0'; 1008 | LogMsg(LOG_DEBUG, LogStr); 1009 | SendTelnetOption(SockB, TNDONT, Command[2]); 1010 | tnstate[Command[2]].is_do = 0; 1011 | break; 1012 | } 1013 | tnstate[Command[2]].sent_do = 0; 1014 | tnstate[Command[2]].sent_dont = 0; 1015 | break; 1016 | 1017 | /* Confirmations for options */ 1018 | case TNDO: 1019 | switch (Command[2]) { 1020 | /* COM Port Control Option */ 1021 | case TNCOM_PORT_OPTION: 1022 | LogMsg(LOG_INFO, "Telnet COM Port Control Enabled (DO)."); 1023 | PortControlEnable = True; 1024 | if (!tnstate[Command[2]].sent_will) 1025 | SendTelnetOption(SockB, TNWILL, Command[2]); 1026 | tnstate[Command[2]].is_will = 1; 1027 | break; 1028 | 1029 | /* Telnet Binary mode */ 1030 | case TN_TRANSMIT_BINARY: 1031 | LogMsg(LOG_INFO, "Telnet Binary Transfer Enabled (DO)."); 1032 | if (!tnstate[Command[2]].sent_will) 1033 | SendTelnetOption(SockB, TNWILL, Command[2]); 1034 | tnstate[Command[2]].is_will = 1; 1035 | break; 1036 | 1037 | /* Echo request handled. The modem will echo for the user. */ 1038 | case TN_ECHO: 1039 | LogMsg(LOG_INFO, "Rejecting Telnet Echo Option (DO)."); 1040 | if (!tnstate[Command[2]].sent_will) 1041 | SendTelnetOption(SockB, TNWILL, Command[2]); 1042 | tnstate[Command[2]].is_will = 1; 1043 | break; 1044 | 1045 | /* No go ahead needed */ 1046 | case TN_SUPPRESS_GO_AHEAD: 1047 | LogMsg(LOG_INFO, "Suppressing Go Ahead characters (DO)."); 1048 | if (!tnstate[Command[2]].sent_will) 1049 | SendTelnetOption(SockB, TNWILL, Command[2]); 1050 | tnstate[Command[2]].is_will = 1; 1051 | break; 1052 | 1053 | /* Reject everything else */ 1054 | default: 1055 | snprintf(LogStr, sizeof(LogStr), "Rejecting option DO: %u", (unsigned int) Command[2]); 1056 | LogStr[sizeof(LogStr) - 1] = '\0'; 1057 | LogMsg(LOG_DEBUG, LogStr); 1058 | SendTelnetOption(SockB, TNWONT, Command[2]); 1059 | tnstate[Command[2]].is_will = 0; 1060 | break; 1061 | } 1062 | tnstate[Command[2]].sent_will = 0; 1063 | tnstate[Command[2]].sent_wont = 0; 1064 | break; 1065 | 1066 | /* Notifications of rejections for options */ 1067 | case TNDONT: 1068 | snprintf(LogStr, sizeof(LogStr), "Received rejection for option: %u", 1069 | (unsigned int) Command[2]); 1070 | LogStr[sizeof(LogStr) - 1] = '\0'; 1071 | LogMsg(LOG_DEBUG, LogStr); 1072 | if (tnstate[Command[2]].is_will) { 1073 | SendTelnetOption(SockB, TNWONT, Command[2]); 1074 | tnstate[Command[2]].is_will = 0; 1075 | } 1076 | tnstate[Command[2]].sent_will = 0; 1077 | tnstate[Command[2]].sent_wont = 0; 1078 | break; 1079 | 1080 | case TNWONT: 1081 | if (Command[2] == TNCOM_PORT_OPTION) { 1082 | LogMsg(LOG_ERR, "Client doesn't support Telnet COM Port " 1083 | "Protocol Option (RFC 2217), trying to serve anyway."); 1084 | } 1085 | else { 1086 | snprintf(LogStr, sizeof(LogStr), 1087 | "Received rejection for option: %u", (unsigned int) Command[2]); 1088 | LogStr[sizeof(LogStr) - 1] = '\0'; 1089 | LogMsg(LOG_DEBUG, LogStr); 1090 | } 1091 | if (tnstate[Command[2]].is_do) { 1092 | SendTelnetOption(SockB, TNDONT, Command[2]); 1093 | tnstate[Command[2]].is_do = 0; 1094 | } 1095 | tnstate[Command[2]].sent_do = 0; 1096 | tnstate[Command[2]].sent_dont = 0; 1097 | break; 1098 | } 1099 | } 1100 | 1101 | /* Check and act upon read/write result. Uses errno. Returns true on error. */ 1102 | Boolean 1103 | IOResultError(int iobytes, const char *err, const char *eof_err) 1104 | { 1105 | switch (iobytes) { 1106 | case -1: 1107 | if (errno != EWOULDBLOCK) { 1108 | LogMsg(LOG_NOTICE, err); 1109 | return True; 1110 | } 1111 | break; 1112 | case 0: 1113 | LogMsg(LOG_NOTICE, eof_err); 1114 | return True; 1115 | break; 1116 | } 1117 | return False; 1118 | } 1119 | 1120 | void 1121 | LogPortSettings(unsigned long speed, unsigned char datasize, unsigned char parity, 1122 | unsigned char stopsize, unsigned char outflow, unsigned char inflow) 1123 | { 1124 | char LogStr[TmpStrLen]; 1125 | char parchar; 1126 | char *stopbits = ""; 1127 | char *outflowtype = ""; 1128 | char *inflowtype = ""; 1129 | 1130 | switch (parity) { 1131 | case TNCOM_ODDPARITY: 1132 | parchar = 'O'; 1133 | break; 1134 | case TNCOM_EVENPARITY: 1135 | parchar = 'E'; 1136 | break; 1137 | case TNCOM_MARKPARITY: 1138 | parchar = 'M'; 1139 | break; 1140 | case TNCOM_SPACEPARITY: 1141 | parchar = 'S'; 1142 | break; 1143 | case TNCOM_NOPARITY: 1144 | parchar = 'N'; 1145 | break; 1146 | default: 1147 | parchar = 'I'; 1148 | break; 1149 | } 1150 | 1151 | switch (stopsize) { 1152 | case TNCOM_ONESTOPBIT: 1153 | stopbits = "1"; 1154 | break; 1155 | case TNCOM_ONE5STOPBITS: 1156 | stopbits = "1.5"; 1157 | break; 1158 | case TNCOM_TWOSTOPBITS: 1159 | stopbits = "2"; 1160 | break; 1161 | } 1162 | 1163 | switch (outflow) { 1164 | case TNCOM_CMD_FLOW_NONE: 1165 | inflowtype = "none"; 1166 | break; 1167 | case TNCOM_CMD_FLOW_XONXOFF: 1168 | inflowtype = "XON/XOFF"; 1169 | break; 1170 | case TNCOM_CMD_FLOW_HARDWARE: 1171 | inflowtype = "RTS/CTS"; 1172 | break; 1173 | case TNCOM_CMD_FLOW_DCD: 1174 | inflowtype = "DCD flow control"; 1175 | break; 1176 | case TNCOM_CMD_FLOW_DSR: 1177 | inflowtype = "DSR"; 1178 | break; 1179 | default: 1180 | inflowtype = "unknown"; 1181 | break; 1182 | } 1183 | 1184 | switch (inflow) { 1185 | case TNCOM_CMD_INFLOW_NONE: 1186 | outflowtype = "none"; 1187 | break; 1188 | case TNCOM_CMD_INFLOW_XONXOFF: 1189 | outflowtype = "XON/XOFF"; 1190 | break; 1191 | case TNCOM_CMD_INFLOW_HARDWARE: 1192 | outflowtype = "RTS/CTS"; 1193 | break; 1194 | case TNCOM_CMD_INFLOW_DTR: 1195 | outflowtype = "DTR"; 1196 | break; 1197 | default: 1198 | outflowtype = "unknown"; 1199 | break; 1200 | } 1201 | 1202 | snprintf(LogStr, sizeof(LogStr), 1203 | "Port settings:%lu-%u-%c-%s outflow:%s inflow:%s", 1204 | speed, datasize, parchar, stopbits, outflowtype, inflowtype); 1205 | LogStr[sizeof(LogStr) - 1] = '\0'; 1206 | LogMsg(LOG_NOTICE, LogStr); 1207 | } 1208 | 1209 | void 1210 | Usage(void) 1211 | { 1212 | /* Write little usage information */ 1213 | fprintf(stderr, 1214 | "sercd %s: RFC 2217 compliant serial port redirector\n" 1215 | "This program can be run by the inetd superserver or standalone\n" 1216 | "\n" 1217 | "Usage:\n" 1218 | #ifndef ANDROID 1219 | "sercd [-ie] [-p port] [-l addr] [pollingterval]\n" 1220 | #else 1221 | "sercd [-ie] [-p port] [-l addr] [pollingterval]\n" 1222 | #endif 1223 | "-i indicates Cisco IOS Bug compatibility\n" 1224 | "-e send output to standard error instead of syslog\n" 1225 | "-p port listen on specified port, instead of port 7000\n" 1226 | "-l addr standalone mode, bind to specified adress, empty string for all\n" 1227 | "Poll interval is in milliseconds, default is %d,\n" 1228 | "0 means no polling\n", VERSION, DEFAULT_POLL_INTERVAL); 1229 | } 1230 | 1231 | #ifdef ANDROID 1232 | SERCD_SOCKET *LSocketFd = NULL; 1233 | #endif 1234 | 1235 | #ifndef ANDROID 1236 | /* Main function */ 1237 | int 1238 | main(int argc, char **argv) 1239 | #else 1240 | JNIEXPORT jint JNICALL Java_gnu_sercd_SercdService_main 1241 | (JNIEnv *env, jobject thiz, jstring serialport, jstring netinterface, jint port) 1242 | #endif 1243 | { 1244 | /* Chars read */ 1245 | char readbuf[512]; 1246 | 1247 | /* Temporary string for logging */ 1248 | char LogStr[TmpStrLen]; 1249 | 1250 | /* Poll interval and timer */ 1251 | long PollInterval; 1252 | 1253 | /* Buffer to Device from Network */ 1254 | BufferType ToDevBuf; 1255 | 1256 | /* Buffer to Network from Device */ 1257 | BufferType ToNetBuf; 1258 | 1259 | int opt = 0; 1260 | char *optstring = "iep:l:"; 1261 | unsigned int opt_port = 7000; 1262 | Boolean inetd_mode = True; 1263 | struct in_addr opt_bind_addr; 1264 | SERCD_SOCKET insocket, outsocket, lsocket; 1265 | PORTHANDLE devicefd; 1266 | 1267 | opt_bind_addr.s_addr = INADDR_ANY; 1268 | 1269 | #ifndef ANDROID 1270 | while (opt != -1) { 1271 | opt = getopt(argc, argv, optstring); 1272 | switch (opt) { 1273 | /* Cisco IOS compatibility */ 1274 | case 'i': 1275 | CiscoIOSCompatible = True; 1276 | break; 1277 | case 'e': 1278 | StdErrLogging = True; 1279 | break; 1280 | case 'p': 1281 | opt_port = strtol(optarg, NULL, 10); 1282 | if (opt_port == 0) { 1283 | fprintf(stderr, "Invalid port\n"); 1284 | exit(Error); 1285 | } 1286 | break; 1287 | case 'l': 1288 | if (*optarg) { 1289 | opt_bind_addr.s_addr = inet_addr(optarg); 1290 | if (opt_bind_addr.s_addr == (unsigned) -1) { 1291 | fprintf(stderr, "Invalid bind address\n"); 1292 | exit(Error); 1293 | } 1294 | } 1295 | inetd_mode = False; 1296 | break; 1297 | } 1298 | } 1299 | 1300 | /* Check the command line argument count */ 1301 | #ifndef ANDROID 1302 | if (argc - optind < 3 || argc - optind > 4) { 1303 | #else 1304 | if (argc - optind < 2 || argc - optind > 3) { 1305 | #endif 1306 | Usage(); 1307 | exit(Error); 1308 | } 1309 | #else /* ANDROID */ 1310 | opt_port = port; 1311 | jboolean isCopy; 1312 | opt_bind_addr.s_addr = inet_addr((*env)->GetStringUTFChars(env, netinterface, &isCopy)); 1313 | inetd_mode = False; 1314 | #endif /* ANDROID */ 1315 | 1316 | /* Sets the log level */ 1317 | #ifndef ANDROID 1318 | MaxLogLevel = atoi(argv[optind++]); 1319 | #else 1320 | MaxLogLevel = 7; 1321 | #endif 1322 | 1323 | /* Gets device and lock file names */ 1324 | #ifndef ANDROID 1325 | DeviceName = argv[optind++]; 1326 | #else 1327 | DeviceName = (char*)(*env)->GetStringUTFChars(env, serialport, &isCopy); 1328 | #endif 1329 | #ifndef ANDROID 1330 | LockFileName = argv[optind++]; 1331 | #endif 1332 | 1333 | /* Retrieve the polling interval */ 1334 | #ifndef ANDROID 1335 | if (optind < argc) { 1336 | char *endptr; 1337 | PollInterval = strtol(argv[optind++], &endptr, 0); 1338 | if (!endptr || *endptr || PollInterval < 0) { 1339 | fprintf(stderr, "Invalid polling interval\n"); 1340 | exit(Error); 1341 | } 1342 | } 1343 | else { 1344 | PollInterval = DEFAULT_POLL_INTERVAL; 1345 | } 1346 | #else 1347 | PollInterval = DEFAULT_POLL_INTERVAL; 1348 | #endif 1349 | 1350 | PlatformInit(); 1351 | 1352 | /* Logs sercd start */ 1353 | LogMsg(LOG_NOTICE, "sercd started."); 1354 | 1355 | /* Logs sercd log level */ 1356 | snprintf(LogStr, sizeof(LogStr), "Log level: %i", MaxLogLevel); 1357 | LogStr[sizeof(LogStr) - 1] = '\0'; 1358 | LogMsg(LOG_INFO, LogStr); 1359 | 1360 | /* Logs the polling interval */ 1361 | snprintf(LogStr, sizeof(LogStr), "Polling interval (ms): %ld", PollInterval); 1362 | LogStr[sizeof(LogStr) - 1] = '\0'; 1363 | LogMsg(LOG_INFO, LogStr); 1364 | 1365 | if (inetd_mode) { 1366 | /* inetd mode */ 1367 | insocket = STDIN_FILENO; 1368 | outsocket = STDOUT_FILENO; 1369 | InSocketFd = &insocket; 1370 | OutSocketFd = &outsocket; 1371 | SetSocketOptions(*InSocketFd, *OutSocketFd); 1372 | InitBuffer(&ToNetBuf); 1373 | InitTelnetStateMachine(); 1374 | SendTelnetInitialOptions(&ToNetBuf); 1375 | } 1376 | else { 1377 | /* Standalone mode */ 1378 | struct sockaddr_in sin; 1379 | lsocket = socket(PF_INET, SOCK_STREAM, 0); 1380 | if (lsocket < 0) { 1381 | perror("socket"); 1382 | exit(Error); 1383 | } 1384 | #ifndef WIN32 1385 | int SockParmEnable = 1; 1386 | /* Windows is totally broken wrt SO_REUSEADDR - it uses 1387 | non-standard and mostly useless semantics. This is 1388 | confirmed by Microsoft: From 1389 | http://msdn.microsoft.com/en-us/library/ms740621(VS.85).aspx: 1390 | "the behavior for all sockets bound to that port is 1391 | indeterminate". "The exception to this non-deterministic 1392 | behavior is multicast sockets. " Instead, they 1393 | are recommending SO_EXCLUSIVEADDRUSE, but it typically only 1394 | works if you have administrator privs. Bah. */ 1395 | setsockopt(lsocket, SOL_SOCKET, SO_REUSEADDR, (char *) &SockParmEnable, 1396 | sizeof(SockParmEnable)); 1397 | #endif 1398 | 1399 | sin.sin_family = AF_INET; 1400 | sin.sin_port = htons(opt_port); 1401 | sin.sin_addr.s_addr = opt_bind_addr.s_addr; 1402 | if (bind(lsocket, (struct sockaddr *) &sin, sizeof(struct sockaddr))) { 1403 | perror("bind"); 1404 | fprintf(stderr, "Couldn't bind to tcp port %d\n", opt_port); 1405 | exit(Error); 1406 | } 1407 | if (listen(lsocket, 1) < 0) { 1408 | perror("listen"); 1409 | exit(Error); 1410 | } 1411 | LSocketFd = &lsocket; 1412 | NewListener(*LSocketFd); 1413 | } 1414 | 1415 | /* Main loop with fd's control. General note: We basically have 1416 | three states: 1417 | 1418 | 1) No client connection, no open port 1419 | 2) Client connected, port not yet open 1420 | 3) Client connected, port open 1421 | 1422 | This means that if DeviceFd is set, InSocketFd and OutSocketFd 1423 | should be set as well. */ 1424 | ChangeState(env, thiz, STATE_READY); 1425 | 1426 | while (True) { 1427 | int selret; 1428 | 1429 | PORTHANDLE *DeviceIn = NULL; 1430 | PORTHANDLE *DeviceOut = NULL; 1431 | PORTHANDLE *Modemstate = NULL; 1432 | SERCD_SOCKET *SocketOut = NULL; 1433 | SERCD_SOCKET *SocketIn = NULL; 1434 | 1435 | if (DeviceFd && BufferHasRoomFor(&ToNetBuf, EscWriteChar_bytes) && InputFlow) { 1436 | DeviceIn = DeviceFd; 1437 | } 1438 | if (DeviceFd && !IsBufferEmpty(&ToDevBuf)) { 1439 | DeviceOut = DeviceFd; 1440 | } 1441 | if (DeviceFd && PortControlEnable && InputFlow && 1442 | BufferHasRoomFor(&ToNetBuf, SendCPCByteCommand_bytes)) { 1443 | Modemstate = DeviceFd; 1444 | } 1445 | if (OutSocketFd && !IsBufferEmpty(&ToNetBuf)) { 1446 | SocketOut = OutSocketFd; 1447 | } 1448 | if (DeviceFd && BufferHasRoomFor(&ToDevBuf, EscRedirectChar_bytes_DevB) && 1449 | InSocketFd && BufferHasRoomFor(&ToNetBuf, EscRedirectChar_bytes_SockB)) { 1450 | SocketIn = InSocketFd; 1451 | } 1452 | 1453 | if (!DeviceIn && !DeviceOut && !SocketOut && !SocketIn && !LSocketFd) { 1454 | /* Nothing more to do */ 1455 | exit(NoError); 1456 | } 1457 | 1458 | selret = SercdSelect(DeviceIn, DeviceOut, Modemstate, SocketOut, SocketIn, 1459 | LSocketFd, PollInterval); 1460 | if (selret < 0) { 1461 | snprintf(LogStr, sizeof(LogStr), "select error: %d", errno); 1462 | LogStr[sizeof(LogStr) - 1] = '\0'; 1463 | LogMsg(LOG_ERR, LogStr); 1464 | exit(Error); 1465 | } 1466 | else if (selret > 0) { 1467 | /* Handle buffers in the following order: 1468 | Serial input 1469 | Serial output 1470 | Network output 1471 | Network input 1472 | 1473 | Motivation: Needs to read away data from the serial 1474 | port to prevent buffer overruns. Needs to drain our 1475 | buffers as fast as possible, to reduce latency and make 1476 | room for more. This order should be used in function 1477 | signatures etc as well. 1478 | */ 1479 | ssize_t iobytes; 1480 | unsigned int i, trybytes; 1481 | unsigned char *p; 1482 | 1483 | if (selret & SERCD_EV_DEVICEIN) { 1484 | /* Read from serial port. Each serial port byte might 1485 | produce EscWriteChar_bytes of network data. */ 1486 | trybytes = MIN(sizeof(readbuf), BufferRoomLeft(&ToNetBuf) / EscWriteChar_bytes); 1487 | iobytes = ReadFromDev(*DeviceFd, &readbuf, trybytes); 1488 | if (IOResultError(iobytes, "Error reading from device", "EOF from device")) { 1489 | #ifndef ANDROID 1490 | DropConnection(DeviceFd, InSocketFd, OutSocketFd, LockFileName); 1491 | #else 1492 | ChangeState(env, thiz, STATE_READY); 1493 | DropConnection(DeviceFd, InSocketFd, OutSocketFd); 1494 | #endif 1495 | InSocketFd = OutSocketFd = NULL; 1496 | DeviceFd = NULL; 1497 | continue; 1498 | } 1499 | else { 1500 | for (i = 0; i < iobytes; i++) { 1501 | EscWriteChar(&ToNetBuf, readbuf[i]); 1502 | } 1503 | } 1504 | } 1505 | 1506 | if (selret & SERCD_EV_DEVICEOUT) { 1507 | /* Write to serial port */ 1508 | p = GetBufferString(&ToDevBuf, &trybytes); 1509 | iobytes = WriteToDev(*DeviceFd, p, trybytes); 1510 | if (IOResultError(iobytes, "Error writing to device.", "EOF to device")) { 1511 | #ifndef ANDROID 1512 | DropConnection(DeviceFd, InSocketFd, OutSocketFd, LockFileName); 1513 | #else 1514 | ChangeState(env, thiz, STATE_READY); 1515 | DropConnection(DeviceFd, InSocketFd, OutSocketFd); 1516 | #endif 1517 | InSocketFd = OutSocketFd = NULL; 1518 | DeviceFd = NULL; 1519 | continue; 1520 | } 1521 | else { 1522 | BufferPopBytes(&ToDevBuf, iobytes); 1523 | } 1524 | } 1525 | 1526 | if (selret & SERCD_EV_SOCKETOUT) { 1527 | /* Write to network */ 1528 | p = GetBufferString(&ToNetBuf, &trybytes); 1529 | iobytes = WriteToNet(*OutSocketFd, p, trybytes); 1530 | if (IOResultError(iobytes, "Error writing to network", "EOF to network")) { 1531 | #ifndef ANDROID 1532 | DropConnection(DeviceFd, InSocketFd, OutSocketFd, LockFileName); 1533 | #else 1534 | ChangeState(env, thiz, STATE_READY); 1535 | DropConnection(DeviceFd, InSocketFd, OutSocketFd); 1536 | #endif 1537 | InSocketFd = OutSocketFd = NULL; 1538 | DeviceFd = NULL; 1539 | continue; 1540 | } 1541 | else { 1542 | BufferPopBytes(&ToNetBuf, iobytes); 1543 | } 1544 | } 1545 | 1546 | if (selret & SERCD_EV_SOCKETIN) { 1547 | /* Read from network. Each network byte might produce 1548 | EscRedirectChar_bytes_DevB or or up to 1549 | EscRedirectChar_bytes_SockB network data. */ 1550 | trybytes = sizeof(readbuf); 1551 | trybytes = MIN(trybytes, BufferRoomLeft(&ToNetBuf) / EscRedirectChar_bytes_SockB); 1552 | trybytes = MIN(trybytes, BufferRoomLeft(&ToDevBuf) / EscRedirectChar_bytes_DevB); 1553 | iobytes = ReadFromNet(*InSocketFd, readbuf, trybytes); 1554 | if (IOResultError(iobytes, "Error readbuf from network.", "EOF from network")) { 1555 | #ifndef ANDROID 1556 | DropConnection(DeviceFd, InSocketFd, OutSocketFd, LockFileName); 1557 | #else 1558 | ChangeState(env, thiz, STATE_READY); 1559 | DropConnection(DeviceFd, InSocketFd, OutSocketFd); 1560 | #endif 1561 | InSocketFd = OutSocketFd = NULL; 1562 | DeviceFd = NULL; 1563 | continue; 1564 | } 1565 | else { 1566 | for (i = 0; i < iobytes; i++) { 1567 | EscRedirectChar(&ToNetBuf, &ToDevBuf, *DeviceFd, readbuf[i]); 1568 | } 1569 | } 1570 | } 1571 | 1572 | /* accept new connections */ 1573 | if (selret & SERCD_EV_SOCKETCONNECT) { 1574 | struct sockaddr addr; 1575 | socklen_t addrlen = sizeof(addr); 1576 | int csock; 1577 | 1578 | /* FIXME: Might be a good idea to log the client addr */ 1579 | LogMsg(LOG_NOTICE, "New connection"); 1580 | csock = accept(*LSocketFd, &addr, &addrlen); 1581 | if (csock < 0) { 1582 | /* FIXME: Log what kind of error. */ 1583 | LogMsg(LOG_ERR, "Error accepting socket"); 1584 | } 1585 | else if (InSocketFd && OutSocketFd) { 1586 | /* We can only handle one connection at a time. */ 1587 | LogMsg(LOG_ERR, "Another client connected, dropping new connection"); 1588 | closesocket(csock); 1589 | } 1590 | else { 1591 | ChangeState(env, thiz, STATE_CONNECTED); 1592 | 1593 | /* Set up networking */ 1594 | insocket = csock; 1595 | OutSocketFd = InSocketFd = &insocket; 1596 | SetSocketOptions(*InSocketFd, *OutSocketFd); 1597 | InitBuffer(&ToNetBuf); 1598 | InitTelnetStateMachine(); 1599 | SendTelnetInitialOptions(&ToNetBuf); 1600 | } 1601 | } 1602 | 1603 | /* Open serial port if not yet open */ 1604 | if (InSocketFd && OutSocketFd && !DeviceFd) { 1605 | DeviceFd = &devicefd; 1606 | #ifndef ANDROID 1607 | if (OpenPort(DeviceName, LockFileName, DeviceFd) == Error) { 1608 | #else 1609 | if (OpenPort(DeviceName, DeviceFd) == Error) { 1610 | #endif 1611 | /* Open failed */ 1612 | snprintf(LogStr, sizeof(LogStr), "Unable to open device %s. Exiting.", 1613 | DeviceName); 1614 | LogStr[sizeof(LogStr) - 1] = '\0'; 1615 | LogMsg(LOG_ERR, LogStr); 1616 | /* Emulate the inetd behaviour: Close the connection. */ 1617 | #ifndef ANDROID 1618 | DropConnection(NULL, InSocketFd, OutSocketFd, LockFileName); 1619 | #else 1620 | ChangeState(env, thiz, STATE_READY); 1621 | DropConnection(NULL, InSocketFd, OutSocketFd); 1622 | #endif 1623 | InSocketFd = OutSocketFd = NULL; 1624 | DeviceFd = NULL; 1625 | continue; 1626 | } 1627 | else { 1628 | /* Successfully opened port */ 1629 | ChangeState(env, thiz, STATE_PORT_OPENED); 1630 | InitBuffer(&ToDevBuf); 1631 | } 1632 | } 1633 | 1634 | /* Check the port state and notify the client if it's changed */ 1635 | if (selret & SERCD_EV_MODEMSTATE) { 1636 | unsigned char newstate; 1637 | ModemStateNotified(); 1638 | newstate = GetModemState(*DeviceFd, ModemState); 1639 | /* Don't send update if only delta changes */ 1640 | if ((newstate & ModemStateMask & TNCOM_MODMASK_NODELTA) 1641 | != (ModemState & ModemStateMask & TNCOM_MODMASK_NODELTA)) { 1642 | ModemState = newstate; 1643 | SendCPCByteCommand(&ToNetBuf, TNASC_NOTIFY_MODEMSTATE, 1644 | (ModemState & ModemStateMask)); 1645 | snprintf(LogStr, sizeof(LogStr), "Sent modem state: %u", 1646 | (unsigned int) (ModemState & ModemStateMask)); 1647 | LogStr[sizeof(LogStr) - 1] = '\0'; 1648 | LogMsg(LOG_DEBUG, LogStr); 1649 | } 1650 | } 1651 | } 1652 | } 1653 | } 1654 | 1655 | #ifdef ANDROID 1656 | JNIEXPORT void JNICALL Java_gnu_sercd_SercdService_exit(JNIEnv *env, jobject thiz) 1657 | { 1658 | /* Close the files descriptors to force the next call to "select" to fail. */ 1659 | DropConnection(DeviceFd, InSocketFd, OutSocketFd); 1660 | close(*LSocketFd); 1661 | } 1662 | #endif 1663 | -------------------------------------------------------------------------------- /android-sercd/project/jni/sercd.h: -------------------------------------------------------------------------------- 1 | /* 2 | * sercd 3 | * Copyright 2008 Peter Åstrand for Cendio AB 4 | * see file COPYING for license details 5 | */ 6 | 7 | #ifndef SERCD_H 8 | #define SERCD_H 9 | 10 | #include "unix.h" 11 | #ifndef ANDROID 12 | #include "win.h" 13 | #endif 14 | #include 15 | 16 | /* Standard boolean definition */ 17 | typedef enum 18 | { False, True } 19 | Boolean; 20 | 21 | /* Maximum length of temporary strings */ 22 | #define TmpStrLen 255 23 | 24 | /* Error conditions constants */ 25 | #define NoError 0 26 | #define Error 1 27 | #define OpenError -1 28 | 29 | /* Base Telnet protocol constants (STD 8) */ 30 | #define TNSE ((unsigned char) 240) 31 | #define TNNOP ((unsigned char) 241) 32 | #define TNSB ((unsigned char) 250) 33 | #define TNWILL ((unsigned char) 251) 34 | #define TNWONT ((unsigned char) 252) 35 | #define TNDO ((unsigned char) 253) 36 | #define TNDONT ((unsigned char) 254) 37 | #define TNIAC ((unsigned char) 255) 38 | 39 | /* Base Telnet protocol options constants (STD 27, STD 28, STD 29) */ 40 | #define TN_TRANSMIT_BINARY ((unsigned char) 0) 41 | #define TN_ECHO ((unsigned char) 1) 42 | #define TN_SUPPRESS_GO_AHEAD ((unsigned char) 3) 43 | 44 | /* Base Telnet Com Port Control (CPC) protocol constants (RFC 2217) */ 45 | #define TNCOM_PORT_OPTION ((unsigned char) 44) 46 | 47 | /* CPC Client to Access Server constants */ 48 | #define TNCAS_SIGNATURE ((unsigned char) 0) 49 | #define TNCAS_SET_BAUDRATE ((unsigned char) 1) 50 | #define TNCAS_SET_DATASIZE ((unsigned char) 2) 51 | #define TNCAS_SET_PARITY ((unsigned char) 3) 52 | #define TNCAS_SET_STOPSIZE ((unsigned char) 4) 53 | #define TNCAS_SET_CONTROL ((unsigned char) 5) 54 | #define TNCAS_NOTIFY_LINESTATE ((unsigned char) 6) 55 | #define TNCAS_NOTIFY_MODEMSTATE ((unsigned char) 7) 56 | #define TNCAS_FLOWCONTROL_SUSPEND ((unsigned char) 8) 57 | #define TNCAS_FLOWCONTROL_RESUME ((unsigned char) 9) 58 | #define TNCAS_SET_LINESTATE_MASK ((unsigned char) 10) 59 | #define TNCAS_SET_MODEMSTATE_MASK ((unsigned char) 11) 60 | #define TNCAS_PURGE_DATA ((unsigned char) 12) 61 | 62 | /* CPC Access Server to Client constants */ 63 | #define TNASC_SIGNATURE ((unsigned char) 100) 64 | #define TNASC_SET_BAUDRATE ((unsigned char) 101) 65 | #define TNASC_SET_DATASIZE ((unsigned char) 102) 66 | #define TNASC_SET_PARITY ((unsigned char) 103) 67 | #define TNASC_SET_STOPSIZE ((unsigned char) 104) 68 | #define TNASC_SET_CONTROL ((unsigned char) 105) 69 | #define TNASC_NOTIFY_LINESTATE ((unsigned char) 106) 70 | #define TNASC_NOTIFY_MODEMSTATE ((unsigned char) 107) 71 | #define TNASC_FLOWCONTROL_SUSPEND ((unsigned char) 108) 72 | #define TNASC_FLOWCONTROL_RESUME ((unsigned char) 109) 73 | #define TNASC_SET_LINESTATE_MASK ((unsigned char) 110) 74 | #define TNASC_SET_MODEMSTATE_MASK ((unsigned char) 111) 75 | #define TNASC_PURGE_DATA ((unsigned char) 112) 76 | 77 | /* CPC set parity */ 78 | #define TNCOM_PARITY_REQUEST ((unsigned char) 0) 79 | #define TNCOM_NOPARITY ((unsigned char) 1) 80 | #define TNCOM_ODDPARITY ((unsigned char) 2) 81 | #define TNCOM_EVENPARITY ((unsigned char) 3) 82 | #define TNCOM_MARKPARITY ((unsigned char) 4) 83 | #define TNCOM_SPACEPARITY ((unsigned char) 5) 84 | 85 | /* CPC set stopsize */ 86 | #define TNCOM_STOPSIZE_REQUEST ((unsigned char) 0) 87 | #define TNCOM_ONESTOPBIT ((unsigned char) 1) 88 | #define TNCOM_TWOSTOPBITS ((unsigned char) 2) 89 | #define TNCOM_ONE5STOPBITS ((unsigned char) 3) 90 | 91 | /* CPC commands */ 92 | #define TNCOM_CMD_FLOW_REQ ((unsigned char) 0) 93 | #define TNCOM_CMD_FLOW_NONE ((unsigned char) 1) 94 | #define TNCOM_CMD_FLOW_XONXOFF ((unsigned char) 2) 95 | #define TNCOM_CMD_FLOW_HARDWARE ((unsigned char) 3) 96 | #define TNCOM_CMD_BREAK_REQ ((unsigned char) 4) 97 | #define TNCOM_CMD_BREAK_ON ((unsigned char) 5) 98 | #define TNCOM_CMD_BREAK_OFF ((unsigned char) 6) 99 | #define TNCOM_CMD_DTR_REQ ((unsigned char) 7) 100 | #define TNCOM_CMD_DTR_ON ((unsigned char) 8) 101 | #define TNCOM_CMD_DTR_OFF ((unsigned char) 9) 102 | #define TNCOM_CMD_RTS_REQ ((unsigned char) 10) 103 | #define TNCOM_CMD_RTS_ON ((unsigned char) 11) 104 | #define TNCOM_CMD_RTS_OFF ((unsigned char) 12) 105 | #define TNCOM_CMD_INFLOW_REQ ((unsigned char) 13) 106 | #define TNCOM_CMD_INFLOW_NONE ((unsigned char) 14) 107 | #define TNCOM_CMD_INFLOW_XONXOFF ((unsigned char) 15) 108 | #define TNCOM_CMD_INFLOW_HARDWARE ((unsigned char) 16) 109 | #define TNCOM_CMD_FLOW_DCD ((unsigned char) 17) 110 | #define TNCOM_CMD_INFLOW_DTR ((unsigned char) 18) 111 | #define TNCOM_CMD_FLOW_DSR ((unsigned char) 19) 112 | 113 | /* CPC linestate mask and notifies */ 114 | #define TNCOM_LINEMASK_TIMEOUT ((unsigned char) 128) 115 | #define TNCOM_LINEMASK_TRANS_SHIFT_EMTPY ((unsigned char) 64) 116 | #define TNCOM_LINEMASK_TRANS_HOLD_EMPTY ((unsigned char) 32) 117 | #define TNCOM_LINEMASK_BREAK_ERR ((unsigned char) 16) 118 | #define TNCOM_LINEMASK_FRAME_ERR ((unsigned char) 8) 119 | #define TNCOM_LINEMASK_PARITY_ERR ((unsigned char) 4) 120 | #define TNCOM_LINEMASK_OVERRUN_ERR ((unsigned char) 2) 121 | #define TNCOM_LINEMASK_DATA_RD ((unsigned char) 1) 122 | 123 | /* CPC modemstate mask and notifies */ 124 | #define TNCOM_MODMASK_RLSD ((unsigned char) 128) 125 | #define TNCOM_MODMASK_RING ((unsigned char) 64) 126 | #define TNCOM_MODMASK_DSR ((unsigned char) 32) 127 | #define TNCOM_MODMASK_CTS ((unsigned char) 16) 128 | #define TNCOM_MODMASK_NODELTA (TNCOM_MODMASK_RLSD|TNCOM_MODMASK_RING|TNCOM_MODMASK_DSR|TNCOM_MODMASK_CTS) 129 | #define TNCOM_MODMASK_RLSD_DELTA ((unsigned char) 8) 130 | #define TNCOM_MODMASK_RING_TRAIL ((unsigned char) 4) 131 | #define TNCOM_MODMASK_DSR_DELTA ((unsigned char) 2) 132 | #define TNCOM_MODMASK_CTS_DELTA ((unsigned char) 1) 133 | 134 | /* CPC purge data */ 135 | #define TNCOM_PURGE_RX ((unsigned char) 1) 136 | #define TNCOM_PURGE_TX ((unsigned char) 2) 137 | #define TNCOM_PURGE_BOTH ((unsigned char) 3) 138 | 139 | /* Generic log function with log level control. Uses the same log levels 140 | of the syslog(3) system call */ 141 | void LogMsg(int LogLevel, const char *const Msg); 142 | 143 | /* Function executed when the program exits */ 144 | void ExitFunction(void); 145 | 146 | /* Function called on break signal */ 147 | void BreakFunction(int unused); 148 | 149 | /* Abstract platform-independent select function */ 150 | int SercdSelect(PORTHANDLE *DeviceIn, PORTHANDLE *DeviceOut, PORTHANDLE *Modemstate, 151 | SERCD_SOCKET *SocketOut, SERCD_SOCKET *SocketIn, 152 | SERCD_SOCKET *SocketConnect, long PollInterval); 153 | #define SERCD_EV_DEVICEIN 1 154 | #define SERCD_EV_DEVICEOUT 2 155 | #define SERCD_EV_SOCKETOUT 4 156 | #define SERCD_EV_SOCKETIN 8 157 | #define SERCD_EV_SOCKETCONNECT 16 158 | #define SERCD_EV_MODEMSTATE 32 159 | 160 | /* macros */ 161 | #ifndef MAX 162 | #define MAX(x,y) (((x) > (y)) ? (x) : (y)) 163 | #endif 164 | #ifndef MIN 165 | #define MIN(x,y) (((x) > (y)) ? (y) : (x)) 166 | #endif 167 | 168 | void NewListener(SERCD_SOCKET LSocketFd); 169 | #ifndef ANDROID 170 | void DropConnection(PORTHANDLE * DeviceFd, SERCD_SOCKET * InSocketFd, SERCD_SOCKET * OutSocketFd, 171 | const char *LockFileName); 172 | #else 173 | void DropConnection(PORTHANDLE * DeviceFd, SERCD_SOCKET * InSocketFd, SERCD_SOCKET * OutSocketFd); 174 | #endif 175 | ssize_t WriteToDev(PORTHANDLE port, const void *buf, size_t count); 176 | ssize_t ReadFromDev(PORTHANDLE port, void *buf, size_t count); 177 | ssize_t WriteToNet(SERCD_SOCKET sock, const void *buf, size_t count); 178 | ssize_t ReadFromNet(SERCD_SOCKET sock, void *buf, size_t count); 179 | void ModemStateNotified(); 180 | void LogPortSettings(unsigned long speed, unsigned char datasize, unsigned char parity, 181 | unsigned char stopsize, unsigned char outflow, unsigned char inflow); 182 | #endif /* SERCD_H */ 183 | -------------------------------------------------------------------------------- /android-sercd/project/jni/unix.c: -------------------------------------------------------------------------------- 1 | /* 2 | * sercd UNIX support 3 | * Copyright 2008 Peter Åstrand for Cendio AB 4 | * see file COPYING for license details 5 | */ 6 | 7 | #ifndef WIN32 8 | #include "sercd.h" 9 | #include "unix.h" 10 | 11 | #include 12 | #ifndef ANDROID 13 | #include 14 | #endif 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include /* gettimeofday */ 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #ifdef ANDROID 27 | #include 28 | #endif 29 | /* timeval macros */ 30 | #ifndef timerisset 31 | #define timerisset(tvp)\ 32 | ((tvp)->tv_sec || (tvp)->tv_usec) 33 | #endif 34 | #ifndef timercmp 35 | #define timercmp(tvp, uvp, cmp)\ 36 | ((tvp)->tv_sec cmp (uvp)->tv_sec ||\ 37 | (tvp)->tv_sec == (uvp)->tv_sec &&\ 38 | (tvp)->tv_usec cmp (uvp)->tv_usec) 39 | #endif 40 | #ifndef timerclear 41 | #define timerclear(tvp)\ 42 | ((tvp)->tv_sec = (tvp)->tv_usec = 0) 43 | #endif 44 | 45 | extern Boolean BreakSignaled; 46 | 47 | extern Boolean StdErrLogging; 48 | 49 | extern int MaxLogLevel; 50 | 51 | static struct timeval LastPoll = { 0, 0 }; 52 | 53 | /* Initial serial port settings */ 54 | static struct termios *InitialPortSettings; 55 | static struct termios initialportsettings; 56 | 57 | /* Locking constants */ 58 | #define LockOk 0 59 | #define Locked 1 60 | #define LockKo 2 61 | 62 | /* File mode and file length for HDB (ASCII) stile lock file */ 63 | #define LockFileMode 0644 64 | #define HDBHeaderLen 11 65 | 66 | /* Convert termios speed to tncom speed */ 67 | static unsigned long int 68 | Termios2TncomSpeed(struct termios *ti) 69 | { 70 | speed_t ispeed, ospeed; 71 | 72 | ispeed = cfgetispeed(ti); 73 | ospeed = cfgetospeed(ti); 74 | 75 | if (ispeed != ospeed) { 76 | LogMsg(LOG_WARNING, "warning: different input and output speed, using output speed"); 77 | } 78 | 79 | switch (ospeed) { 80 | case B50: 81 | return (50UL); 82 | case B75: 83 | return (75UL); 84 | case B110: 85 | return (110UL); 86 | case B134: 87 | return (134UL); 88 | case B150: 89 | return (150UL); 90 | case B200: 91 | return (200UL); 92 | case B300: 93 | return (300UL); 94 | case B600: 95 | return (600UL); 96 | case B1200: 97 | return (1200UL); 98 | case B1800: 99 | return (1800UL); 100 | case B2400: 101 | return (2400UL); 102 | case B4800: 103 | return (4800UL); 104 | case B9600: 105 | return (9600UL); 106 | case B19200: 107 | return (19200UL); 108 | case B38400: 109 | return (38400UL); 110 | case B57600: 111 | return (57600UL); 112 | case B115200: 113 | return (115200UL); 114 | case B230400: 115 | return (230400UL); 116 | case B460800: 117 | return (460800UL); 118 | default: 119 | return (0UL); 120 | } 121 | } 122 | 123 | /* Convert termios data size to tncom size */ 124 | static unsigned char 125 | Termios2TncomDataSize(struct termios *ti) 126 | { 127 | tcflag_t DataSize; 128 | DataSize = ti->c_cflag & CSIZE; 129 | 130 | switch (DataSize) { 131 | case CS5: 132 | return ((unsigned char) 5); 133 | case CS6: 134 | return ((unsigned char) 6); 135 | case CS7: 136 | return ((unsigned char) 7); 137 | case CS8: 138 | return ((unsigned char) 8); 139 | default: 140 | return ((unsigned char) 0); 141 | } 142 | } 143 | 144 | /* Convert termios parity to tncom parity */ 145 | static unsigned char 146 | Termios2TncomParity(struct termios *ti) 147 | { 148 | if ((ti->c_cflag & PARENB) == 0) 149 | return TNCOM_NOPARITY; 150 | 151 | if ((ti->c_cflag & PARENB) && (ti->c_cflag & PARODD)) 152 | return TNCOM_ODDPARITY; 153 | 154 | return TNCOM_EVENPARITY; 155 | } 156 | 157 | /* Convert termios stop size to tncom size */ 158 | static unsigned char 159 | Termios2TncomStopSize(struct termios *ti) 160 | { 161 | if ((ti->c_cflag & CSTOPB) == 0) 162 | return TNCOM_ONESTOPBIT; 163 | else 164 | return TNCOM_TWOSTOPBITS; 165 | } 166 | 167 | /* Convert termios output flow control to tncom flow */ 168 | static unsigned char 169 | Termios2TncomOutFlow(struct termios *ti) 170 | { 171 | if (ti->c_iflag & IXON) 172 | return TNCOM_CMD_FLOW_XONXOFF; 173 | if (ti->c_cflag & CRTSCTS) 174 | return TNCOM_CMD_FLOW_HARDWARE; 175 | return TNCOM_CMD_FLOW_NONE; 176 | } 177 | 178 | /* Convert termios input flow control to tncom flow */ 179 | static unsigned char 180 | Termios2TncomInFlow(struct termios *ti) 181 | { 182 | if (ti->c_iflag & IXOFF) 183 | return TNCOM_CMD_INFLOW_XONXOFF; 184 | if (ti->c_cflag & CRTSCTS) 185 | return TNCOM_CMD_INFLOW_HARDWARE; 186 | return TNCOM_CMD_INFLOW_NONE; 187 | } 188 | 189 | static void 190 | UnixLogPortSettings(struct termios *ti) 191 | { 192 | unsigned long speed; 193 | unsigned char datasize; 194 | unsigned char parity; 195 | unsigned char stopsize; 196 | unsigned char outflow, inflow; 197 | 198 | speed = Termios2TncomSpeed(ti); 199 | datasize = Termios2TncomDataSize(ti); 200 | parity = Termios2TncomParity(ti); 201 | stopsize = Termios2TncomStopSize(ti); 202 | outflow = Termios2TncomOutFlow(ti); 203 | inflow = Termios2TncomInFlow(ti); 204 | 205 | LogPortSettings(speed, datasize, parity, stopsize, outflow, inflow); 206 | } 207 | 208 | /* Retrieves the port speed from PortFd */ 209 | unsigned long int 210 | GetPortSpeed(PORTHANDLE PortFd) 211 | { 212 | struct termios PortSettings; 213 | 214 | tcgetattr(PortFd, &PortSettings); 215 | return Termios2TncomSpeed(&PortSettings); 216 | } 217 | 218 | /* Retrieves the data size from PortFd */ 219 | unsigned char 220 | GetPortDataSize(PORTHANDLE PortFd) 221 | { 222 | struct termios PortSettings; 223 | 224 | tcgetattr(PortFd, &PortSettings); 225 | return Termios2TncomDataSize(&PortSettings); 226 | } 227 | 228 | /* Retrieves the parity settings from PortFd */ 229 | unsigned char 230 | GetPortParity(PORTHANDLE PortFd) 231 | { 232 | struct termios PortSettings; 233 | 234 | tcgetattr(PortFd, &PortSettings); 235 | return Termios2TncomParity(&PortSettings); 236 | } 237 | 238 | /* Retrieves the stop bits size from PortFd */ 239 | unsigned char 240 | GetPortStopSize(PORTHANDLE PortFd) 241 | { 242 | struct termios PortSettings; 243 | 244 | tcgetattr(PortFd, &PortSettings); 245 | return Termios2TncomStopSize(&PortSettings); 246 | } 247 | 248 | /* Retrieves the flow control status, including DTR and RTS status, 249 | from PortFd */ 250 | unsigned char 251 | GetPortFlowControl(PORTHANDLE PortFd, unsigned char Which) 252 | { 253 | struct termios PortSettings; 254 | int MLines; 255 | 256 | /* Gets the basic informations from the port */ 257 | tcgetattr(PortFd, &PortSettings); 258 | ioctl(PortFd, TIOCMGET, &MLines); 259 | 260 | /* Check wich kind of information is requested */ 261 | switch (Which) { 262 | /* DTR Signal State */ 263 | case TNCOM_CMD_DTR_REQ: 264 | /* See comment below. */ 265 | if (MLines & TIOCM_DSR) 266 | return TNCOM_CMD_DTR_ON; 267 | else 268 | return TNCOM_CMD_DTR_OFF; 269 | break; 270 | 271 | /* RTS Signal State */ 272 | case TNCOM_CMD_RTS_REQ: 273 | /* Note: RFC2217 mentions RTS but never CTS. Since RTS is an 274 | output signal, it doesn't make sense to return it's status, 275 | especially if this means we cannot return the CTS 276 | status. We believe the RFC is in error in this 277 | area. Therefore, we are returning CTS rather than RTS. */ 278 | if (MLines & TIOCM_CTS) 279 | return TNCOM_CMD_RTS_ON; 280 | else 281 | return TNCOM_CMD_RTS_OFF; 282 | break; 283 | 284 | /* Com Port Flow Control Setting (inbound) */ 285 | case TNCOM_CMD_INFLOW_REQ: 286 | return Termios2TncomInFlow(&PortSettings); 287 | break; 288 | 289 | /* Com Port Flow Control Setting (outbound/both) */ 290 | case TNCOM_CMD_FLOW_REQ: 291 | default: 292 | return Termios2TncomOutFlow(&PortSettings); 293 | break; 294 | } 295 | } 296 | 297 | /* Return the status of the modem control lines (DCD, CTS, DSR, RNG) */ 298 | unsigned char 299 | GetModemState(PORTHANDLE PortFd, unsigned char PMState) 300 | { 301 | int MLines; 302 | unsigned char MState = (unsigned char) 0; 303 | 304 | ioctl(PortFd, TIOCMGET, &MLines); 305 | 306 | if ((MLines & TIOCM_CAR) != 0) 307 | MState += TNCOM_MODMASK_RLSD; 308 | if ((MLines & TIOCM_RNG) != 0) 309 | MState += TNCOM_MODMASK_RING; 310 | if ((MLines & TIOCM_DSR) != 0) 311 | MState += TNCOM_MODMASK_DSR; 312 | if ((MLines & TIOCM_CTS) != 0) 313 | MState += TNCOM_MODMASK_CTS; 314 | if ((MState & TNCOM_MODMASK_RLSD) != (PMState & TNCOM_MODMASK_RLSD)) 315 | MState += TNCOM_MODMASK_RLSD_DELTA; 316 | if ((MState & TNCOM_MODMASK_RING) != (PMState & TNCOM_MODMASK_RING)) 317 | MState += TNCOM_MODMASK_RING_TRAIL; 318 | if ((MState & TNCOM_MODMASK_DSR) != (PMState & TNCOM_MODMASK_DSR)) 319 | MState += TNCOM_MODMASK_DSR_DELTA; 320 | if ((MState & TNCOM_MODMASK_CTS) != (PMState & TNCOM_MODMASK_CTS)) 321 | MState += TNCOM_MODMASK_CTS_DELTA; 322 | 323 | return (MState); 324 | } 325 | 326 | /* Set the serial port data size */ 327 | void 328 | SetPortDataSize(PORTHANDLE PortFd, unsigned char DataSize) 329 | { 330 | struct termios PortSettings; 331 | tcflag_t PDataSize; 332 | 333 | switch (DataSize) { 334 | case 5: 335 | PDataSize = CS5; 336 | break; 337 | case 6: 338 | PDataSize = CS6; 339 | break; 340 | case 7: 341 | PDataSize = CS7; 342 | break; 343 | case 8: 344 | PDataSize = CS8; 345 | break; 346 | default: 347 | PDataSize = CS8; 348 | break; 349 | } 350 | 351 | tcgetattr(PortFd, &PortSettings); 352 | PortSettings.c_cflag &= ~CSIZE; 353 | PortSettings.c_cflag |= PDataSize & CSIZE; 354 | tcsetattr(PortFd, TCSADRAIN, &PortSettings); 355 | UnixLogPortSettings(&PortSettings); 356 | } 357 | 358 | /* Set the serial port parity */ 359 | void 360 | SetPortParity(PORTHANDLE PortFd, unsigned char Parity) 361 | { 362 | struct termios PortSettings; 363 | 364 | tcgetattr(PortFd, &PortSettings); 365 | 366 | switch (Parity) { 367 | case TNCOM_NOPARITY: 368 | PortSettings.c_cflag = PortSettings.c_cflag & ~PARENB; 369 | break; 370 | case TNCOM_ODDPARITY: 371 | PortSettings.c_cflag = PortSettings.c_cflag | PARENB | PARODD; 372 | break; 373 | case TNCOM_EVENPARITY: 374 | PortSettings.c_cflag = (PortSettings.c_cflag | PARENB) & ~PARODD; 375 | break; 376 | /* There's no support for MARK and SPACE parity so sets no parity */ 377 | default: 378 | LogMsg(LOG_WARNING, "Requested unsupported parity, set to no parity."); 379 | PortSettings.c_cflag = PortSettings.c_cflag & ~PARENB; 380 | break; 381 | } 382 | 383 | tcsetattr(PortFd, TCSADRAIN, &PortSettings); 384 | UnixLogPortSettings(&PortSettings); 385 | } 386 | 387 | /* Set the serial port stop bits size */ 388 | void 389 | SetPortStopSize(PORTHANDLE PortFd, unsigned char StopSize) 390 | { 391 | struct termios PortSettings; 392 | 393 | tcgetattr(PortFd, &PortSettings); 394 | 395 | switch (StopSize) { 396 | case TNCOM_ONESTOPBIT: 397 | PortSettings.c_cflag = PortSettings.c_cflag & ~CSTOPB; 398 | break; 399 | case TNCOM_TWOSTOPBITS: 400 | PortSettings.c_cflag = PortSettings.c_cflag | CSTOPB; 401 | break; 402 | case TNCOM_ONE5STOPBITS: 403 | PortSettings.c_cflag = PortSettings.c_cflag & ~CSTOPB; 404 | LogMsg(LOG_WARNING, "Requested unsupported 1.5 bits stop size, set to 1 bit stop size."); 405 | break; 406 | default: 407 | PortSettings.c_cflag = PortSettings.c_cflag & ~CSTOPB; 408 | break; 409 | } 410 | 411 | tcsetattr(PortFd, TCSADRAIN, &PortSettings); 412 | UnixLogPortSettings(&PortSettings); 413 | } 414 | 415 | /* Set the port flow control and DTR and RTS status */ 416 | void 417 | SetPortFlowControl(PORTHANDLE PortFd, unsigned char How) 418 | { 419 | struct termios PortSettings; 420 | int MLines; 421 | 422 | /* Gets the base status from the port */ 423 | tcgetattr(PortFd, &PortSettings); 424 | ioctl(PortFd, TIOCMGET, &MLines); 425 | 426 | /* Check which settings to change */ 427 | switch (How) { 428 | /* No Flow Control (outbound/both) */ 429 | case TNCOM_CMD_FLOW_NONE: 430 | PortSettings.c_iflag = PortSettings.c_iflag & ~IXON; 431 | PortSettings.c_iflag = PortSettings.c_iflag & ~IXOFF; 432 | PortSettings.c_cflag = PortSettings.c_cflag & ~CRTSCTS; 433 | break; 434 | /* XON/XOFF Flow Control (outbound/both) */ 435 | case TNCOM_CMD_FLOW_XONXOFF: 436 | PortSettings.c_iflag = PortSettings.c_iflag | IXON; 437 | PortSettings.c_iflag = PortSettings.c_iflag | IXOFF; 438 | PortSettings.c_cflag = PortSettings.c_cflag & ~CRTSCTS; 439 | break; 440 | /* HARDWARE Flow Control (outbound/both) */ 441 | case TNCOM_CMD_FLOW_HARDWARE: 442 | PortSettings.c_iflag = PortSettings.c_iflag & ~IXON; 443 | PortSettings.c_iflag = PortSettings.c_iflag & ~IXOFF; 444 | PortSettings.c_cflag = PortSettings.c_cflag | CRTSCTS; 445 | break; 446 | /* DTR Signal State ON */ 447 | case TNCOM_CMD_DTR_ON: 448 | MLines = MLines | TIOCM_DTR; 449 | break; 450 | /* DTR Signal State OFF */ 451 | case TNCOM_CMD_DTR_OFF: 452 | MLines = MLines & ~TIOCM_DTR; 453 | break; 454 | /* RTS Signal State ON */ 455 | case TNCOM_CMD_RTS_ON: 456 | MLines = MLines | TIOCM_RTS; 457 | break; 458 | /* RTS Signal State OFF */ 459 | case TNCOM_CMD_RTS_OFF: 460 | MLines = MLines & ~TIOCM_RTS; 461 | break; 462 | 463 | /* INBOUND FLOW CONTROL is ignored */ 464 | case TNCOM_CMD_INFLOW_NONE: 465 | case TNCOM_CMD_INFLOW_XONXOFF: 466 | case TNCOM_CMD_INFLOW_HARDWARE: 467 | LogMsg(LOG_WARNING, "Inbound flow control ignored."); 468 | break; 469 | 470 | case TNCOM_CMD_FLOW_DCD: 471 | LogMsg(LOG_WARNING, "DCD Flow Control ignored."); 472 | break; 473 | 474 | case TNCOM_CMD_INFLOW_DTR: 475 | LogMsg(LOG_WARNING, "DTR Flow Control ignored."); 476 | break; 477 | 478 | case TNCOM_CMD_FLOW_DSR: 479 | LogMsg(LOG_WARNING, "DSR Flow Control ignored."); 480 | break; 481 | 482 | default: 483 | LogMsg(LOG_WARNING, "Requested invalid flow control."); 484 | break; 485 | } 486 | 487 | tcsetattr(PortFd, TCSADRAIN, &PortSettings); 488 | ioctl(PortFd, TIOCMSET, &MLines); 489 | UnixLogPortSettings(&PortSettings); 490 | } 491 | 492 | /* Set the serial port speed */ 493 | void 494 | SetPortSpeed(PORTHANDLE PortFd, unsigned long BaudRate) 495 | { 496 | struct termios PortSettings; 497 | speed_t Speed; 498 | 499 | switch (BaudRate) { 500 | case 50UL: 501 | Speed = B50; 502 | break; 503 | case 75UL: 504 | Speed = B75; 505 | break; 506 | case 110UL: 507 | Speed = B110; 508 | break; 509 | case 134UL: 510 | Speed = B134; 511 | break; 512 | case 150UL: 513 | Speed = B150; 514 | break; 515 | case 200UL: 516 | Speed = B200; 517 | break; 518 | case 300UL: 519 | Speed = B300; 520 | break; 521 | case 600UL: 522 | Speed = B600; 523 | break; 524 | case 1200UL: 525 | Speed = B1200; 526 | break; 527 | case 1800UL: 528 | Speed = B1800; 529 | break; 530 | case 2400UL: 531 | Speed = B2400; 532 | break; 533 | case 4800UL: 534 | Speed = B4800; 535 | break; 536 | case 9600UL: 537 | Speed = B9600; 538 | break; 539 | case 19200UL: 540 | Speed = B19200; 541 | break; 542 | case 38400UL: 543 | Speed = B38400; 544 | break; 545 | case 57600UL: 546 | Speed = B57600; 547 | break; 548 | case 115200UL: 549 | Speed = B115200; 550 | break; 551 | case 230400UL: 552 | Speed = B230400; 553 | break; 554 | case 460800UL: 555 | Speed = B460800; 556 | break; 557 | default: 558 | LogMsg(LOG_WARNING, "Unknwon baud rate requested, setting to 9600."); 559 | Speed = B9600; 560 | break; 561 | } 562 | 563 | tcgetattr(PortFd, &PortSettings); 564 | cfsetospeed(&PortSettings, Speed); 565 | cfsetispeed(&PortSettings, Speed); 566 | tcsetattr(PortFd, TCSADRAIN, &PortSettings); 567 | UnixLogPortSettings(&PortSettings); 568 | } 569 | 570 | void 571 | SetBreak(PORTHANDLE PortFd, Boolean on) 572 | { 573 | if (on) { 574 | tcsendbreak(PortFd, 0); 575 | } 576 | } 577 | 578 | void 579 | SetFlush(PORTHANDLE PortFd, int selector) 580 | { 581 | switch (selector) { 582 | /* Inbound flush */ 583 | case TNCOM_PURGE_RX: 584 | tcflush(PortFd, TCIFLUSH); 585 | break; 586 | /* Outbound flush */ 587 | case TNCOM_PURGE_TX: 588 | tcflush(PortFd, TCOFLUSH); 589 | break; 590 | /* Inbound/outbound flush */ 591 | case TNCOM_PURGE_BOTH: 592 | tcflush(PortFd, TCIOFLUSH); 593 | break; 594 | } 595 | } 596 | 597 | /* Try to lock the file given in LockFile as pid LockPid using the classical 598 | HDB (ASCII) file locking scheme */ 599 | static int 600 | HDBLockFile(const char *LockFile, pid_t LockPid) 601 | { 602 | pid_t Pid; 603 | int FileDes; 604 | int N; 605 | char HDBBuffer[HDBHeaderLen + 1]; 606 | char LogStr[TmpStrLen]; 607 | 608 | /* Try to create the lock file */ 609 | while ((FileDes = open(LockFile, O_CREAT | O_WRONLY | O_EXCL, LockFileMode)) == OpenError) { 610 | /* Check the kind of error */ 611 | if ((errno == EEXIST) 612 | && ((FileDes = open(LockFile, O_RDONLY, 0)) != OpenError)) { 613 | /* Read the HDB header from the existing lockfile */ 614 | N = read(FileDes, HDBBuffer, HDBHeaderLen); 615 | close(FileDes); 616 | 617 | /* Check if the header has been read */ 618 | if (N <= 0) { 619 | /* Emtpy lock file or error: may be another application 620 | was writing its pid in it */ 621 | snprintf(LogStr, sizeof(LogStr), "Can't read pid from lock file %s.", LockFile); 622 | LogStr[sizeof(LogStr) - 1] = '\0'; 623 | LogMsg(LOG_NOTICE, LogStr); 624 | 625 | /* Lock process failed */ 626 | return (LockKo); 627 | } 628 | 629 | /* Gets the pid of the locking process */ 630 | HDBBuffer[N] = '\0'; 631 | Pid = atoi(HDBBuffer); 632 | 633 | /* Check if it is our pid */ 634 | if (Pid == LockPid) { 635 | /* File already locked by us */ 636 | snprintf(LogStr, sizeof(LogStr), "Read our pid from lock %s.", LockFile); 637 | LogStr[sizeof(LogStr) - 1] = '\0'; 638 | LogMsg(LOG_DEBUG, LogStr); 639 | 640 | /* Lock process succeded */ 641 | return (LockOk); 642 | } 643 | 644 | /* Check if hte HDB header is valid and if the locking process 645 | is still alive */ 646 | if ((Pid == 0) || ((kill(Pid, 0) != 0) && (errno == ESRCH))) 647 | /* Invalid lock, remove it */ 648 | if (unlink(LockFile) == NoError) { 649 | snprintf(LogStr, sizeof(LogStr), 650 | "Removed stale lock %s (pid %d).", LockFile, Pid); 651 | LogStr[sizeof(LogStr) - 1] = '\0'; 652 | LogMsg(LOG_NOTICE, LogStr); 653 | } 654 | else { 655 | snprintf(LogStr, sizeof(LogStr), 656 | "Couldn't remove stale lock %s (pid %d).", LockFile, Pid); 657 | LogStr[sizeof(LogStr) - 1] = '\0'; 658 | LogMsg(LOG_ERR, LogStr); 659 | return (LockKo); 660 | } 661 | else { 662 | /* The lock file is owned by another valid process */ 663 | snprintf(LogStr, sizeof(LogStr), "Lock %s is owned by pid %d.", LockFile, Pid); 664 | LogStr[sizeof(LogStr) - 1] = '\0'; 665 | LogMsg(LOG_INFO, LogStr); 666 | 667 | /* Lock process failed */ 668 | return (Locked); 669 | } 670 | } 671 | else { 672 | /* Lock file creation problem */ 673 | snprintf(LogStr, sizeof(LogStr), "Can't create lock file %s.", LockFile); 674 | LogStr[sizeof(LogStr) - 1] = '\0'; 675 | LogMsg(LOG_ERR, LogStr); 676 | 677 | /* Lock process failed */ 678 | return (LockKo); 679 | } 680 | } 681 | 682 | /* Prepare the HDB buffer with our pid */ 683 | snprintf(HDBBuffer, sizeof(HDBBuffer), "%10d\n", (int) LockPid); 684 | LogStr[sizeof(HDBBuffer) - 1] = '\0'; 685 | 686 | /* Fill the lock file with the HDB buffer */ 687 | if (write(FileDes, HDBBuffer, HDBHeaderLen) != HDBHeaderLen) { 688 | /* Lock file creation problem, remove it */ 689 | close(FileDes); 690 | snprintf(LogStr, sizeof(LogStr), "Can't write HDB header to lock file %s.", LockFile); 691 | LogStr[sizeof(LogStr) - 1] = '\0'; 692 | LogMsg(LOG_ERR, LogStr); 693 | unlink(LockFile); 694 | 695 | /* Lock process failed */ 696 | return (LockKo); 697 | } 698 | 699 | /* Closes the lock file */ 700 | close(FileDes); 701 | 702 | /* Lock process succeded */ 703 | return (LockOk); 704 | } 705 | 706 | /* Remove the lock file created with HDBLockFile */ 707 | static void 708 | HDBUnlockFile(const char *LockFile, pid_t LockPid) 709 | { 710 | char LogStr[TmpStrLen]; 711 | 712 | /* Check if the lock file is still owned by us */ 713 | if (HDBLockFile(LockFile, LockPid) == LockOk) { 714 | /* Remove the lock file */ 715 | unlink(LockFile); 716 | snprintf(LogStr, sizeof(LogStr), "Unlocked lock file %s.", LockFile); 717 | LogStr[sizeof(LogStr) - 1] = '\0'; 718 | LogMsg(LOG_NOTICE, LogStr); 719 | } 720 | } 721 | 722 | int 723 | #ifndef ANDROID 724 | OpenPort(const char *DeviceName, const char *LockFileName, PORTHANDLE * PortFd) 725 | #else 726 | OpenPort(const char *DeviceName, PORTHANDLE * PortFd) 727 | #endif 728 | { 729 | char LogStr[TmpStrLen]; 730 | /* Actual port settings */ 731 | struct termios PortSettings; 732 | 733 | #ifndef ANDROID 734 | /* Try to lock the device */ 735 | if (HDBLockFile(LockFileName, getpid()) != LockOk) { 736 | /* Lock failed */ 737 | snprintf(LogStr, sizeof(LogStr), "Unable to lock %s. Exiting.", LockFileName); 738 | LogStr[sizeof(LogStr) - 1] = '\0'; 739 | LogMsg(LOG_NOTICE, LogStr); 740 | return (Error); 741 | } 742 | else { 743 | /* Lock succeeded */ 744 | snprintf(LogStr, sizeof(LogStr), "Device %s locked.", DeviceName); 745 | LogStr[sizeof(LogStr) - 1] = '\0'; 746 | LogMsg(LOG_INFO, LogStr); 747 | } 748 | #endif 749 | 750 | /* Open the device */ 751 | if ((*PortFd = open(DeviceName, O_RDWR | O_NOCTTY | O_NONBLOCK, 0)) == OpenError) { 752 | return (Error); 753 | } 754 | 755 | /* Get the actual port settings */ 756 | InitialPortSettings = &initialportsettings; 757 | tcgetattr(*PortFd, InitialPortSettings); 758 | tcgetattr(*PortFd, &PortSettings); 759 | UnixLogPortSettings(&PortSettings); 760 | 761 | /* Set the serial port to raw mode */ 762 | cfmakeraw(&PortSettings); 763 | 764 | /* Enable HANGUP on close and disable modem control line handling */ 765 | PortSettings.c_cflag = (PortSettings.c_cflag | HUPCL) | CLOCAL; 766 | 767 | /* Enable break handling */ 768 | PortSettings.c_iflag = (PortSettings.c_iflag & ~IGNBRK) | BRKINT; 769 | 770 | /* Write the port settings to device */ 771 | tcsetattr(*PortFd, TCSANOW, &PortSettings); 772 | 773 | return NoError; 774 | } 775 | 776 | #ifndef ANDROID 777 | void 778 | ClosePort(PORTHANDLE PortFd, const char *LockFileName) 779 | #else 780 | void 781 | ClosePort(PORTHANDLE PortFd) 782 | #endif 783 | { 784 | /* Restores initial port settings */ 785 | if (InitialPortSettings) 786 | tcsetattr(PortFd, TCSANOW, InitialPortSettings); 787 | 788 | /* Closes the device */ 789 | close(PortFd); 790 | 791 | /* Removes the lock file */ 792 | #ifndef ANDROID 793 | HDBUnlockFile(LockFileName, getpid()); 794 | #endif 795 | 796 | /* Closes the log */ 797 | if (!StdErrLogging) { 798 | closelog(); 799 | } 800 | } 801 | 802 | /* Function called on many signals */ 803 | static void 804 | SignalFunction(int unused) 805 | { 806 | /* Just to avoid compilation warnings */ 807 | /* There's no performance penalty in doing this 808 | because this function is almost never called */ 809 | unused = unused; 810 | 811 | /* Same as the exit function */ 812 | ExitFunction(); 813 | } 814 | 815 | void 816 | PlatformInit() 817 | { 818 | #ifndef ANDROID 819 | if (!StdErrLogging) { 820 | openlog("sercd", LOG_PID, LOG_USER); 821 | } 822 | 823 | /* Register exit and signal handler functions */ 824 | atexit(ExitFunction); 825 | signal(SIGHUP, SignalFunction); 826 | signal(SIGQUIT, SignalFunction); 827 | signal(SIGABRT, SignalFunction); 828 | signal(SIGTERM, SignalFunction); 829 | 830 | /* Register the function to be called on break condition */ 831 | signal(SIGINT, BreakFunction); 832 | #endif 833 | } 834 | 835 | /* Generic log function with log level control. Uses the same log levels 836 | of the syslog(3) system call */ 837 | void 838 | LogMsg(int LogLevel, const char *const Msg) 839 | { 840 | if (LogLevel <= MaxLogLevel) { 841 | #ifndef ANDROID 842 | if (StdErrLogging) { 843 | fprintf(stderr, "%s\n", Msg); 844 | } 845 | else { 846 | syslog(LogLevel, "%s", Msg); 847 | } 848 | #else 849 | int prio; 850 | switch(LogLevel) { 851 | case LOG_EMERG: 852 | prio = ANDROID_LOG_FATAL; 853 | break; 854 | case LOG_ALERT: 855 | case LOG_CRIT: 856 | case LOG_ERR: 857 | prio = ANDROID_LOG_ERROR; 858 | break; 859 | case LOG_WARNING: 860 | prio = ANDROID_LOG_WARN; 861 | break; 862 | case LOG_NOTICE: 863 | case LOG_INFO: 864 | prio = ANDROID_LOG_INFO; 865 | break; 866 | case LOG_DEBUG: 867 | prio = ANDROID_LOG_DEBUG; 868 | } 869 | __android_log_write(prio, "sercd", Msg); 870 | #endif 871 | } 872 | } 873 | 874 | 875 | int 876 | SercdSelect(PORTHANDLE * DeviceIn, PORTHANDLE * DeviceOut, PORTHANDLE * Modemstate, 877 | SERCD_SOCKET * SocketOut, SERCD_SOCKET * SocketIn, 878 | SERCD_SOCKET * SocketConnect, long PollInterval) 879 | { 880 | fd_set InFdSet; 881 | fd_set OutFdSet; 882 | int highest_fd = -1, selret; 883 | struct timeval BTimeout; 884 | struct timeval newpoll; 885 | int ret = 0; 886 | 887 | FD_ZERO(&InFdSet); 888 | FD_ZERO(&OutFdSet); 889 | 890 | if (DeviceIn) { 891 | FD_SET(*DeviceIn, &InFdSet); 892 | highest_fd = MAX(highest_fd, *DeviceIn); 893 | } 894 | if (DeviceOut) { 895 | FD_SET(*DeviceOut, &OutFdSet); 896 | highest_fd = MAX(highest_fd, *DeviceOut); 897 | } 898 | if (SocketOut) { 899 | FD_SET(*SocketOut, &OutFdSet); 900 | highest_fd = MAX(highest_fd, *SocketOut); 901 | } 902 | if (SocketIn) { 903 | FD_SET(*SocketIn, &InFdSet); 904 | highest_fd = MAX(highest_fd, *SocketIn); 905 | } 906 | if (SocketConnect) { 907 | FD_SET(*SocketConnect, &InFdSet); 908 | highest_fd = MAX(highest_fd, *SocketConnect); 909 | } 910 | 911 | BTimeout.tv_sec = PollInterval / 1000; 912 | BTimeout.tv_usec = (PollInterval % 1000) * 1000; 913 | 914 | selret = select(highest_fd + 1, &InFdSet, &OutFdSet, NULL, &BTimeout); 915 | 916 | if (selret < 0) 917 | return selret; 918 | 919 | if (DeviceIn && FD_ISSET(*DeviceIn, &InFdSet)) { 920 | ret |= SERCD_EV_DEVICEIN; 921 | } 922 | if (DeviceOut && FD_ISSET(*DeviceOut, &OutFdSet)) { 923 | ret |= SERCD_EV_DEVICEOUT; 924 | } 925 | if (SocketOut && FD_ISSET(*SocketOut, &OutFdSet)) { 926 | ret |= SERCD_EV_SOCKETOUT; 927 | } 928 | if (SocketIn && FD_ISSET(*SocketIn, &InFdSet)) { 929 | ret |= SERCD_EV_SOCKETIN; 930 | } 931 | if (SocketConnect && FD_ISSET(*SocketConnect, &InFdSet)) { 932 | ret |= SERCD_EV_SOCKETCONNECT; 933 | } 934 | 935 | if (Modemstate) { 936 | gettimeofday(&newpoll, NULL); 937 | if (timercmp(&newpoll, &LastPoll, <)) { 938 | /* Time moved backwards */ 939 | timerclear(&LastPoll); 940 | } 941 | newpoll.tv_sec -= PollInterval / 1000; 942 | newpoll.tv_usec -= PollInterval % 1000; 943 | if (timercmp(&LastPoll, &newpoll, <)) { 944 | gettimeofday(&LastPoll, NULL); 945 | ret |= SERCD_EV_MODEMSTATE; 946 | } 947 | } 948 | 949 | return ret; 950 | } 951 | 952 | void 953 | NewListener(SERCD_SOCKET LSocketFd) 954 | { 955 | 956 | } 957 | 958 | /* Drop client connection and close serial port */ 959 | #ifndef ANDROID 960 | void 961 | DropConnection(PORTHANDLE * DeviceFd, SERCD_SOCKET * InSocketFd, SERCD_SOCKET * OutSocketFd, 962 | const char *LockFileName) 963 | #else 964 | void 965 | DropConnection(PORTHANDLE * DeviceFd, SERCD_SOCKET * InSocketFd, SERCD_SOCKET * OutSocketFd) 966 | #endif 967 | { 968 | if (DeviceFd) { 969 | #ifndef ANDROID 970 | ClosePort(*DeviceFd, LockFileName); 971 | #else 972 | ClosePort(*DeviceFd); 973 | #endif 974 | } 975 | 976 | if (InSocketFd) { 977 | close(*InSocketFd); 978 | } 979 | 980 | if (OutSocketFd) { 981 | close(*OutSocketFd); 982 | } 983 | } 984 | 985 | ssize_t 986 | WriteToDev(PORTHANDLE port, const void *buf, size_t count) 987 | { 988 | return write(port, buf, count); 989 | } 990 | 991 | ssize_t 992 | ReadFromDev(PORTHANDLE port, void *buf, size_t count) 993 | { 994 | return read(port, buf, count); 995 | } 996 | 997 | ssize_t 998 | WriteToNet(SERCD_SOCKET sock, const void *buf, size_t count) 999 | { 1000 | return write(sock, buf, count); 1001 | } 1002 | 1003 | ssize_t 1004 | ReadFromNet(SERCD_SOCKET sock, void *buf, size_t count) 1005 | { 1006 | return read(sock, buf, count); 1007 | } 1008 | 1009 | void 1010 | ModemStateNotified() 1011 | { 1012 | } 1013 | 1014 | #endif /* WIN32 */ 1015 | -------------------------------------------------------------------------------- /android-sercd/project/jni/unix.h: -------------------------------------------------------------------------------- 1 | /* 2 | * sercd UNIX support 3 | * Copyright 2008 Peter Åstrand for Cendio AB 4 | * see file COPYING for license details 5 | */ 6 | 7 | #ifndef WIN32 8 | #ifndef SERCD_UNIX_H 9 | #define SERCD_UNIX_H 10 | 11 | #include 12 | #include /* ioctl */ 13 | #include /* htonl */ 14 | #include /* IPTOS_LOWDELAY */ 15 | #include /* inet_addr */ 16 | #include /* setsockopt */ 17 | 18 | #define PORTHANDLE int 19 | 20 | #define SERCD_SOCKET int 21 | 22 | #define closesocket close 23 | 24 | /* Default modem state polling in milliseconds (100 msec should be enough) */ 25 | #define DEFAULT_POLL_INTERVAL 100 26 | 27 | #endif /* SERCD_UNIX_H */ 28 | #endif /* WIN32 */ 29 | -------------------------------------------------------------------------------- /android-sercd/project/res/drawable/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cepr/android-serialport-api/2be0c20f0f8defba0dc6de5144f4799f0bbabfc6/android-sercd/project/res/drawable/icon.png -------------------------------------------------------------------------------- /android-sercd/project/res/drawable/notification_icon_connected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cepr/android-serialport-api/2be0c20f0f8defba0dc6de5144f4799f0bbabfc6/android-sercd/project/res/drawable/notification_icon_connected.png -------------------------------------------------------------------------------- /android-sercd/project/res/drawable/notification_icon_ready.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cepr/android-serialport-api/2be0c20f0f8defba0dc6de5144f4799f0bbabfc6/android-sercd/project/res/drawable/notification_icon_ready.png -------------------------------------------------------------------------------- /android-sercd/project/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Serial Port Proxy 4 | About sercd 5 | About android-serialport-api 6 | About 7 | Hardware 8 | General 9 | Network 10 | Interface 11 | Port 12 | tty device 13 | Enabled 14 | Waiting for a remote connection 15 | Remote idle 16 | Remote connected to serial port 17 | Failed, check your parameters 18 | Failed changing device permissions 19 | 20 | -------------------------------------------------------------------------------- /android-sercd/project/res/xml/preferences.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 10 | 11 | 13 | 17 | 18 | 20 | 24 | 28 | 29 | 31 | 34 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /android-sercd/project/src/android/serialport/SerialPortFinder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009 Cedric Priscal 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package android.serialport; 18 | 19 | import java.io.File; 20 | import java.io.FileReader; 21 | import java.io.IOException; 22 | import java.io.LineNumberReader; 23 | import java.util.Iterator; 24 | import java.util.Vector; 25 | 26 | import android.util.Log; 27 | 28 | public class SerialPortFinder { 29 | 30 | public class Driver { 31 | public Driver(String name, String root) { 32 | mDriverName = name; 33 | mDeviceRoot = root; 34 | } 35 | private String mDriverName; 36 | private String mDeviceRoot; 37 | Vector mDevices = null; 38 | public Vector getDevices() { 39 | if (mDevices == null) { 40 | mDevices = new Vector(); 41 | File dev = new File("/dev"); 42 | File[] files = dev.listFiles(); 43 | int i; 44 | for (i=0; i mDrivers = null; 61 | 62 | Vector getDrivers() throws IOException { 63 | if (mDrivers == null) { 64 | mDrivers = new Vector(); 65 | LineNumberReader r = new LineNumberReader(new FileReader("/proc/tty/drivers")); 66 | String l; 67 | while((l = r.readLine()) != null) { 68 | String[] w = l.split(" +"); 69 | if ((w.length == 5) && (w[4].equals("serial"))) { 70 | Log.d(TAG, "Found new driver: " + w[1]); 71 | mDrivers.add(new Driver(w[0], w[1])); 72 | } 73 | } 74 | r.close(); 75 | } 76 | return mDrivers; 77 | } 78 | 79 | public String[] getAllDevices() { 80 | Vector devices = new Vector(); 81 | // Parse each driver 82 | Iterator itdriv; 83 | try { 84 | itdriv = getDrivers().iterator(); 85 | while(itdriv.hasNext()) { 86 | Driver driver = itdriv.next(); 87 | Iterator itdev = driver.getDevices().iterator(); 88 | while(itdev.hasNext()) { 89 | String device = itdev.next().getName(); 90 | String value = String.format("%s (%s)", device, driver.getName()); 91 | devices.add(value); 92 | } 93 | } 94 | } catch (IOException e) { 95 | e.printStackTrace(); 96 | } 97 | return devices.toArray(new String[devices.size()]); 98 | } 99 | 100 | public String[] getAllDevicesPath() { 101 | Vector devices = new Vector(); 102 | // Parse each driver 103 | Iterator itdriv; 104 | try { 105 | itdriv = getDrivers().iterator(); 106 | while(itdriv.hasNext()) { 107 | Driver driver = itdriv.next(); 108 | Iterator itdev = driver.getDevices().iterator(); 109 | while(itdev.hasNext()) { 110 | String device = itdev.next().getAbsolutePath(); 111 | devices.add(device); 112 | } 113 | } 114 | } catch (IOException e) { 115 | e.printStackTrace(); 116 | } 117 | return devices.toArray(new String[devices.size()]); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /android-sercd/project/src/gnu/sercd/Sercd.java: -------------------------------------------------------------------------------- 1 | package gnu.sercd; 2 | 3 | import java.io.File; 4 | import java.net.InetAddress; 5 | import java.net.NetworkInterface; 6 | import java.net.SocketException; 7 | import java.util.ArrayList; 8 | import java.util.Enumeration; 9 | 10 | import android.app.AlertDialog; 11 | import android.os.Bundle; 12 | import android.preference.CheckBoxPreference; 13 | import android.preference.EditTextPreference; 14 | import android.preference.ListPreference; 15 | import android.preference.Preference; 16 | import android.preference.PreferenceActivity; 17 | import android.preference.Preference.OnPreferenceChangeListener; 18 | import android.serialport.SerialPortFinder; 19 | import android.util.Log; 20 | 21 | public class Sercd extends PreferenceActivity { 22 | 23 | protected static final String TAG = "Sercd"; 24 | private CheckBoxPreference mEnabled; 25 | private ListPreference mSerialPort; 26 | private ListPreference mNetworkInterfaces; 27 | private EditTextPreference mNetworkPort; 28 | 29 | private OnPreferenceChangeListener mPreferenceChangeListener = new OnPreferenceChangeListener() { 30 | @Override 31 | public boolean onPreferenceChange(Preference preference, Object newValue) { 32 | preference.setSummary((CharSequence)newValue); 33 | return true; 34 | } 35 | }; 36 | 37 | /** Called when the activity is first created. */ 38 | @Override 39 | public void onCreate(Bundle savedInstanceState) { 40 | super.onCreate(savedInstanceState); 41 | 42 | /* Load preferences from XML */ 43 | addPreferencesFromResource(R.xml.preferences); 44 | 45 | /* Fetch corresponding Java objects */ 46 | mEnabled = (CheckBoxPreference)findPreference("enabled"); 47 | mSerialPort = (ListPreference)findPreference("serialport"); 48 | mNetworkInterfaces = (ListPreference)findPreference("netinterface"); 49 | mNetworkPort = (EditTextPreference)findPreference("portnumber"); 50 | 51 | /* Complete lists, etc */ 52 | mSerialPort.setOnPreferenceChangeListener(mPreferenceChangeListener); 53 | mSerialPort.setSummary(mSerialPort.getValue()); 54 | mNetworkInterfaces.setOnPreferenceChangeListener(mPreferenceChangeListener); 55 | mNetworkInterfaces.setSummary(mNetworkInterfaces.getValue()); 56 | mNetworkPort.setOnPreferenceChangeListener(mPreferenceChangeListener); 57 | mNetworkPort.setSummary(mNetworkPort.getText()); 58 | mEnabled.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { 59 | @Override 60 | public boolean onPreferenceChange(Preference preference, Object newValue) { 61 | if ((Boolean)newValue) { 62 | String serialport = mSerialPort.getValue(); 63 | String networkinterface = mNetworkInterfaces.getValue(); 64 | 65 | /* Check access permission */ 66 | File device = new File(serialport); 67 | if (!device.canRead() || !device.canWrite()) { 68 | try { 69 | /* Missing read/write permission, trying to chmod the file */ 70 | Process su; 71 | su = Runtime.getRuntime().exec("/system/bin/su"); 72 | String cmd = "chmod 666 " + device.getAbsolutePath() + "\n" 73 | + "exit\n"; 74 | su.getOutputStream().write(cmd.getBytes()); 75 | if ((su.waitFor() != 0) || !device.canRead() 76 | || !device.canWrite()) { 77 | new AlertDialog.Builder(Sercd.this) 78 | .setMessage(R.string.su_failed) 79 | .show(); 80 | return false; 81 | } 82 | } catch (Exception e) { 83 | e.printStackTrace(); 84 | new AlertDialog.Builder(Sercd.this) 85 | .setMessage(R.string.su_failed) 86 | .show(); 87 | return false; 88 | } 89 | } 90 | 91 | int port = Integer.parseInt(mNetworkPort.getText()); 92 | Log.d(TAG, "Starting sercd with parameters " 93 | + serialport + ", " + networkinterface 94 | + ":" + port); 95 | SercdService.Start( 96 | Sercd.this, 97 | serialport, 98 | networkinterface, 99 | port 100 | ); 101 | } else { 102 | SercdService.Stop(Sercd.this); 103 | } 104 | return true; 105 | } 106 | }); 107 | 108 | feedNetworkInterfacesList(); 109 | feedSerialPortList(); 110 | 111 | if (mEnabled.isChecked()) { 112 | // SercdService.Start(this, "/dev/ttyMSM2", "127.0.0.1", 30001); 113 | } 114 | } 115 | 116 | private void feedSerialPortList() { 117 | SerialPortFinder spf = new SerialPortFinder(); 118 | mSerialPort.setEntries(spf.getAllDevices()); 119 | mSerialPort.setEntryValues(spf.getAllDevicesPath()); 120 | } 121 | 122 | private void feedNetworkInterfacesList() { 123 | Enumeration nets; 124 | try { 125 | nets = NetworkInterface.getNetworkInterfaces(); 126 | ArrayList displaynames = new ArrayList(); 127 | ArrayList names = new ArrayList(); 128 | while(nets.hasMoreElements()) { 129 | NetworkInterface net = nets.nextElement(); 130 | Enumeration inets = net.getInetAddresses(); 131 | while(inets.hasMoreElements()) { 132 | InetAddress inet = inets.nextElement(); 133 | String address = inet.getHostAddress(); 134 | displaynames.add(address + " (" + net.getDisplayName() + ")"); 135 | names.add(address); 136 | } 137 | } 138 | int size = displaynames.size(); 139 | int i; 140 | CharSequence[] a = new CharSequence[size]; 141 | CharSequence[] b = new CharSequence[size]; 142 | for (i=0; i 2 | 6 | 7 | 11 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /android-serialport-api/project/jni/Android.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2009 Cedric Priscal 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | LOCAL_PATH := $(call my-dir) 18 | 19 | include $(CLEAR_VARS) 20 | 21 | TARGET_PLATFORM := android-3 22 | LOCAL_MODULE := serial_port 23 | LOCAL_SRC_FILES := SerialPort.c 24 | LOCAL_LDLIBS := -llog 25 | 26 | include $(BUILD_SHARED_LIBRARY) 27 | -------------------------------------------------------------------------------- /android-serialport-api/project/jni/Application.mk: -------------------------------------------------------------------------------- 1 | APP_ABI := armeabi armeabi-v7a x86 2 | -------------------------------------------------------------------------------- /android-serialport-api/project/jni/SerialPort.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009-2011 Cedric Priscal 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "SerialPort.h" 26 | 27 | #include "android/log.h" 28 | static const char *TAG="serial_port"; 29 | #define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO, TAG, fmt, ##args) 30 | #define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args) 31 | #define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args) 32 | 33 | static speed_t getBaudrate(jint baudrate) 34 | { 35 | switch(baudrate) { 36 | case 0: return B0; 37 | case 50: return B50; 38 | case 75: return B75; 39 | case 110: return B110; 40 | case 134: return B134; 41 | case 150: return B150; 42 | case 200: return B200; 43 | case 300: return B300; 44 | case 600: return B600; 45 | case 1200: return B1200; 46 | case 1800: return B1800; 47 | case 2400: return B2400; 48 | case 4800: return B4800; 49 | case 9600: return B9600; 50 | case 19200: return B19200; 51 | case 38400: return B38400; 52 | case 57600: return B57600; 53 | case 115200: return B115200; 54 | case 230400: return B230400; 55 | case 460800: return B460800; 56 | case 500000: return B500000; 57 | case 576000: return B576000; 58 | case 921600: return B921600; 59 | case 1000000: return B1000000; 60 | case 1152000: return B1152000; 61 | case 1500000: return B1500000; 62 | case 2000000: return B2000000; 63 | case 2500000: return B2500000; 64 | case 3000000: return B3000000; 65 | case 3500000: return B3500000; 66 | case 4000000: return B4000000; 67 | default: return -1; 68 | } 69 | } 70 | 71 | /* 72 | * Class: android_serialport_SerialPort 73 | * Method: open 74 | * Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor; 75 | */ 76 | JNIEXPORT jobject JNICALL Java_android_1serialport_1api_SerialPort_open 77 | (JNIEnv *env, jclass thiz, jstring path, jint baudrate, jint flags) 78 | { 79 | int fd; 80 | speed_t speed; 81 | jobject mFileDescriptor; 82 | 83 | /* Check arguments */ 84 | { 85 | speed = getBaudrate(baudrate); 86 | if (speed == -1) { 87 | /* TODO: throw an exception */ 88 | LOGE("Invalid baudrate"); 89 | return NULL; 90 | } 91 | } 92 | 93 | /* Opening device */ 94 | { 95 | jboolean iscopy; 96 | const char *path_utf = (*env)->GetStringUTFChars(env, path, &iscopy); 97 | LOGD("Opening serial port %s with flags 0x%x", path_utf, O_RDWR | flags); 98 | fd = open(path_utf, O_RDWR | flags); 99 | LOGD("open() fd = %d", fd); 100 | (*env)->ReleaseStringUTFChars(env, path, path_utf); 101 | if (fd == -1) 102 | { 103 | /* Throw an exception */ 104 | LOGE("Cannot open port"); 105 | /* TODO: throw an exception */ 106 | return NULL; 107 | } 108 | } 109 | 110 | /* Configure device */ 111 | { 112 | struct termios cfg; 113 | LOGD("Configuring serial port"); 114 | if (tcgetattr(fd, &cfg)) 115 | { 116 | LOGE("tcgetattr() failed"); 117 | close(fd); 118 | /* TODO: throw an exception */ 119 | return NULL; 120 | } 121 | 122 | cfmakeraw(&cfg); 123 | cfsetispeed(&cfg, speed); 124 | cfsetospeed(&cfg, speed); 125 | 126 | if (tcsetattr(fd, TCSANOW, &cfg)) 127 | { 128 | LOGE("tcsetattr() failed"); 129 | close(fd); 130 | /* TODO: throw an exception */ 131 | return NULL; 132 | } 133 | } 134 | 135 | /* Create a corresponding file descriptor */ 136 | { 137 | jclass cFileDescriptor = (*env)->FindClass(env, "java/io/FileDescriptor"); 138 | jmethodID iFileDescriptor = (*env)->GetMethodID(env, cFileDescriptor, "", "()V"); 139 | jfieldID descriptorID = (*env)->GetFieldID(env, cFileDescriptor, "descriptor", "I"); 140 | mFileDescriptor = (*env)->NewObject(env, cFileDescriptor, iFileDescriptor); 141 | (*env)->SetIntField(env, mFileDescriptor, descriptorID, (jint)fd); 142 | } 143 | 144 | return mFileDescriptor; 145 | } 146 | 147 | /* 148 | * Class: cedric_serial_SerialPort 149 | * Method: close 150 | * Signature: ()V 151 | */ 152 | JNIEXPORT void JNICALL Java_android_1serialport_1api_SerialPort_close 153 | (JNIEnv *env, jobject thiz) 154 | { 155 | jclass SerialPortClass = (*env)->GetObjectClass(env, thiz); 156 | jclass FileDescriptorClass = (*env)->FindClass(env, "java/io/FileDescriptor"); 157 | 158 | jfieldID mFdID = (*env)->GetFieldID(env, SerialPortClass, "mFd", "Ljava/io/FileDescriptor;"); 159 | jfieldID descriptorID = (*env)->GetFieldID(env, FileDescriptorClass, "descriptor", "I"); 160 | 161 | jobject mFd = (*env)->GetObjectField(env, thiz, mFdID); 162 | jint descriptor = (*env)->GetIntField(env, mFd, descriptorID); 163 | 164 | LOGD("close(fd = %d)", descriptor); 165 | close(descriptor); 166 | } 167 | 168 | -------------------------------------------------------------------------------- /android-serialport-api/project/jni/SerialPort.h: -------------------------------------------------------------------------------- 1 | /* DO NOT EDIT THIS FILE - it is machine generated */ 2 | #include 3 | /* Header for class android_serialport_api_SerialPort */ 4 | 5 | #ifndef _Included_android_serialport_api_SerialPort 6 | #define _Included_android_serialport_api_SerialPort 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | /* 11 | * Class: android_serialport_api_SerialPort 12 | * Method: open 13 | * Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor; 14 | */ 15 | JNIEXPORT jobject JNICALL Java_android_1serialport_1api_SerialPort_open 16 | (JNIEnv *, jclass, jstring, jint, jint); 17 | 18 | /* 19 | * Class: android_serialport_api_SerialPort 20 | * Method: close 21 | * Signature: ()V 22 | */ 23 | JNIEXPORT void JNICALL Java_android_1serialport_1api_SerialPort_close 24 | (JNIEnv *, jobject); 25 | 26 | #ifdef __cplusplus 27 | } 28 | #endif 29 | #endif 30 | -------------------------------------------------------------------------------- /android-serialport-api/project/jni/gen_SerialPort_h.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | javah -o SerialPort.h -jni -classpath ../src android_serialport_api.SerialPort 3 | 4 | -------------------------------------------------------------------------------- /android-serialport-api/project/libs/armeabi-v7a/libserial_port.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cepr/android-serialport-api/2be0c20f0f8defba0dc6de5144f4799f0bbabfc6/android-serialport-api/project/libs/armeabi-v7a/libserial_port.so -------------------------------------------------------------------------------- /android-serialport-api/project/libs/armeabi/libserial_port.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cepr/android-serialport-api/2be0c20f0f8defba0dc6de5144f4799f0bbabfc6/android-serialport-api/project/libs/armeabi/libserial_port.so -------------------------------------------------------------------------------- /android-serialport-api/project/libs/x86/libserial_port.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cepr/android-serialport-api/2be0c20f0f8defba0dc6de5144f4799f0bbabfc6/android-serialport-api/project/libs/x86/libserial_port.so -------------------------------------------------------------------------------- /android-serialport-api/project/res/drawable/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cepr/android-serialport-api/2be0c20f0f8defba0dc6de5144f4799f0bbabfc6/android-serialport-api/project/res/drawable/icon.png -------------------------------------------------------------------------------- /android-serialport-api/project/res/layout/console.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 17 | 18 | 19 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /android-serialport-api/project/res/layout/loopback.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 21 | 22 | 28 | 29 | 30 | 35 | 36 | 43 | 44 | 50 | 51 | 52 | 56 | 57 | 64 | 65 | 71 | 72 | 73 | 77 | 78 | 85 | 86 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /android-serialport-api/project/res/layout/main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 |