├── 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 |
16 |
17 |
23 |
24 |
30 |
31 |
37 |
38 |
44 |
45 |
51 |
52 |
--------------------------------------------------------------------------------
/android-serialport-api/project/res/layout/sending01010101.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/android-serialport-api/project/res/values/baudrates.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | - 50
6 | - 75
7 | - 110
8 | - 134
9 | - 150
10 | - 200
11 | - 300
12 | - 600
13 | - 1200
14 | - 1800
15 | - 2400
16 | - 4800
17 | - 9600
18 | - 19200
19 | - 38400
20 | - 57600
21 | - 115200
22 | - 230400
23 | - 460800
24 | - 500000
25 | - 576000
26 | - 921600
27 | - 1000000
28 | - 1152000
29 | - 1500000
30 | - 2000000
31 | - 2500000
32 | - 3000000
33 | - 3500000
34 | - 4000000
35 |
36 |
37 | - 50
38 | - 75
39 | - 110
40 | - 134
41 | - 150
42 | - 200
43 | - 300
44 | - 600
45 | - 1200
46 | - 1800
47 | - 2400
48 | - 4800
49 | - 9600
50 | - 19200
51 | - 38400
52 | - 57600
53 | - 115200
54 | - 230400
55 | - 460800
56 | - 500000
57 | - 576000
58 | - 921600
59 | - 1000000
60 | - 1152000
61 | - 1500000
62 | - 2000000
63 | - 2500000
64 | - 3000000
65 | - 3500000
66 | - 4000000
67 |
68 |
69 |
--------------------------------------------------------------------------------
/android-serialport-api/project/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Serial Port API sample
5 |
6 | Serial Port API sample v1.1\n
7 | \n
8 | This program is the sample application provided with project android-serialport-api.\n
9 | \n
10 | More information and bug report on [http://code.google.com/p/android-serialport-api]\n
11 | \n
12 | Copyright 2010-2011 Cedric Priscal\n
13 | \n
14 | Licensed under the Apache License, Version 2.0 (the "License");
15 | you may not use this file except in compliance with the License.
16 | You may obtain a copy of the License at\n
17 | \n
18 | http://www.apache.org/licenses/LICENSE-2.0\n
19 | \n
20 | Unless required by applicable law or agreed to in writing, software
21 | distributed under the License is distributed on an "AS IS" BASIS,
22 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23 | See the License for the specific language governing permissions and
24 | limitations under the License.\n
25 |
26 | Please configure your serial port first.
27 | You do not have read/write permission to the serial
28 | port.
29 | The serial port can not be opened for an unknown
30 | reason.
31 |
32 |
--------------------------------------------------------------------------------
/android-serialport-api/project/res/xml/serial_port_preferences.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/android-serialport-api/project/run_emulator.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | {
3 | adb wait-for-device
4 | adb shell chmod 666 /dev/ttyS2
5 | } &
6 | emulator-arm -avd Android_1.5 -qemu -serial stdio
7 |
8 |
--------------------------------------------------------------------------------
/android-serialport-api/project/src/android_serialport_api/SerialPort.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_api;
18 |
19 | import java.io.File;
20 | import java.io.FileDescriptor;
21 | import java.io.FileInputStream;
22 | import java.io.FileOutputStream;
23 | import java.io.IOException;
24 | import java.io.InputStream;
25 | import java.io.OutputStream;
26 |
27 | import android.util.Log;
28 |
29 | public class SerialPort {
30 |
31 | private static final String TAG = "SerialPort";
32 |
33 | /*
34 | * Do not remove or rename the field mFd: it is used by native method close();
35 | */
36 | private FileDescriptor mFd;
37 | private FileInputStream mFileInputStream;
38 | private FileOutputStream mFileOutputStream;
39 |
40 | public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException {
41 |
42 | /* Check access permission */
43 | if (!device.canRead() || !device.canWrite()) {
44 | try {
45 | /* Missing read/write permission, trying to chmod the file */
46 | Process su;
47 | su = Runtime.getRuntime().exec("/system/bin/su");
48 | String cmd = "chmod 666 " + device.getAbsolutePath() + "\n"
49 | + "exit\n";
50 | su.getOutputStream().write(cmd.getBytes());
51 | if ((su.waitFor() != 0) || !device.canRead()
52 | || !device.canWrite()) {
53 | throw new SecurityException();
54 | }
55 | } catch (Exception e) {
56 | e.printStackTrace();
57 | throw new SecurityException();
58 | }
59 | }
60 |
61 | mFd = open(device.getAbsolutePath(), baudrate, flags);
62 | if (mFd == null) {
63 | Log.e(TAG, "native open returns null");
64 | throw new IOException();
65 | }
66 | mFileInputStream = new FileInputStream(mFd);
67 | mFileOutputStream = new FileOutputStream(mFd);
68 | }
69 |
70 | // Getters and setters
71 | public InputStream getInputStream() {
72 | return mFileInputStream;
73 | }
74 |
75 | public OutputStream getOutputStream() {
76 | return mFileOutputStream;
77 | }
78 |
79 | // JNI
80 | private native static FileDescriptor open(String path, int baudrate, int flags);
81 | public native void close();
82 | static {
83 | System.loadLibrary("serial_port");
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/android-serialport-api/project/src/android_serialport_api/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_api;
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 | // Issue 3:
69 | // Since driver name may contain spaces, we do not extract driver name with split()
70 | String drivername = l.substring(0, 0x15).trim();
71 | String[] w = l.split(" +");
72 | if ((w.length >= 5) && (w[w.length-1].equals("serial"))) {
73 | Log.d(TAG, "Found new driver " + drivername + " on " + w[w.length-4]);
74 | mDrivers.add(new Driver(drivername, w[w.length-4]));
75 | }
76 | }
77 | r.close();
78 | }
79 | return mDrivers;
80 | }
81 |
82 | public String[] getAllDevices() {
83 | Vector devices = new Vector();
84 | // Parse each driver
85 | Iterator itdriv;
86 | try {
87 | itdriv = getDrivers().iterator();
88 | while(itdriv.hasNext()) {
89 | Driver driver = itdriv.next();
90 | Iterator itdev = driver.getDevices().iterator();
91 | while(itdev.hasNext()) {
92 | String device = itdev.next().getName();
93 | String value = String.format("%s (%s)", device, driver.getName());
94 | devices.add(value);
95 | }
96 | }
97 | } catch (IOException e) {
98 | e.printStackTrace();
99 | }
100 | return devices.toArray(new String[devices.size()]);
101 | }
102 |
103 | public String[] getAllDevicesPath() {
104 | Vector devices = new Vector();
105 | // Parse each driver
106 | Iterator itdriv;
107 | try {
108 | itdriv = getDrivers().iterator();
109 | while(itdriv.hasNext()) {
110 | Driver driver = itdriv.next();
111 | Iterator itdev = driver.getDevices().iterator();
112 | while(itdev.hasNext()) {
113 | String device = itdev.next().getAbsolutePath();
114 | devices.add(device);
115 | }
116 | }
117 | } catch (IOException e) {
118 | e.printStackTrace();
119 | }
120 | return devices.toArray(new String[devices.size()]);
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/android-serialport-api/project/src/android_serialport_api/sample/Application.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_api.sample;
18 |
19 | import java.io.File;
20 | import java.io.IOException;
21 | import java.security.InvalidParameterException;
22 |
23 |
24 | import android.content.SharedPreferences;
25 | import android_serialport_api.SerialPort;
26 | import android_serialport_api.SerialPortFinder;
27 |
28 | public class Application extends android.app.Application {
29 |
30 | public SerialPortFinder mSerialPortFinder = new SerialPortFinder();
31 | private SerialPort mSerialPort = null;
32 |
33 | public SerialPort getSerialPort() throws SecurityException, IOException, InvalidParameterException {
34 | if (mSerialPort == null) {
35 | /* Read serial port parameters */
36 | SharedPreferences sp = getSharedPreferences("android_serialport_api.sample_preferences", MODE_PRIVATE);
37 | String path = sp.getString("DEVICE", "");
38 | int baudrate = Integer.decode(sp.getString("BAUDRATE", "-1"));
39 |
40 | /* Check parameters */
41 | if ( (path.length() == 0) || (baudrate == -1)) {
42 | throw new InvalidParameterException();
43 | }
44 |
45 | /* Open the serial port */
46 | mSerialPort = new SerialPort(new File(path), baudrate, 0);
47 | }
48 | return mSerialPort;
49 | }
50 |
51 | public void closeSerialPort() {
52 | if (mSerialPort != null) {
53 | mSerialPort.close();
54 | mSerialPort = null;
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/android-serialport-api/project/src/android_serialport_api/sample/ConsoleActivity.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_api.sample;
18 |
19 | import java.io.IOException;
20 |
21 | import android.os.Bundle;
22 | import android.view.KeyEvent;
23 | import android.widget.EditText;
24 | import android.widget.TextView;
25 | import android.widget.TextView.OnEditorActionListener;
26 |
27 | public class ConsoleActivity extends SerialPortActivity {
28 |
29 | EditText mReception;
30 |
31 | @Override
32 | protected void onCreate(Bundle savedInstanceState) {
33 | super.onCreate(savedInstanceState);
34 | setContentView(R.layout.console);
35 |
36 | // setTitle("Loopback test");
37 | mReception = (EditText) findViewById(R.id.EditTextReception);
38 |
39 | EditText Emission = (EditText) findViewById(R.id.EditTextEmission);
40 | Emission.setOnEditorActionListener(new OnEditorActionListener() {
41 | public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
42 | int i;
43 | CharSequence t = v.getText();
44 | char[] text = new char[t.length()];
45 | for (i=0; i 0) {
51 | onDataReceived(buffer, size);
52 | }
53 | } catch (IOException e) {
54 | e.printStackTrace();
55 | return;
56 | }
57 | }
58 | }
59 | }
60 |
61 | private void DisplayError(int resourceId) {
62 | AlertDialog.Builder b = new AlertDialog.Builder(this);
63 | b.setTitle("Error");
64 | b.setMessage(resourceId);
65 | b.setPositiveButton("OK", new OnClickListener() {
66 | public void onClick(DialogInterface dialog, int which) {
67 | SerialPortActivity.this.finish();
68 | }
69 | });
70 | b.show();
71 | }
72 |
73 | @Override
74 | protected void onCreate(Bundle savedInstanceState) {
75 | super.onCreate(savedInstanceState);
76 | mApplication = (Application) getApplication();
77 | try {
78 | mSerialPort = mApplication.getSerialPort();
79 | mOutputStream = mSerialPort.getOutputStream();
80 | mInputStream = mSerialPort.getInputStream();
81 |
82 | /* Create a receiving thread */
83 | mReadThread = new ReadThread();
84 | mReadThread.start();
85 | } catch (SecurityException e) {
86 | DisplayError(R.string.error_security);
87 | } catch (IOException e) {
88 | DisplayError(R.string.error_unknown);
89 | } catch (InvalidParameterException e) {
90 | DisplayError(R.string.error_configuration);
91 | }
92 | }
93 |
94 | protected abstract void onDataReceived(final byte[] buffer, final int size);
95 |
96 | @Override
97 | protected void onDestroy() {
98 | if (mReadThread != null)
99 | mReadThread.interrupt();
100 | mApplication.closeSerialPort();
101 | mSerialPort = null;
102 | super.onDestroy();
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/android-serialport-api/project/src/android_serialport_api/sample/SerialPortPreferences.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_api.sample;
18 |
19 | import android.os.Bundle;
20 | import android.preference.ListPreference;
21 | import android.preference.Preference;
22 | import android.preference.Preference.OnPreferenceChangeListener;
23 | import android.preference.PreferenceActivity;
24 | import android_serialport_api.SerialPortFinder;
25 |
26 | public class SerialPortPreferences extends PreferenceActivity {
27 |
28 | private Application mApplication;
29 | private SerialPortFinder mSerialPortFinder;
30 |
31 | @Override
32 | protected void onCreate(Bundle savedInstanceState) {
33 | super.onCreate(savedInstanceState);
34 |
35 | mApplication = (Application) getApplication();
36 | mSerialPortFinder = mApplication.mSerialPortFinder;
37 |
38 | addPreferencesFromResource(R.xml.serial_port_preferences);
39 |
40 | // Devices
41 | final ListPreference devices = (ListPreference)findPreference("DEVICE");
42 | String[] entries = mSerialPortFinder.getAllDevices();
43 | String[] entryValues = mSerialPortFinder.getAllDevicesPath();
44 | devices.setEntries(entries);
45 | devices.setEntryValues(entryValues);
46 | devices.setSummary(devices.getValue());
47 | devices.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
48 | public boolean onPreferenceChange(Preference preference, Object newValue) {
49 | preference.setSummary((String)newValue);
50 | return true;
51 | }
52 | });
53 |
54 | // Baud rates
55 | final ListPreference baudrates = (ListPreference)findPreference("BAUDRATE");
56 | baudrates.setSummary(baudrates.getValue());
57 | baudrates.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
58 | public boolean onPreferenceChange(Preference preference, Object newValue) {
59 | preference.setSummary((String)newValue);
60 | return true;
61 | }
62 | });
63 | }
64 | }
65 |
--------------------------------------------------------------------------------