Compare commits
501 Commits
master
...
jolly/work
Author | SHA1 | Date |
---|---|---|
Andreas Eversberg | 873c068f94 | |
Andreas Eversberg | 0e63492c76 | |
Andreas Eversberg | 2ba5ba8f33 | |
Andreas Eversberg | d2656ac3b2 | |
Andreas Eversberg | 688f7eff12 | |
Eric Wild | cb8209390a | |
Andreas Eversberg | d845adafeb | |
Andreas Eversberg | 6d28717a59 | |
Andreas Eversberg | 68208848a0 | |
Andreas Eversberg | df9f6c6e32 | |
Andreas Eversberg | 379bac0ecb | |
Andreas Eversberg | 7268e8b646 | |
Andreas Eversberg | b0e65f0cb2 | |
Eric Wild | 450b38031a | |
Andreas Eversberg | 4dc9a6ffc2 | |
Andreas Eversberg | 717b64fb17 | |
Andreas Eversberg | 1eb1d32f40 | |
Andreas Eversberg | cedd34759a | |
Andreas Eversberg | 4cd2c70ee9 | |
Andreas Eversberg | ff3c350049 | |
Andreas Eversberg | 093edc657c | |
Andreas Eversberg | d23409eecd | |
Andreas Eversberg | 2e2861402a | |
Andreas Eversberg | fd747c4dbb | |
Asterisk Development Team | af5acc405d | |
Asterisk Development Team | 9b6c74e82a | |
George Joseph | d7597e5148 | |
Asterisk Development Team | 959babc472 | |
Naveen Albert | 40fd161575 | |
Naveen Albert | 5ade71ec9a | |
Shaaah | 395bcab787 | |
Naveen Albert | 3469e515de | |
Sean Bright | f8da5a2ba3 | |
George Joseph | f02ac33364 | |
George Joseph | 44563b5043 | |
George Joseph | efc2124594 | |
George Joseph | be5fd6180c | |
George Joseph | fd27df9479 | |
Sean Bright | 507c28f268 | |
Sebastian Jennen | 77808edbd4 | |
Shyju Kanaprath | 2868366f00 | |
Sean Bright | 02a17926c4 | |
George Joseph | 4152f67a0b | |
George Joseph | 41ae2d754f | |
romryz | a494b61fe2 | |
Naveen Albert | 70ff49c474 | |
George Joseph | f770c9c92c | |
George Joseph | 6df5fbee65 | |
Naveen Albert | bf6a367955 | |
Ben Ford | ab2163cacb | |
cmaj | db99ad892b | |
Joshua C. Colp | ba68bb9221 | |
Mike Bradeen | ec69680801 | |
George Joseph | 36fd2ac5b6 | |
Naveen Albert | e2cb63120f | |
Sean Bright | f74eafcf65 | |
Brad Smith | 17757f76fe | |
Brad Smith | afe0fb310d | |
Sean Bright | 4d09fb191c | |
Sean Bright | 347494a130 | |
Naveen Albert | faf4c3b5d3 | |
Naveen Albert | 309ec5e762 | |
Sean Bright | 61c78fc48b | |
Mike Bradeen | 9652a215e8 | |
Naveen Albert | e17c4e172f | |
PeterHolik | 9943bc5f1f | |
PeterHolik | 07715c4c27 | |
Naveen Albert | 410909fbfb | |
Asterisk Development Team | b05169bcac | |
Asterisk Development Team | f258d08bac | |
Naveen Albert | 87fb29020b | |
Asterisk Development Team | 3ba0470953 | |
George Joseph | a42c5438e9 | |
Naveen Albert | fd57ddb3e9 | |
Maximilian Fridrich | b2eb25a88c | |
Naveen Albert | d7948f5425 | |
Naveen Albert | c6b82b19a4 | |
Naveen Albert | 8a73bac226 | |
Naveen Albert | 776c2ca6d7 | |
Sean Bright | cfe826791e | |
Naveen Albert | 91127a618f | |
George Joseph | 98a44b95df | |
Maximilian Fridrich | 8f9200d106 | |
George Joseph | 9ae72b0a23 | |
Sean Bright | 2c6385a1b3 | |
Matthew Fredrickson | 37a89d3cee | |
Sean Bright | 5988da4ec5 | |
Sean Bright | 2f7416711e | |
Sean Bright | 3ed329edc9 | |
Sean Bright | 06d86c41af | |
Naveen Albert | 7279d7547f | |
Sean Bright | d52c427533 | |
Sean Bright | b7e66d49b2 | |
Naveen Albert | a6d856aba2 | |
Sean Bright | f19b74ad31 | |
Sean Bright | 989e61890a | |
Sean Bright | 69a19aabd8 | |
Sean Bright | fe92d09361 | |
Sean Bright | eb48273bdf | |
George Joseph | 3127baec78 | |
Naveen Albert | 4d928ee975 | |
Matthew Fredrickson | eac9ad69a8 | |
Naveen Albert | 52388f11f8 | |
Naveen Albert | 0007625ad0 | |
Sean Bright | c2680f63c5 | |
George Joseph | 1d87c27cab | |
Sean Bright | da35b6a244 | |
Sean Bright | fb7d39db6d | |
George Joseph | 94f931a6d7 | |
Sean Bright | f96d7ef7b5 | |
Naveen Albert | e75aebc9bc | |
Holger Hans Peter Freyther | 7699af00e1 | |
Holger Hans Peter Freyther | 28f52d35f3 | |
Brad Smith | 089ddaaaed | |
Brad Smith | fb3067dd71 | |
Naveen Albert | 6a4fe8bdab | |
Naveen Albert | b47a403b80 | |
Mark Murawski | 3b70dfcced | |
Naveen Albert | b5eb5e19c3 | |
Sean Bright | 3ded0c95fc | |
George Joseph | e2f246c067 | |
Naveen Albert | 120dbba2b3 | |
Mike Bradeen | 0b4427d621 | |
Sean Bright | ea74f942ce | |
Sean Bright | 58f78d2d0e | |
George Joseph | 027c748e57 | |
Sean Bright | 93697458a6 | |
Samuel Olaechea | 59181860ec | |
George Joseph | e52175341e | |
sungtae kim | faf046ea86 | |
George Joseph | 95656c409d | |
George Joseph | 13f2d126fd | |
George Joseph | 2cb140f801 | |
Mike Bradeen | 0f2eb00a52 | |
Holger Hans Peter Freyther | 1f7e9bfad5 | |
Sean Bright | d7a01afa50 | |
George Joseph | fd487b48a3 | |
George Joseph | e1ce35c3f5 | |
Joshua C. Colp | b7cc7e804b | |
George Joseph | f0edab9f3e | |
George Joseph | 393d8cb947 | |
Mike Bradeen | 0df2848147 | |
Naveen Albert | c06fd10f0a | |
Bastian Triller | 7a1208410a | |
Mike Bradeen | c47a386cf2 | |
Naveen Albert | 0a834c8d75 | |
Eduardo | 7a2305a08b | |
George Joseph | 9afa54b3b3 | |
George Joseph | 97674e1d20 | |
Tinet-mucw | a86376fe68 | |
Mike Bradeen | 3b61583c20 | |
Naveen Albert | 3fef46e776 | |
George Joseph | d5a285c8f2 | |
Naveen Albert | accedd4c3e | |
Vitezslav Novy | c275ee9e54 | |
George Joseph | 172602d30e | |
Mike Bradeen | 58a37523dd | |
Sean Bright | d9dc7b66e4 | |
Mike Bradeen | b68370ba9c | |
George Joseph | 9ee35c259a | |
George Joseph | 52929efb83 | |
Maximilian Fridrich | 38598701da | |
Jaco Kroon | bc72c76891 | |
Joshua C. Colp | 6521066fbe | |
George Joseph | c2d3ad489d | |
Asterisk Development Team | 4988f9131f | |
George Joseph | 32b57067a6 | |
Asterisk Development Team | f7a8ac086d | |
Gitea | b6122db51d | |
Mike Bradeen | 48e435f84f | |
George Joseph | e46cc258ab | |
Ben Ford | d44f07244a | |
Asterisk Development Team | c94e2b2000 | |
Asterisk Development Team | a2fb6d4dd4 | |
George Joseph | f7fd2c8e20 | |
George Joseph | 1d9ea90058 | |
George Joseph | e5a653622a | |
Bastian Triller | 9d41064bc0 | |
George Joseph | abc84c6618 | |
Naveen Albert | 7959c64792 | |
Mike Bradeen | 7353462be3 | |
George Joseph | 4dcf73b6df | |
Naveen Albert | 2d1e4aed4f | |
zhengsh | 6ef2389e9b | |
George Joseph | c3f4b56886 | |
Maximilian Fridrich | b2cd0583c9 | |
Naveen Albert | 534269e3e6 | |
Matthew Fredrickson | 8bf9b1d966 | |
Matthew Fredrickson | 65082ae112 | |
George Joseph | b145430957 | |
Jason D. McCormick | f86f5fd809 | |
MikeNaso | 714b9e8b21 | |
Sean Bright | cce02a9d60 | |
George Joseph | 44d7349958 | |
Naveen Albert | 9367926380 | |
George Joseph | 5e3652e738 | |
Joshua C. Colp | 592c85b8de | |
Maximilian Fridrich | 68fc422247 | |
Naveen Albert | 65a2bca074 | |
Joshua C. Colp | fcf7187cd6 | |
Naveen Albert | 18aa912f46 | |
Holger Hans Peter Freyther | 986c71953c | |
Sean Bright | e05f51a8ae | |
phoneben | cbcde0624b | |
Sean Bright | 4ed17ced6c | |
Sean Bright | 29fbf1b2c8 | |
Joshua C. Colp | ef7a9e91fe | |
George Joseph | c0898cb265 | |
Sean Bright | 22f31ecedd | |
Sean Bright | db8601dd77 | |
Mike Bradeen | dd76dfdd57 | |
Mike Bradeen | d9c4a37aaa | |
zhengsh | 37b1ceab2b | |
George Joseph | 5cf2c9f0e4 | |
George Joseph | e33e6c6429 | |
Naveen Albert | 967e8f6beb | |
Asterisk Development Team | 9e2b9424f5 | |
Asterisk Development Team | 3a0d24d969 | |
George Joseph | 6cfafdeb37 | |
George Joseph | 9b3abda528 | |
Asterisk Development Team | c35471ad10 | |
George Joseph | 1491da61eb | |
Mike Bradeen | d180c58c36 | |
Mike Bradeen | 9dbd80ab73 | |
Mike Bradeen | 714950bd7c | |
George Joseph | 244e0b69ea | |
George Joseph | 37d2378073 | |
George Joseph | 46bb9e8fde | |
George Joseph | 64ecad8309 | |
George Joseph | f6630916f4 | |
George Joseph | 157d478b27 | |
George Joseph | 8a152fb4aa | |
George Joseph | 37dce12781 | |
George Joseph | fdfe61bf4d | |
Olaf Titz | f7f2872b3f | |
Sean Bright | 81b490ab0a | |
Ben Ford | ff4f3c1187 | |
Nathan Bruning | f0df2eba9d | |
Sean Bright | ff60aae1c8 | |
Sean Bright | 99622c35e0 | |
Sean Bright | 5497b1abe3 | |
zhou_jiajian | 3ad8ab6d52 | |
Sean Bright | f971db6685 | |
George Joseph | 8e6f15d185 | |
Sean Bright | 0503e2b612 | |
Jaco Kroon | dafa9917ff | |
Jiajian Zhou | a6a5498b0d | |
George Joseph | b7775ae4e1 | |
George Joseph | ee09bbbb5f | |
George Joseph | 40ff67d636 | |
Sean Bright | 79d271fa7f | |
alex2grad | 319da11fae | |
Sean Bright | 228244a96e | |
Miguel Angel Nubla | 25de041d5e | |
Naveen Albert | 8cdf711531 | |
Naveen Albert | 457a72304d | |
Ben Ford | 8da7b4606b | |
Naveen Albert | f40e50ce19 | |
Joe Searle | 5018c09d99 | |
Niklas Larsson | 1589efa5dd | |
George Joseph | b68bf5683f | |
Mike Bradeen | 26401ddcc0 | |
George Joseph | da66f402c9 | |
George Joseph | 75c13b2c95 | |
Naveen Albert | ba1c363d3e | |
Naveen Albert | c8b7570cad | |
Maximilian Fridrich | 173c433274 | |
Naveen Albert | c5c89ed377 | |
George Joseph | 0d214b6611 | |
Naveen Albert | ca51a25056 | |
George Joseph | cd2eafe588 | |
George Joseph | 955c2e06ff | |
George Joseph | 5e37887d82 | |
Jaco Kroon | dda4dd513f | |
Sean Bright | bbf47fefab | |
zhengsh | 2d1e5f81ee | |
Sean Bright | 0e4a9d7251 | |
Joshua C. Colp | 6812357bef | |
Gitea | d35a0d3d4e | |
Joshua C. Colp | 31c11bec74 | |
Asterisk Development Team | 6dc1877b2d | |
Sean Bright | 9ca24c9c2b | |
George Joseph | 90069a94b0 | |
Stanislav Abramenkov | 0fa022a39c | |
Asterisk Development Team | 282045db34 | |
George Joseph | a004574465 | |
Asterisk Development Team | 2e1842229a | |
George Joseph | 3fe0d8088f | |
Henning Westerholt | ac747ce562 | |
Mike Bradeen | 21ee5f705a | |
Sean Bright | 7677e78b4f | |
George Joseph | 9a1ac9142f | |
George Joseph | 272fbca4d0 | |
George Joseph | e3b9f66678 | |
George Joseph | 6aa490d373 | |
Maximilian Fridrich | 9cfda39d36 | |
George Joseph | ea564b640d | |
Joshua C. Colp | 42c243866e | |
Naveen Albert | e6b84eca75 | |
George Joseph | 81310a031c | |
George Joseph | 5cb6d8a453 | |
George Joseph | cc36ae8de5 | |
George Joseph | f994463aee | |
Joshua C. Colp | 6a347f413d | |
Joshua Colp | 9c5f5358d7 | |
Naveen Albert | 59c9e4531e | |
Naveen Albert | 99d17db963 | |
The_Blode | 81a912f3ce | |
Henning Westerholt | 51509309ca | |
Naveen Albert | c9aa3b0169 | |
Naveen Albert | 5e7d21e5a5 | |
George Joseph | d0ce6d4ee5 | |
Jaco Kroon | 3a158c07a1 | |
Sean Bright | 255565e240 | |
Sean Bright | 6ff3258c17 | |
Mike Bradeen | 2ac8388c6d | |
Mike Bradeen | e00eaa74e3 | |
Mike Bradeen | 3a4fd2fa42 | |
Sean Bright | b376d16d81 | |
Naveen Albert | e104bd0852 | |
Naveen Albert | 3dcf6ddde5 | |
Naveen Albert | 0dd0bc3e65 | |
Fabrice Fontaine | bdd2bac055 | |
Mike Bradeen | 5a85b372af | |
Jaco Kroon | d6e733d4bc | |
George Joseph | bd1f8b89da | |
Holger Hans Peter Freyther | 723c9093ad | |
Fabrice Fontaine | b17177c419 | |
Sean Bright | 61c8f9b225 | |
Asterisk Development Team | 1d64cb99d2 | |
Mike Bradeen | f8dfbaf225 | |
Sean Bright | 6e50550d28 | |
Asterisk Development Team | e7f0440032 | |
Asterisk Development Team | 460d13e916 | |
Asterisk Development Team | 93813c9dca | |
George Joseph | ceda5a9859 | |
Sean Bright | e5c5cd6e25 | |
Naveen Albert | ede67a99be | |
Sean Bright | 827222d607 | |
Nick French | 200dc7d0e8 | |
Mike Bradeen | 5c11d7adea | |
cmaj | 5b0e3444c3 | |
Mike Bradeen | 2308afed8e | |
Mike Bradeen | 98742388b6 | |
Mike Bradeen | 37e558f6ef | |
Sean Bright | aeb16aa7d8 | |
Sean Bright | aef0c0ce0e | |
Mike Bradeen | 58636a6ea6 | |
Sean Bright | 96d9ad51ac | |
Naveen Albert | 88b2c741ca | |
Mike Bradeen | 70856e865f | |
Naveen Albert | 8a45cd7af4 | |
sungtae kim | f99849f8d5 | |
Sean Bright | 56051d1ac5 | |
Naveen Albert | a1da8042d1 | |
Sean Bright | ef16eaee36 | |
George Joseph | 2f5aece0c9 | |
Alexei Gradinari | e86d5d7fda | |
Igor Goncharovsky | 3526441e41 | |
George Joseph | 4710f37ef6 | |
George Joseph | 62ca063fca | |
Naveen Albert | d33bd6d67a | |
Naveen Albert | e06fe8e344 | |
Naveen Albert | 68e345286b | |
Naveen Albert | 3b3fef2347 | |
Naveen Albert | 7b8f7428da | |
George Joseph | 24102ba236 | |
Boris P. Korzun | edc90c96ac | |
Holger Hans Peter Freyther | 3d9b9a2b16 | |
George Joseph | d454801c2d | |
Naveen Albert | cc8d9b947b | |
Naveen Albert | c7598ee947 | |
Ben Ford | 881faf544f | |
Naveen Albert | 20d4775d0a | |
Naveen Albert | cbb1fd2cb9 | |
Igor Goncharovsky | 115a1b4f0a | |
Peter Fern | 58404b5c22 | |
Naveen Albert | 36bea9ad33 | |
Asterisk Development Team | fefc236e7c | |
Alexandre Fournier | 01b3962201 | |
Joshua C. Colp | b6855755ce | |
Naveen Albert | 2f9cdfbc50 | |
Michael Kuron | 5c114dcb4a | |
Michael Kuron | fee9012fe1 | |
Joshua C. Colp | 564349ff5d | |
Naveen Albert | b9c031c1f8 | |
Marcel Wagner | 58534b309f | |
Naveen Albert | 531eacd6c9 | |
Naveen Albert | b365ea8601 | |
Naveen Albert | 0d6003fa9a | |
Marcel Wagner | b83af13f65 | |
Naveen Albert | 80e6205bb0 | |
Naveen Albert | 406143ae61 | |
Naveen Albert | 83eb113e0f | |
Naveen Albert | b90e57758b | |
Naveen Albert | 52c7d3ed07 | |
Naveen Albert | a4bcdce1db | |
Naveen Albert | 691178c48e | |
Ben Ford | d476994768 | |
George Joseph | 7684c9e907 | |
Mike Bradeen | 81f10e847e | |
Mike Bradeen | eb1d7ab53c | |
Naveen Albert | c7df5ee7c1 | |
Naveen Albert | 5ede4e217a | |
Maximilian Fridrich | 60b81eabe0 | |
Naveen Albert | 2efa290d3c | |
Jaco Kroon | ce2153fc5a | |
Naveen Albert | 002afc3f2a | |
Naveen Albert | 1e77b8c473 | |
Joshua C. Colp | 61922d2934 | |
Naveen Albert | 6e59b01e1a | |
Naveen Albert | 49cfdbbdff | |
Naveen Albert | 8142b313c3 | |
George Joseph | 0c1c623dee | |
Naveen Albert | dfe2f38642 | |
George Joseph | f723b465e5 | |
Mike Bradeen | 50e2921a48 | |
Naveen Albert | afd86b47c1 | |
Igor Goncharovsky | 096529d33f | |
Naveen Albert | ca8900b0f6 | |
Henning Westerholt | 12445040d3 | |
Naveen Albert | 40b52322e5 | |
Naveen Albert | c32b39d123 | |
Frederic LE FOLL | 50a4495799 | |
Naveen Albert | 180ca32565 | |
Naveen Albert | 9258d8212a | |
Naveen Albert | 407216a0a5 | |
Philip Prindeville | d0bea5a725 | |
Mike Bradeen | 907d7e7d7d | |
Naveen Albert | b331caca30 | |
Naveen Albert | e0e7f35730 | |
Naveen Albert | 98fc05f13b | |
Philip Prindeville | ef74ecacc7 | |
Philip Prindeville | 5e2485b5c0 | |
George Joseph | 2a500b325a | |
Maximilian Fridrich | 0d2e140123 | |
Asterisk Development Team | 7f80830ced | |
Holger Hans Peter Freyther | 62881c668b | |
Naveen Albert | 8afb313a43 | |
Naveen Albert | 7335b0cffe | |
Naveen Albert | 407167cc28 | |
Naveen Albert | a5ec60e6c6 | |
Naveen Albert | 1e29607b5c | |
Naveen Albert | 8c791f9a65 | |
Philip Prindeville | 3e7ce90f9c | |
Naveen Albert | 1ed4518328 | |
Maximilian Fridrich | 5bbad0d27c | |
Naveen Albert | 8aae0b9f08 | |
Jaco Kroon | 278c5726ca | |
Naveen Albert | ab1dbfef75 | |
George Joseph | e25b690d10 | |
George Joseph | e33f2dcc0f | |
Philip Prindeville | 026dc08529 | |
Asterisk Development Team | f01ed3eea4 | |
Mike Bradeen | 7a44296ca9 | |
George Joseph | 8cbea1c7ef | |
sungtae kim | 80bc844fd6 | |
Ben Ford | 881a3f2306 | |
Philip Prindeville | 3e054c9ebc | |
Philip Prindeville | 736cdf84f4 | |
Philip Prindeville | 2d7656cb50 | |
Philip Prindeville | 5809d879b0 | |
Philip Prindeville | 2c4c44ca64 | |
Philip Prindeville | b9df2c481b | |
Philip Prindeville | d13afaf302 | |
Naveen Albert | 2dac2bf8dc | |
Naveen Albert | c487425620 | |
Naveen Albert | 205c7c8d21 | |
Naveen Albert | 2de016b181 | |
George Joseph | 05f42806cc | |
George Joseph | c799db6a21 | |
George Joseph | 4ffc5561c4 | |
George Joseph | 2d5a6498dd | |
Joshua C. Colp | f3de933b16 | |
Naveen Albert | c7612521be | |
Joshua C. Colp | a0713a9f70 | |
Naveen Albert | 754346a4a9 | |
Mike Bradeen | 46776c77c4 | |
Sean Bright | 583e017f34 | |
Alexei Gradinari | 12c4c1bf5f | |
Sean Bright | 155c796203 | |
Naveen Albert | 3fa66c92b5 | |
Mike Bradeen | adffb975dc | |
Mike Bradeen | 4fc9e06db1 | |
Naveen Albert | e2e049e473 | |
George Joseph | 8a8416e365 | |
Naveen Albert | ff044c222b | |
Naveen Albert | dc7ec11c26 | |
George Joseph | 30d7a212b0 | |
Naveen Albert | f4a020a45b | |
Naveen Albert | c654486547 | |
Naveen Albert | 5feebc0857 | |
Naveen Albert | 165368bf0b | |
Naveen Albert | 2d8f2696b2 | |
Naveen Albert | 4af881506e | |
Naveen Albert | 83912496ab | |
Naveen Albert | c771e2dd7a | |
Sergey V. Lobanov | f645157a4b | |
Naveen Albert | a9223f210e | |
Naveen Albert | ce18196280 | |
George Joseph | f8000daff5 |
|
@ -0,0 +1,87 @@
|
|||
name: Bug
|
||||
description: File a bug report
|
||||
title: "[bug]: "
|
||||
labels: ["bug", "triage"]
|
||||
#assignees:
|
||||
# - octocat
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for creating a report! The issue has entered the triage process. That means the issue will wait in this status until a Bug Marshal has an opportunity to review the issue. Once the issue has been reviewed you will receive comments regarding the next steps towards resolution. Please note that log messages and other files should not be sent to the Sangoma Asterisk Team unless explicitly asked for. All files should be placed on this issue in a sanitized fashion as needed.
|
||||
|
||||
A good first step is for you to review the Asterisk Issue Guidelines if you haven't already. The guidelines detail what is expected from an Asterisk issue report.
|
||||
|
||||
Then, if you are submitting a patch, please review the Patch Contribution Process.
|
||||
|
||||
Please note that once your issue enters an open state it has been accepted. As Asterisk is an open source project there is no guarantee or timeframe on when your issue will be looked into. If you need expedient resolution you will need to find and pay a suitable developer. Asking for an update on your issue will not yield any progress on it and will not result in a response. All updates are posted to the issue when they occur.
|
||||
|
||||
Please note that by submitting data, code, or documentation to Sangoma through GitHub, you accept the Terms of Use present at
|
||||
https://www.asterisk.org/terms-of-use/.
|
||||
Thanks for taking the time to fill out this bug report!
|
||||
- type: dropdown
|
||||
id: severity
|
||||
attributes:
|
||||
label: Severity
|
||||
options:
|
||||
- Trivial
|
||||
- Minor
|
||||
- Major
|
||||
- Critical
|
||||
- Blocker
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: versions
|
||||
attributes:
|
||||
label: Versions
|
||||
description: Enter one or more versions separated by commas.
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: components
|
||||
attributes:
|
||||
label: Components/Modules
|
||||
description: Enter one or more components or modules separated by commas.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: environment
|
||||
attributes:
|
||||
label: Operating Environment
|
||||
description: OS, Disribution, Version, etc.
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: frequency
|
||||
attributes:
|
||||
label: Frequency of Occurrence
|
||||
options:
|
||||
- "Never"
|
||||
- "One Time"
|
||||
- "Occasional"
|
||||
- "Frequent"
|
||||
- "Constant"
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Issue Description
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Relevant log output
|
||||
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
|
||||
render: shell
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
[Asterisk Issue Guidelines](https://wiki.asterisk.org/wiki/display/AST/Asterisk+Issue+Guidelines)
|
||||
- type: checkboxes
|
||||
id: guidelines
|
||||
attributes:
|
||||
label: Asterisk Issue Guidelines
|
||||
options:
|
||||
- label: Yes, I have read the Asterisk Issue Guidelines
|
||||
required: true
|
|
@ -0,0 +1,11 @@
|
|||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Asterisk Community Support
|
||||
url: https://community.asterisk.org
|
||||
about: Please ask and answer questions here.
|
||||
- name: Feature Requests (Without Code)
|
||||
url: https://github.com/asterisk/asterisk-feature-requests/issues
|
||||
about: Please submit feature requests (without code) here.
|
||||
- name: Improvement Requests (Without Code)
|
||||
url: https://github.com/asterisk/asterisk-feature-requests/issues
|
||||
about: Please submit improvement requests (without code) here.
|
|
@ -0,0 +1,27 @@
|
|||
name: Improvement
|
||||
description: Submit an improvement to existing functionality
|
||||
title: "[improvement]: "
|
||||
labels: ["improvement", "triage"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for creating a report! The issue has entered the triage process. That means the issue will wait in this status until a Bug Marshal has an opportunity to review the issue. Once the issue has been reviewed you will receive comments regarding the next steps towards resolution. Please note that log messages and other files should not be sent to the Sangoma Asterisk Team unless explicitly asked for. All files should be placed on this issue in a sanitized fashion as needed.
|
||||
|
||||
A good first step is for you to review the Asterisk Issue Guidelines if you haven't already. The guidelines detail what is expected from an Asterisk issue report.
|
||||
|
||||
Then, if you are submitting a patch, please review the Patch Contribution Process.
|
||||
|
||||
Please note that once your issue enters an open state it has been accepted. As Asterisk is an open source project there is no guarantee or timeframe on when your issue will be looked into. If you need expedient resolution you will need to find and pay a suitable developer. Asking for an update on your issue will not yield any progress on it and will not result in a response. All updates are posted to the issue when they occur.
|
||||
|
||||
Please note that by submitting data, code, or documentation to Sangoma through GitHub, you accept the Terms of Use present at
|
||||
https://www.asterisk.org/terms-of-use/.
|
||||
Thanks for taking the time to fill out this bug report!
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Improvement Description
|
||||
description: Describe the improvement in as much detail as possible
|
||||
validations:
|
||||
required: true
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
name: New Feature Submission
|
||||
description: Submit a New Feature
|
||||
title: "[new-feature]: "
|
||||
labels: ["new-feature", "triage"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for creating a report! The issue has entered the triage process. That means the issue will wait in this status until a Bug Marshal has an opportunity to review the issue. Once the issue has been reviewed you will receive comments regarding the next steps towards resolution. Please note that log messages and other files should not be sent to the Sangoma Asterisk Team unless explicitly asked for. All files should be placed on this issue in a sanitized fashion as needed.
|
||||
|
||||
A good first step is for you to review the Asterisk Issue Guidelines if you haven't already. The guidelines detail what is expected from an Asterisk issue report.
|
||||
|
||||
Then, if you are submitting a patch, please review the Patch Contribution Process.
|
||||
|
||||
Please note that once your issue enters an open state it has been accepted. As Asterisk is an open source project there is no guarantee or timeframe on when your issue will be looked into. If you need expedient resolution you will need to find and pay a suitable developer. Asking for an update on your issue will not yield any progress on it and will not result in a response. All updates are posted to the issue when they occur.
|
||||
|
||||
Please note that by submitting data, code, or documentation to Sangoma through GitHub, you accept the Terms of Use present at
|
||||
https://www.asterisk.org/terms-of-use/.
|
||||
Thanks for taking the time to fill out this bug report!
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Feature Description
|
||||
description: Describe the new feature in as much detail as possible
|
||||
validations:
|
||||
required: true
|
||||
|
|
@ -0,0 +1,167 @@
|
|||
name: CherryPickTest
|
||||
run-name: "Cherry-Pick Tests for PR ${{github.event.number}}"
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [ labeled ]
|
||||
|
||||
concurrency:
|
||||
group: ${{github.workflow}}-${{github.event.number}}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
PR_NUMBER: ${{ github.event.number }}
|
||||
MODULES_BLACKLIST: ${{ vars.GATETEST_MODULES_BLACKLIST }} ${{ vars.UNITTEST_MODULES_BLACKLIST }}
|
||||
|
||||
jobs:
|
||||
IdentifyBranches:
|
||||
name: IdentifyBranches
|
||||
if: ${{ github.event.label.name == vars.CHERRY_PICK_TEST_LABEL }}
|
||||
outputs:
|
||||
branches: ${{ steps.getbranches.outputs.branches }}
|
||||
branch_count: ${{ steps.getbranches.outputs.branch_count }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Remove Trigger Label, Add InProgress Label
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
gh pr edit --repo ${{github.repository}} \
|
||||
--remove-label ${{vars.CHERRY_PICK_TEST_LABEL}} \
|
||||
--remove-label ${{vars.CHERRY_PICK_CHECKS_PASSED_LABEL}} \
|
||||
--remove-label ${{vars.CHERRY_PICK_CHECKS_FAILED_LABEL}} \
|
||||
--remove-label ${{vars.CHERRY_PICK_GATES_PASSED_LABEL}} \
|
||||
--remove-label ${{vars.CHERRY_PICK_GATES_FAILED_LABEL}} \
|
||||
--remove-label ${{vars.CHERRY_PICK_TESTING_IN_PROGRESS}} \
|
||||
${{env.PR_NUMBER}} || :
|
||||
|
||||
- name: Get cherry-pick branches
|
||||
uses: asterisk/asterisk-ci-actions/GetCherryPickBranchesFromPR@main
|
||||
id: getbranches
|
||||
with:
|
||||
repo: ${{github.repository}}
|
||||
pr_number: ${{env.PR_NUMBER}}
|
||||
cherry_pick_regex: ${{vars.CHERRY_PICK_REGEX}}
|
||||
github_token: ${{secrets.GITHUB_TOKEN}}
|
||||
|
||||
- name: Check Branch Count
|
||||
if: ${{ steps.getbranches.outputs.branch_count > 0 }}
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
gh pr edit --repo ${{github.repository}} \
|
||||
--add-label ${{vars.CHERRY_PICK_TESTING_IN_PROGRESS}} \
|
||||
${{env.PR_NUMBER}} || :
|
||||
|
||||
CherryPickUnitTestMatrix:
|
||||
needs: [ IdentifyBranches ]
|
||||
if: ${{ needs.IdentifyBranches.outputs.branch_count > 0 && ( success() || failure() ) }}
|
||||
continue-on-error: false
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
branch: ${{ fromJSON(needs.IdentifyBranches.outputs.branches) }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Run Unit Tests for branch ${{matrix.branch}}
|
||||
uses: asterisk/asterisk-ci-actions/AsteriskUnitComposite@main
|
||||
with:
|
||||
asterisk_repo: ${{github.repository}}
|
||||
pr_number: ${{env.PR_NUMBER}}
|
||||
base_branch: ${{matrix.branch}}
|
||||
is_cherry_pick: true
|
||||
modules_blacklist: ${{env.MODULES_BLACKLIST}}
|
||||
github_token: ${{secrets.GITHUB_TOKEN}}
|
||||
unittest_command: ${{vars.UNITTEST_COMMAND}}
|
||||
|
||||
CherryPickUnitTests:
|
||||
needs: [ IdentifyBranches, CherryPickUnitTestMatrix ]
|
||||
if: ${{ needs.IdentifyBranches.outputs.branch_count > 0 && ( success() || failure() ) }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check unit test matrix status
|
||||
env:
|
||||
RESULT: ${{needs.CherryPickUnitTestMatrix.result}}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
case $RESULT in
|
||||
success)
|
||||
gh pr edit --repo ${{github.repository}} \
|
||||
--add-label ${{vars.CHERRY_PICK_CHECKS_PASSED_LABEL}} \
|
||||
${{env.PR_NUMBER}} || :
|
||||
echo "::notice::All tests passed"
|
||||
exit 0
|
||||
;;
|
||||
skipped)
|
||||
gh pr edit --repo ${{github.repository}} \
|
||||
--remove-label ${{vars.CHERRY_PICK_TESTING_IN_PROGRESS}} \
|
||||
--add-label ${{vars.CHERRY_PICK_CHECKS_FAILED_LABEL}} \
|
||||
${{env.PR_NUMBER}} || :
|
||||
echo "::notice::Unit tests were skipped because of an earlier failure"
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
gh pr edit --repo ${{github.repository}} \
|
||||
--remove-label ${{vars.CHERRY_PICK_TESTING_IN_PROGRESS}} \
|
||||
--add-label ${{vars.CHERRY_PICK_CHECKS_FAILED_LABEL}} \
|
||||
${{env.PR_NUMBER}} || :
|
||||
echo "::error::One or more tests failed ($RESULT)"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
CherryPickGateTestMatrix:
|
||||
needs: [ IdentifyBranches, CherryPickUnitTests ]
|
||||
if: ${{ success() }}
|
||||
continue-on-error: false
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
branch: ${{ fromJSON(needs.IdentifyBranches.outputs.branches) }}
|
||||
group: ${{ fromJSON(vars.GATETEST_LIST) }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Run Gate Tests for ${{ matrix.group }}-${{matrix.branch}}
|
||||
uses: asterisk/asterisk-ci-actions/AsteriskGateComposite@main
|
||||
with:
|
||||
test_type: Gate
|
||||
asterisk_repo: ${{github.repository}}
|
||||
pr_number: ${{env.PR_NUMBER}}
|
||||
base_branch: ${{matrix.branch}}
|
||||
is_cherry_pick: true
|
||||
modules_blacklist: ${{env.MODULES_BLACKLIST}}
|
||||
github_token: ${{secrets.GITHUB_TOKEN}}
|
||||
testsuite_repo: ${{vars.TESTSUITE_REPO}}
|
||||
gatetest_group: ${{matrix.group}}
|
||||
gatetest_command: ${{ toJSON(fromJSON(vars.GATETEST_COMMANDS)[matrix.group]) }}
|
||||
|
||||
CherryPickGateTests:
|
||||
needs: [ IdentifyBranches, CherryPickGateTestMatrix ]
|
||||
if: ${{ success() || failure() }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check test matrix status
|
||||
env:
|
||||
RESULT: ${{needs.CherryPickGateTestMatrix.result}}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
gh pr edit --repo ${{github.repository}} \
|
||||
--remove-label ${{vars.CHERRY_PICK_TESTING_IN_PROGRESS}} \
|
||||
${{env.PR_NUMBER}} || :
|
||||
case $RESULT in
|
||||
success)
|
||||
gh pr edit --repo ${{github.repository}} \
|
||||
--add-label ${{vars.CHERRY_PICK_GATES_PASSED_LABEL}} \
|
||||
${{env.PR_NUMBER}} || :
|
||||
echo "::notice::All Testsuite tests passed"
|
||||
exit 0
|
||||
;;
|
||||
skipped)
|
||||
echo "::error::Testsuite tests were skipped because of an earlier failure"
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
gh pr edit --repo ${{github.repository}} \
|
||||
--add-label ${{vars.CHERRY_PICK_GATES_FAILED_LABEL}} \
|
||||
${{env.PR_NUMBER}} || :
|
||||
echo "::error::One or more Testsuite tests failed ($RESULT)"
|
||||
exit 1
|
||||
esac
|
|
@ -0,0 +1,123 @@
|
|||
name: CreateDocs
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
branches:
|
||||
description: "JSON array of branches: ['18','20'] (no spaces)"
|
||||
required: false
|
||||
type: string
|
||||
schedule:
|
||||
# Times are UTC
|
||||
- cron: '0 04 * * *'
|
||||
|
||||
env:
|
||||
ASTERISK_REPO: ${{ github.repository }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
DEFAULT_BRANCHES: ${{ vars.WIKIDOC_BRANCHES }}
|
||||
INPUT_BRANCHES: ${{ inputs.branches }}
|
||||
|
||||
jobs:
|
||||
|
||||
CreateDocsDebug:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
manual_branches: ${{ steps.setup.outputs.manual_branches }}
|
||||
steps:
|
||||
- name: setup
|
||||
run: |
|
||||
MANUAL_BRANCHES="$INPUT_BRANCHES"
|
||||
[ -z "$MANUAL_BRANCHES" ] && MANUAL_BRANCHES="$DEFAULT_BRANCHES" || :
|
||||
echo "manual_branches=${MANUAL_BRANCHES}"
|
||||
echo "manual_branches=${MANUAL_BRANCHES}" >>${GITHUB_OUTPUT}
|
||||
exit 0
|
||||
|
||||
- name: DumpEnvironment
|
||||
uses: asterisk/asterisk-ci-actions/DumpEnvironmentAction@main
|
||||
with:
|
||||
action-inputs: ${{toJSON(inputs)}}
|
||||
action-vars: ${{ toJSON(steps.setup.outputs) }}
|
||||
|
||||
CreateDocsScheduledMatrix:
|
||||
needs: [ CreateDocsDebug ]
|
||||
if: ${{github.event_name == 'schedule' && fromJSON(vars.WIKIDOCS_ENABLE) == true }}
|
||||
continue-on-error: false
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
branch: ${{ fromJSON(vars.WIKIDOC_BRANCHES) }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: CreateDocs for ${{matrix.branch}}
|
||||
uses: asterisk/asterisk-ci-actions/CreateAsteriskDocsComposite@main
|
||||
with:
|
||||
asterisk_repo: ${{env.ASTERISK_REPO}}
|
||||
base_branch: ${{matrix.branch}}
|
||||
docs_dir: docs_dir/${{matrix.branch}}
|
||||
github_token: ${{secrets.GITHUB_TOKEN}}
|
||||
|
||||
CreateDocsScheduled:
|
||||
needs: [ CreateDocsScheduledMatrix ]
|
||||
if: ${{ success() || failure() }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check CreateDocsScheduledMatrix status
|
||||
env:
|
||||
RESULT: ${{needs.CreateDocsScheduledMatrix.result}}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
case $RESULT in
|
||||
success)
|
||||
echo "::notice::Docs created"
|
||||
exit 0
|
||||
;;
|
||||
skipped)
|
||||
echo "::notice::Skipped"
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
echo "::error::One or CreateDocs failed ($RESULT)"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
CreateDocsManualMatrix:
|
||||
needs: [ CreateDocsDebug ]
|
||||
if: ${{github.event_name == 'workflow_dispatch'}}
|
||||
continue-on-error: false
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
branch: ${{ fromJSON(vars.WIKIDOC_MANUAL_BRANCHES) }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: CreateDocs for ${{matrix.branch}}
|
||||
uses: asterisk/asterisk-ci-actions/CreateAsteriskDocsComposite@main
|
||||
with:
|
||||
asterisk_repo: ${{env.ASTERISK_REPO}}
|
||||
base_branch: ${{matrix.branch}}
|
||||
docs_dir: docs_dir/${{matrix.branch}}
|
||||
github_token: ${{secrets.GITHUB_TOKEN}}
|
||||
|
||||
CreateDocsManual:
|
||||
needs: [ CreateDocsManualMatrix ]
|
||||
if: ${{ success() || failure() }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check CreateDocsManualMatrix status
|
||||
env:
|
||||
RESULT: ${{needs.CreateDocsManualMatrix.result}}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
case $RESULT in
|
||||
success)
|
||||
echo "::notice::Docs created"
|
||||
exit 0
|
||||
;;
|
||||
skipped)
|
||||
echo "::notice::Skipped"
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
echo "::error::One or CreateDocs failed ($RESULT)"
|
||||
exit 1
|
||||
esac
|
|
@ -0,0 +1,15 @@
|
|||
name: Issue Opened
|
||||
run-name: "Issue ${{github.event.number}} ${{github.event.action}} by ${{github.actor}}"
|
||||
on:
|
||||
issues:
|
||||
types: opened
|
||||
|
||||
jobs:
|
||||
triage:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: initial labeling
|
||||
uses: andymckay/labeler@master
|
||||
with:
|
||||
add-labels: "triage"
|
||||
ignore-if-labeled: true
|
|
@ -0,0 +1,187 @@
|
|||
name: MergeApproved
|
||||
run-name: "Merge Approved for PR ${{github.event.number}}"
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [labeled]
|
||||
|
||||
env:
|
||||
PR_NUMBER: ${{ github.event.number }}
|
||||
BASE_BRANCH: ${{github.event.pull_request.base.ref}}
|
||||
MODULES_BLACKLIST: ${{ vars.GATETEST_MODULES_BLACKLIST }} ${{ vars.UNITTEST_MODULES_BLACKLIST }}
|
||||
FORCE: ${{ endsWith(github.event.label.name, '-force') }}
|
||||
|
||||
jobs:
|
||||
IdentifyBranches:
|
||||
if: contains(fromJSON(vars.MERGE_APPROVED_LABELS), github.event.label.name)
|
||||
outputs:
|
||||
branches: ${{ steps.getbranches.outputs.branches }}
|
||||
all_branches: ${{ steps.checkbranches.outputs.all_branches }}
|
||||
branch_count: ${{ steps.getbranches.outputs.branch_count }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clean up labels
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
gh pr edit --repo ${{github.repository}} \
|
||||
--remove-label ${{github.event.label.name}} \
|
||||
--remove-label ${{vars.PRE_MERGE_CHECKS_PASSED_LABEL}} \
|
||||
--remove-label ${{vars.PRE_MERGE_CHECKS_FAILED_LABEL}} \
|
||||
--remove-label ${{vars.PRE_MERGE_GATES_PASSED_LABEL}} \
|
||||
--remove-label ${{vars.PRE_MERGE_GATES_FAILED_LABEL}} \
|
||||
--remove-label ${{vars.PRE_MERGE_TESTING_IN_PROGRESS}} \
|
||||
${{env.PR_NUMBER}} || :
|
||||
|
||||
- name: Get cherry-pick branches
|
||||
uses: asterisk/asterisk-ci-actions/GetCherryPickBranchesFromPR@main
|
||||
id: getbranches
|
||||
with:
|
||||
repo: ${{github.repository}}
|
||||
pr_number: ${{env.PR_NUMBER}}
|
||||
cherry_pick_regex: ${{vars.CHERRY_PICK_REGEX}}
|
||||
github_token: ${{secrets.GITHUB_TOKEN}}
|
||||
|
||||
- name: Check Branch Count
|
||||
id: checkbranches
|
||||
env:
|
||||
BRANCH_COUNT: ${{ steps.getbranches.outputs.branch_count }}
|
||||
BRANCHES: ${{ steps.getbranches.outputs.branches }}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
gh pr edit --repo ${{github.repository}} \
|
||||
--add-label ${{vars.PRE_MERGE_TESTING_IN_PROGRESS}} \
|
||||
${{env.PR_NUMBER}} || :
|
||||
all_branches=$(echo "$BRANCHES" | jq -c "[ \"$BASE_BRANCH\" ] + .")
|
||||
echo "all_branches=${all_branches}" >>${GITHUB_OUTPUT}
|
||||
|
||||
- name: Pre Check Cherry-Picks
|
||||
if: ${{ steps.getbranches.outputs.branch_count > 0 }}
|
||||
uses: asterisk/asterisk-ci-actions/CherryPick@main
|
||||
with:
|
||||
repo: ${{github.repository}}
|
||||
pr_number: ${{env.PR_NUMBER}}
|
||||
branches: ${{steps.getbranches.outputs.branches}}
|
||||
github_token: ${{secrets.GITHUB_TOKEN}}
|
||||
push: false
|
||||
|
||||
PreMergeUnitTestMatrix:
|
||||
needs: [ IdentifyBranches ]
|
||||
if: success()
|
||||
continue-on-error: false
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
branch: ${{ fromJSON(needs.IdentifyBranches.outputs.all_branches) }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Run Unit Tests for branch ${{matrix.branch}}
|
||||
uses: asterisk/asterisk-ci-actions/AsteriskUnitComposite@main
|
||||
with:
|
||||
asterisk_repo: ${{github.repository}}
|
||||
pr_number: ${{env.PR_NUMBER}}
|
||||
base_branch: ${{matrix.branch}}
|
||||
is_cherry_pick: true
|
||||
modules_blacklist: ${{env.MODULES_BLACKLIST}}
|
||||
github_token: ${{secrets.GITHUB_TOKEN}}
|
||||
unittest_command: ${{vars.UNITTEST_COMMAND}}
|
||||
|
||||
PreMergeUnitTests:
|
||||
needs: [ IdentifyBranches, PreMergeUnitTestMatrix ]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check unit test matrix status
|
||||
env:
|
||||
RESULT: ${{needs.PreMergeUnitTestMatrix.result}}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
case $RESULT in
|
||||
success)
|
||||
gh pr edit --repo ${{github.repository}} \
|
||||
--remove-label ${{vars.PRE_MERGE_TESTING_IN_PROGRESS}} \
|
||||
--add-label ${{vars.PRE_MERGE_CHECKS_PASSED_LABEL}} \
|
||||
${{env.PR_NUMBER}} || :
|
||||
echo "::notice::All tests passed"
|
||||
exit 0
|
||||
;;
|
||||
skipped)
|
||||
gh pr edit --repo ${{github.repository}} \
|
||||
--remove-label ${{vars.PRE_MERGE_TESTING_IN_PROGRESS}} \
|
||||
--add-label ${{vars.PRE_MERGE_CHECKS_FAILED_LABEL}} \
|
||||
${{env.PR_NUMBER}} || :
|
||||
echo "::notice::Unit tests were skipped because of an earlier failure"
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
gh pr edit --repo ${{github.repository}} \
|
||||
--remove-label ${{vars.PRE_MERGE_TESTING_IN_PROGRESS}} \
|
||||
--add-label ${{vars.PRE_MERGE_CHECKS_FAILED_LABEL}} \
|
||||
${{env.PR_NUMBER}} || :
|
||||
echo "::error::One or more tests failed ($RESULT)"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
MergeAndCherryPick:
|
||||
needs: [ IdentifyBranches, PreMergeUnitTests ]
|
||||
if: success()
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Start Merge
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
gh pr edit --repo ${{github.repository}} \
|
||||
--add-label ${{vars.MERGE_IN_PROGRESS_LABEL}} \
|
||||
${{env.PR_NUMBER}} || :
|
||||
|
||||
- name: Get Token needed to push cherry-picks
|
||||
id: get_workflow_token
|
||||
uses: peter-murray/workflow-application-token-action@v2
|
||||
with:
|
||||
application_id: ${{secrets.ASTERISK_ORG_ACCESS_APP_ID}}
|
||||
application_private_key: ${{secrets.ASTERISK_ORG_ACCESS_APP_PRIV_KEY}}
|
||||
organization: asterisk
|
||||
|
||||
- name: Merge and Cherry Pick to ${{needs.IdentifyBranches.outputs.branches}}
|
||||
id: mergecp
|
||||
uses: asterisk/asterisk-ci-actions/MergeAndCherryPickComposite@main
|
||||
with:
|
||||
repo: ${{github.repository}}
|
||||
pr_number: ${{env.PR_NUMBER}}
|
||||
branches: ${{needs.IdentifyBranches.outputs.branches}}
|
||||
force: ${{env.FORCE}}
|
||||
github_token: ${{steps.get_workflow_token.outputs.token}}
|
||||
|
||||
- name: Merge Cleanup
|
||||
if: always()
|
||||
env:
|
||||
RESULT: ${{ steps.mergecp.outcome }}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
BRANCH_COUNT: ${{ needs.IdentifyBranches.outputs.branch_count }}
|
||||
BRANCHES: ${{ needs.IdentifyBranches.outputs.branches }}
|
||||
|
||||
run: |
|
||||
case $RESULT in
|
||||
success)
|
||||
gh pr edit --repo ${{github.repository}} \
|
||||
--remove-label ${{vars.MERGE_IN_PROGRESS_LABEL}} \
|
||||
${{env.PR_NUMBER}} || :
|
||||
if [ $BRANCH_COUNT -eq 0 ] ; then
|
||||
gh pr comment --repo ${{github.repository}} \
|
||||
-b "Successfully merged to branch $BASE_BRANCH." \
|
||||
${{env.PR_NUMBER}} || :
|
||||
else
|
||||
gh pr comment --repo ${{github.repository}} \
|
||||
-b "Successfully merged to branch $BASE_BRANCH and cherry-picked to $BRANCHES" \
|
||||
${{env.PR_NUMBER}} || :
|
||||
fi
|
||||
exit 0
|
||||
;;
|
||||
failure)
|
||||
gh pr edit --repo ${{github.repository}} \
|
||||
--remove-label ${{vars.MERGE_IN_PROGRESS_LABEL}} \
|
||||
--add-label ${{vars.MERGE_FAILED_LABEL}} \
|
||||
${{env.PR_NUMBER}} || :
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
esac
|
|
@ -0,0 +1,28 @@
|
|||
name: Nightly Admin
|
||||
on:
|
||||
schedule:
|
||||
- cron: '30 1 * * *'
|
||||
|
||||
env:
|
||||
ASTERISK_REPO: ${{ github.repository }}
|
||||
PR_NUMBER: 0
|
||||
PR_COMMIT: ''
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
MODULES_BLACKLIST: ${{ vars.GATETEST_MODULES_BLACKLIST }} ${{ vars.UNITTEST_MODULES_BLACKLIST }}
|
||||
|
||||
jobs:
|
||||
CloseStaleIssues:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Close Stale Issues
|
||||
uses: actions/stale@v7
|
||||
with:
|
||||
stale-issue-message: 'This issue is stale because it has been open 7 days with no activity. Remove stale label or comment or this will be closed in 14 days.'
|
||||
stale-issue-label: stale
|
||||
close-issue-message: 'This issue was closed because it has been stalled for 14 days with no activity.'
|
||||
days-before-stale: 7
|
||||
days-before-close: 14
|
||||
days-before-pr-close: -1
|
||||
only-labels: triage,feedback-required
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
name: NightlyTests
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
schedule:
|
||||
- cron: '0 2 * * *'
|
||||
|
||||
env:
|
||||
ASTERISK_REPO: ${{ github.repository }}
|
||||
PR_NUMBER: 0
|
||||
PR_COMMIT: ''
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
MODULES_BLACKLIST: ${{ vars.GATETEST_MODULES_BLACKLIST }}
|
||||
|
||||
jobs:
|
||||
AsteriskNightly:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
branch: ${{ fromJSON(vars.NIGHTLYTEST_BRANCHES) }}
|
||||
group: ${{ fromJSON(vars.NIGHTLYTEST_LIST) }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Run Nightly Tests for ${{ matrix.group }}/${{ matrix.branch }}
|
||||
uses: asterisk/asterisk-ci-actions/AsteriskGateComposite@main
|
||||
with:
|
||||
test_type: Nightly
|
||||
asterisk_repo: ${{env.ASTERISK_REPO}}
|
||||
pr_number: ${{env.PR_NUMBER}}
|
||||
base_branch: ${{matrix.branch}}
|
||||
modules_blacklist: ${{env.MODULES_BLACKLIST}}
|
||||
github_token: ${{secrets.GITHUB_TOKEN}}
|
||||
testsuite_repo: ${{vars.TESTSUITE_REPO}}
|
||||
gatetest_group: ${{matrix.group}}
|
||||
gatetest_command: ${{ toJSON(fromJSON(vars.GATETEST_COMMANDS)[matrix.group]) }}
|
||||
|
||||
AsteriskNightlyTests:
|
||||
if: ${{ always() }}
|
||||
runs-on: ubuntu-latest
|
||||
needs: AsteriskNightly
|
||||
steps:
|
||||
- name: Check test matrix status
|
||||
env:
|
||||
RESULT: ${{needs.AsteriskNightly.result}}
|
||||
run: |
|
||||
case $RESULT in
|
||||
success)
|
||||
echo "::notice::All Testsuite tests passed"
|
||||
exit 0
|
||||
;;
|
||||
skipped)
|
||||
echo "::error::Testsuite tests were skipped because of an earlier failure"
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
echo "::error::One or more Testsuite tests failed"
|
||||
exit 1
|
||||
esac
|
|
@ -0,0 +1,32 @@
|
|||
name: PRMerged
|
||||
run-name: "PR ${{github.event.number || inputs.pr_number}} ${{github.event.action || 'MANUAL POST MERGE'}} by ${{ github.actor }}"
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [closed]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
pr_number:
|
||||
description: 'PR number'
|
||||
required: true
|
||||
type: number
|
||||
|
||||
concurrency:
|
||||
group: ${{github.workflow}}-${{github.event.number || inputs.pr_number}}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
REPO: ${{github.repository}}
|
||||
PR_NUMBER: ${{github.event.number || inputs.pr_number}}
|
||||
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
||||
|
||||
jobs:
|
||||
CloseIssues:
|
||||
if: github.event.pull_request.merged == true
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: wow-actions/auto-close-fixed-issues@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
name: PRSubmitActions
|
||||
run-name: "PRSubmitActions: Test ${{github.event.action}}"
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: [PRSubmitTests]
|
||||
types:
|
||||
- requested
|
||||
- completed
|
||||
env:
|
||||
ACTION: ${{ github.event.action }}
|
||||
CONCLUSION: ${{ github.event.workflow_run.conclusion }}
|
||||
REPO: ${{ github.repository }}
|
||||
|
||||
jobs:
|
||||
PRSubmitActions:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Get PR Number
|
||||
id: getpr
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
retries: 5
|
||||
script: |
|
||||
let search = `repo:${context.repo.owner}/${context.repo.repo} ${context.payload.workflow_run.head_sha}`;
|
||||
let prs = await github.rest.search.issuesAndPullRequests({
|
||||
q: search,
|
||||
});
|
||||
if (prs.data.total_count == 0) {
|
||||
core.setFailed(`Unable to get PR for ${context.payload.workflow_run.head_sha}`);
|
||||
return;
|
||||
}
|
||||
let pr_number = prs.data.items[0].number;
|
||||
core.setOutput('pr_number', pr_number);
|
||||
return;
|
||||
|
||||
- name: Set Label
|
||||
id: setlabel
|
||||
uses: actions/github-script@v7
|
||||
env:
|
||||
PR_NUMBER: ${{ steps.getpr.outputs.PR_NUMBER }}
|
||||
LABEL_TIP: ${{ vars.PR_SUBMIT_TESTING_IN_PROGRESS }}
|
||||
LABEL_PASS: ${{ vars.PR_SUBMIT_TESTS_PASSED }}
|
||||
LABEL_FAIL: ${{ vars.PR_SUBMIT_TESTS_FAILED }}
|
||||
with:
|
||||
retries: 5
|
||||
script: |
|
||||
let label;
|
||||
if (process.env.ACTION === 'requested') {
|
||||
label = process.env.LABEL_TIP;
|
||||
} else {
|
||||
if ( process.env.CONCLUSION === 'success' ) {
|
||||
label = process.env.LABEL_PASS;
|
||||
} else {
|
||||
label = process.env.LABEL_FAIL;
|
||||
}
|
||||
}
|
||||
core.info(`Setting label ${label}`);
|
||||
github.rest.issues.setLabels({
|
||||
issue_number: process.env.PR_NUMBER,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
labels: [ label ]
|
||||
});
|
||||
return;
|
||||
|
||||
- name: Get cherry-pick branches
|
||||
if: github.event.action == 'completed'
|
||||
id: getbranches
|
||||
uses: asterisk/asterisk-ci-actions/GetCherryPickBranchesFromPR@main
|
||||
with:
|
||||
repo: ${{env.REPO}}
|
||||
pr_number: ${{steps.getpr.outputs.PR_NUMBER}}
|
||||
cherry_pick_regex: ${{vars.CHERRY_PICK_REGEX}}
|
||||
github_token: ${{secrets.GITHUB_TOKEN}}
|
||||
|
||||
- name: Add cherry-pick reminder
|
||||
if: github.event.action == 'completed'
|
||||
uses: actions/github-script@v7
|
||||
env:
|
||||
PR_NUMBER: ${{steps.getpr.outputs.PR_NUMBER}}
|
||||
CHERRY_PICK_REMINDER: ${{vars.CHERRY_PICK_REMINDER}}
|
||||
BRANCHES_OUTPUT: ${{toJSON(steps.getbranches.outputs)}}
|
||||
BRANCH_COUNT: ${{steps.getbranches.outputs.branch_count}}
|
||||
FORCED_NONE: ${{steps.getbranches.outputs.forced_none}}
|
||||
with:
|
||||
retries: 5
|
||||
script: |
|
||||
if (process.env.FORCED_NONE === 'true' ||
|
||||
process.env.BRANCH_COUNT > 0) {
|
||||
core.info("No cherry-pick reminder needed.");
|
||||
return;
|
||||
}
|
||||
let comments = await github.rest.issues.listComments({
|
||||
issue_number: process.env.PR_NUMBER,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
});
|
||||
let found = false;
|
||||
for (const c of comments.data) {
|
||||
if (c.body.startsWith("<!--CPR-->")) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
core.info("Cherry-pick reminder already exists.");
|
||||
return;
|
||||
}
|
||||
core.info("Adding cherry-pick reminder.");
|
||||
await github.rest.issues.createComment({
|
||||
issue_number: process.env.PR_NUMBER,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: process.env.CHERRY_PICK_REMINDER
|
||||
})
|
||||
return;
|
||||
|
||||
- name: Add reviewers
|
||||
if: github.event.action == 'completed'
|
||||
uses: actions/github-script@v7
|
||||
env:
|
||||
PR_NUMBER: ${{steps.getpr.outputs.PR_NUMBER}}
|
||||
REVIEWERS: ${{vars.PR_REVIEWERS}}
|
||||
with:
|
||||
retries: 5
|
||||
script: |
|
||||
let rs = JSON.parse(process.env.REVIEWERS);
|
||||
let users = [];
|
||||
let teams = [];
|
||||
for (const r of rs) {
|
||||
if (r.indexOf("/") > 0) {
|
||||
teams.push(r.split('/')[1]);
|
||||
} else {
|
||||
users.push(r);
|
||||
}
|
||||
}
|
||||
if (teams.length > 0 || users.length > 0) {
|
||||
core.info(`Adding user reviewers ${users}`);
|
||||
core.info(`Adding team reviewers ${teams}`);
|
||||
await github.rest.pulls.requestReviewers({
|
||||
pull_number: process.env.PR_NUMBER,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
reviewers: users,
|
||||
team_reviewers: teams
|
||||
});
|
||||
}
|
||||
return;
|
|
@ -0,0 +1,114 @@
|
|||
name: PRSubmitTests
|
||||
run-name: "PR ${{github.event.number}} ${{github.event.action}} by ${{ github.actor }}"
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, reopened, synchronize]
|
||||
|
||||
concurrency:
|
||||
group: ${{github.workflow}}-${{github.event.number}}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
ASTERISK_REPO: ${{github.repository}}
|
||||
PR_NUMBER: ${{github.event.number}}
|
||||
PR_COMMIT: ${{github.event.pull_request.head.sha}}
|
||||
BRANCH: ${{github.event.pull_request.base.ref}}
|
||||
|
||||
jobs:
|
||||
#
|
||||
# Pull requests created from forked respositories don't have access to
|
||||
# the "Action Variables" ('vars' context) so we need to retrieve control
|
||||
# data from an action.
|
||||
#
|
||||
PRSGetControlData:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
control_data: ${{ steps.setvars.outputs.control_data }}
|
||||
steps:
|
||||
- id: setvars
|
||||
uses: asterisk/asterisk-ci-actions/GetRepoControlData@main
|
||||
with:
|
||||
repo: ${{ github.event.repository.name}}
|
||||
- name: DumpEnvironment
|
||||
uses: asterisk/asterisk-ci-actions/DumpEnvironmentAction@main
|
||||
with:
|
||||
action-inputs: ${{toJSON(inputs)}}
|
||||
action-vars: ${{ toJSON(steps.setvars.outputs) }}
|
||||
|
||||
PRSUnitTests:
|
||||
needs: PRSGetControlData
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
UNITTEST_COMMAND: ${{ fromJSON(needs.PRSGetControlData.outputs.control_data).UNITTEST_COMMAND }}
|
||||
steps:
|
||||
- name: Run Unit Tests
|
||||
uses: asterisk/asterisk-ci-actions/AsteriskUnitComposite@main
|
||||
with:
|
||||
asterisk_repo: ${{env.ASTERISK_REPO}}
|
||||
pr_number: ${{env.PR_NUMBER}}
|
||||
base_branch: ${{env.BRANCH}}
|
||||
unittest_command: ${{env.UNITTEST_COMMAND}}
|
||||
|
||||
PRSGateTestMatrix:
|
||||
runs-on: ubuntu-latest
|
||||
needs: PRSGetControlData
|
||||
continue-on-error: false
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
group: ${{ fromJSON(fromJSON(needs.PRSGetControlData.outputs.control_data).GATETEST_LIST) }}
|
||||
env:
|
||||
TESTSUITE_REPO: "${{ fromJSON(needs.PRSGetControlData.outputs.control_data).TESTSUITE_REPO }}"
|
||||
GATETEST_COMMANDS: "${{ fromJSON(needs.PRSGetControlData.outputs.control_data).GATETEST_COMMANDS }}"
|
||||
GATETEST_COMMAND: "${{ toJSON(fromJSON(fromJSON(needs.PRSGetControlData.outputs.control_data).GATETEST_COMMANDS)[matrix.group]) }}"
|
||||
steps:
|
||||
- id: runtest
|
||||
name: Run Gate Tests for ${{ matrix.group }}
|
||||
uses: asterisk/asterisk-ci-actions/AsteriskGateComposite@main
|
||||
with:
|
||||
test_type: Gate
|
||||
asterisk_repo: ${{env.ASTERISK_REPO}}
|
||||
pr_number: ${{env.PR_NUMBER}}
|
||||
base_branch: ${{env.BRANCH}}
|
||||
testsuite_repo: ${{env.TESTSUITE_REPO}}
|
||||
gatetest_group: ${{matrix.group}}
|
||||
gatetest_command: ${{env.GATETEST_COMMAND}}
|
||||
|
||||
PRSTestResults:
|
||||
if: always()
|
||||
runs-on: ubuntu-latest
|
||||
needs: [PRSUnitTests,PRSGateTestMatrix]
|
||||
steps:
|
||||
- name: Check test matrix status
|
||||
env:
|
||||
RESULT_UNIT: ${{ needs.PRSUnitTests.result }}
|
||||
RESULT_GATE: ${{ needs.PRSGateTestMatrix.result }}
|
||||
run: |
|
||||
declare -i rc=0
|
||||
echo "all results: ${{ toJSON(needs.*.result) }}"
|
||||
case $RESULT_UNIT in
|
||||
success)
|
||||
echo "::notice::Unit tests passed"
|
||||
;;
|
||||
skipped)
|
||||
echo "::error::Unit tests were skipped because of an earlier failure"
|
||||
rc+=1
|
||||
;;
|
||||
*)
|
||||
echo "::error::One or more unit tests failed ($RESULT_UNIT)"
|
||||
rc+=1
|
||||
esac
|
||||
case $RESULT_GATE in
|
||||
success)
|
||||
echo "::notice::Gate tests passed"
|
||||
;;
|
||||
skipped)
|
||||
echo "::error::Gate tests were skipped because of an earlier failure"
|
||||
rc+=1
|
||||
;;
|
||||
*)
|
||||
echo "::error::One or more gate tests failed ($RESULT_GATE)"
|
||||
rc+=1
|
||||
esac
|
||||
echo "::notice::Final result code: $rc"
|
||||
exit $rc
|
|
@ -0,0 +1,99 @@
|
|||
name: Releaser
|
||||
run-name: ${{ github.actor }} is creating ${{vars.PRODUCT_NAME}} release ${{inputs.new_version}}
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
new_version:
|
||||
description: |
|
||||
New Version:
|
||||
Examples:
|
||||
20.4.0-rc1, 20.4.0-rc2, 20.4.0, 20.4.1
|
||||
certified-20.4-cert1-rc1, certified-20.4-cert1
|
||||
required: true
|
||||
type: string
|
||||
is_security:
|
||||
description: |
|
||||
Security?
|
||||
(No prev RCs)
|
||||
required: true
|
||||
type: boolean
|
||||
default: false
|
||||
advisories:
|
||||
description: |
|
||||
Comma separated list of advisories.
|
||||
NO SPACES
|
||||
Example: GHSA-4xjp-22g4-9fxm,GHSA-4xjp-22g4-zzzz
|
||||
required: false
|
||||
type: string
|
||||
is_hotfix:
|
||||
description: |
|
||||
Hotfix?
|
||||
(A patch release but not security. No prev RCs)
|
||||
required: true
|
||||
type: boolean
|
||||
default: false
|
||||
force_cherry_pick:
|
||||
description: |
|
||||
Force cherry-pick for non-RC1 releases? USE WITH CAUTION!
|
||||
required: true
|
||||
type: boolean
|
||||
default: false
|
||||
push_release_branches:
|
||||
description: |
|
||||
Push release branches live?
|
||||
required: true
|
||||
type: boolean
|
||||
default: false
|
||||
create_github_release:
|
||||
description: |
|
||||
Create the GitHub release?
|
||||
required: true
|
||||
type: boolean
|
||||
default: false
|
||||
push_tarballs:
|
||||
description: |
|
||||
Push tarballs to downloads server?
|
||||
required: true
|
||||
type: boolean
|
||||
default: false
|
||||
send_email:
|
||||
description: |
|
||||
Send announcement emails?
|
||||
required: true
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
jobs:
|
||||
ReleaseAsterisk:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Run Releaser
|
||||
uses: asterisk/asterisk-ci-actions/ReleaserComposite@main
|
||||
with:
|
||||
product: ${{vars.PRODUCT_NAME}}
|
||||
is_security: ${{inputs.is_security}}
|
||||
advisories: ${{inputs.advisories}}
|
||||
is_hotfix: ${{inputs.is_hotfix}}
|
||||
new_version: ${{inputs.new_version}}
|
||||
force_cherry_pick: ${{inputs.force_cherry_pick}}
|
||||
push_release_branches: ${{inputs.push_release_branches}}
|
||||
create_github_release: ${{inputs.create_github_release}}
|
||||
push_tarballs: ${{inputs.push_tarballs}}
|
||||
send_email: ${{inputs.send_email}}
|
||||
repo: ${{github.repository}}
|
||||
mail_list_ga: ${{vars.MAIL_LIST_GA}}
|
||||
mail_list_rc: ${{vars.MAIL_LIST_RC}}
|
||||
mail_list_cert_ga: ${{vars.MAIL_LIST_CERT_GA}}
|
||||
mail_list_cert_rc: ${{vars.MAIL_LIST_CERT_RC}}
|
||||
mail_list_sec: ${{vars.MAIL_LIST_SEC_ADV}}
|
||||
sec_adv_url_base: ${{vars.SEC_ADV_URL_BASE}}
|
||||
gpg_private_key: ${{secrets.ASTDEV_GPG_PRIV_KEY}}
|
||||
github_token: ${{secrets.GITHUB_TOKEN}}
|
||||
application_id: ${{secrets.ASTERISK_ORG_ACCESS_APP_ID}}
|
||||
application_private_key: ${{secrets.ASTERISK_ORG_ACCESS_APP_PRIV_KEY}}
|
||||
asteriskteamsa_username: ${{secrets.ASTERISKTEAMSA_GMAIL_ACCT}}
|
||||
asteriskteamsa_token: ${{secrets.ASTERISKTEAMSA_GMAIL_TOKEN}}
|
||||
deploy_ssh_priv_key: ${{secrets.DOWNLOADS_DEPLOY_SSH_PRIV_KEY}}
|
||||
deploy_ssh_username: ${{secrets.DOWNLOADS_DEPLOY_SSH_USERNAME}}
|
||||
deploy_host: ${{vars.DEPLOY_HOST}}
|
||||
deploy_dir: ${{vars.DEPLOY_DIR}}
|
|
@ -38,3 +38,4 @@ out/
|
|||
*.orig
|
||||
tests/CI/output
|
||||
.develvars
|
||||
configure
|
||||
|
|
11
.gitreview
11
.gitreview
|
@ -1,11 +0,0 @@
|
|||
[gerrit]
|
||||
defaultbranch=master
|
||||
basebranch=master
|
||||
#
|
||||
# Intentional padding to ensure it is possible to point a commit
|
||||
# to an alternative gerrit server/repository without breaking
|
||||
# cherry-pick between branches.
|
||||
#
|
||||
host=gerrit.asterisk.org
|
||||
port=29418
|
||||
project=asterisk.git
|
|
@ -0,0 +1 @@
|
|||
40
|
10
BUGS
10
BUGS
|
@ -1,22 +1,22 @@
|
|||
Asterisk Bug Tracking Information
|
||||
=================================
|
||||
|
||||
To learn about and report Asterisk bugs, please visit
|
||||
To learn about and report Asterisk bugs, please visit
|
||||
the official Asterisk Bug Tracker at:
|
||||
|
||||
https://issues.asterisk.org/jira
|
||||
https://github.com/asterisk/asterisk/issues/
|
||||
|
||||
For more information on using the bug tracker, or to
|
||||
For more information on using the bug tracker, or to
|
||||
learn how you can contribute by acting as a bug marshal
|
||||
please see:
|
||||
|
||||
http://www.asterisk.org/developers/bug-guidelines
|
||||
https://docs.asterisk.org/Asterisk-Community/Asterisk-Issue-Guidelines/
|
||||
|
||||
If you would like to submit a feature request, please
|
||||
resist the temptation to post it to the bug tracker.
|
||||
Feature requests should be posted to the asterisk-dev
|
||||
mailing list, located at:
|
||||
|
||||
http://lists.digium.com
|
||||
http://lists.digium.com
|
||||
|
||||
Thank you!
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
ChangeLogs/ChangeLog-20.7.0.md
|
|
@ -0,0 +1,741 @@
|
|||
|
||||
Change Log for Release 20.3.0
|
||||
========================================
|
||||
|
||||
Summary:
|
||||
----------------------------------------
|
||||
|
||||
- Set up new ChangeLogs directory
|
||||
- .github: Add AsteriskReleaser
|
||||
- chan_pjsip: also return all codecs on empty re-INVITE for late offers
|
||||
- cel: add local optimization begin event
|
||||
- core: Cleanup gerrit and JIRA references. (#57)
|
||||
- .github: Fix CherryPickTest to only run when it should
|
||||
- .github: Fix reference to CHERRY_PICK_TESTING_IN_PROGRESS
|
||||
- .github: Remove separate set labels step from new PR
|
||||
- .github: Refactor CP progress and add new PR test progress
|
||||
- res_pjsip: mediasec: Add Security-Client headers after 401
|
||||
- .github: Add cherry-pick test progress labels
|
||||
- LICENSE: Update link to trademark policy.
|
||||
- chan_dahdi: Add dialmode option for FXS lines.
|
||||
- .github: Update issue templates
|
||||
- .github: Remove unnecessary parameter in CherryPickTest
|
||||
- Initial GitHub PRs
|
||||
- Initial GitHub Issue Templates
|
||||
- pbx_dundi: Fix PJSIP endpoint configuration check.
|
||||
- Revert "app_queue: periodic announcement configurable start time."
|
||||
- res_pjsip_stir_shaken: Fix JSON field ordering and disallowed TN characters.
|
||||
- pbx_dundi: Add PJSIP support.
|
||||
- install_prereq: Add Linux Mint support.
|
||||
- chan_pjsip: fix music on hold continues after INVITE with replaces
|
||||
- voicemail.conf: Fix incorrect comment about #include.
|
||||
- app_queue: Fix minor xmldoc duplication and vagueness.
|
||||
- test.c: Fix counting of tests and add 2 new tests
|
||||
- res_calendar: output busy state as part of show calendar.
|
||||
- loader.c: Minor module key check simplification.
|
||||
- ael: Regenerate lexers and parsers.
|
||||
- bridge_builtin_features: add beep via touch variable
|
||||
- res_mixmonitor: MixMonitorMute by MixMonitor ID
|
||||
- format_sln: add .slin as supported file extension
|
||||
- res_agi: RECORD FILE plays 2 beeps.
|
||||
- func_json: Fix JSON parsing issues.
|
||||
- app_senddtmf: Add SendFlash AMI action.
|
||||
- app_dial: Fix DTMF not relayed to caller on unanswered calls.
|
||||
- configure: fix detection of re-entrant resolver functions
|
||||
- cli: increase channel column width
|
||||
- app_queue: periodic announcement configurable start time.
|
||||
- make_version: Strip svn stuff and suppress ref HEAD errors
|
||||
- res_http_media_cache: Introduce options and customize
|
||||
- main/iostream.c: fix build with libressl
|
||||
- contrib: rc.archlinux.asterisk uses invalid redirect.
|
||||
|
||||
User Notes:
|
||||
----------------------------------------
|
||||
|
||||
- ### cel: add local optimization begin event
|
||||
The new AST_CEL_LOCAL_OPTIMIZE_BEGIN can be used
|
||||
by itself or in conert with the existing
|
||||
AST_CEL_LOCAL_OPTIMIZE to book-end local channel optimizaion.
|
||||
|
||||
- ### chan_dahdi: Add dialmode option for FXS lines.
|
||||
A "dialmode" option has been added which allows
|
||||
specifying, on a per-channel basis, what methods of
|
||||
subscriber dialing (pulse and/or tone) are permitted.
|
||||
Additionally, this can be changed on a channel
|
||||
at any point during a call using the CHANNEL
|
||||
function.
|
||||
|
||||
- ### pbx_dundi: Add PJSIP support.
|
||||
DUNDi now supports chan_pjsip. Outgoing calls using
|
||||
PJSIP require the pjsip_outgoing_endpoint option
|
||||
to be set in dundi.conf.
|
||||
|
||||
- ### cli: increase channel column width
|
||||
This change increases the display width on 'core show channels'
|
||||
amd 'core show channels verbose'
|
||||
For 'core show channels', the Channel name field is increased to
|
||||
64 characters and the Location name field is increased to 32
|
||||
characters.
|
||||
For 'core show channels verbose', the Channel name field is
|
||||
increased to 80 characters, the Context is increased to 24
|
||||
characters and the Extension is increased to 24 characters.
|
||||
|
||||
- ### app_senddtmf: Add SendFlash AMI action.
|
||||
The SendFlash AMI action now allows sending
|
||||
a hook flash event on a channel.
|
||||
|
||||
- ### res_http_media_cache: Introduce options and customize
|
||||
The res_http_media_cache module now attempts to load
|
||||
configuration from the res_http_media_cache.conf file.
|
||||
The following options were added:
|
||||
* timeout_secs
|
||||
* user_agent
|
||||
* follow_location
|
||||
* max_redirects
|
||||
* protocols
|
||||
* redirect_protocols
|
||||
* dns_cache_timeout_secs
|
||||
|
||||
- ### test.c: Fix counting of tests and add 2 new tests
|
||||
The "tests" attribute of the "testsuite" element in the
|
||||
output XML now reflects only the tests actually requested
|
||||
to be executed instead of all the tests registered.
|
||||
The "failures" attribute was added to the "testsuite"
|
||||
element.
|
||||
Also added two new unit tests that just pass and fail
|
||||
to be used for testing CI itself.
|
||||
|
||||
- ### res_mixmonitor: MixMonitorMute by MixMonitor ID
|
||||
It is now possible to specify the MixMonitorID when calling
|
||||
the manager action: MixMonitorMute. This will allow an
|
||||
individual MixMonitor instance to be muted via ID.
|
||||
The MixMonitorID can be stored as a channel variable using
|
||||
the 'i' MixMonitor option and is returned upon creation if
|
||||
this option is used.
|
||||
As part of this change, if no MixMonitorID is specified in
|
||||
the manager action MixMonitorMute, Asterisk will set the mute
|
||||
flag on all MixMonitor audiohooks on the channel. Previous
|
||||
behavior would set the flag on the first MixMonitor audiohook
|
||||
found.
|
||||
|
||||
- ### bridge_builtin_features: add beep via touch variable
|
||||
Add optional touch variable : TOUCH_MIXMONITOR_BEEP(interval)
|
||||
Setting TOUCH_MIXMONITOR_BEEP/TOUCH_MONITOR_BEEP to a valid
|
||||
interval in seconds will result in a periodic beep being
|
||||
played to the monitored channel upon MixMontior/Monitor
|
||||
feature start.
|
||||
If an interval less than 5 seconds is specified, the interval
|
||||
will default to 5 seconds. If the value is set to an invalid
|
||||
interval, the default of 15 seconds will be used.
|
||||
|
||||
- ### format_sln: add .slin as supported file extension
|
||||
format_sln now recognizes '.slin' as a valid
|
||||
file extension in addition to the existing
|
||||
'.sln' and '.raw'.
|
||||
|
||||
|
||||
Upgrade Notes:
|
||||
----------------------------------------
|
||||
|
||||
- ### cel: add local optimization begin event
|
||||
The existing AST_CEL_LOCAL_OPTIMIZE can continue
|
||||
to be used as-is and the AST_CEL_LOCAL_OPTIMIZE_BEGIN event
|
||||
can be ignored if desired.
|
||||
|
||||
|
||||
Closed Issues:
|
||||
----------------------------------------
|
||||
|
||||
- #35: [New Feature]: chan_dahdi: Allow disabling pulse or tone dialing
|
||||
- #39: [Bug]: Remove .gitreview from repository.
|
||||
- #43: [Bug]: Link to trademark policy is no longer correct
|
||||
- #48: [bug]: res_pjsip: Mediasec requires different headers on 401 response
|
||||
- #52: [improvement]: Add local optimization begin cel event
|
||||
|
||||
Commits By Author:
|
||||
----------------------------------------
|
||||
|
||||
- ### Asterisk Development Team (1):
|
||||
- Update for 20.3.0-rc1
|
||||
|
||||
- ### Fabrice Fontaine (2):
|
||||
- main/iostream.c: fix build with libressl
|
||||
- configure: fix detection of re-entrant resolver functions
|
||||
|
||||
- ### George Joseph (13):
|
||||
- make_version: Strip svn stuff and suppress ref HEAD errors
|
||||
- test.c: Fix counting of tests and add 2 new tests
|
||||
- Initial GitHub Issue Templates
|
||||
- Initial GitHub PRs
|
||||
- .github: Remove unnecessary parameter in CherryPickTest
|
||||
- .github: Update issue templates
|
||||
- .github: Add cherry-pick test progress labels
|
||||
- .github: Refactor CP progress and add new PR test progress
|
||||
- .github: Remove separate set labels step from new PR
|
||||
- .github: Fix reference to CHERRY_PICK_TESTING_IN_PROGRESS
|
||||
- .github: Fix CherryPickTest to only run when it should
|
||||
- .github: Add AsteriskReleaser
|
||||
- Set up new ChangeLogs directory
|
||||
|
||||
- ### Henning Westerholt (2):
|
||||
- chan_pjsip: fix music on hold continues after INVITE with replaces
|
||||
- chan_pjsip: also return all codecs on empty re-INVITE for late offers
|
||||
|
||||
- ### Holger Hans Peter Freyther (1):
|
||||
- res_http_media_cache: Introduce options and customize
|
||||
|
||||
- ### Jaco Kroon (2):
|
||||
- app_queue: periodic announcement configurable start time.
|
||||
- res_calendar: output busy state as part of show calendar.
|
||||
|
||||
- ### Joshua C. Colp (2):
|
||||
- pbx_dundi: Fix PJSIP endpoint configuration check.
|
||||
- LICENSE: Update link to trademark policy.
|
||||
|
||||
- ### Joshua Colp (1):
|
||||
- Revert "app_queue: periodic announcement configurable start time."
|
||||
|
||||
- ### Maximilian Fridrich (1):
|
||||
- res_pjsip: mediasec: Add Security-Client headers after 401
|
||||
|
||||
- ### Mike Bradeen (5):
|
||||
- cli: increase channel column width
|
||||
- format_sln: add .slin as supported file extension
|
||||
- res_mixmonitor: MixMonitorMute by MixMonitor ID
|
||||
- bridge_builtin_features: add beep via touch variable
|
||||
- cel: add local optimization begin event
|
||||
|
||||
- ### Naveen Albert (8):
|
||||
- app_dial: Fix DTMF not relayed to caller on unanswered calls.
|
||||
- app_senddtmf: Add SendFlash AMI action.
|
||||
- func_json: Fix JSON parsing issues.
|
||||
- app_queue: Fix minor xmldoc duplication and vagueness.
|
||||
- voicemail.conf: Fix incorrect comment about #include.
|
||||
- pbx_dundi: Add PJSIP support.
|
||||
- res_pjsip_stir_shaken: Fix JSON field ordering and disallowed TN characters.
|
||||
- chan_dahdi: Add dialmode option for FXS lines.
|
||||
|
||||
- ### Sean Bright (5):
|
||||
- contrib: rc.archlinux.asterisk uses invalid redirect.
|
||||
- res_agi: RECORD FILE plays 2 beeps.
|
||||
- ael: Regenerate lexers and parsers.
|
||||
- loader.c: Minor module key check simplification.
|
||||
- core: Cleanup gerrit and JIRA references. (#57)
|
||||
|
||||
- ### The_Blode (1):
|
||||
- install_prereq: Add Linux Mint support.
|
||||
|
||||
|
||||
Detail:
|
||||
----------------------------------------
|
||||
|
||||
- ### Set up new ChangeLogs directory
|
||||
Author: George Joseph
|
||||
Date: 2023-05-09
|
||||
|
||||
|
||||
- ### .github: Add AsteriskReleaser
|
||||
Author: George Joseph
|
||||
Date: 2023-05-05
|
||||
|
||||
|
||||
- ### chan_pjsip: also return all codecs on empty re-INVITE for late offers
|
||||
Author: Henning Westerholt
|
||||
Date: 2023-05-03
|
||||
|
||||
We should also return all codecs on an re-INVITE without SDP for a
|
||||
call that used late offer (e.g. no SDP in the initial INVITE, SDP
|
||||
in the ACK). Bugfix for feature introduced in ASTERISK-30193
|
||||
(https://issues.asterisk.org/jira/browse/ASTERISK-30193)
|
||||
|
||||
Migration from previous gerrit change that was not merged.
|
||||
|
||||
|
||||
- ### cel: add local optimization begin event
|
||||
Author: Mike Bradeen
|
||||
Date: 2023-05-02
|
||||
|
||||
The current AST_CEL_LOCAL_OPTIMIZE event is and has been
|
||||
triggered on a local optimization end to serve as a flag
|
||||
indicating the event occurred. This change adds a second
|
||||
AST_CEL_LOCAL_OPTIMIZE_BEGIN event for further detail.
|
||||
|
||||
Resolves: #52
|
||||
|
||||
UpgradeNote: The existing AST_CEL_LOCAL_OPTIMIZE can continue
|
||||
to be used as-is and the AST_CEL_LOCAL_OPTIMIZE_BEGIN event
|
||||
can be ignored if desired.
|
||||
|
||||
UserNote: The new AST_CEL_LOCAL_OPTIMIZE_BEGIN can be used
|
||||
by itself or in conert with the existing
|
||||
AST_CEL_LOCAL_OPTIMIZE to book-end local channel optimizaion.
|
||||
|
||||
|
||||
- ### core: Cleanup gerrit and JIRA references. (#57)
|
||||
Author: Sean Bright
|
||||
Date: 2023-05-03
|
||||
|
||||
* Remove .gitreview and switch to pulling the main asterisk branch
|
||||
version from configure.ac instead.
|
||||
|
||||
* Replace references to JIRA with GitHub.
|
||||
|
||||
* Other minor cleanup found along the way.
|
||||
|
||||
Resolves: #39
|
||||
|
||||
- ### .github: Fix CherryPickTest to only run when it should
|
||||
Author: George Joseph
|
||||
Date: 2023-05-03
|
||||
|
||||
Fixed CherryPickTest so it triggers only on the
|
||||
"cherry-pick-test" label instead of all labels.
|
||||
|
||||
|
||||
- ### .github: Fix reference to CHERRY_PICK_TESTING_IN_PROGRESS
|
||||
Author: George Joseph
|
||||
Date: 2023-05-02
|
||||
|
||||
|
||||
- ### .github: Remove separate set labels step from new PR
|
||||
Author: George Joseph
|
||||
Date: 2023-05-02
|
||||
|
||||
|
||||
- ### .github: Refactor CP progress and add new PR test progress
|
||||
Author: George Joseph
|
||||
Date: 2023-05-02
|
||||
|
||||
|
||||
- ### res_pjsip: mediasec: Add Security-Client headers after 401
|
||||
Author: Maximilian Fridrich
|
||||
Date: 2023-05-02
|
||||
|
||||
When using mediasec, requests sent after a 401 must still contain the
|
||||
Security-Client header according to
|
||||
draft-dawes-sipcore-mediasec-parameter.
|
||||
|
||||
Resolves: #48
|
||||
|
||||
- ### .github: Add cherry-pick test progress labels
|
||||
Author: George Joseph
|
||||
Date: 2023-05-02
|
||||
|
||||
|
||||
- ### LICENSE: Update link to trademark policy.
|
||||
Author: Joshua C. Colp
|
||||
Date: 2023-05-01
|
||||
|
||||
Resolves: #43
|
||||
|
||||
- ### chan_dahdi: Add dialmode option for FXS lines.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-04-28
|
||||
|
||||
Currently, both pulse and tone dialing are always enabled
|
||||
on all FXS lines, with no way of disabling one or the other.
|
||||
|
||||
In some circumstances, it is desirable or necessary to
|
||||
disable one of these, and this behavior can be problematic.
|
||||
|
||||
A new "dialmode" option is added which allows setting the
|
||||
methods to support on a per channel basis for FXS (FXO
|
||||
signalled lines). The four options are "both", "pulse",
|
||||
"dtmf"/"tone", and "none".
|
||||
|
||||
Additionally, integration with the CHANNEL function is
|
||||
added so that this setting can be updated for a channel
|
||||
during a call.
|
||||
|
||||
Resolves: #35
|
||||
ASTERISK-29992
|
||||
|
||||
UserNote: A "dialmode" option has been added which allows
|
||||
specifying, on a per-channel basis, what methods of
|
||||
subscriber dialing (pulse and/or tone) are permitted.
|
||||
|
||||
Additionally, this can be changed on a channel
|
||||
at any point during a call using the CHANNEL
|
||||
function.
|
||||
|
||||
|
||||
- ### .github: Update issue templates
|
||||
Author: George Joseph
|
||||
Date: 2023-05-01
|
||||
|
||||
|
||||
- ### .github: Remove unnecessary parameter in CherryPickTest
|
||||
Author: George Joseph
|
||||
Date: 2023-05-01
|
||||
|
||||
|
||||
- ### Initial GitHub PRs
|
||||
Author: George Joseph
|
||||
Date: 2023-04-28
|
||||
|
||||
|
||||
- ### Initial GitHub Issue Templates
|
||||
Author: George Joseph
|
||||
Date: 2023-04-28
|
||||
|
||||
|
||||
- ### pbx_dundi: Fix PJSIP endpoint configuration check.
|
||||
Author: Joshua C. Colp
|
||||
Date: 2023-04-13
|
||||
|
||||
ASTERISK-28233
|
||||
|
||||
|
||||
- ### Revert "app_queue: periodic announcement configurable start time."
|
||||
Author: Joshua Colp
|
||||
Date: 2023-04-11
|
||||
|
||||
This reverts commit 3fd0b65bae4b1b14434737ffcf0da4aa9ff717f6.
|
||||
|
||||
Reason for revert: Causes segmentation fault.
|
||||
|
||||
|
||||
- ### res_pjsip_stir_shaken: Fix JSON field ordering and disallowed TN characters.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-02-17
|
||||
|
||||
The current STIR/SHAKEN signing process is inconsistent with the
|
||||
RFCs in a couple ways that can cause interoperability issues.
|
||||
|
||||
RFC8225 specifies that the keys must be ordered lexicographically, but
|
||||
currently the fields are simply ordered according to the order
|
||||
in which they were added to the JSON object, which is not
|
||||
compliant with the RFC and can cause issues with some carriers.
|
||||
|
||||
To fix this, we now leverage libjansson's ability to dump a JSON
|
||||
object sorted by key value, yielding the correct field ordering.
|
||||
|
||||
Additionally, telephone numbers must have any leading + prefix removed
|
||||
and must not contain characters outside of 0-9, *, and # in order
|
||||
to comply with the RFCs. Numbers are now properly formatted as such.
|
||||
|
||||
ASTERISK-30407 #close
|
||||
|
||||
|
||||
- ### pbx_dundi: Add PJSIP support.
|
||||
Author: Naveen Albert
|
||||
Date: 2022-12-09
|
||||
|
||||
Adds PJSIP as a supported technology to DUNDi.
|
||||
|
||||
To facilitate this, we now allow an endpoint to be specified
|
||||
for outgoing PJSIP calls. We also allow users to force a specific
|
||||
channel technology for outgoing SIP-protocol calls.
|
||||
|
||||
ASTERISK-28109 #close
|
||||
ASTERISK-28233 #close
|
||||
|
||||
|
||||
- ### install_prereq: Add Linux Mint support.
|
||||
Author: The_Blode
|
||||
Date: 2023-03-17
|
||||
|
||||
ASTERISK-30359 #close
|
||||
|
||||
|
||||
- ### chan_pjsip: fix music on hold continues after INVITE with replaces
|
||||
Author: Henning Westerholt
|
||||
Date: 2023-03-21
|
||||
|
||||
In a three party scenario with INVITE with replaces, we need to
|
||||
unhold the call, otherwise one party continues to get music on
|
||||
hold, and the call is not properly bridged between them.
|
||||
|
||||
ASTERISK-30428
|
||||
|
||||
|
||||
- ### voicemail.conf: Fix incorrect comment about #include.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-03-28
|
||||
|
||||
A comment at the top of voicemail.conf says that #include
|
||||
cannot be used in voicemail.conf because this breaks
|
||||
the ability for app_voicemail to auto-update passwords.
|
||||
This is factually incorrect, since Asterisk has no problem
|
||||
updating files that are #include'd in the main configuration
|
||||
file, and this does work in voicemail.conf as well.
|
||||
|
||||
ASTERISK-30479 #close
|
||||
|
||||
|
||||
- ### app_queue: Fix minor xmldoc duplication and vagueness.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-04-03
|
||||
|
||||
The F option in the xmldocs for the Queue application
|
||||
was erroneously duplicated, causing it to display
|
||||
twice on the wiki. The two sections are now merged into one.
|
||||
|
||||
Additionally, the description for the d option was quite
|
||||
vague. Some more details are added to provide context
|
||||
as to what this actually does.
|
||||
|
||||
ASTERISK-30486 #close
|
||||
|
||||
|
||||
- ### test.c: Fix counting of tests and add 2 new tests
|
||||
Author: George Joseph
|
||||
Date: 2023-03-28
|
||||
|
||||
The unit test XML output was counting all registered tests as "run"
|
||||
even when only a subset were actually requested to be run and
|
||||
the "failures" attribute was missing.
|
||||
|
||||
* The "tests" attribute of the "testsuite" element in the
|
||||
output XML now reflects only the tests actually requested
|
||||
to be executed instead of all the tests registered.
|
||||
|
||||
* The "failures" attribute was added to the "testsuite"
|
||||
element.
|
||||
|
||||
Also added 2 new unit tests that just pass and fail to be
|
||||
used for CI testing.
|
||||
|
||||
|
||||
- ### res_calendar: output busy state as part of show calendar.
|
||||
Author: Jaco Kroon
|
||||
Date: 2023-03-23
|
||||
|
||||
Signed-off-by: Jaco Kroon <jaco@uls.co.za>
|
||||
|
||||
- ### loader.c: Minor module key check simplification.
|
||||
Author: Sean Bright
|
||||
Date: 2023-03-23
|
||||
|
||||
|
||||
- ### ael: Regenerate lexers and parsers.
|
||||
Author: Sean Bright
|
||||
Date: 2023-03-21
|
||||
|
||||
Various changes to ensure that the lexers and parsers can be correctly
|
||||
generated when REBUILD_PARSERS is enabled.
|
||||
|
||||
Some notes:
|
||||
|
||||
* Because of the version of flex we are using to generate the lexers
|
||||
(2.5.35) some post-processing in the Makefile is still required.
|
||||
|
||||
* The generated lexers do not contain the problematic C99 check that
|
||||
was being replaced by the call to sed in the respective Makefiles so
|
||||
it was removed.
|
||||
|
||||
* Since these files are generated, they will include trailing
|
||||
whitespace in some places. This does not need to be corrected.
|
||||
|
||||
|
||||
- ### bridge_builtin_features: add beep via touch variable
|
||||
Author: Mike Bradeen
|
||||
Date: 2023-03-01
|
||||
|
||||
Add periodic beep option to one-touch recording by setting
|
||||
the touch variable TOUCH_MONITOR_BEEP or
|
||||
TOUCH_MIXMONITOR_BEEP to the desired interval in seconds.
|
||||
|
||||
If the interval is less than 5 seconds, a minimum of 5
|
||||
seconds will be imposed. If the interval is set to an
|
||||
invalid value, it will default to 15 seconds.
|
||||
|
||||
A new test event PERIODIC_HOOK_ENABLED was added to the
|
||||
func_periodic_hook hook_on function to indicate when
|
||||
a hook is started. This is so we can test that the touch
|
||||
variable starts the hook as expected.
|
||||
|
||||
ASTERISK-30446
|
||||
|
||||
|
||||
- ### res_mixmonitor: MixMonitorMute by MixMonitor ID
|
||||
Author: Mike Bradeen
|
||||
Date: 2023-03-13
|
||||
|
||||
While it is possible to create multiple mixmonitor instances
|
||||
on a channel, it was not previously possible to mute individual
|
||||
instances.
|
||||
|
||||
This change includes the ability to specify the MixMonitorID
|
||||
when calling the manager action: MixMonitorMute. This will
|
||||
allow an individual MixMonitor instance to be muted via id.
|
||||
This id can be stored as a channel variable using the 'i'
|
||||
MixMonitor option.
|
||||
|
||||
As part of this change, if no MixMonitorID is specified in
|
||||
the manager action MixMonitorMute, Asterisk will set the mute
|
||||
flag on all MixMonitor spy-type audiohooks on the channel.
|
||||
This is done via the new audiohook function:
|
||||
ast_audiohook_set_mute_all.
|
||||
|
||||
ASTERISK-30464
|
||||
|
||||
|
||||
- ### format_sln: add .slin as supported file extension
|
||||
Author: Mike Bradeen
|
||||
Date: 2023-03-14
|
||||
|
||||
Adds '.slin' to existing supported file extensions:
|
||||
.sln and .raw
|
||||
|
||||
ASTERISK-30465
|
||||
|
||||
|
||||
- ### res_agi: RECORD FILE plays 2 beeps.
|
||||
Author: Sean Bright
|
||||
Date: 2023-03-08
|
||||
|
||||
Sending the "RECORD FILE" command without the optional
|
||||
`offset_samples` argument can result in two beeps playing on the
|
||||
channel.
|
||||
|
||||
This bug has been present since Asterisk 0.3.0 (2003-02-06).
|
||||
|
||||
ASTERISK-30457 #close
|
||||
|
||||
|
||||
- ### func_json: Fix JSON parsing issues.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-02-26
|
||||
|
||||
Fix issue with returning empty instead of dumping
|
||||
the JSON string when recursing.
|
||||
|
||||
Also adds a unit test to capture this fix.
|
||||
|
||||
ASTERISK-30441 #close
|
||||
|
||||
|
||||
- ### app_senddtmf: Add SendFlash AMI action.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-02-26
|
||||
|
||||
Adds an AMI action to send a flash event
|
||||
on a channel.
|
||||
|
||||
ASTERISK-30440 #close
|
||||
|
||||
|
||||
- ### app_dial: Fix DTMF not relayed to caller on unanswered calls.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-03-04
|
||||
|
||||
DTMF frames are not handled in app_dial when sent towards the
|
||||
caller. This means that if DTMF is sent to the calling party
|
||||
and the call has not yet been answered, the DTMF is not audible.
|
||||
This is now fixed by relaying DTMF frames if only a single
|
||||
destination is being dialed.
|
||||
|
||||
ASTERISK-29516 #close
|
||||
|
||||
|
||||
- ### configure: fix detection of re-entrant resolver functions
|
||||
Author: Fabrice Fontaine
|
||||
Date: 2023-03-08
|
||||
|
||||
uClibc does not provide res_nsearch:
|
||||
asterisk-16.0.0/main/dns.c:506: undefined reference to `res_nsearch'
|
||||
|
||||
Patch coded by Yann E. MORIN:
|
||||
http://lists.busybox.net/pipermail/buildroot/2018-October/232630.html
|
||||
|
||||
ASTERISK-21795 #close
|
||||
|
||||
Signed-off-by: Bernd Kuhls <bernd.kuhls@t-online.de>
|
||||
[Retrieved from:
|
||||
https: //git.buildroot.net/buildroot/tree/package/asterisk/0005-configure-fix-detection-of-re-entrant-resolver-funct.patch]
|
||||
Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
|
||||
|
||||
- ### cli: increase channel column width
|
||||
Author: Mike Bradeen
|
||||
Date: 2023-03-06
|
||||
|
||||
For 'core show channels', the Channel name field is increased
|
||||
to 64 characters and the Location name field is increased to
|
||||
32 characters.
|
||||
|
||||
For 'core show channels verbose', the Channel name field is
|
||||
increased to 80 characters, the Context is increased to 24
|
||||
characters and the Extension is increased to 24 characters.
|
||||
|
||||
ASTERISK-30455
|
||||
|
||||
|
||||
- ### app_queue: periodic announcement configurable start time.
|
||||
Author: Jaco Kroon
|
||||
Date: 2023-02-21
|
||||
|
||||
This newly introduced periodic-announce-startdelay makes it possible to
|
||||
configure the initial start delay of the first periodic announcement
|
||||
after which periodic-announce-frequency takes over.
|
||||
|
||||
ASTERISK-30437 #close
|
||||
Signed-off-by: Jaco Kroon <jaco@uls.co.za>
|
||||
|
||||
- ### make_version: Strip svn stuff and suppress ref HEAD errors
|
||||
Author: George Joseph
|
||||
Date: 2023-03-13
|
||||
|
||||
* All of the code that used subversion has been removed.
|
||||
|
||||
* When Asterisk is checked out from a tag or commit instead
|
||||
of one of the regular branches, git would emit messages like
|
||||
"fatal: ref HEAD is not a symbolic ref" which weren't fatal
|
||||
at all. Those are now suppressed.
|
||||
|
||||
|
||||
- ### res_http_media_cache: Introduce options and customize
|
||||
Author: Holger Hans Peter Freyther
|
||||
Date: 2022-10-16
|
||||
|
||||
Make the existing CURL parameters configurable and allow
|
||||
to specify the usable protocols, proxy and DNS timeout.
|
||||
|
||||
ASTERISK-30340
|
||||
|
||||
|
||||
- ### main/iostream.c: fix build with libressl
|
||||
Author: Fabrice Fontaine
|
||||
Date: 2023-02-25
|
||||
|
||||
Fix the following build failure with libressl by using SSL_is_server
|
||||
which is available since version 2.7.0 and
|
||||
https://github.com/libressl-portable/openbsd/commit/d7ec516916c5eaac29b02d7a8ac6570f63b458f7:
|
||||
|
||||
iostream.c: In function 'ast_iostream_close':
|
||||
iostream.c:559:41: error: invalid use of incomplete typedef 'SSL' {aka 'struct ssl_st'}
|
||||
559 | if (!stream->ssl->server) {
|
||||
| ^~
|
||||
|
||||
ASTERISK-30107 #close
|
||||
|
||||
Fixes: - http://autobuild.buildroot.org/results/ce4d62d00bb77ba5b303cacf6be7e350581a62f9
|
||||
|
||||
- ### contrib: rc.archlinux.asterisk uses invalid redirect.
|
||||
Author: Sean Bright
|
||||
Date: 2023-03-02
|
||||
|
||||
`rc.archlinux.asterisk`, which explicitly requests bash in its
|
||||
shebang, uses the following command syntax:
|
||||
|
||||
${DAEMON} -rx "core stop now" > /dev/null 2&>1
|
||||
|
||||
The intent of which is to execute:
|
||||
|
||||
${DAEMON} -rx "core stop now"
|
||||
|
||||
While sending both stdout and stderr to `/dev/null`. Unfortunately,
|
||||
because the `&` is in the wrong place, bash is interpreting the `2` as
|
||||
just an additional argument to the `$DAEMON` command and not as a file
|
||||
descriptor and proceeds to use the bashism `&>` to send stderr and
|
||||
stdout to a file named `1`.
|
||||
|
||||
So we clean it up and just use bash's shortcut syntax.
|
||||
|
||||
Issue raised and a fix suggested (but not used) by peutch on GitHub¹.
|
||||
|
||||
ASTERISK-30449 #close
|
||||
|
||||
1. https://github.com/asterisk/asterisk/pull/31
|
||||
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
|
||||
Change Log for Release 20.3.1
|
||||
========================================
|
||||
|
||||
Links:
|
||||
----------------------------------------
|
||||
|
||||
- [Full ChangeLog](https://downloads.asterisk.org/pub/telephony/asterisk/releases/ChangeLog-20.3.1.md)
|
||||
- [GitHub Diff](https://github.com/asterisk/asterisk/compare/20.3.0...20.3.1)
|
||||
- [Tarball](https://downloads.asterisk.org/pub/telephony/asterisk/asterisk-20.3.1.tar.gz)
|
||||
- [Downloads](https://downloads.asterisk.org/pub/telephony/asterisk)
|
||||
|
||||
Summary:
|
||||
----------------------------------------
|
||||
|
||||
- apply_patches: Use globbing instead of file/sort.
|
||||
- apply_patches: Sort patch list before applying
|
||||
- pjsip: Upgrade bundled version to pjproject 2.13.1
|
||||
|
||||
User Notes:
|
||||
----------------------------------------
|
||||
|
||||
- ### res_http_media_cache: Introduce options and customize
|
||||
The res_http_media_cache module now attempts to load
|
||||
configuration from the res_http_media_cache.conf file.
|
||||
The following options were added:
|
||||
* timeout_secs
|
||||
* user_agent
|
||||
* follow_location
|
||||
* max_redirects
|
||||
* protocols
|
||||
* redirect_protocols
|
||||
* dns_cache_timeout_secs
|
||||
|
||||
- ### format_sln: add .slin as supported file extension
|
||||
format_sln now recognizes '.slin' as a valid
|
||||
file extension in addition to the existing
|
||||
'.sln' and '.raw'.
|
||||
|
||||
- ### bridge_builtin_features: add beep via touch variable
|
||||
Add optional touch variable : TOUCH_MIXMONITOR_BEEP(interval)
|
||||
Setting TOUCH_MIXMONITOR_BEEP/TOUCH_MONITOR_BEEP to a valid
|
||||
interval in seconds will result in a periodic beep being
|
||||
played to the monitored channel upon MixMontior/Monitor
|
||||
feature start.
|
||||
If an interval less than 5 seconds is specified, the interval
|
||||
will default to 5 seconds. If the value is set to an invalid
|
||||
interval, the default of 15 seconds will be used.
|
||||
|
||||
- ### app_senddtmf: Add SendFlash AMI action.
|
||||
The SendFlash AMI action now allows sending
|
||||
a hook flash event on a channel.
|
||||
|
||||
- ### res_mixmonitor: MixMonitorMute by MixMonitor ID
|
||||
It is now possible to specify the MixMonitorID when calling
|
||||
the manager action: MixMonitorMute. This will allow an
|
||||
individual MixMonitor instance to be muted via ID.
|
||||
The MixMonitorID can be stored as a channel variable using
|
||||
the 'i' MixMonitor option and is returned upon creation if
|
||||
this option is used.
|
||||
As part of this change, if no MixMonitorID is specified in
|
||||
the manager action MixMonitorMute, Asterisk will set the mute
|
||||
flag on all MixMonitor audiohooks on the channel. Previous
|
||||
behavior would set the flag on the first MixMonitor audiohook
|
||||
found.
|
||||
|
||||
- ### pbx_dundi: Add PJSIP support.
|
||||
DUNDi now supports chan_pjsip. Outgoing calls using
|
||||
PJSIP require the pjsip_outgoing_endpoint option
|
||||
to be set in dundi.conf.
|
||||
|
||||
- ### test.c: Fix counting of tests and add 2 new tests
|
||||
The "tests" attribute of the "testsuite" element in the
|
||||
output XML now reflects only the tests actually requested
|
||||
to be executed instead of all the tests registered.
|
||||
The "failures" attribute was added to the "testsuite"
|
||||
element.
|
||||
Also added two new unit tests that just pass and fail
|
||||
to be used for testing CI itself.
|
||||
|
||||
- ### cli: increase channel column width
|
||||
This change increases the display width on 'core show channels'
|
||||
amd 'core show channels verbose'
|
||||
For 'core show channels', the Channel name field is increased to
|
||||
64 characters and the Location name field is increased to 32
|
||||
characters.
|
||||
For 'core show channels verbose', the Channel name field is
|
||||
increased to 80 characters, the Context is increased to 24
|
||||
characters and the Extension is increased to 24 characters.
|
||||
|
||||
|
||||
Upgrade Notes:
|
||||
----------------------------------------
|
||||
|
||||
|
||||
Closed Issues:
|
||||
----------------------------------------
|
||||
|
||||
- #193: [bug]: third-party/apply-patches doesn't sort the patch file list before applying
|
||||
|
||||
Commits By Author:
|
||||
----------------------------------------
|
||||
|
||||
- ### George Joseph (1):
|
||||
- apply_patches: Sort patch list before applying
|
||||
|
||||
- ### Sean Bright (1):
|
||||
- apply_patches: Use globbing instead of file/sort.
|
||||
|
||||
- ### Stanislav Abramenkov (1):
|
||||
- pjsip: Upgrade bundled version to pjproject 2.13.1
|
||||
|
||||
|
||||
Detail:
|
||||
----------------------------------------
|
||||
|
||||
- ### apply_patches: Use globbing instead of file/sort.
|
||||
Author: Sean Bright
|
||||
Date: 2023-07-06
|
||||
|
||||
This accomplishes the same thing as a `find ... | sort` but with the
|
||||
added benefit of clarity and avoiding a call to a subshell.
|
||||
|
||||
Additionally drop the -s option from call to patch as it is not POSIX.
|
||||
|
||||
- ### apply_patches: Sort patch list before applying
|
||||
Author: George Joseph
|
||||
Date: 2023-07-06
|
||||
|
||||
The apply_patches script wasn't sorting the list of patches in
|
||||
the "patches" directory before applying them. This left the list
|
||||
in an indeterminate order. In most cases, the list is actually
|
||||
sorted but rarely, they can be out of order and cause dependent
|
||||
patches to fail to apply.
|
||||
|
||||
We now sort the list but the "sort" program wasn't in the
|
||||
configure scripts so we needed to add that and regenerate
|
||||
the scripts as well.
|
||||
|
||||
Resolves: #193
|
||||
|
||||
- ### pjsip: Upgrade bundled version to pjproject 2.13.1
|
||||
Author: Stanislav Abramenkov
|
||||
Date: 2023-07-05
|
||||
|
||||
|
|
@ -0,0 +1,854 @@
|
|||
|
||||
Change Log for Release 20.4.0
|
||||
========================================
|
||||
|
||||
Links:
|
||||
----------------------------------------
|
||||
|
||||
- [Full ChangeLog](https://downloads.asterisk.org/pub/telephony/asterisk/releases/ChangeLog-20.4.0.md)
|
||||
- [GitHub Diff](https://github.com/asterisk/asterisk/compare/20.3.1...20.4.0)
|
||||
- [Tarball](https://downloads.asterisk.org/pub/telephony/asterisk/asterisk-20.4.0.tar.gz)
|
||||
- [Downloads](https://downloads.asterisk.org/pub/telephony/asterisk)
|
||||
|
||||
Summary:
|
||||
----------------------------------------
|
||||
|
||||
- app.h: Move declaration of ast_getdata_result before its first use
|
||||
- doc: Remove obsolete CHANGES-staging and UPGRADE-staging
|
||||
- .github: Updates for AsteriskReleaser
|
||||
- app_voicemail: fix imap compilation errors
|
||||
- res_musiconhold: avoid moh state access on unlocked chan
|
||||
- utils: add lock timestamps for DEBUG_THREADS
|
||||
- .github: Back out triggering PROpenedOrUpdated by label
|
||||
- .github: Move publish docs to new file CreateDocs.yml
|
||||
- rest-api: Updates for new documentation site
|
||||
- .github: Remove result check from PROpenUpdateGateTests
|
||||
- .github: Fix use of 'contains'
|
||||
- .github: Add recheck label test to additional jobs
|
||||
- .github: Fix recheck label typos
|
||||
- .github: Fix recheck label manipulation
|
||||
- .github: Allow PR submit checks to be re-run by label
|
||||
- app_voicemail_imap: Fix message count when IMAP server is unavailable
|
||||
- res_pjsip_rfc3326: Prefer Q.850 cause code over SIP.
|
||||
- res_pjsip_session: Added new function calls to avoid ABI issues.
|
||||
- app_queue: Add force_longest_waiting_caller option.
|
||||
- pjsip_transport_events.c: Use %zu printf specifier for size_t.
|
||||
- res_crypto.c: Gracefully handle potential key filename truncation.
|
||||
- configure: Remove obsolete and deprecated constructs.
|
||||
- res_fax_spandsp.c: Clean up a spaces/tabs issue
|
||||
- ast-db-manage: Synchronize revisions between comments and code.
|
||||
- test_statis_endpoints: Fix channel_messages test again
|
||||
- res_crypto.c: Avoid using the non-portable ALLPERMS macro.
|
||||
- tcptls: when disabling a server port, we should set the accept_fd to -1.
|
||||
- AMI: Add parking position parameter to Park action
|
||||
- test_stasis_endpoints.c: Make channel_messages more stable
|
||||
- build: Fix a few gcc 13 issues
|
||||
- .github: Rework for merge approval
|
||||
- ast-db-manage: Fix alembic branching error caused by #122.
|
||||
- app_followme: fix issue with enable_callee_prompt=no (#88)
|
||||
- sounds: Update download URL to use HTTPS.
|
||||
- configure: Makefile downloader enable follow redirects.
|
||||
- res_musiconhold: Add option to loop last file.
|
||||
- chan_dahdi: Fix Caller ID presentation for FXO ports.
|
||||
- AMI: Add CoreShowChannelMap action.
|
||||
- sig_analog: Add fuller Caller ID support.
|
||||
- res_stasis.c: Add new type 'sdp_label' for bridge creation.
|
||||
- app_queue: Preserve reason for realtime queues
|
||||
- .github: Fix issues with cherry-pick-reminder
|
||||
- indications: logging changes
|
||||
- .github Ignore error when adding reviewrs to PR
|
||||
- .github: Update field descriptions for AsteriskReleaser
|
||||
- callerid: Allow specifying timezone for date/time.
|
||||
- logrotate: Fix duplicate log entries.
|
||||
- chan_pjsip: Allow topology/session refreshes in early media state
|
||||
- chan_dahdi: Fix broken hidecallerid setting.
|
||||
- .github: Change title of AsteriskReleaser job
|
||||
- asterisk.c: Fix option warning for remote console.
|
||||
- .github: Don't add cherry-pick reminder if it's already present
|
||||
- .github: Fix quoting in PROpenedOrUpdated
|
||||
- .github: Add cherry-pick reminder to new PRs
|
||||
- configure: fix test code to match gethostbyname_r prototype.
|
||||
- res_pjsip_pubsub.c: Use pjsip version for pending NOTIFY check. (#77)
|
||||
- res_sorcery_memory_cache.c: Fix memory leak
|
||||
- xml.c: Process XML Inclusions recursively.
|
||||
- .github: Tweak improvement issue type language.
|
||||
- .github: Tweak new feature language, and move feature requests elsewhere.
|
||||
- .github: Fix staleness check to only run on certain labels.
|
||||
|
||||
User Notes:
|
||||
----------------------------------------
|
||||
|
||||
- ### AMI: Add parking position parameter to Park action
|
||||
New ParkingSpace parameter has been added to AMI action Park.
|
||||
|
||||
- ### res_musiconhold: Add option to loop last file.
|
||||
The loop_last option in musiconhold.conf now
|
||||
allows the last file in the directory to be looped once reached.
|
||||
|
||||
- ### AMI: Add CoreShowChannelMap action.
|
||||
New AMI action CoreShowChannelMap has been added.
|
||||
|
||||
- ### sig_analog: Add fuller Caller ID support.
|
||||
Additional Caller ID properties are now supported on
|
||||
incoming calls to FXS stations, namely the
|
||||
redirecting reason and call qualifier.
|
||||
|
||||
- ### res_stasis.c: Add new type 'sdp_label' for bridge creation.
|
||||
When creating a bridge using the ARI the 'type' argument now
|
||||
accepts a new value 'sdp_label' which will configure the bridge to add
|
||||
labels for each stream in the SDP with the corresponding channel id.
|
||||
|
||||
- ### app_queue: Preserve reason for realtime queues
|
||||
Make paused reason in realtime queues persist an
|
||||
Asterisk restart. This was fixed for non-realtime
|
||||
queues in ASTERISK_25732.
|
||||
|
||||
|
||||
Upgrade Notes:
|
||||
----------------------------------------
|
||||
|
||||
- ### app_queue: Preserve reason for realtime queues
|
||||
Add a new column to the queue_member table:
|
||||
reason_paused VARCHAR(80) so the reason can be preserved.
|
||||
|
||||
|
||||
Closed Issues:
|
||||
----------------------------------------
|
||||
|
||||
- #45: [bug]: Non-bundled PJSIP check for evsub pending NOTIFY check is insufficient/ineffective
|
||||
- #55: [bug]: res_sorcery_memory_cache: Memory leak when calling sorcery_memory_cache_open
|
||||
- #64: [bug]: app_voicemail_imap wrong behavior when losing IMAP connection
|
||||
- #65: [bug]: heap overflow by default at startup
|
||||
- #66: [improvement]: Fix preserve reason of pause when Asterisk is restared for realtime queues
|
||||
- #73: [new-feature]: pjsip: Allow topology/session refreshes in early media state
|
||||
- #87: [bug]: app_followme: Setting enable_callee_prompt=no breaks timeout
|
||||
- #89: [improvement]: indications: logging changes
|
||||
- #91: [improvement]: Add parameter on ARI bridge create to allow it to send SDP labels
|
||||
- #94: [new-feature]: sig_analog: Add full Caller ID support for incoming calls
|
||||
- #96: [bug]: make install-logrotate causes logrotate to fail on service restart
|
||||
- #98: [new-feature]: callerid: Allow timezone to be specified at runtime
|
||||
- #100: [bug]: sig_analog: hidecallerid setting is broken
|
||||
- #102: [bug]: Strange warning - 'T' option is not compatible with remote console mode and has no effect.
|
||||
- #104: [improvement]: Add AMI action to get a list of connected channels
|
||||
- #108: [new-feature]: fair handling of calls in multi-queue scenarios
|
||||
- #110: [improvement]: utils - add lock timing information with DEBUG_THREADS
|
||||
- #116: [bug]: SIP Reason: "Call completed elsewhere" no longer propagating
|
||||
- #120: [bug]: chan_dahdi: Fix broken presentation for FXO caller ID
|
||||
- #122: [new-feature]: res_musiconhold: Add looplast option
|
||||
- #133: [bug]: unlock channel after moh state access
|
||||
- #136: [bug]: Makefile downloader does not follow redirects.
|
||||
- #145: [bug]: ABI issue with pjproject and pjsip_inv_session
|
||||
- #155: [bug]: GCC 13 is catching a few new trivial issues
|
||||
- #158: [bug]: test_stasis_endpoints.c: Unit test channel_messages is unstable
|
||||
- #174: [bug]: app_voicemail imap compile errors
|
||||
- #200: [bug]: Regression: In app.h an enum is used before its declaration.
|
||||
|
||||
Commits By Author:
|
||||
----------------------------------------
|
||||
|
||||
- ### Asterisk Development Team (2):
|
||||
- Update for 20.4.0-rc1
|
||||
- Update for 20.4.0-rc2
|
||||
|
||||
- ### Ben Ford (2):
|
||||
- AMI: Add CoreShowChannelMap action.
|
||||
- res_pjsip_session: Added new function calls to avoid ABI issues.
|
||||
|
||||
- ### George Joseph (23):
|
||||
- .github: Add cherry-pick reminder to new PRs
|
||||
- .github: Fix quoting in PROpenedOrUpdated
|
||||
- .github: Don't add cherry-pick reminder if it's already present
|
||||
- .github: Change title of AsteriskReleaser job
|
||||
- .github: Update field descriptions for AsteriskReleaser
|
||||
- .github Ignore error when adding reviewrs to PR
|
||||
- .github: Fix issues with cherry-pick-reminder
|
||||
- .github: Rework for merge approval
|
||||
- build: Fix a few gcc 13 issues
|
||||
- test_stasis_endpoints.c: Make channel_messages more stable
|
||||
- test_statis_endpoints: Fix channel_messages test again
|
||||
- .github: Allow PR submit checks to be re-run by label
|
||||
- .github: Fix recheck label manipulation
|
||||
- .github: Fix recheck label typos
|
||||
- .github: Add recheck label test to additional jobs
|
||||
- .github: Fix use of 'contains'
|
||||
- .github: Remove result check from PROpenUpdateGateTests
|
||||
- rest-api: Updates for new documentation site
|
||||
- .github: Move publish docs to new file CreateDocs.yml
|
||||
- .github: Back out triggering PROpenedOrUpdated by label
|
||||
- .github: Updates for AsteriskReleaser
|
||||
- doc: Remove obsolete CHANGES-staging and UPGRADE-staging
|
||||
- app.h: Move declaration of ast_getdata_result before its first use
|
||||
|
||||
- ### Gitea (1):
|
||||
- .github: Tweak new feature language, and move feature requests elsewhere.
|
||||
|
||||
- ### Jaco Kroon (2):
|
||||
- configure: fix test code to match gethostbyname_r prototype.
|
||||
- tcptls: when disabling a server port, we should set the accept_fd to -1.
|
||||
|
||||
- ### Jiajian Zhou (1):
|
||||
- AMI: Add parking position parameter to Park action
|
||||
|
||||
- ### Joe Searle (1):
|
||||
- res_stasis.c: Add new type 'sdp_label' for bridge creation.
|
||||
|
||||
- ### Joshua C. Colp (2):
|
||||
- .github: Fix staleness check to only run on certain labels.
|
||||
- .github: Tweak improvement issue type language.
|
||||
|
||||
- ### Maximilian Fridrich (1):
|
||||
- chan_pjsip: Allow topology/session refreshes in early media state
|
||||
|
||||
- ### Miguel Angel Nubla (1):
|
||||
- configure: Makefile downloader enable follow redirects.
|
||||
|
||||
- ### Mike Bradeen (4):
|
||||
- indications: logging changes
|
||||
- utils: add lock timestamps for DEBUG_THREADS
|
||||
- res_musiconhold: avoid moh state access on unlocked chan
|
||||
- app_voicemail: fix imap compilation errors
|
||||
|
||||
- ### Nathan Bruning (1):
|
||||
- app_queue: Add force_longest_waiting_caller option.
|
||||
|
||||
- ### Naveen Albert (7):
|
||||
- asterisk.c: Fix option warning for remote console.
|
||||
- chan_dahdi: Fix broken hidecallerid setting.
|
||||
- logrotate: Fix duplicate log entries.
|
||||
- callerid: Allow specifying timezone for date/time.
|
||||
- sig_analog: Add fuller Caller ID support.
|
||||
- chan_dahdi: Fix Caller ID presentation for FXO ports.
|
||||
- res_musiconhold: Add option to loop last file.
|
||||
|
||||
- ### Niklas Larsson (1):
|
||||
- app_queue: Preserve reason for realtime queues
|
||||
|
||||
- ### Olaf Titz (1):
|
||||
- app_voicemail_imap: Fix message count when IMAP server is unavailable
|
||||
|
||||
- ### Sean Bright (10):
|
||||
- xml.c: Process XML Inclusions recursively.
|
||||
- res_pjsip_pubsub.c: Use pjsip version for pending NOTIFY check. (#77)
|
||||
- sounds: Update download URL to use HTTPS.
|
||||
- ast-db-manage: Fix alembic branching error caused by #122.
|
||||
- res_crypto.c: Avoid using the non-portable ALLPERMS macro.
|
||||
- ast-db-manage: Synchronize revisions between comments and code.
|
||||
- configure: Remove obsolete and deprecated constructs.
|
||||
- res_crypto.c: Gracefully handle potential key filename truncation.
|
||||
- pjsip_transport_events.c: Use %zu printf specifier for size_t.
|
||||
- res_pjsip_rfc3326: Prefer Q.850 cause code over SIP.
|
||||
|
||||
- ### alex2grad (1):
|
||||
- app_followme: fix issue with enable_callee_prompt=no (#88)
|
||||
|
||||
- ### zhengsh (1):
|
||||
- res_sorcery_memory_cache.c: Fix memory leak
|
||||
|
||||
- ### zhou_jiajian (1):
|
||||
- res_fax_spandsp.c: Clean up a spaces/tabs issue
|
||||
|
||||
|
||||
Detail:
|
||||
----------------------------------------
|
||||
|
||||
- ### app.h: Move declaration of ast_getdata_result before its first use
|
||||
Author: George Joseph
|
||||
Date: 2023-07-10
|
||||
|
||||
The ast_app_getdata() and ast_app_getdata_terminator() declarations
|
||||
in app.h were changed recently to return enum ast_getdata_result
|
||||
(which is how they were defined in app.c). The existing
|
||||
declaration of ast_getdata_result in app.h was about 1000 lines
|
||||
after those functions however so under certain circumstances,
|
||||
a "use before declaration" error was thrown by the compiler.
|
||||
The declaration of the enum was therefore moved to before those
|
||||
functions.
|
||||
|
||||
Resolves: #200
|
||||
|
||||
- ### doc: Remove obsolete CHANGES-staging and UPGRADE-staging
|
||||
Author: George Joseph
|
||||
Date: 2023-07-10
|
||||
|
||||
|
||||
- ### .github: Updates for AsteriskReleaser
|
||||
Author: George Joseph
|
||||
Date: 2023-06-30
|
||||
|
||||
|
||||
- ### app_voicemail: fix imap compilation errors
|
||||
Author: Mike Bradeen
|
||||
Date: 2023-06-26
|
||||
|
||||
Fixes two compilation errors in app_voicemail_imap, one due to an unsed
|
||||
variable and one due to a new variable added in the incorrect location
|
||||
in _163.
|
||||
|
||||
Resolves: #174
|
||||
|
||||
- ### res_musiconhold: avoid moh state access on unlocked chan
|
||||
Author: Mike Bradeen
|
||||
Date: 2023-05-31
|
||||
|
||||
Move channel unlock to after moh state access to avoid
|
||||
potential unlocked access to state.
|
||||
|
||||
Resolves: #133
|
||||
|
||||
- ### utils: add lock timestamps for DEBUG_THREADS
|
||||
Author: Mike Bradeen
|
||||
Date: 2023-05-23
|
||||
|
||||
Adds last locked and unlocked timestamps as well as a
|
||||
counter for the number of times the lock has been
|
||||
attempted (vs locked/unlocked) to debug output printed
|
||||
using the DEBUG_THREADS option.
|
||||
|
||||
Resolves: #110
|
||||
|
||||
- ### .github: Back out triggering PROpenedOrUpdated by label
|
||||
Author: George Joseph
|
||||
Date: 2023-06-29
|
||||
|
||||
|
||||
- ### .github: Move publish docs to new file CreateDocs.yml
|
||||
Author: George Joseph
|
||||
Date: 2023-06-27
|
||||
|
||||
|
||||
- ### rest-api: Updates for new documentation site
|
||||
Author: George Joseph
|
||||
Date: 2023-06-26
|
||||
|
||||
The new documentation site uses traditional markdown instead
|
||||
of the Confluence flavored version. This required changes in
|
||||
the mustache templates and the python that generates the files.
|
||||
|
||||
|
||||
- ### .github: Remove result check from PROpenUpdateGateTests
|
||||
Author: George Joseph
|
||||
Date: 2023-06-27
|
||||
|
||||
|
||||
- ### .github: Fix use of 'contains'
|
||||
Author: George Joseph
|
||||
Date: 2023-06-26
|
||||
|
||||
|
||||
- ### .github: Add recheck label test to additional jobs
|
||||
Author: George Joseph
|
||||
Date: 2023-06-26
|
||||
|
||||
|
||||
- ### .github: Fix recheck label typos
|
||||
Author: George Joseph
|
||||
Date: 2023-06-26
|
||||
|
||||
|
||||
- ### .github: Fix recheck label manipulation
|
||||
Author: George Joseph
|
||||
Date: 2023-06-26
|
||||
|
||||
|
||||
- ### .github: Allow PR submit checks to be re-run by label
|
||||
Author: George Joseph
|
||||
Date: 2023-06-26
|
||||
|
||||
|
||||
- ### app_voicemail_imap: Fix message count when IMAP server is unavailable
|
||||
Author: Olaf Titz
|
||||
Date: 2023-06-15
|
||||
|
||||
Some callers of __messagecount did not correctly handle error return,
|
||||
instead returning a -1 message count.
|
||||
This caused a notification with "Messages-Waiting: yes" and
|
||||
"Voice-Message: -1/0 (0/0)" if the IMAP server was unavailable.
|
||||
|
||||
Fixes: #64
|
||||
|
||||
- ### res_pjsip_rfc3326: Prefer Q.850 cause code over SIP.
|
||||
Author: Sean Bright
|
||||
Date: 2023-06-12
|
||||
|
||||
Resolves: #116
|
||||
|
||||
- ### res_pjsip_session: Added new function calls to avoid ABI issues.
|
||||
Author: Ben Ford
|
||||
Date: 2023-06-05
|
||||
|
||||
Added two new functions (ast_sip_session_get_dialog and
|
||||
ast_sip_session_get_pjsip_inv_state) that retrieve the dialog and the
|
||||
pjsip_inv_state respectively from the pjsip_inv_session on the
|
||||
ast_sip_session struct. This is due to pjproject adding a new field to
|
||||
the pjsip_inv_session struct that caused crashes when trying to access
|
||||
fields that were no longer where they were expected to be if a module
|
||||
was compiled against a different version of pjproject.
|
||||
|
||||
Resolves: #145
|
||||
|
||||
- ### app_queue: Add force_longest_waiting_caller option.
|
||||
Author: Nathan Bruning
|
||||
Date: 2023-01-24
|
||||
|
||||
This adds an option 'force_longest_waiting_caller' which changes the
|
||||
global behavior of the queue engine to prevent queue callers from
|
||||
'jumping ahead' when an agent is in multiple queues.
|
||||
|
||||
Resolves: #108
|
||||
|
||||
Also closes old asterisk issues:
|
||||
- ASTERISK-17732
|
||||
- ASTERISK-17570
|
||||
|
||||
|
||||
- ### pjsip_transport_events.c: Use %zu printf specifier for size_t.
|
||||
Author: Sean Bright
|
||||
Date: 2023-06-05
|
||||
|
||||
Partially resolves #143.
|
||||
|
||||
|
||||
- ### res_crypto.c: Gracefully handle potential key filename truncation.
|
||||
Author: Sean Bright
|
||||
Date: 2023-06-05
|
||||
|
||||
Partially resolves #143.
|
||||
|
||||
|
||||
- ### configure: Remove obsolete and deprecated constructs.
|
||||
Author: Sean Bright
|
||||
Date: 2023-06-01
|
||||
|
||||
These were uncovered when trying to run `bootstrap.sh` with Autoconf
|
||||
2.71:
|
||||
|
||||
* AC_CONFIG_HEADER() is deprecated in favor of AC_CONFIG_HEADERS().
|
||||
* AC_HEADER_TIME is obsolete.
|
||||
* $as_echo is deprecated in favor of AS_ECHO() which requires an update
|
||||
to ax_pthread.m4.
|
||||
|
||||
Note that the generated artifacts in this commit are from Autoconf 2.69.
|
||||
|
||||
Resolves #139
|
||||
|
||||
|
||||
- ### res_fax_spandsp.c: Clean up a spaces/tabs issue
|
||||
Author: zhou_jiajian
|
||||
Date: 2023-05-26
|
||||
|
||||
|
||||
- ### ast-db-manage: Synchronize revisions between comments and code.
|
||||
Author: Sean Bright
|
||||
Date: 2023-06-06
|
||||
|
||||
In a handful of migrations, the comment header that indicates the
|
||||
current and previous revisions has drifted from the identifiers
|
||||
revision and down_revision variables. This updates the comment headers
|
||||
to match the code.
|
||||
|
||||
|
||||
- ### test_statis_endpoints: Fix channel_messages test again
|
||||
Author: George Joseph
|
||||
Date: 2023-06-12
|
||||
|
||||
|
||||
- ### res_crypto.c: Avoid using the non-portable ALLPERMS macro.
|
||||
Author: Sean Bright
|
||||
Date: 2023-06-05
|
||||
|
||||
ALLPERMS is not POSIX and it's trivial enough to not jump through
|
||||
autoconf hoops to check for it.
|
||||
|
||||
Fixes #149.
|
||||
|
||||
|
||||
- ### tcptls: when disabling a server port, we should set the accept_fd to -1.
|
||||
Author: Jaco Kroon
|
||||
Date: 2023-06-02
|
||||
|
||||
If we don't set this to -1 if the structure can be potentially re-used
|
||||
later then it's possible that we'll issue a close() on an unrelated file
|
||||
descriptor, breaking asterisk in other interesting ways.
|
||||
|
||||
I believe this to be an unlikely scenario, but it costs nothing to be
|
||||
safe.
|
||||
|
||||
Signed-off-by: Jaco Kroon <jaco@uls.co.za>
|
||||
|
||||
- ### AMI: Add parking position parameter to Park action
|
||||
Author: Jiajian Zhou
|
||||
Date: 2023-05-19
|
||||
|
||||
Add a parking space extension parameter (ParkingSpace) to the Park action.
|
||||
Park action will attempt to park the call to that extension.
|
||||
If the extension is already in use, then execution will continue at the next priority.
|
||||
|
||||
UserNote: New ParkingSpace parameter has been added to AMI action Park.
|
||||
|
||||
- ### test_stasis_endpoints.c: Make channel_messages more stable
|
||||
Author: George Joseph
|
||||
Date: 2023-06-09
|
||||
|
||||
The channel_messages test was assuming that stasis would return
|
||||
messages in a specific order. This is an incorrect assumption as
|
||||
message ordering was never guaranteed. This was causing the test
|
||||
to fail occasionally. We now test all the messages for the
|
||||
required message types instead of testing one by one.
|
||||
|
||||
Resolves: #158
|
||||
|
||||
- ### build: Fix a few gcc 13 issues
|
||||
Author: George Joseph
|
||||
Date: 2023-06-09
|
||||
|
||||
* gcc 13 is now catching when a function is declared as returning
|
||||
an enum but defined as returning an int or vice versa. Fixed
|
||||
a few in app.h, loader.c, stasis_message.c.
|
||||
|
||||
* gcc 13 is also now (incorrectly) complaining of dangling pointers
|
||||
when assigning a pointer to a local char array to a char *. Had
|
||||
to change that to an ast_alloca.
|
||||
|
||||
Resolves: #155
|
||||
|
||||
- ### .github: Rework for merge approval
|
||||
Author: George Joseph
|
||||
Date: 2023-06-06
|
||||
|
||||
|
||||
- ### ast-db-manage: Fix alembic branching error caused by #122.
|
||||
Author: Sean Bright
|
||||
Date: 2023-06-05
|
||||
|
||||
Fixes #147.
|
||||
|
||||
|
||||
- ### app_followme: fix issue with enable_callee_prompt=no (#88)
|
||||
Author: alex2grad
|
||||
Date: 2023-06-05
|
||||
|
||||
* app_followme: fix issue with enable_callee_prompt=no
|
||||
|
||||
If the FollowMe option 'enable_callee_prompt' is set to 'no' then Asterisk
|
||||
incorrectly sets a winner channel to the channel from which any control frame was read.
|
||||
|
||||
This fix sets the winner channel only to the answered channel.
|
||||
|
||||
Resolves: #87
|
||||
|
||||
ASTERISK-30326
|
||||
|
||||
|
||||
- ### sounds: Update download URL to use HTTPS.
|
||||
Author: Sean Bright
|
||||
Date: 2023-06-01
|
||||
|
||||
Related to #136
|
||||
|
||||
|
||||
- ### configure: Makefile downloader enable follow redirects.
|
||||
Author: Miguel Angel Nubla
|
||||
Date: 2023-06-01
|
||||
|
||||
If curl is used for building, any download such as a sounds package
|
||||
will fail to follow HTTP redirects and will download wrong data.
|
||||
|
||||
Resolves: #136
|
||||
|
||||
- ### res_musiconhold: Add option to loop last file.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-05-25
|
||||
|
||||
Adds the loop_last option to res_musiconhold,
|
||||
which allows the last audio file in the directory
|
||||
to be looped perpetually once reached, rather than
|
||||
circling back to the beginning again.
|
||||
|
||||
Resolves: #122
|
||||
ASTERISK-30462
|
||||
|
||||
UserNote: The loop_last option in musiconhold.conf now
|
||||
allows the last file in the directory to be looped once reached.
|
||||
|
||||
|
||||
- ### chan_dahdi: Fix Caller ID presentation for FXO ports.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-05-25
|
||||
|
||||
Currently, the presentation for incoming channels is
|
||||
always available, because it is never actually set,
|
||||
meaning the channel presentation can be nonsensical.
|
||||
If the presentation from the incoming Caller ID spill
|
||||
is private or unavailable, we now update the channel
|
||||
presentation to reflect this.
|
||||
|
||||
Resolves: #120
|
||||
ASTERISK-30333
|
||||
ASTERISK-21741
|
||||
|
||||
|
||||
- ### AMI: Add CoreShowChannelMap action.
|
||||
Author: Ben Ford
|
||||
Date: 2023-05-18
|
||||
|
||||
Adds a new AMI action (CoreShowChannelMap) that takes in a channel name
|
||||
and provides a list of all channels that are connected to that channel,
|
||||
following local channel connections as well.
|
||||
|
||||
Resolves: #104
|
||||
|
||||
UserNote: New AMI action CoreShowChannelMap has been added.
|
||||
|
||||
- ### sig_analog: Add fuller Caller ID support.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-05-18
|
||||
|
||||
A previous change, ASTERISK_29991, made it possible
|
||||
to send additional Caller ID parameters that were
|
||||
not previously supported.
|
||||
|
||||
This change adds support for analog DAHDI channels
|
||||
to now be able to receive these parameters for
|
||||
on-hook Caller ID, in order to enhance the usability
|
||||
of CPE that support these parameters.
|
||||
|
||||
Resolves: #94
|
||||
ASTERISK-30331
|
||||
|
||||
UserNote: Additional Caller ID properties are now supported on
|
||||
incoming calls to FXS stations, namely the
|
||||
redirecting reason and call qualifier.
|
||||
|
||||
|
||||
- ### res_stasis.c: Add new type 'sdp_label' for bridge creation.
|
||||
Author: Joe Searle
|
||||
Date: 2023-05-25
|
||||
|
||||
Add new type 'sdp_label' when creating a bridge using the ARI. This will
|
||||
add labels to the SDP for each stream, the label is set to the
|
||||
corresponding channel id.
|
||||
|
||||
Resolves: #91
|
||||
|
||||
UserNote: When creating a bridge using the ARI the 'type' argument now
|
||||
accepts a new value 'sdp_label' which will configure the bridge to add
|
||||
labels for each stream in the SDP with the corresponding channel id.
|
||||
|
||||
|
||||
- ### app_queue: Preserve reason for realtime queues
|
||||
Author: Niklas Larsson
|
||||
Date: 2023-05-05
|
||||
|
||||
When Asterisk is restarted it does not preserve paused reason for
|
||||
members of realtime queues. This was fixed for non-realtime queues in
|
||||
ASTERISK_25732
|
||||
|
||||
Resolves: #66
|
||||
|
||||
UpgradeNote: Add a new column to the queue_member table:
|
||||
reason_paused VARCHAR(80) so the reason can be preserved.
|
||||
|
||||
UserNote: Make paused reason in realtime queues persist an
|
||||
Asterisk restart. This was fixed for non-realtime
|
||||
queues in ASTERISK_25732.
|
||||
|
||||
|
||||
- ### .github: Fix issues with cherry-pick-reminder
|
||||
Author: George Joseph
|
||||
Date: 2023-06-05
|
||||
|
||||
|
||||
- ### indications: logging changes
|
||||
Author: Mike Bradeen
|
||||
Date: 2023-05-16
|
||||
|
||||
Increase verbosity to indicate failure due to missing country
|
||||
and to specify default on CLI dump
|
||||
|
||||
Resolves: #89
|
||||
|
||||
- ### .github Ignore error when adding reviewrs to PR
|
||||
Author: George Joseph
|
||||
Date: 2023-06-05
|
||||
|
||||
|
||||
- ### .github: Update field descriptions for AsteriskReleaser
|
||||
Author: George Joseph
|
||||
Date: 2023-05-26
|
||||
|
||||
|
||||
- ### callerid: Allow specifying timezone for date/time.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-05-18
|
||||
|
||||
The Caller ID generation routine currently is hardcoded
|
||||
to always use the system time zone. This makes it possible
|
||||
to optionally specify any TZ-format time zone.
|
||||
|
||||
Resolves: #98
|
||||
ASTERISK-30330
|
||||
|
||||
|
||||
- ### logrotate: Fix duplicate log entries.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-05-18
|
||||
|
||||
The Asterisk logrotate script contains explicit
|
||||
references to files with the .log extension,
|
||||
which are also included when *log is expanded.
|
||||
This causes issues with newer versions of logrotate.
|
||||
This fixes this by ensuring that a log file cannot
|
||||
be referenced multiple times after expansion occurs.
|
||||
|
||||
Resolves: #96
|
||||
ASTERISK-30442
|
||||
Reported by: EN Barnett
|
||||
Tested by: EN Barnett
|
||||
|
||||
|
||||
- ### chan_pjsip: Allow topology/session refreshes in early media state
|
||||
Author: Maximilian Fridrich
|
||||
Date: 2023-05-10
|
||||
|
||||
With this change, session modifications in the early media state are
|
||||
possible if the SDP was sent reliably and confirmed by a PRACK. For
|
||||
details, see RFC 6337, escpecially section 3.2.
|
||||
|
||||
Resolves: #73
|
||||
|
||||
- ### chan_dahdi: Fix broken hidecallerid setting.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-05-18
|
||||
|
||||
The hidecallerid setting in chan_dahdi.conf currently
|
||||
is broken for a couple reasons.
|
||||
|
||||
First, the actual code in sig_analog to "allow" or "block"
|
||||
Caller ID depending on this setting improperly used
|
||||
ast_set_callerid instead of updating the presentation.
|
||||
This issue was mostly fixed in ASTERISK_29991, and that
|
||||
fix is carried forward to this code as well.
|
||||
|
||||
Secondly, the hidecallerid setting is set on the DAHDI
|
||||
pvt but not carried forward to the analog pvt properly.
|
||||
This is because the chan_dahdi config loading code improperly
|
||||
set permhidecallerid to permhidecallerid from the config file,
|
||||
even though hidecallerid is what is actually set from the config
|
||||
file. (This is done correctly for call waiting, a few lines above.)
|
||||
This is fixed to read the proper value.
|
||||
|
||||
Thirdly, in sig_analog, hidecallerid is set to permhidecallerid
|
||||
only on hangup. This can lead to potential security vulnerabilities
|
||||
as an allowed Caller ID from an initial call can "leak" into subsequent
|
||||
calls if no hangup occurs between them. This is fixed by setting
|
||||
hidecallerid to permcallerid when calls begin, rather than when they end.
|
||||
This also means we don't need to also set hidecallerid in chan_dahdi.c
|
||||
when copying from the config, as we would have to otherwise.
|
||||
|
||||
Fourthly, sig_analog currently only allows dialing *67 or *82 if
|
||||
that would actually toggle the presentation. A comment is added
|
||||
clarifying that this behavior is okay.
|
||||
|
||||
Finally, a couple log messages are updated to be more accurate.
|
||||
|
||||
Resolves: #100
|
||||
ASTERISK-30349 #close
|
||||
|
||||
|
||||
- ### .github: Change title of AsteriskReleaser job
|
||||
Author: George Joseph
|
||||
Date: 2023-05-23
|
||||
|
||||
|
||||
- ### asterisk.c: Fix option warning for remote console.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-05-18
|
||||
|
||||
Commit 09e989f972e2583df4e9bf585c246c37322d8d2f
|
||||
categorized the T option as not being compatible
|
||||
with remote consoles, but they do affect verbose
|
||||
messages with remote console. This fixes this.
|
||||
|
||||
Resolves: #102
|
||||
|
||||
- ### .github: Don't add cherry-pick reminder if it's already present
|
||||
Author: George Joseph
|
||||
Date: 2023-05-22
|
||||
|
||||
|
||||
- ### .github: Fix quoting in PROpenedOrUpdated
|
||||
Author: George Joseph
|
||||
Date: 2023-05-16
|
||||
|
||||
|
||||
- ### .github: Add cherry-pick reminder to new PRs
|
||||
Author: George Joseph
|
||||
Date: 2023-05-15
|
||||
|
||||
|
||||
- ### configure: fix test code to match gethostbyname_r prototype.
|
||||
Author: Jaco Kroon
|
||||
Date: 2023-05-10
|
||||
|
||||
This enables the test to work with CC=clang.
|
||||
|
||||
Without this the test for 6 args would fail with:
|
||||
|
||||
utils.c:99:12: error: static declaration of 'gethostbyname_r' follows non-static declaration
|
||||
static int gethostbyname_r (const char *name, struct hostent *ret, char *buf,
|
||||
^
|
||||
/usr/include/netdb.h:177:12: note: previous declaration is here
|
||||
extern int gethostbyname_r (const char *__restrict __name,
|
||||
^
|
||||
|
||||
Fixing the expected return type to int sorts this out.
|
||||
|
||||
Signed-off-by: Jaco Kroon <jaco@uls.co.za>
|
||||
|
||||
- ### res_pjsip_pubsub.c: Use pjsip version for pending NOTIFY check. (#77)
|
||||
Author: Sean Bright
|
||||
Date: 2023-05-11
|
||||
|
||||
The functionality we are interested in is present only in pjsip 2.13
|
||||
and newer.
|
||||
|
||||
Resolves: #45
|
||||
|
||||
- ### res_sorcery_memory_cache.c: Fix memory leak
|
||||
Author: zhengsh
|
||||
Date: 2023-05-03
|
||||
|
||||
Replace the original call to ast_strdup with a call to ast_strdupa to fix the leak issue.
|
||||
|
||||
Resolves: #55
|
||||
ASTERISK-30429
|
||||
|
||||
|
||||
- ### xml.c: Process XML Inclusions recursively.
|
||||
Author: Sean Bright
|
||||
Date: 2023-05-09
|
||||
|
||||
If processing an XInclude results in new <xi:include> elements, we
|
||||
need to run XInclude processing again. This continues until no
|
||||
replacement occurs or an error is encountered.
|
||||
|
||||
There is a separate issue with dynamic strings (ast_str) that will be
|
||||
addressed separately.
|
||||
|
||||
Resolves: #65
|
||||
|
||||
- ### .github: Tweak improvement issue type language.
|
||||
Author: Joshua C. Colp
|
||||
Date: 2023-05-09
|
||||
|
||||
|
||||
- ### .github: Tweak new feature language, and move feature requests elsewhere.
|
||||
Author: Gitea
|
||||
Date: 2023-05-09
|
||||
|
||||
|
||||
- ### .github: Fix staleness check to only run on certain labels.
|
||||
Author: Joshua C. Colp
|
||||
Date: 2023-05-09
|
||||
|
||||
|
|
@ -0,0 +1,748 @@
|
|||
|
||||
Change Log for Release asterisk-20.5.0
|
||||
========================================
|
||||
|
||||
Links:
|
||||
----------------------------------------
|
||||
|
||||
- [Full ChangeLog](https://downloads.asterisk.org/pub/telephony/asterisk/releases/ChangeLog-20.5.0.md)
|
||||
- [GitHub Diff](https://github.com/asterisk/asterisk/compare/20.4.0...20.5.0)
|
||||
- [Tarball](https://downloads.asterisk.org/pub/telephony/asterisk/asterisk-20.5.0.tar.gz)
|
||||
- [Downloads](https://downloads.asterisk.org/pub/telephony/asterisk)
|
||||
|
||||
Summary:
|
||||
----------------------------------------
|
||||
|
||||
- ari-stubs: Fix more local anchor references
|
||||
- ari-stubs: Fix more local anchor references
|
||||
- ari-stubs: Fix broken documentation anchors
|
||||
- res_pjsip_session: Send Session Interval too small response
|
||||
- .github: Update workflow-application-token-action to v2
|
||||
- app_dial: Fix infinite loop when sending digits.
|
||||
- app_voicemail: Fix for loop declarations
|
||||
- alembic: Fix quoting of the 100rel column
|
||||
- pbx.c: Fix gcc 12 compiler warning.
|
||||
- app_audiosocket: Fixed timeout with -1 to avoid busy loop.
|
||||
- download_externals: Fix a few version related issues
|
||||
- main/refer.c: Fix double free in refer_data_destructor + potential leak
|
||||
- sig_analog: Add Called Subscriber Held capability.
|
||||
- app_macro: Fix locking around datastore access
|
||||
- Revert "app_stack: Print proper exit location for PBXless channels."
|
||||
- .github: Use generic releaser
|
||||
- install_prereq: Fix dependency install on aarch64.
|
||||
- res_pjsip.c: Set contact_user on incoming call local Contact header
|
||||
- extconfig: Allow explicit DB result set ordering to be disabled.
|
||||
- rest-api: Run make ari-stubs
|
||||
- res_pjsip_header_funcs: Make prefix argument optional.
|
||||
- pjproject_bundled: Increase PJSIP_MAX_MODULE to 38
|
||||
- manager: Tolerate stasis messages with no channel snapshot.
|
||||
- core/ari/pjsip: Add refer mechanism
|
||||
- chan_dahdi: Allow autoreoriginating after hangup.
|
||||
- audiohook: Unlock channel in mute if no audiohooks present.
|
||||
- sig_analog: Allow three-way flash to time out to silence.
|
||||
- res_prometheus: Do not generate broken metrics
|
||||
- res_pjsip: Enable TLS v1.3 if present.
|
||||
- func_cut: Add example to documentation.
|
||||
- extensions.conf.sample: Remove reference to missing context.
|
||||
- func_export: Use correct function argument as variable name.
|
||||
- app_queue: Add support for applying caller priority change immediately.
|
||||
- .github: Fix cherry-pick reminder issues
|
||||
- chan_iax2.c: Avoid crash with IAX2 switch support.
|
||||
- res_geolocation: Ensure required 'location_info' is present.
|
||||
- Adds manager actions to allow move/remove/forward individual messages in a particular mailbox folder. The forward command can be used to copy a message within a mailbox or to another mailbox. Also adds a VoicemailBoxSummarry, required to retrieve message ID's.
|
||||
- app_voicemail: add CLI commands for message manipulation
|
||||
- res_rtp_asterisk: Move ast_rtp_rtcp_report_alloc using `rtp->themssrc_valid` into the scope of the rtp_instance lock.
|
||||
- .github: Minor tweak to Asterisk Releaser
|
||||
- .github: Suppress cherry-pick reminder for some situations
|
||||
- sig_analog: Allow immediate fake ring to be suppressed.
|
||||
|
||||
User Notes:
|
||||
----------------------------------------
|
||||
|
||||
- ### sig_analog: Add Called Subscriber Held capability.
|
||||
Called Subscriber Held is now supported for analog
|
||||
FXS channels, using the calledsubscriberheld option. This allows
|
||||
a station user to go on hook when receiving an incoming call
|
||||
and resume from another phone on the same line by going on hook,
|
||||
without disconnecting the call.
|
||||
|
||||
- ### res_pjsip_header_funcs: Make prefix argument optional.
|
||||
The prefix argument to PJSIP_HEADERS is now
|
||||
optional. If not specified, all header names will be
|
||||
returned.
|
||||
|
||||
- ### core/ari/pjsip: Add refer mechanism
|
||||
There is a new ARI endpoint `/endpoints/refer` for referring
|
||||
an endpoint to some URI or endpoint.
|
||||
|
||||
- ### chan_dahdi: Allow autoreoriginating after hangup.
|
||||
The autoreoriginate setting now allows for kewlstart FXS
|
||||
channels to automatically reoriginate and provide dial tone to the
|
||||
user again after all calls on the line have cleared. This saves users
|
||||
from having to manually hang up and pick up the receiver again before
|
||||
making another call.
|
||||
|
||||
- ### sig_analog: Allow three-way flash to time out to silence.
|
||||
The threewaysilenthold option now allows the three-way
|
||||
dial tone to time out to silence, rather than continuing forever.
|
||||
|
||||
- ### res_pjsip: Enable TLS v1.3 if present.
|
||||
res_pjsip now allows TLS v1.3 to be enabled if supported by
|
||||
the underlying PJSIP library. The bundled version of PJSIP supports
|
||||
TLS v1.3.
|
||||
|
||||
- ### app_queue: Add support for applying caller priority change immediately.
|
||||
The 'queue priority caller' CLI command and
|
||||
'QueueChangePriorityCaller' AMI action now have an 'immediate'
|
||||
argument which allows the caller priority change to be reflected
|
||||
immediately, causing the position of a caller to move within the
|
||||
queue depending on the priorities of the other callers.
|
||||
|
||||
- ### Adds manager actions to allow move/remove/forward individual messages in a particular mailbox folder. The forward command can be used to copy a message within a mailbox or to another mailbox. Also adds a VoicemailBoxSummarry, required to retrieve message ID's.
|
||||
The following manager actions have been added
|
||||
VoicemailBoxSummary - Generate message list for a given mailbox
|
||||
VoicemailRemove - Remove a message from a mailbox folder
|
||||
VoicemailMove - Move a message from one folder to another within a mailbox
|
||||
VoicemailForward - Copy a message from one folder in one mailbox
|
||||
to another folder in another or the same mailbox.
|
||||
|
||||
- ### app_voicemail: add CLI commands for message manipulation
|
||||
The following CLI commands have been added to app_voicemail
|
||||
voicemail show mailbox <mailbox> <context>
|
||||
Show contents of mailbox <mailbox>@<context>
|
||||
voicemail remove <mailbox> <context> <from_folder> <messageid>
|
||||
Remove message <messageid> from <from_folder> in mailbox <mailbox>@<context>
|
||||
voicemail move <mailbox> <context> <from_folder> <messageid> <to_folder>
|
||||
Move message <messageid> in mailbox <mailbox>&<context> from <from_folder> to <to_folder>
|
||||
voicemail forward <from_mailbox> <from_context> <from_folder> <messageid> <to_mailbox> <to_context> <to_folder>
|
||||
Forward message <messageid> in mailbox <mailbox>@<context> <from_folder> to
|
||||
mailbox <mailbox>@<context> <to_folder>
|
||||
|
||||
- ### sig_analog: Allow immediate fake ring to be suppressed.
|
||||
The immediatering option can now be set to no to suppress
|
||||
the fake audible ringback provided when immediate=yes on FXS channels.
|
||||
|
||||
|
||||
Upgrade Notes:
|
||||
----------------------------------------
|
||||
|
||||
|
||||
Closed Issues:
|
||||
----------------------------------------
|
||||
|
||||
- #37: [Bug]: contrib/scripts/install_prereq tries to install armhf packages on aarch64 Debian platforms
|
||||
- #71: [new-feature]: core/ari/pjsip: Add refer mechanism to refer endpoints to some resource
|
||||
- #118: [new-feature]: chan_dahdi: Allow fake ringing to be inhibited when immediate=yes
|
||||
- #170: [improvement]: app_voicemail - add CLI commands to manipulate messages
|
||||
- #179: [bug]: Queue strategy “Linear” with Asterisk 20 on Realtime
|
||||
- #181: [improvement]: app_voicemail - add manager actions to display and manipulate messages
|
||||
- #202: [improvement]: app_queue: Add support for immediately applying queue caller priority change
|
||||
- #205: [new-feature]: sig_analog: Allow flash to time out to silent hold
|
||||
- #224: [new-feature]: chan_dahdi: Allow automatic reorigination on hangup
|
||||
- #226: [improvement]: Apply contact_user to incoming calls
|
||||
- #230: [bug]: PJSIP_RESPONSE_HEADERS function documentation is misleading
|
||||
- #233: [bug]: Deadlock with MixMonitorMute AMI action
|
||||
- #240: [new-feature]: sig_analog: Add Called Subscriber Held capability
|
||||
- #253: app_gosub patch appear to have broken predial handlers that utilize macros that call gosubs
|
||||
- #255: [bug]: pjsip_endpt_register_module: Assertion "Too many modules registered"
|
||||
- #263: [bug]: download_externals doesn't always handle versions correctly
|
||||
- #265: [bug]: app_macro isn't locking around channel datastore access
|
||||
- #267: [bug]: ari: refer with display_name key in request body leads to crash
|
||||
- #274: [bug]: Syntax Error in SQL Code
|
||||
- #275: [bug]:Asterisk make now requires ASTCFLAGS='-std=gnu99 -Wdeclaration-after-statement'
|
||||
- #277: [bug]: pbx.c: Compiler error with gcc 12.2
|
||||
- #281: [bug]: app_dial: Infinite loop if called channel hangs up while receiving digits
|
||||
|
||||
Commits By Author:
|
||||
----------------------------------------
|
||||
|
||||
- ### Asterisk Development Team (1):
|
||||
- Update for 20.5.0-rc1
|
||||
|
||||
- ### Bastian Triller (1):
|
||||
- res_pjsip_session: Send Session Interval too small response
|
||||
|
||||
- ### George Joseph (12):
|
||||
- .github: Suppress cherry-pick reminder for some situations
|
||||
- .github: Minor tweak to Asterisk Releaser
|
||||
- .github: Fix cherry-pick reminder issues
|
||||
- pjproject_bundled: Increase PJSIP_MAX_MODULE to 38
|
||||
- rest-api: Run make ari-stubs
|
||||
- .github: Use generic releaser
|
||||
- download_externals: Fix a few version related issues
|
||||
- alembic: Fix quoting of the 100rel column
|
||||
- .github: Update workflow-application-token-action to v2
|
||||
- ari-stubs: Fix broken documentation anchors
|
||||
- ari-stubs: Fix more local anchor references
|
||||
- ari-stubs: Fix more local anchor references
|
||||
|
||||
- ### Holger Hans Peter Freyther (1):
|
||||
- res_prometheus: Do not generate broken metrics
|
||||
|
||||
- ### Jason D. McCormick (1):
|
||||
- install_prereq: Fix dependency install on aarch64.
|
||||
|
||||
- ### Joshua C. Colp (3):
|
||||
- app_queue: Add support for applying caller priority change immediately.
|
||||
- audiohook: Unlock channel in mute if no audiohooks present.
|
||||
- manager: Tolerate stasis messages with no channel snapshot.
|
||||
|
||||
- ### Matthew Fredrickson (2):
|
||||
- Revert "app_stack: Print proper exit location for PBXless channels."
|
||||
- app_macro: Fix locking around datastore access
|
||||
|
||||
- ### Maximilian Fridrich (2):
|
||||
- core/ari/pjsip: Add refer mechanism
|
||||
- main/refer.c: Fix double free in refer_data_destructor + potential leak
|
||||
|
||||
- ### Mike Bradeen (3):
|
||||
- app_voicemail: add CLI commands for message manipulation
|
||||
- Adds manager actions to allow move/remove/forward individual messages in a particular mailbox folder. The forward command can be used to copy a message within a mailbox or to another mailbox. Also adds a VoicemailBoxSummarry, required to retrieve message ID's.
|
||||
- app_voicemail: Fix for loop declarations
|
||||
|
||||
- ### MikeNaso (1):
|
||||
- res_pjsip.c: Set contact_user on incoming call local Contact header
|
||||
|
||||
- ### Naveen Albert (7):
|
||||
- sig_analog: Allow immediate fake ring to be suppressed.
|
||||
- sig_analog: Allow three-way flash to time out to silence.
|
||||
- chan_dahdi: Allow autoreoriginating after hangup.
|
||||
- res_pjsip_header_funcs: Make prefix argument optional.
|
||||
- sig_analog: Add Called Subscriber Held capability.
|
||||
- pbx.c: Fix gcc 12 compiler warning.
|
||||
- app_dial: Fix infinite loop when sending digits.
|
||||
|
||||
- ### Sean Bright (6):
|
||||
- res_geolocation: Ensure required 'location_info' is present.
|
||||
- chan_iax2.c: Avoid crash with IAX2 switch support.
|
||||
- func_export: Use correct function argument as variable name.
|
||||
- extensions.conf.sample: Remove reference to missing context.
|
||||
- res_pjsip: Enable TLS v1.3 if present.
|
||||
- extconfig: Allow explicit DB result set ordering to be disabled.
|
||||
|
||||
- ### phoneben (1):
|
||||
- func_cut: Add example to documentation.
|
||||
|
||||
- ### zhengsh (2):
|
||||
- res_rtp_asterisk: Move ast_rtp_rtcp_report_alloc using `rtp->themssrc_valid` into the scope of the rtp_instance lock.
|
||||
- app_audiosocket: Fixed timeout with -1 to avoid busy loop.
|
||||
|
||||
|
||||
Detail:
|
||||
----------------------------------------
|
||||
|
||||
- ### ari-stubs: Fix more local anchor references
|
||||
Author: George Joseph
|
||||
Date: 2023-09-05
|
||||
|
||||
Also allow CreateDocs job to be run manually with default branches.
|
||||
|
||||
|
||||
- ### ari-stubs: Fix more local anchor references
|
||||
Author: George Joseph
|
||||
Date: 2023-09-05
|
||||
|
||||
Also allow CreateDocs job to be run manually with default branches.
|
||||
|
||||
|
||||
- ### ari-stubs: Fix broken documentation anchors
|
||||
Author: George Joseph
|
||||
Date: 2023-09-05
|
||||
|
||||
All of the links that reference page anchors with capital letters in
|
||||
the ids (#Something) have been changed to lower case to match the
|
||||
anchors that are generated by mkdocs.
|
||||
|
||||
|
||||
- ### res_pjsip_session: Send Session Interval too small response
|
||||
Author: Bastian Triller
|
||||
Date: 2023-08-28
|
||||
|
||||
Handle session interval lower than endpoint's configured minimum timer
|
||||
when sending first answer. Timer setting is checked during this step and
|
||||
needs to handled appropriately.
|
||||
Before this change, no response was sent at all. After this change a
|
||||
response with 422 Session Interval too small is sent to UAC.
|
||||
|
||||
|
||||
- ### .github: Update workflow-application-token-action to v2
|
||||
Author: George Joseph
|
||||
Date: 2023-08-31
|
||||
|
||||
|
||||
- ### app_dial: Fix infinite loop when sending digits.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-08-28
|
||||
|
||||
If the called party hangs up while digits are being
|
||||
sent, -1 is returned to indicate so, but app_dial
|
||||
was not checking the return value, resulting in
|
||||
the hangup being lost and looping forever until
|
||||
the caller manually hangs up the channel. We now
|
||||
abort if digit sending fails.
|
||||
|
||||
ASTERISK-29428 #close
|
||||
|
||||
Resolves: #281
|
||||
|
||||
- ### app_voicemail: Fix for loop declarations
|
||||
Author: Mike Bradeen
|
||||
Date: 2023-08-29
|
||||
|
||||
Resolve for loop initial declarations added in cli changes.
|
||||
|
||||
Resolves: #275
|
||||
|
||||
- ### alembic: Fix quoting of the 100rel column
|
||||
Author: George Joseph
|
||||
Date: 2023-08-28
|
||||
|
||||
Add quoting around the ps_endpoints 100rel column in the ALTER
|
||||
statements. Although alembic doesn't complain when generating
|
||||
sql statements, postgresql does (rightly so).
|
||||
|
||||
Resolves: #274
|
||||
|
||||
- ### pbx.c: Fix gcc 12 compiler warning.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-08-27
|
||||
|
||||
Resolves: #277
|
||||
|
||||
- ### app_audiosocket: Fixed timeout with -1 to avoid busy loop.
|
||||
Author: zhengsh
|
||||
Date: 2023-08-24
|
||||
|
||||
Resolves: asterisk#234
|
||||
|
||||
- ### download_externals: Fix a few version related issues
|
||||
Author: George Joseph
|
||||
Date: 2023-08-18
|
||||
|
||||
* Fixed issue with the script not parsing the new tag format for
|
||||
certified releases. The format changed from certified/18.9-cert5
|
||||
to certified-18.9-cert5.
|
||||
|
||||
* Fixed issue where the asterisk version wasn't being considered
|
||||
when looking for cached versions.
|
||||
|
||||
Resolves: #263
|
||||
|
||||
- ### main/refer.c: Fix double free in refer_data_destructor + potential leak
|
||||
Author: Maximilian Fridrich
|
||||
Date: 2023-08-21
|
||||
|
||||
Resolves: #267
|
||||
|
||||
- ### sig_analog: Add Called Subscriber Held capability.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-08-09
|
||||
|
||||
This adds support for Called Subscriber Held for FXS
|
||||
lines, which allows users to go on hook when receiving
|
||||
a call and resume the call later from another phone on
|
||||
the same line, without disconnecting the call. This is
|
||||
a convenience mechanism that most real PSTN telephone
|
||||
switches support.
|
||||
|
||||
ASTERISK-30372 #close
|
||||
|
||||
Resolves: #240
|
||||
|
||||
UserNote: Called Subscriber Held is now supported for analog
|
||||
FXS channels, using the calledsubscriberheld option. This allows
|
||||
a station user to go on hook when receiving an incoming call
|
||||
and resume from another phone on the same line by going on hook,
|
||||
without disconnecting the call.
|
||||
|
||||
|
||||
- ### app_macro: Fix locking around datastore access
|
||||
Author: Matthew Fredrickson
|
||||
Date: 2023-08-21
|
||||
|
||||
app_macro sometimes would crash due to datastore list corruption on the
|
||||
channel because of lack of locking around find and create process for
|
||||
the macro datastore. This patch locks the channel lock prior to protect
|
||||
against this problem.
|
||||
|
||||
Resolves: #265
|
||||
|
||||
- ### Revert "app_stack: Print proper exit location for PBXless channels."
|
||||
Author: Matthew Fredrickson
|
||||
Date: 2023-08-10
|
||||
|
||||
This reverts commit 617dad4cba1513dddce87b8e95a61415fb587cf1.
|
||||
|
||||
apps/app_stack.c: Revert buggy gosub patch
|
||||
|
||||
This seems to break the case when a predial macro calls a gosub.
|
||||
When the gosub calls return, the Return function outputs:
|
||||
|
||||
app_stack.c:423 return_exec: Return without Gosub: stack is empty
|
||||
|
||||
This returns -1 to the calling macro, which returns to app_dial
|
||||
and causes the call to hangup instead of proceeding with the macro
|
||||
that invoked the gosub.
|
||||
|
||||
Resolves: #253
|
||||
|
||||
- ### .github: Use generic releaser
|
||||
Author: George Joseph
|
||||
Date: 2023-08-15
|
||||
|
||||
|
||||
- ### install_prereq: Fix dependency install on aarch64.
|
||||
Author: Jason D. McCormick
|
||||
Date: 2023-04-28
|
||||
|
||||
Fixes dependency solutions in install_prereq for Debian aarch64
|
||||
platforms. install_prereq was attempting to forcibly install 32-bit
|
||||
armhf packages due to the aptitude search for dependencies.
|
||||
|
||||
Resolves: #37
|
||||
|
||||
- ### res_pjsip.c: Set contact_user on incoming call local Contact header
|
||||
Author: MikeNaso
|
||||
Date: 2023-08-08
|
||||
|
||||
If the contact_user is configured on the endpoint it will now be set on the local Contact header URI for incoming calls. The contact_user has already been set on the local Contact header URI for outgoing calls.
|
||||
|
||||
Resolves: #226
|
||||
|
||||
- ### extconfig: Allow explicit DB result set ordering to be disabled.
|
||||
Author: Sean Bright
|
||||
Date: 2023-07-12
|
||||
|
||||
Added a new boolean configuration flag -
|
||||
`order_multi_row_results_by_initial_column` - to both res_pgsql.conf
|
||||
and res_config_odbc.conf that allows the administrator to disable the
|
||||
explicit `ORDER BY` that was previously being added to all generated
|
||||
SQL statements that returned multiple rows.
|
||||
|
||||
Fixes: #179
|
||||
|
||||
- ### rest-api: Run make ari-stubs
|
||||
Author: George Joseph
|
||||
Date: 2023-08-09
|
||||
|
||||
An earlier cherry-pick that involved rest-api somehow didn't include
|
||||
a comment change in res/ari/resource_endpoints.h. This commit
|
||||
corrects that. No changes other than the comment.
|
||||
|
||||
|
||||
- ### res_pjsip_header_funcs: Make prefix argument optional.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-08-09
|
||||
|
||||
The documentation for PJSIP_HEADERS claims that
|
||||
prefix is optional, but in the code it is actually not.
|
||||
However, there is no inherent reason for this, as users
|
||||
may want to retrieve all header names, not just those
|
||||
beginning with a certain prefix.
|
||||
|
||||
This makes the prefix optional for this function,
|
||||
simply fetching all header names if not specified.
|
||||
As a result, the documentation is now correct.
|
||||
|
||||
Resolves: #230
|
||||
|
||||
UserNote: The prefix argument to PJSIP_HEADERS is now
|
||||
optional. If not specified, all header names will be
|
||||
returned.
|
||||
|
||||
|
||||
- ### pjproject_bundled: Increase PJSIP_MAX_MODULE to 38
|
||||
Author: George Joseph
|
||||
Date: 2023-08-11
|
||||
|
||||
The default is 32 with 8 being used by pjproject itself. Recent
|
||||
commits have put us over the limit resulting in assertions in
|
||||
pjproject. Since this value is used in invites, dialogs,
|
||||
transports and subscriptions as well as the global pjproject
|
||||
endpoint, we don't want to increase it too much.
|
||||
|
||||
Resolves: #255
|
||||
|
||||
- ### manager: Tolerate stasis messages with no channel snapshot.
|
||||
Author: Joshua C. Colp
|
||||
Date: 2023-08-09
|
||||
|
||||
In some cases I have yet to determine some stasis messages may
|
||||
be created without a channel snapshot. This change adds some
|
||||
tolerance to this scenario, preventing a crash from occurring.
|
||||
|
||||
|
||||
- ### core/ari/pjsip: Add refer mechanism
|
||||
Author: Maximilian Fridrich
|
||||
Date: 2023-05-10
|
||||
|
||||
This change adds support for refers that are not session based. It
|
||||
includes a refer implementation for the PJSIP technology which results
|
||||
in out-of-dialog REFERs being sent to a PJSIP endpoint. These can be
|
||||
triggered using the new ARI endpoint `/endpoints/refer`.
|
||||
|
||||
Resolves: #71
|
||||
|
||||
UserNote: There is a new ARI endpoint `/endpoints/refer` for referring
|
||||
an endpoint to some URI or endpoint.
|
||||
|
||||
|
||||
- ### chan_dahdi: Allow autoreoriginating after hangup.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-08-04
|
||||
|
||||
Currently, if an FXS channel is still off hook when
|
||||
all calls on the line have hung up, the user is provided
|
||||
reorder tone until going back on hook again.
|
||||
|
||||
In addition to not reflecting what most commercial switches
|
||||
actually do, it's very common for switches to automatically
|
||||
reoriginate for the user so that dial tone is provided without
|
||||
the user having to depress and release the hookswitch manually.
|
||||
This can increase convenience for users.
|
||||
|
||||
This behavior is now supported for kewlstart FXS channels.
|
||||
It's supported only for kewlstart (FXOKS) mainly because the
|
||||
behavior doesn't make any sense for ground start channels,
|
||||
and loop start signalling doesn't provide the necessary DAHDI
|
||||
event that makes this easy to implement. Likely almost everyone
|
||||
is using FXOKS over FXOLS anyways since FXOLS is pretty useless
|
||||
these days.
|
||||
|
||||
ASTERISK-30357 #close
|
||||
|
||||
Resolves: #224
|
||||
|
||||
UserNote: The autoreoriginate setting now allows for kewlstart FXS
|
||||
channels to automatically reoriginate and provide dial tone to the
|
||||
user again after all calls on the line have cleared. This saves users
|
||||
from having to manually hang up and pick up the receiver again before
|
||||
making another call.
|
||||
|
||||
|
||||
- ### audiohook: Unlock channel in mute if no audiohooks present.
|
||||
Author: Joshua C. Colp
|
||||
Date: 2023-08-09
|
||||
|
||||
In the case where mute was called on a channel that had no
|
||||
audiohooks the code was not unlocking the channel, resulting
|
||||
in a deadlock.
|
||||
|
||||
Resolves: #233
|
||||
|
||||
- ### sig_analog: Allow three-way flash to time out to silence.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-07-10
|
||||
|
||||
sig_analog allows users to flash and use the three-way dial
|
||||
tone as a primitive hold function, simply by never timing
|
||||
it out.
|
||||
|
||||
Some systems allow this dial tone to time out to silence,
|
||||
so the user is not annoyed by a persistent dial tone.
|
||||
This option allows the dial tone to time out normally to
|
||||
silence.
|
||||
|
||||
ASTERISK-30004 #close
|
||||
Resolves: #205
|
||||
|
||||
UserNote: The threewaysilenthold option now allows the three-way
|
||||
dial tone to time out to silence, rather than continuing forever.
|
||||
|
||||
|
||||
- ### res_prometheus: Do not generate broken metrics
|
||||
Author: Holger Hans Peter Freyther
|
||||
Date: 2023-04-07
|
||||
|
||||
In 8d6fdf9c3adede201f0ef026dab201b3a37b26b6 invisible bridges were
|
||||
skipped but that lead to producing metrics with no name and no help.
|
||||
|
||||
Keep track of the number of metrics configured and then only emit these.
|
||||
Add a basic testcase that verifies that there is no '(NULL)' in the
|
||||
output.
|
||||
|
||||
ASTERISK-30474
|
||||
|
||||
|
||||
- ### res_pjsip: Enable TLS v1.3 if present.
|
||||
Author: Sean Bright
|
||||
Date: 2023-08-02
|
||||
|
||||
Fixes #221
|
||||
|
||||
UserNote: res_pjsip now allows TLS v1.3 to be enabled if supported by
|
||||
the underlying PJSIP library. The bundled version of PJSIP supports
|
||||
TLS v1.3.
|
||||
|
||||
|
||||
- ### func_cut: Add example to documentation.
|
||||
Author: phoneben
|
||||
Date: 2023-07-19
|
||||
|
||||
This adds an example to the XML documentation clarifying usage
|
||||
of the CUT function to address a common misusage.
|
||||
|
||||
|
||||
- ### extensions.conf.sample: Remove reference to missing context.
|
||||
Author: Sean Bright
|
||||
Date: 2023-07-16
|
||||
|
||||
c3ff4648 removed the [iaxtel700] context but neglected to remove
|
||||
references to it.
|
||||
|
||||
This commit addresses that and also removes iaxtel and freeworlddialup
|
||||
references from other config files.
|
||||
|
||||
|
||||
- ### func_export: Use correct function argument as variable name.
|
||||
Author: Sean Bright
|
||||
Date: 2023-07-12
|
||||
|
||||
Fixes #208
|
||||
|
||||
|
||||
- ### app_queue: Add support for applying caller priority change immediately.
|
||||
Author: Joshua C. Colp
|
||||
Date: 2023-07-07
|
||||
|
||||
The app_queue module provides both an AMI action and a CLI command
|
||||
to change the priority of a caller in a queue. Up to now this change
|
||||
of priority has only been reflected to new callers into the queue.
|
||||
|
||||
This change adds an "immediate" option to both the AMI action and
|
||||
CLI command which immediately applies the priority change respective
|
||||
to the other callers already in the queue. This can allow, for example,
|
||||
a caller to be placed at the head of the queue immediately if their
|
||||
priority is sufficient.
|
||||
|
||||
Resolves: #202
|
||||
|
||||
UserNote: The 'queue priority caller' CLI command and
|
||||
'QueueChangePriorityCaller' AMI action now have an 'immediate'
|
||||
argument which allows the caller priority change to be reflected
|
||||
immediately, causing the position of a caller to move within the
|
||||
queue depending on the priorities of the other callers.
|
||||
|
||||
|
||||
- ### .github: Fix cherry-pick reminder issues
|
||||
Author: George Joseph
|
||||
Date: 2023-07-17
|
||||
|
||||
|
||||
- ### chan_iax2.c: Avoid crash with IAX2 switch support.
|
||||
Author: Sean Bright
|
||||
Date: 2023-07-07
|
||||
|
||||
A change made in 82cebaa0 did not properly handle the case when a
|
||||
channel was not provided, triggering a crash. ast_check_hangup(...)
|
||||
does not protect against NULL pointers.
|
||||
|
||||
Fixes #180
|
||||
|
||||
|
||||
- ### res_geolocation: Ensure required 'location_info' is present.
|
||||
Author: Sean Bright
|
||||
Date: 2023-07-07
|
||||
|
||||
Fixes #189
|
||||
|
||||
|
||||
- ### Adds manager actions to allow move/remove/forward individual messages in a particular mailbox folder. The forward command can be used to copy a message within a mailbox or to another mailbox. Also adds a VoicemailBoxSummarry, required to retrieve message ID's.
|
||||
Author: Mike Bradeen
|
||||
Date: 2023-06-29
|
||||
|
||||
Resolves: #181
|
||||
|
||||
UserNote: The following manager actions have been added
|
||||
|
||||
VoicemailBoxSummary - Generate message list for a given mailbox
|
||||
|
||||
VoicemailRemove - Remove a message from a mailbox folder
|
||||
|
||||
VoicemailMove - Move a message from one folder to another within a mailbox
|
||||
|
||||
VoicemailForward - Copy a message from one folder in one mailbox
|
||||
to another folder in another or the same mailbox.
|
||||
|
||||
|
||||
- ### app_voicemail: add CLI commands for message manipulation
|
||||
Author: Mike Bradeen
|
||||
Date: 2023-06-20
|
||||
|
||||
Adds CLI commands to allow move/remove/forward individual messages
|
||||
from a particular mailbox folder. The forward command can be used
|
||||
to copy a message within a mailbox or to another mailbox. Also adds
|
||||
a show mailbox, required to retrieve message ID's.
|
||||
|
||||
Resolves: #170
|
||||
|
||||
UserNote: The following CLI commands have been added to app_voicemail
|
||||
|
||||
voicemail show mailbox <mailbox> <context>
|
||||
Show contents of mailbox <mailbox>@<context>
|
||||
|
||||
voicemail remove <mailbox> <context> <from_folder> <messageid>
|
||||
Remove message <messageid> from <from_folder> in mailbox <mailbox>@<context>
|
||||
|
||||
voicemail move <mailbox> <context> <from_folder> <messageid> <to_folder>
|
||||
Move message <messageid> in mailbox <mailbox>&<context> from <from_folder> to <to_folder>
|
||||
|
||||
voicemail forward <from_mailbox> <from_context> <from_folder> <messageid> <to_mailbox> <to_context> <to_folder>
|
||||
Forward message <messageid> in mailbox <mailbox>@<context> <from_folder> to
|
||||
mailbox <mailbox>@<context> <to_folder>
|
||||
|
||||
|
||||
- ### res_rtp_asterisk: Move ast_rtp_rtcp_report_alloc using `rtp->themssrc_valid` into the scope of the rtp_instance lock.
|
||||
Author: zhengsh
|
||||
Date: 2023-06-30
|
||||
|
||||
From the gdb information, it was found that when calling __ast_free, the size of the
|
||||
allocated space pointed to by the pointer matches the size created when rtp->themssrc_valid
|
||||
is equal to 0. However, in reality, when reading the value of rtp->themssrc_valid in gdb,
|
||||
it is found to be 1.
|
||||
|
||||
Within ast_rtcp_write(), the call to ast_rtp_rtcp_report_alloc() uses rtp->themssrc_valid,
|
||||
which is outside the protection of the rtp_instance lock. However,
|
||||
ast_rtcp_generate_report(), which is called by ast_rtcp_generate_compound_prefix(), uses
|
||||
rtp->themssrc_valid within the protection of the rtp_instance lock.
|
||||
|
||||
This can lead to the possibility that the value of rtp->themssrc_valid used in the call to
|
||||
ast_rtp_rtcp_report_alloc() may be different from the value of rtp->themssrc_valid used
|
||||
within ast_rtcp_generate_report().
|
||||
|
||||
Resolves: asterisk#63
|
||||
|
||||
- ### .github: Minor tweak to Asterisk Releaser
|
||||
Author: George Joseph
|
||||
Date: 2023-07-12
|
||||
|
||||
|
||||
- ### .github: Suppress cherry-pick reminder for some situations
|
||||
Author: George Joseph
|
||||
Date: 2023-07-11
|
||||
|
||||
In PROpenedOrUpdated, the cherry-pick reminder will now be
|
||||
suppressed if there are already valid 'cherry-pick-to' comments
|
||||
in the PR or the PR contained a 'cherry-pick-to: none' comment.
|
||||
|
||||
|
||||
- ### sig_analog: Allow immediate fake ring to be suppressed.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-06-08
|
||||
|
||||
When immediate=yes on an FXS channel, sig_analog will
|
||||
start fake audible ringback that continues until the
|
||||
channel is answered. Even if it answers immediately,
|
||||
the ringback is still audible for a brief moment.
|
||||
This can be disruptive and unwanted behavior.
|
||||
|
||||
This adds an option to disable this behavior, though
|
||||
the default behavior remains unchanged.
|
||||
|
||||
ASTERISK-30003 #close
|
||||
Resolves: #118
|
||||
|
||||
UserNote: The immediatering option can now be set to no to suppress
|
||||
the fake audible ringback provided when immediate=yes on FXS channels.
|
||||
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
|
||||
Change Log for Release asterisk-20.5.1
|
||||
========================================
|
||||
|
||||
Links:
|
||||
----------------------------------------
|
||||
|
||||
- [Full ChangeLog](https://downloads.asterisk.org/pub/telephony/asterisk/releases/ChangeLog-20.5.1.md)
|
||||
- [GitHub Diff](https://github.com/asterisk/asterisk/compare/20.5.0...20.5.1)
|
||||
- [Tarball](https://downloads.asterisk.org/pub/telephony/asterisk/asterisk-20.5.1.tar.gz)
|
||||
- [Downloads](https://downloads.asterisk.org/pub/telephony/asterisk)
|
||||
|
||||
Summary:
|
||||
----------------------------------------
|
||||
|
||||
- res_pjsip_header_funcs: Duplicate new header value, don't copy.
|
||||
- res_pjsip: disable raw bad packet logging
|
||||
- res_rtp_asterisk.c: Check DTLS packets against ICE candidate list
|
||||
- manager.c: Prevent path traversal with GetConfig.
|
||||
|
||||
User Notes:
|
||||
----------------------------------------
|
||||
|
||||
|
||||
Upgrade Notes:
|
||||
----------------------------------------
|
||||
|
||||
|
||||
Closed Issues:
|
||||
----------------------------------------
|
||||
|
||||
None
|
||||
|
||||
Commits By Author:
|
||||
----------------------------------------
|
||||
|
||||
- ### Ben Ford (1):
|
||||
- manager.c: Prevent path traversal with GetConfig.
|
||||
|
||||
- ### George Joseph (1):
|
||||
- res_rtp_asterisk.c: Check DTLS packets against ICE candidate list
|
||||
|
||||
- ### Gitea (1):
|
||||
- res_pjsip_header_funcs: Duplicate new header value, don't copy.
|
||||
|
||||
- ### Mike Bradeen (1):
|
||||
- res_pjsip: disable raw bad packet logging
|
||||
|
||||
|
||||
Detail:
|
||||
----------------------------------------
|
||||
|
||||
- ### res_pjsip_header_funcs: Duplicate new header value, don't copy.
|
||||
Author: Gitea
|
||||
Date: 2023-07-10
|
||||
|
||||
When updating an existing header the 'update' code incorrectly
|
||||
just copied the new value into the existing buffer. If the
|
||||
new value exceeded the available buffer size memory outside
|
||||
of the buffer would be written into, potentially causing
|
||||
a crash.
|
||||
|
||||
This change makes it so that the 'update' now duplicates
|
||||
the new header value instead of copying it into the existing
|
||||
buffer.
|
||||
|
||||
- ### res_pjsip: disable raw bad packet logging
|
||||
Author: Mike Bradeen
|
||||
Date: 2023-07-25
|
||||
|
||||
Add patch to split the log level for invalid packets received on the
|
||||
signaling port. The warning regarding the packet will move to level 2
|
||||
so that it can still be displayed, while the raw packet will be at level
|
||||
4.
|
||||
|
||||
- ### res_rtp_asterisk.c: Check DTLS packets against ICE candidate list
|
||||
Author: George Joseph
|
||||
Date: 2023-11-09
|
||||
|
||||
When ICE is in use, we can prevent a possible DOS attack by allowing
|
||||
DTLS protocol messages (client hello, etc) only from sources that
|
||||
are in the active remote candidates list.
|
||||
|
||||
Resolves: GHSA-hxj9-xwr8-w8pq
|
||||
|
||||
- ### manager.c: Prevent path traversal with GetConfig.
|
||||
Author: Ben Ford
|
||||
Date: 2023-11-13
|
||||
|
||||
When using AMI GetConfig, it was possible to access files outside of the
|
||||
Asterisk configuration directory by using filenames with ".." and "./"
|
||||
even while live_dangerously was not enabled. This change resolves the
|
||||
full path and ensures we are still in the configuration directory before
|
||||
attempting to access the file.
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
|
||||
Change Log for Release asterisk-20.5.2
|
||||
========================================
|
||||
|
||||
Links:
|
||||
----------------------------------------
|
||||
|
||||
- [Full ChangeLog](https://downloads.asterisk.org/pub/telephony/asterisk/releases/ChangeLog-20.5.2.md)
|
||||
- [GitHub Diff](https://github.com/asterisk/asterisk/compare/20.5.1...20.5.2)
|
||||
- [Tarball](https://downloads.asterisk.org/pub/telephony/asterisk/asterisk-20.5.2.tar.gz)
|
||||
- [Downloads](https://downloads.asterisk.org/pub/telephony/asterisk)
|
||||
|
||||
Summary:
|
||||
----------------------------------------
|
||||
|
||||
- res_rtp_asterisk: Fix regression issues with DTLS client check
|
||||
|
||||
User Notes:
|
||||
----------------------------------------
|
||||
|
||||
|
||||
Upgrade Notes:
|
||||
----------------------------------------
|
||||
|
||||
|
||||
Closed Issues:
|
||||
----------------------------------------
|
||||
|
||||
- #500: [bug regression]: res_rtp_asterisk doesn't build if pjproject isn't used
|
||||
- #503: [bug]: The res_rtp_asterisk DTLS check against ICE candidates fails when it shouldn't
|
||||
- #505: [bug]: res_pjproject: ast_sockaddr_cmp() always fails on sockaddrs created by ast_sockaddr_from_pj_sockaddr()
|
||||
|
||||
Commits By Author:
|
||||
----------------------------------------
|
||||
|
||||
- ### George Joseph (1):
|
||||
- res_rtp_asterisk: Fix regression issues with DTLS client check
|
||||
|
||||
|
||||
Detail:
|
||||
----------------------------------------
|
||||
|
||||
- ### res_rtp_asterisk: Fix regression issues with DTLS client check
|
||||
Author: George Joseph
|
||||
Date: 2023-12-15
|
||||
|
||||
* Since ICE candidates are used for the check and pjproject is
|
||||
required to use ICE, res_rtp_asterisk was failing to compile
|
||||
when pjproject wasn't available. The check is now wrapped
|
||||
with an #ifdef HAVE_PJPROJECT.
|
||||
|
||||
* The rtp->ice_active_remote_candidates container was being
|
||||
used to check the address on incoming packets but that
|
||||
container doesn't contain peer reflexive candidates discovered
|
||||
during negotiation. This was causing the check to fail
|
||||
where it shouldn't. We now check against pjproject's
|
||||
real_ice->rcand array which will contain those candidates.
|
||||
|
||||
* Also fixed a bug in ast_sockaddr_from_pj_sockaddr() where
|
||||
we weren't zeroing out sin->sin_zero before returning. This
|
||||
was causing ast_sockaddr_cmp() to always return false when
|
||||
one of the inputs was converted from a pj_sockaddr, even
|
||||
if both inputs had the same address and port.
|
||||
|
||||
Resolves: #500
|
||||
Resolves: #503
|
||||
Resolves: #505
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,736 @@
|
|||
|
||||
Change Log for Release asterisk-20.7.0
|
||||
========================================
|
||||
|
||||
Links:
|
||||
----------------------------------------
|
||||
|
||||
- [Full ChangeLog](https://downloads.asterisk.org/pub/telephony/asterisk/releases/ChangeLog-20.7.0.md)
|
||||
- [GitHub Diff](https://github.com/asterisk/asterisk/compare/20.6.0...20.7.0)
|
||||
- [Tarball](https://downloads.asterisk.org/pub/telephony/asterisk/asterisk-20.7.0.tar.gz)
|
||||
- [Downloads](https://downloads.asterisk.org/pub/telephony/asterisk)
|
||||
|
||||
Summary:
|
||||
----------------------------------------
|
||||
|
||||
- res_pjsip_stir_shaken.c: Add checks for missing parameters
|
||||
- app_dial: Add dial time for progress/ringing.
|
||||
- app_voicemail: Properly reinitialize config after unit tests.
|
||||
- app_queue.c : fix "queue add member" usage string
|
||||
- app_voicemail: Allow preventing mark messages as urgent.
|
||||
- res_pjsip: Use consistent type for boolean columns.
|
||||
- attestation_config.c: Use ast_free instead of ast_std_free
|
||||
- Makefile: Add stir_shaken/cache to directories created on install
|
||||
- Stir/Shaken Refactor
|
||||
- alembic: Synchronize alembic heads between supported branches.
|
||||
- translate.c: implement new direct comp table mode
|
||||
- README.md: Removed outdated link
|
||||
- strings.h: Ensure ast_str_buffer(…) returns a 0 terminated string.
|
||||
- res_rtp_asterisk.c: Correct coefficient in MOS calculation.
|
||||
- dsp.c: Fix and improve potentially inaccurate log message.
|
||||
- pjsip show channelstats: Prevent possible segfault when faxing
|
||||
- Reduce startup/shutdown verbose logging
|
||||
- configure: Rerun bootstrap on modern platform.
|
||||
- Upgrade bundled pjproject to 2.14.
|
||||
- app_speech_utils.c: Allow partial speech results.
|
||||
- utils: Make behavior of ast_strsep* match strsep.
|
||||
- app_chanspy: Add 'D' option for dual-channel audio
|
||||
- app_if: Fix next priority calculation.
|
||||
- res_pjsip_t38.c: Permit IPv6 SDP connection addresses.
|
||||
- BuildSystem: Bump autotools versions on OpenBSD.
|
||||
- main/utils: Simplify the FreeBSD ast_get_tid() handling
|
||||
- res_pjsip_session.c: Correctly format SDP connection addresses.
|
||||
- rtp_engine.c: Correct sample rate typo for L16/44100.
|
||||
- manager.c: Fix erroneous reloads in UpdateConfig.
|
||||
- res_calendar_icalendar: Print iCalendar error on parsing failure.
|
||||
- app_confbridge: Don't emit warnings on valid configurations.
|
||||
- app_voicemail: add NoOp alembic script to maintain sync
|
||||
- chan_dahdi: Allow MWI to be manually toggled on channels.
|
||||
- chan_rtp.c: MulticastRTP missing refcount without codec option
|
||||
- chan_rtp.c: Change MulticastRTP nameing to avoid memory leak
|
||||
- func_frame_trace: Add CLI command to dump frame queue.
|
||||
|
||||
User Notes:
|
||||
----------------------------------------
|
||||
|
||||
- ### app_dial: Add dial time for progress/ringing.
|
||||
The timeout argument to Dial now allows
|
||||
specifying the maximum amount of time to dial if
|
||||
early media is not received.
|
||||
|
||||
- ### app_voicemail: Allow preventing mark messages as urgent.
|
||||
The leaveurgent mailbox option can now be used to
|
||||
control whether callers may leave messages marked as 'Urgent'.
|
||||
|
||||
- ### Stir/Shaken Refactor
|
||||
Asterisk's stir-shaken feature has been refactored to
|
||||
correct interoperability, RFC compliance, and performance issues.
|
||||
See https://docs.asterisk.org/Deployment/STIR-SHAKEN for more
|
||||
information.
|
||||
|
||||
- ### Upgrade bundled pjproject to 2.14.
|
||||
Bundled pjproject has been upgraded to 2.14. For more
|
||||
information on what all is included in this change, check out the
|
||||
pjproject Github page: https://github.com/pjsip/pjproject/releases
|
||||
|
||||
- ### app_speech_utils.c: Allow partial speech results.
|
||||
The SpeechBackground dialplan application now supports a 'p'
|
||||
option that will return partial results from speech engines that
|
||||
provide them when a timeout occurs.
|
||||
|
||||
- ### app_chanspy: Add 'D' option for dual-channel audio
|
||||
The ChanSpy application now accepts the 'D' option which
|
||||
will interleave the spied audio within the outgoing frames. The
|
||||
purpose of this is to allow the audio to be read as a Dual channel
|
||||
stream with separate incoming and outgoing audio. Setting both the
|
||||
'o' option and the 'D' option and results in the 'D' option being
|
||||
ignored.
|
||||
|
||||
- ### chan_dahdi: Allow MWI to be manually toggled on channels.
|
||||
The 'dahdi set mwi' now allows MWI on channels
|
||||
to be manually toggled if needed for troubleshooting.
|
||||
Resolves: #440
|
||||
|
||||
|
||||
Upgrade Notes:
|
||||
----------------------------------------
|
||||
|
||||
- ### Stir/Shaken Refactor
|
||||
The stir-shaken refactor is a breaking change but since
|
||||
it's not working now we don't think it matters. The
|
||||
stir_shaken.conf file has changed significantly which means that
|
||||
existing ones WILL need to be changed. The stir_shaken.conf.sample
|
||||
file in configs/samples/ has quite a bit more information. This is
|
||||
also an ABI breaking change since some of the existing objects
|
||||
needed to be changed or removed, and new ones added. Additionally,
|
||||
if res_stir_shaken is enabled in menuselect, you'll need to either
|
||||
have the development package for libjwt v1.15.3 installed or use
|
||||
the --with-libjwt-bundled option with ./configure.
|
||||
|
||||
|
||||
Closed Issues:
|
||||
----------------------------------------
|
||||
|
||||
- #46: [bug]: Stir/Shaken: Wrong CID used when looking up certificates
|
||||
- #351: [improvement]: Refactor res_stir_shaken to use libjwt
|
||||
- #406: [improvement]: pjsip: Upgrade bundled version to pjproject 2.14
|
||||
- #440: [new-feature]: chan_dahdi: Allow manually toggling MWI on channels
|
||||
- #492: [improvement]: res_calendar_icalendar: Print icalendar error if available on parsing failure
|
||||
- #527: [bug]: app_voicemail_odbc no longer working after removal of macrocontext.
|
||||
- #529: [bug]: MulticastRTP without selected codec leeds to "FRACK!, Failed assertion bad magic number 0x0 for object" after ~30 calls
|
||||
- #533: [improvement]: channel.c, func_frame_trace.c: Improve debuggability of channel frame queue
|
||||
- #551: [bug]: manager: UpdateConfig triggers reload with "Reload: no"
|
||||
- #560: [bug]: EndIf() causes next priority to be skipped
|
||||
- #565: [bug]: Application Read() returns immediately
|
||||
- #569: [improvement]: Add option to interleave input and output frames on spied channel
|
||||
- #572: [improvement]: Copy partial speech results when Asterisk is ready to move on but the speech backend is not
|
||||
- #582: [improvement]: Reduce unneeded logging during startup and shutdown
|
||||
- #586: [bug]: The "restrict" keyword used in chan_iax2.c isn't supported in older gcc versions
|
||||
- #588: [new-feature]: app_dial: Allow Dial to be aborted if early media is not received
|
||||
- #592: [bug]: In certain circumstances, "pjsip show channelstats" can segfault when a fax session is active
|
||||
- #595: [improvement]: dsp.c: Fix and improve confusing warning message.
|
||||
- #597: [bug]: wrong MOS calculation
|
||||
- #601: [new-feature]: translate.c: implement new direct comp table mode (PR #585)
|
||||
- #619: [new-feature]: app_voicemail: Allow preventing callers from marking messages as urgent
|
||||
- #629: [bug]: app_voicemail: Multiple executions of unit tests cause segfault
|
||||
- #634: [bug]: make install doesn't create the stir_shaken cache directory
|
||||
- #636: [bug]: Possible SEGV in res_stir_shaken due to wrong free function
|
||||
- #645: [bug]: Occasional SEGV in res_pjsip_stir_shaken.c
|
||||
|
||||
Commits By Author:
|
||||
----------------------------------------
|
||||
|
||||
- ### Ben Ford (1):
|
||||
- Upgrade bundled pjproject to 2.14.
|
||||
|
||||
- ### Brad Smith (2):
|
||||
- main/utils: Simplify the FreeBSD ast_get_tid() handling
|
||||
- BuildSystem: Bump autotools versions on OpenBSD.
|
||||
|
||||
- ### George Joseph (6):
|
||||
- Reduce startup/shutdown verbose logging
|
||||
- pjsip show channelstats: Prevent possible segfault when faxing
|
||||
- Stir/Shaken Refactor
|
||||
- Makefile: Add stir_shaken/cache to directories created on install
|
||||
- attestation_config.c: Use ast_free instead of ast_std_free
|
||||
- res_pjsip_stir_shaken.c: Add checks for missing parameters
|
||||
|
||||
- ### Joshua C. Colp (1):
|
||||
- utils: Make behavior of ast_strsep* match strsep.
|
||||
|
||||
- ### Mike Bradeen (2):
|
||||
- app_voicemail: add NoOp alembic script to maintain sync
|
||||
- app_chanspy: Add 'D' option for dual-channel audio
|
||||
|
||||
- ### Naveen Albert (10):
|
||||
- func_frame_trace: Add CLI command to dump frame queue.
|
||||
- chan_dahdi: Allow MWI to be manually toggled on channels.
|
||||
- res_calendar_icalendar: Print iCalendar error on parsing failure.
|
||||
- manager.c: Fix erroneous reloads in UpdateConfig.
|
||||
- app_if: Fix next priority calculation.
|
||||
- configure: Rerun bootstrap on modern platform.
|
||||
- dsp.c: Fix and improve potentially inaccurate log message.
|
||||
- app_voicemail: Allow preventing mark messages as urgent.
|
||||
- app_voicemail: Properly reinitialize config after unit tests.
|
||||
- app_dial: Add dial time for progress/ringing.
|
||||
|
||||
- ### PeterHolik (2):
|
||||
- chan_rtp.c: Change MulticastRTP nameing to avoid memory leak
|
||||
- chan_rtp.c: MulticastRTP missing refcount without codec option
|
||||
|
||||
- ### Sean Bright (7):
|
||||
- app_confbridge: Don't emit warnings on valid configurations.
|
||||
- rtp_engine.c: Correct sample rate typo for L16/44100.
|
||||
- res_pjsip_session.c: Correctly format SDP connection addresses.
|
||||
- res_pjsip_t38.c: Permit IPv6 SDP connection addresses.
|
||||
- strings.h: Ensure ast_str_buffer(…) returns a 0 terminated string.
|
||||
- alembic: Synchronize alembic heads between supported branches.
|
||||
- res_pjsip: Use consistent type for boolean columns.
|
||||
|
||||
- ### Sebastian Jennen (1):
|
||||
- translate.c: implement new direct comp table mode
|
||||
|
||||
- ### Shaaah (1):
|
||||
- app_queue.c : fix "queue add member" usage string
|
||||
|
||||
- ### Shyju Kanaprath (1):
|
||||
- README.md: Removed outdated link
|
||||
|
||||
- ### cmaj (1):
|
||||
- app_speech_utils.c: Allow partial speech results.
|
||||
|
||||
- ### romryz (1):
|
||||
- res_rtp_asterisk.c: Correct coefficient in MOS calculation.
|
||||
|
||||
|
||||
Detail:
|
||||
----------------------------------------
|
||||
|
||||
- ### res_pjsip_stir_shaken.c: Add checks for missing parameters
|
||||
Author: George Joseph
|
||||
Date: 2024-03-11
|
||||
|
||||
* Added checks for missing session, session->channel and rdata
|
||||
in stir_shaken_incoming_request.
|
||||
|
||||
* Added checks for missing session, session->channel and tdata
|
||||
in stir_shaken_outgoing_request.
|
||||
|
||||
Resolves: #645
|
||||
|
||||
- ### app_dial: Add dial time for progress/ringing.
|
||||
Author: Naveen Albert
|
||||
Date: 2024-02-08
|
||||
|
||||
Add a timeout option to control the amount of time
|
||||
to wait if no early media is received before giving
|
||||
up. This allows aborting early if the destination
|
||||
is not being responsive.
|
||||
|
||||
Resolves: #588
|
||||
|
||||
UserNote: The timeout argument to Dial now allows
|
||||
specifying the maximum amount of time to dial if
|
||||
early media is not received.
|
||||
|
||||
|
||||
- ### app_voicemail: Properly reinitialize config after unit tests.
|
||||
Author: Naveen Albert
|
||||
Date: 2024-02-29
|
||||
|
||||
Most app_voicemail unit tests were not properly cleaning up
|
||||
after themselves after running. This led to test mailboxes
|
||||
lingering around in the system. It also meant that if any
|
||||
unit tests in app_voicemail that create mailboxes were executed
|
||||
and the module was not unloaded/loaded again prior to running
|
||||
the test_voicemail_vm_info unit test, Asterisk would segfault
|
||||
due to an attempt to copy a NULL string.
|
||||
|
||||
The load_config test did actually have logic to reinitialize
|
||||
the config after the test. However, this did not work in practice
|
||||
since load_config() would not reload the config since voicemail.conf
|
||||
had not changed during the test; thus, additional logic has been
|
||||
added to ensure that voicemail.conf is truly reloaded, after any
|
||||
unit tests which modify the users list.
|
||||
|
||||
This prevents the SEGV due to invalid mailboxes lingering around,
|
||||
and also ensures that the system state is restored to what it was
|
||||
prior to the tests running.
|
||||
|
||||
Resolves: #629
|
||||
|
||||
- ### app_queue.c : fix "queue add member" usage string
|
||||
Author: Shaaah
|
||||
Date: 2024-01-23
|
||||
|
||||
Fixing bracket placement in the "queue add member" cli usage string.
|
||||
|
||||
|
||||
- ### app_voicemail: Allow preventing mark messages as urgent.
|
||||
Author: Naveen Albert
|
||||
Date: 2024-02-24
|
||||
|
||||
This adds an option to allow preventing callers from leaving
|
||||
messages marked as 'urgent'.
|
||||
|
||||
Resolves: #619
|
||||
|
||||
UserNote: The leaveurgent mailbox option can now be used to
|
||||
control whether callers may leave messages marked as 'Urgent'.
|
||||
|
||||
|
||||
- ### res_pjsip: Use consistent type for boolean columns.
|
||||
Author: Sean Bright
|
||||
Date: 2024-02-27
|
||||
|
||||
This migrates the relevant schema objects from the `('yes', 'no')`
|
||||
definition to the `('0', '1', 'off', 'on', 'false', 'true', 'yes', 'no')`
|
||||
one.
|
||||
|
||||
Fixes #617
|
||||
|
||||
|
||||
- ### attestation_config.c: Use ast_free instead of ast_std_free
|
||||
Author: George Joseph
|
||||
Date: 2024-03-05
|
||||
|
||||
In as_check_common_config, we were calling ast_std_free on
|
||||
raw_key but raw_key was allocated with ast_malloc so it
|
||||
should be freed with ast_free.
|
||||
|
||||
Resolves: #636
|
||||
|
||||
- ### Makefile: Add stir_shaken/cache to directories created on install
|
||||
Author: George Joseph
|
||||
Date: 2024-03-04
|
||||
|
||||
The default location for the stir_shaken cache is
|
||||
/var/lib/asterisk/keys/stir_shaken/cache but we were only creating
|
||||
/var/lib/asterisk/keys/stir_shaken on istall. We now create
|
||||
the cache sub-directory.
|
||||
|
||||
Resolves: #634
|
||||
|
||||
- ### Stir/Shaken Refactor
|
||||
Author: George Joseph
|
||||
Date: 2023-10-26
|
||||
|
||||
Why do we need a refactor?
|
||||
|
||||
The original stir/shaken implementation was started over 3 years ago
|
||||
when little was understood about practical implementation. The
|
||||
result was an implementation that wouldn't actually interoperate
|
||||
with any other stir-shaken implementations.
|
||||
|
||||
There were also a number of stir-shaken features and RFC
|
||||
requirements that were never implemented such as TNAuthList
|
||||
certificate validation, sending Reason headers in SIP responses
|
||||
when verification failed but we wished to continue the call, and
|
||||
the ability to send Media Key(mky) grants in the Identity header
|
||||
when the call involved DTLS.
|
||||
|
||||
Finally, there were some performance concerns around outgoing
|
||||
calls and selection of the correct certificate and private key.
|
||||
The configuration was keyed by an arbitrary name which meant that
|
||||
for every outgoing call, we had to scan the entire list of
|
||||
configured TNs to find the correct cert to use. With only a few
|
||||
TNs configured, this wasn't an issue but if you have a thousand,
|
||||
it could be.
|
||||
|
||||
What's changed?
|
||||
|
||||
* Configuration objects have been refactored to be clearer about
|
||||
their uses and to fix issues.
|
||||
* The "general" object was renamed to "verification" since it
|
||||
contains parameters specific to the incoming verification
|
||||
process. It also never handled ca_path and crl_path
|
||||
correctly.
|
||||
* A new "attestation" object was added that controls the
|
||||
outgoing attestation process. It sets default certificates,
|
||||
keys, etc.
|
||||
* The "certificate" object was renamed to "tn" and had it's key
|
||||
change to telephone number since outgoing call attestation
|
||||
needs to look up certificates by telephone number.
|
||||
* The "profile" object had more parameters added to it that can
|
||||
override default parameters specified in the "attestation"
|
||||
and "verification" objects.
|
||||
* The "store" object was removed altogther as it was never
|
||||
implemented.
|
||||
|
||||
* We now use libjwt to create outgoing Identity headers and to
|
||||
parse and validate signatures on incoming Identiy headers. Our
|
||||
previous custom implementation was much of the source of the
|
||||
interoperability issues.
|
||||
|
||||
* General code cleanup and refactor.
|
||||
* Moved things to better places.
|
||||
* Separated some of the complex functions to smaller ones.
|
||||
* Using context objects rather than passing tons of parameters
|
||||
in function calls.
|
||||
* Removed some complexity and unneeded encapsuation from the
|
||||
config objects.
|
||||
|
||||
Resolves: #351
|
||||
Resolves: #46
|
||||
|
||||
UserNote: Asterisk's stir-shaken feature has been refactored to
|
||||
correct interoperability, RFC compliance, and performance issues.
|
||||
See https://docs.asterisk.org/Deployment/STIR-SHAKEN for more
|
||||
information.
|
||||
|
||||
UpgradeNote: The stir-shaken refactor is a breaking change but since
|
||||
it's not working now we don't think it matters. The
|
||||
stir_shaken.conf file has changed significantly which means that
|
||||
existing ones WILL need to be changed. The stir_shaken.conf.sample
|
||||
file in configs/samples/ has quite a bit more information. This is
|
||||
also an ABI breaking change since some of the existing objects
|
||||
needed to be changed or removed, and new ones added. Additionally,
|
||||
if res_stir_shaken is enabled in menuselect, you'll need to either
|
||||
have the development package for libjwt v1.15.3 installed or use
|
||||
the --with-libjwt-bundled option with ./configure.
|
||||
|
||||
|
||||
- ### alembic: Synchronize alembic heads between supported branches.
|
||||
Author: Sean Bright
|
||||
Date: 2024-02-28
|
||||
|
||||
This adds a dummy migration to 18 and 20 so that our alembic heads are
|
||||
synchronized across all supported branches.
|
||||
|
||||
In this case the migration we are stubbing (24c12d8e9014) is:
|
||||
|
||||
https://github.com/asterisk/asterisk/commit/775352ee6c2a5bcd4f0e3df51aee5d1b0abf4cbe
|
||||
|
||||
- ### translate.c: implement new direct comp table mode
|
||||
Author: Sebastian Jennen
|
||||
Date: 2024-02-25
|
||||
|
||||
The new mode lists for each codec translation the actual real cost in cpu microseconds per second translated audio.
|
||||
This allows to compare the real cpu usage of translations and helps in evaluation of codec implementation changes regarding performance (regression testing).
|
||||
|
||||
- add new table mode
|
||||
- hide the 999999 comp values, as these only indicate an issue with transcoding
|
||||
- hide the 0 values, as these also do not contain any information (only indicate a multistep transcoding)
|
||||
|
||||
Resolves: #601
|
||||
|
||||
- ### README.md: Removed outdated link
|
||||
Author: Shyju Kanaprath
|
||||
Date: 2024-02-23
|
||||
|
||||
Removed outdated link http://www.quicknet.net from README.md
|
||||
|
||||
cherry-pick-to: 18
|
||||
cherry-pick-to: 20
|
||||
cherry-pick-to: 21
|
||||
|
||||
- ### strings.h: Ensure ast_str_buffer(…) returns a 0 terminated string.
|
||||
Author: Sean Bright
|
||||
Date: 2024-02-17
|
||||
|
||||
If a dynamic string is created with an initial length of 0,
|
||||
`ast_str_buffer(…)` will return an invalid pointer.
|
||||
|
||||
This was a secondary discovery when fixing #65.
|
||||
|
||||
|
||||
- ### res_rtp_asterisk.c: Correct coefficient in MOS calculation.
|
||||
Author: romryz
|
||||
Date: 2024-02-06
|
||||
|
||||
Media Experience Score relies on incorrect pseudo_mos variable
|
||||
calculation. According to forming an opinion section of the
|
||||
documentation, calculation relies on ITU-T G.107 standard:
|
||||
|
||||
https://docs.asterisk.org/Deployment/Media-Experience-Score/#forming-an-opinion
|
||||
|
||||
ITU-T G.107 Annex B suggests to calculate MOS with a coefficient
|
||||
"seven times ten to the power of negative six", 7 * 10^(-6). which
|
||||
would mean 6 digits after the decimal point. Current implementation
|
||||
has 7 digits after the decimal point, which downrates the calls.
|
||||
|
||||
Fixes: #597
|
||||
|
||||
- ### dsp.c: Fix and improve potentially inaccurate log message.
|
||||
Author: Naveen Albert
|
||||
Date: 2024-02-09
|
||||
|
||||
If ast_dsp_process is called with a codec besides slin, ulaw,
|
||||
or alaw, a warning is logged that in-band DTMF is not supported,
|
||||
but this message is not always appropriate or correct, because
|
||||
ast_dsp_process is much more generic than just DTMF detection.
|
||||
|
||||
This logs a more generic message in those cases, and also improves
|
||||
codec-mismatch logging throughout dsp.c by ensuring incompatible
|
||||
codecs are printed out.
|
||||
|
||||
Resolves: #595
|
||||
|
||||
- ### pjsip show channelstats: Prevent possible segfault when faxing
|
||||
Author: George Joseph
|
||||
Date: 2024-02-09
|
||||
|
||||
Under rare circumstances, it's possible for the original audio
|
||||
session in the active_media_state default_session to be corrupted
|
||||
instead of removed when switching to the t38/image media session
|
||||
during fax negotiation. This can cause a segfault when a "pjsip
|
||||
show channelstats" attempts to print that audio media session's
|
||||
rtp statistics. In these cases, the active_media_state
|
||||
topology is correctly showing only a single t38/image stream
|
||||
so we now check that there's an audio stream in the topology
|
||||
before attempting to use the audio media session to get the rtp
|
||||
statistics.
|
||||
|
||||
Resolves: #592
|
||||
|
||||
- ### Reduce startup/shutdown verbose logging
|
||||
Author: George Joseph
|
||||
Date: 2024-01-31
|
||||
|
||||
When started with a verbose level of 3, asterisk can emit over 1500
|
||||
verbose message that serve no real purpose other than to fill up
|
||||
logs. When asterisk shuts down, it emits another 1100 that are of
|
||||
even less use. Since the testsuite runs asterisk with a verbose
|
||||
level of 3, and asterisk starts and stops for every one of the 700+
|
||||
tests, the number of log messages is staggering. Besides taking up
|
||||
resources, it also makes it hard to debug failing tests.
|
||||
|
||||
This commit changes the log level for those verbose messages to 5
|
||||
instead of 3 which reduces the number of log messages to only a
|
||||
handful. Of course, NOTICE, WARNING and ERROR message are
|
||||
unaffected.
|
||||
|
||||
There's also one other minor change...
|
||||
ast_context_remove_extension_callerid2() logs a DEBUG message
|
||||
instead of an ERROR if the extension you're deleting doesn't exist.
|
||||
The pjsip_config_wizard calls that function to clean up the config
|
||||
and has been triggering that annoying error message for years.
|
||||
|
||||
Resolves: #582
|
||||
|
||||
- ### configure: Rerun bootstrap on modern platform.
|
||||
Author: Naveen Albert
|
||||
Date: 2024-02-12
|
||||
|
||||
The last time configure was run, it was run on a system that
|
||||
did not enable -std=gnu11 by default, which meant that the
|
||||
restrict qualifier would not be recognized on certain platforms.
|
||||
This regenerates the configure files from running bootstrap.sh,
|
||||
so that these should be recognized on all supported platforms.
|
||||
|
||||
Resolves: #586
|
||||
|
||||
- ### Upgrade bundled pjproject to 2.14.
|
||||
Author: Ben Ford
|
||||
Date: 2024-02-05
|
||||
|
||||
Fixes: #406
|
||||
|
||||
UserNote: Bundled pjproject has been upgraded to 2.14. For more
|
||||
information on what all is included in this change, check out the
|
||||
pjproject Github page: https://github.com/pjsip/pjproject/releases
|
||||
|
||||
|
||||
- ### app_speech_utils.c: Allow partial speech results.
|
||||
Author: cmaj
|
||||
Date: 2024-02-02
|
||||
|
||||
Adds 'p' option to SpeechBackground() application.
|
||||
With this option, when the app timeout is reached,
|
||||
whatever the backend speech engine collected will
|
||||
be returned as if it were the final, full result.
|
||||
(This works for engines that make partial results.)
|
||||
|
||||
Resolves: #572
|
||||
|
||||
UserNote: The SpeechBackground dialplan application now supports a 'p'
|
||||
option that will return partial results from speech engines that
|
||||
provide them when a timeout occurs.
|
||||
|
||||
|
||||
- ### utils: Make behavior of ast_strsep* match strsep.
|
||||
Author: Joshua C. Colp
|
||||
Date: 2024-01-31
|
||||
|
||||
Given the scenario of passing an empty string to the
|
||||
ast_strsep functions the functions would return NULL
|
||||
instead of an empty string. This is counter to how
|
||||
strsep itself works.
|
||||
|
||||
This change alters the behavior of the functions to
|
||||
match that of strsep.
|
||||
|
||||
Fixes: #565
|
||||
|
||||
- ### app_chanspy: Add 'D' option for dual-channel audio
|
||||
Author: Mike Bradeen
|
||||
Date: 2024-01-31
|
||||
|
||||
Adds the 'D' option to app chanspy that causes the input and output
|
||||
frames of the spied channel to be interleaved in the spy output frame.
|
||||
This allows the input and output of the spied channel to be decoded
|
||||
separately by the receiver.
|
||||
|
||||
If the 'o' option is also set, the 'D' option is ignored as the
|
||||
audio being spied is inherently one direction.
|
||||
|
||||
Fixes: #569
|
||||
|
||||
UserNote: The ChanSpy application now accepts the 'D' option which
|
||||
will interleave the spied audio within the outgoing frames. The
|
||||
purpose of this is to allow the audio to be read as a Dual channel
|
||||
stream with separate incoming and outgoing audio. Setting both the
|
||||
'o' option and the 'D' option and results in the 'D' option being
|
||||
ignored.
|
||||
|
||||
|
||||
- ### app_if: Fix next priority calculation.
|
||||
Author: Naveen Albert
|
||||
Date: 2024-01-28
|
||||
|
||||
Commit fa3922a4d28860d415614347d9f06c233d2beb07 fixed
|
||||
a branching issue but "overshoots" when calculating
|
||||
the next priority. This fixes that; accompanying
|
||||
test suite tests have also been extended.
|
||||
|
||||
Resolves: #560
|
||||
|
||||
- ### res_pjsip_t38.c: Permit IPv6 SDP connection addresses.
|
||||
Author: Sean Bright
|
||||
Date: 2024-01-29
|
||||
|
||||
The existing code prevented IPv6 addresses from being properly parsed.
|
||||
|
||||
Fixes #558
|
||||
|
||||
|
||||
- ### BuildSystem: Bump autotools versions on OpenBSD.
|
||||
Author: Brad Smith
|
||||
Date: 2024-01-27
|
||||
|
||||
Bump up to the more commonly used and modern versions of
|
||||
autoconf and automake.
|
||||
|
||||
|
||||
- ### main/utils: Simplify the FreeBSD ast_get_tid() handling
|
||||
Author: Brad Smith
|
||||
Date: 2024-01-27
|
||||
|
||||
FreeBSD has had kernel threads for 20+ years.
|
||||
|
||||
|
||||
- ### res_pjsip_session.c: Correctly format SDP connection addresses.
|
||||
Author: Sean Bright
|
||||
Date: 2024-01-27
|
||||
|
||||
Resolves a regression identified by @justinludwig involving the
|
||||
rendering of IPv6 addresses in outgoing SDP.
|
||||
|
||||
Also updates `media_address` on PJSIP endpoints so that if we are able
|
||||
to parse the configured value as an IP we store it in a format that we
|
||||
can directly use later. Based on my reading of the code it appeared
|
||||
that one could configure `media_address` as:
|
||||
|
||||
```
|
||||
[foo]
|
||||
type = endpoint
|
||||
...
|
||||
media_address = [2001:db8::]
|
||||
```
|
||||
|
||||
And that value would be blindly copied into the outgoing SDP without
|
||||
regard to its format.
|
||||
|
||||
Fixes #541
|
||||
|
||||
|
||||
- ### rtp_engine.c: Correct sample rate typo for L16/44100.
|
||||
Author: Sean Bright
|
||||
Date: 2024-01-28
|
||||
|
||||
Fixes #555
|
||||
|
||||
|
||||
- ### manager.c: Fix erroneous reloads in UpdateConfig.
|
||||
Author: Naveen Albert
|
||||
Date: 2024-01-25
|
||||
|
||||
Currently, a reload will always occur if the
|
||||
Reload header is provided for the UpdateConfig
|
||||
action. However, we should not be doing a reload
|
||||
if the header value has a falsy value, per the
|
||||
documentation, so this makes the reload behavior
|
||||
consistent with the existing documentation.
|
||||
|
||||
Resolves: #551
|
||||
|
||||
- ### res_calendar_icalendar: Print iCalendar error on parsing failure.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-12-14
|
||||
|
||||
If libical fails to parse a calendar, print the error message it provdes.
|
||||
|
||||
Resolves: #492
|
||||
|
||||
- ### app_confbridge: Don't emit warnings on valid configurations.
|
||||
Author: Sean Bright
|
||||
Date: 2024-01-21
|
||||
|
||||
The numeric bridge profile options `internal_sample_rate` and
|
||||
`maximum_sample_rate` are documented to accept the special values
|
||||
`auto` and `none`, respectively. While these values currently work,
|
||||
they also emit warnings when used which could be confusing for users.
|
||||
|
||||
In passing, also ensure that we only accept the documented range of
|
||||
sample rate values between 8000 and 192000.
|
||||
|
||||
Fixes #546
|
||||
|
||||
|
||||
- ### app_voicemail: add NoOp alembic script to maintain sync
|
||||
Author: Mike Bradeen
|
||||
Date: 2024-01-17
|
||||
|
||||
Adding a NoOp alembic script for the voicemail database to maintain
|
||||
version sync with other branches.
|
||||
|
||||
Fixes: #527
|
||||
|
||||
- ### chan_dahdi: Allow MWI to be manually toggled on channels.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-11-10
|
||||
|
||||
This adds a CLI command to manually toggle the MWI status
|
||||
of a channel, useful for troubleshooting or resetting
|
||||
MWI devices, similar to the capabilities offered with
|
||||
SIP messaging to manually control MWI status.
|
||||
|
||||
UserNote: The 'dahdi set mwi' now allows MWI on channels
|
||||
to be manually toggled if needed for troubleshooting.
|
||||
|
||||
Resolves: #440
|
||||
|
||||
- ### chan_rtp.c: MulticastRTP missing refcount without codec option
|
||||
Author: PeterHolik
|
||||
Date: 2024-01-15
|
||||
|
||||
Fixes: #529
|
||||
|
||||
- ### chan_rtp.c: Change MulticastRTP nameing to avoid memory leak
|
||||
Author: PeterHolik
|
||||
Date: 2024-01-16
|
||||
|
||||
Fixes: asterisk#536
|
||||
|
||||
- ### func_frame_trace: Add CLI command to dump frame queue.
|
||||
Author: Naveen Albert
|
||||
Date: 2024-01-12
|
||||
|
||||
This adds a simple CLI command that can be used for
|
||||
analyzing all frames currently queued to a channel.
|
||||
|
||||
A couple log messages are also adjusted to be more
|
||||
useful in tracing bridging problems.
|
||||
|
||||
Resolves: #533
|
||||
|
|
@ -12,10 +12,316 @@
|
|||
===
|
||||
==============================================================================
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
--- Functionality changes from Asterisk 20.1.0 to Asterisk 20.2.0 ------------
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
app_broadcast
|
||||
------------------
|
||||
* A Broadcast application is now available which allows
|
||||
for asynchronous one-to-many and many-to-one channel audio.
|
||||
|
||||
app_directory
|
||||
------------------
|
||||
* A new option 's' has been added to the Directory() application that
|
||||
will skip calling the extension and instead set the extension as
|
||||
DIRECTORY_EXTEN channel variable.
|
||||
|
||||
app_read
|
||||
------------------
|
||||
* A new option 'e' has been added to allow Read() to return the
|
||||
terminator as the dialed digits in the case where only the terminator
|
||||
is entered.
|
||||
|
||||
app_senddtmf
|
||||
------------------
|
||||
* A new option has been added to SendDTMF() which will answer the
|
||||
specified channel if it is not already up. If no channel is specified,
|
||||
the current channel will be answered instead.
|
||||
|
||||
app_signal
|
||||
------------------
|
||||
* Adds Signal and WaitForSignal applications
|
||||
which can be used for signaling or as a
|
||||
simple message queue in the dialplan.
|
||||
|
||||
func_json
|
||||
------------------
|
||||
* Additional parsing capabilities have been added to the
|
||||
JSON_DECODE function, including support for arrays
|
||||
and recursive indexing.
|
||||
|
||||
res_phoneprov
|
||||
------------------
|
||||
* On multihomed Asterisk servers with dynamic SERVER template variables,
|
||||
reloading this module is no longer required when re-provisioning your
|
||||
phone to another interface address (e.g. when moving between VLANs.)
|
||||
|
||||
res_pjsip_rfc3326
|
||||
------------------
|
||||
* Add ability to set HANGUPCAUSE when SIP causecode received in BYE Reason header (in
|
||||
addition to currently supported Q.850). The first header found will be used to set
|
||||
the HANGUPCAUSE variable.
|
||||
|
||||
res_pjsip_session
|
||||
------------------
|
||||
* The overlap_context option now allows explicitly
|
||||
specifying a context to use for overlap dialing matches.
|
||||
|
||||
res_rtp_asterisk
|
||||
------------------
|
||||
* This module has been updated to provide additional
|
||||
quality statistics in the form of an Asterisk
|
||||
Media Experience Score. The score is available using
|
||||
the same mechanisms you'd use to retrieve jitter, loss,
|
||||
and rtt statistics. For more information about the
|
||||
score and how to retrieve it, see
|
||||
https://wiki.asterisk.org/wiki/display/AST/Media+Experience+Score
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
--- Functionality changes from Asterisk 20.0.0 to Asterisk 20.1.0 ------------
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
AMI
|
||||
------------------
|
||||
* The AOCMessage action can now be used to generate AOC-S messages.
|
||||
|
||||
Add support for named capture agent.
|
||||
------------------
|
||||
* A name for the capture agent can now be specified
|
||||
using the capture_name option which, if specified,
|
||||
will be sent to the HEP server.
|
||||
|
||||
app_if
|
||||
------------------
|
||||
* Adds the If, ElseIf, Else, EndIf, and ExitIf applications
|
||||
for conditional execution of a block of code.
|
||||
|
||||
app_mixmonitor
|
||||
------------------
|
||||
* The d option for MixMonitor now allows deleting
|
||||
the original recording when MixMonitor exits,
|
||||
which can be useful when MixMonitor copies it
|
||||
somewhere else before exiting.
|
||||
|
||||
* Adds the c option to use the real Caller ID on
|
||||
the channel in voicemail recordings as opposed
|
||||
to the Connected Line.
|
||||
|
||||
app_voicemail
|
||||
------------------
|
||||
* The voicemail user option attachextrecs can
|
||||
now be set to control whether external recordings
|
||||
trigger voicemail email notifications.
|
||||
|
||||
cdr
|
||||
------------------
|
||||
* Two new options have been added which allow
|
||||
bridging and dial state changes to be ignored
|
||||
in CDRs, which can be useful if a single CDR
|
||||
is desired for a channel.
|
||||
|
||||
chan_dahdi
|
||||
------------------
|
||||
* FXO channels (FXS signaled) that don't use callerid or
|
||||
distinctive ring detection can now be configured
|
||||
to enter the dialplan immediately using immediate=yes,
|
||||
instead of waiting for at least one ring.
|
||||
|
||||
pbx_builtins
|
||||
------------------
|
||||
* It is now possible to not wait for media on
|
||||
a channel when answering it using Answer,
|
||||
by specifying the i option.
|
||||
|
||||
res_pjsip
|
||||
------------------
|
||||
* Added options "security_negotiation" and "security_mechanisms" to pjsip
|
||||
endpoints and registrations. "security_negotiation" can be set to "no" (default)
|
||||
or "mediasec", and "security_mechanisms" can be a list of comma-separated
|
||||
security_mechanisms in the form defined by RFC 3329 section 2.2.
|
||||
|
||||
* A new option named "all_codecs_on_empty_reinvite" has been added to the
|
||||
global section. When this option is enabled, on reception of a re-INVITE
|
||||
without SDP, Asterisk will send an SDP offer in the 200 OK response containing
|
||||
all configured codecs on the endpoint, instead of simply those that have
|
||||
already been negotiated. RFC 3261 specifies this as a SHOULD requirement.
|
||||
The default value is "off".
|
||||
|
||||
res_pjsip_aoc
|
||||
------------------
|
||||
* Added res_pjsip_aoc which gives chan_pjsip the ability to send Advice-of-Charge messages.
|
||||
A new endpoint option, send_aoc, controls this.
|
||||
|
||||
res_pjsip_header_funcs
|
||||
------------------
|
||||
* The new PJSIP_HEADER_PARAM function now fully supports both
|
||||
URI and header parameters. Both reading and writing
|
||||
parameters are supported.
|
||||
|
||||
res_pjsip_logger
|
||||
------------------
|
||||
* SIP messages can now be filtered by SIP request method
|
||||
(INVITE, CANCEL, ACK, BYE, REGISTER, OPTION,
|
||||
SUBSCRIBE, NOTIFY, PUBLISH, INFO, and MESSAGE),
|
||||
allowing for more granular debugging to be done
|
||||
in the CLI. This applies to requests but not responses.
|
||||
|
||||
res_pjsip_notify
|
||||
------------------
|
||||
* Allows using the config options in pjsip_notify.conf
|
||||
from AMI actions as with the existing CLI commands.
|
||||
|
||||
res_tonedetect
|
||||
------------------
|
||||
* The TONE_DETECT function now supports
|
||||
detection of audible ringback tone
|
||||
using the p option.
|
||||
|
||||
xmldocs
|
||||
------------------
|
||||
* The XML documentation can now be reloaded without restarting
|
||||
Asterisk, which makes it possible to load new modules that
|
||||
enforce documentation without restarting Asterisk.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
--- Functionality changes from Asterisk 19.0.0 to Asterisk 20.0.0 ------------
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
New EXPORT function
|
||||
------------------
|
||||
* A new function, EXPORT, allows writing variables
|
||||
and functions on other channels, the complement
|
||||
of the IMPORT function.
|
||||
|
||||
app_amd
|
||||
------------------
|
||||
* An audio file to play during AMD processing can
|
||||
now be specified to the AMD application or configured
|
||||
in the amd.conf configuration file.
|
||||
|
||||
app_bridgewait
|
||||
------------------
|
||||
* Adds the n option to not answer the channel when
|
||||
the BridgeWait application is called.
|
||||
|
||||
features
|
||||
------------------
|
||||
* The Bridge application now has the n "no answer" option
|
||||
that can be used to prevent the channel from being
|
||||
automatically answered prior to bridging.
|
||||
|
||||
func_strings
|
||||
------------------
|
||||
* Three new functions, TRIM, LTRIM, and RTRIM, are
|
||||
now available for trimming leading and trailing
|
||||
whitespace.
|
||||
|
||||
res_pjsip
|
||||
------------------
|
||||
* A new option named "peer_supported" has been added to the endpoint option
|
||||
100rel. When set to this option, Asterisk sends provisional responses
|
||||
reliably if the peer supports it. If the peer does not support reliable
|
||||
provisional responses, Asterisk sends them normally.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
--- Functionality changes from Asterisk 19.0.0 to Asterisk 20.0.0 ------------
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
Transfer feature
|
||||
------------------
|
||||
* The following capabilities have been added to the
|
||||
transfer feature:
|
||||
|
||||
- The transfer initiation announcement prompt can
|
||||
now be customized in features.conf.
|
||||
|
||||
- The TRANSFER_EXTEN variable now can be set on the
|
||||
transferer's channel in order to allow the transfer
|
||||
function to automatically attempt to go to the extension
|
||||
contained in this variable, if it exists. The transfer
|
||||
context behavior is not changed (TRANSFER_CONTEXT is used
|
||||
if it exists; otherwise the default context is used).
|
||||
|
||||
app_confbridge
|
||||
------------------
|
||||
* Adds the end_marked_any option which can be used
|
||||
to kick users from a conference after any
|
||||
marked user leaves (including marked users).
|
||||
|
||||
db
|
||||
------------------
|
||||
* The DBPrefixGet AMI action now allows retrieving
|
||||
all of the DB keys beginning with a particular
|
||||
prefix.
|
||||
|
||||
locks
|
||||
------------------
|
||||
* A new AMI event, DeadlockStart, is now available
|
||||
when Asterisk is compiled with DETECT_DEADLOCKS,
|
||||
and can indicate that a deadlock has occured.
|
||||
|
||||
res_geolocation
|
||||
------------------
|
||||
* * Added processing for the 'confidence' element.
|
||||
* Added documentation to some APIs.
|
||||
* removed a lot of complex code related to the very-off-nominal
|
||||
case of needing to process multiple location info sources.
|
||||
* Create a new 'ast_geoloc_eprofile_to_pidf' API that just takes
|
||||
one eprofile instead of a datastore of multiples.
|
||||
* Plugged a huge leak in XML processing that arose from
|
||||
insufficient documentation by the libxml/libxslt authors.
|
||||
* Refactored stylesheets to be more efficient.
|
||||
* Renamed 'profile_action' to 'profile_precedence' to better
|
||||
reflect it's purpose.
|
||||
* Added the config option for 'allow_routing_use' which
|
||||
sets the value of the 'Geolocation-Routing' header.
|
||||
* Removed the GeolocProfileCreate and GeolocProfileDelete
|
||||
dialplan apps.
|
||||
* Changed the GEOLOC_PROFILE dialplan function as follows:
|
||||
* Removed the 'profile' argument.
|
||||
* Automatically create a profile if it doesn't exist.
|
||||
* Delete a profile if 'inheritable' is set to no.
|
||||
* Fixed various bugs and leaks
|
||||
* Updated Asterisk WiKi documentation.
|
||||
|
||||
Added 4 built-in profiles:
|
||||
"<prefer_config>"
|
||||
"<discard_config>"
|
||||
"<prefer_incoming>"
|
||||
"<discard_incoming>"
|
||||
The profiles are empty except for having their precedence
|
||||
set.
|
||||
|
||||
Added profile parameter "suppress_empty_ca_elements" that
|
||||
will cause Civic Address elements that are empty to be
|
||||
suppressed from the outgoing PIDF-LO document.
|
||||
|
||||
You can now specify the location object's format, location_info,
|
||||
method, location_source and confidence parameters directly on
|
||||
a profile object for simple scenarios where the location
|
||||
information isn't common with any other profiles. This is
|
||||
mutually exclusive with setting location_reference on the
|
||||
profile.
|
||||
|
||||
Added an 'a' option to the GEOLOC_PROFILE function to allow
|
||||
variable lists like location_info_refinement to be appended
|
||||
to instead of replacing the entire list.
|
||||
|
||||
Added an 'r' option to the GEOLOC_PROFILE function to resolve all
|
||||
variables before a read operation and after a Set operation.
|
||||
|
||||
res_musiconhold_answeredonly
|
||||
------------------
|
||||
* This change adds an option, answeredonly, that will prevent music
|
||||
on hold on channels that are not answered.
|
||||
|
||||
res_pjsip
|
||||
------------------
|
||||
* TLS transports in res_pjsip can now reload their TLS certificate
|
||||
and private key files, provided the filename of them has not
|
||||
changed.
|
||||
|
||||
Applications
|
||||
------------------
|
||||
* added support for Danish syntax, playing the correct plural sound file
|
File diff suppressed because it is too large
Load Diff
2
LICENSE
2
LICENSE
|
@ -45,7 +45,7 @@ redistribution of Asterisk source code obtained from Digium, you
|
|||
should contact our licensing department to determine the necessary
|
||||
steps you must take. For more information on this policy, please read:
|
||||
|
||||
https://www.sangoma.com/wp-content/uploads/Sangoma-Trademark-Policy.pdf
|
||||
https://www.sangoma.com/wp-content/uploads/Sangoma-Trademark-Policy-1.pdf
|
||||
|
||||
If you have any questions regarding our licensing policy, please
|
||||
contact us:
|
||||
|
|
15
Makefile
15
Makefile
|
@ -377,7 +377,7 @@ $(MOD_SUBDIRS_MENUSELECT_TREE):
|
|||
+@$(SUBMAKE) -C $(@:-menuselect-tree=) SUBDIR=$(@:-menuselect-tree=) moduleinfo
|
||||
+@$(SUBMAKE) -C $(@:-menuselect-tree=) SUBDIR=$(@:-menuselect-tree=) makeopts
|
||||
|
||||
$(SUBDIRS): makeopts .lastclean main/version.c include/asterisk/build.h include/asterisk/buildopts.h defaults.h
|
||||
$(SUBDIRS): makeopts .lastclean main/version.c include/asterisk/build.h defaults.h
|
||||
|
||||
ifeq ($(findstring $(OSARCH), mingw32 cygwin ),)
|
||||
main: third-party
|
||||
|
@ -403,7 +403,7 @@ defaults.h: makeopts .lastclean build_tools/make_defaults_h
|
|||
@cmp -s $@.tmp $@ || mv $@.tmp $@
|
||||
@rm -f $@.tmp
|
||||
|
||||
main/version.c: FORCE menuselect.makeopts .lastclean
|
||||
main/version.c: FORCE include/asterisk/buildopts.h menuselect.makeopts .lastclean
|
||||
@build_tools/make_version_c > $@.tmp
|
||||
@cmp -s $@.tmp $@ || mv $@.tmp $@
|
||||
@rm -f $@.tmp
|
||||
|
@ -545,7 +545,7 @@ INSTALLDIRS="$(ASTLIBDIR)" "$(ASTMODDIR)" "$(ASTSBINDIR)" "$(ASTCACHEDIR)" "$(AS
|
|||
"$(ASTDATADIR)/firmware/iax" "$(ASTDATADIR)/images" "$(ASTDATADIR)/keys" \
|
||||
"$(ASTDATADIR)/phoneprov" "$(ASTDATADIR)/rest-api" "$(ASTDATADIR)/static-http" \
|
||||
"$(ASTDATADIR)/sounds" "$(ASTDATADIR)/moh" "$(ASTMANDIR)/man8" "$(AGI_DIR)" "$(ASTDBDIR)" \
|
||||
"$(ASTDATADIR)/third-party" "${ASTDATADIR}/keys/stir_shaken"
|
||||
"$(ASTDATADIR)/third-party" "${ASTDATADIR}/keys/stir_shaken" "${ASTDATADIR}/keys/stir_shaken/cache"
|
||||
|
||||
installdirs:
|
||||
@for i in $(INSTALLDIRS); do \
|
||||
|
@ -561,9 +561,9 @@ bininstall: _all installdirs $(SUBDIRS_INSTALL) main-bininstall
|
|||
$(INSTALL) -m 755 contrib/scripts/astversion "$(DESTDIR)$(ASTSBINDIR)/"
|
||||
$(INSTALL) -m 755 contrib/scripts/astgenkey "$(DESTDIR)$(ASTSBINDIR)/"
|
||||
$(INSTALL) -m 755 contrib/scripts/autosupport "$(DESTDIR)$(ASTSBINDIR)/"
|
||||
if [ ! -f /sbin/launchd ]; then \
|
||||
./build_tools/install_subst contrib/scripts/safe_asterisk "$(DESTDIR)$(ASTSBINDIR)/safe_asterisk"; \
|
||||
fi
|
||||
ifneq ($(HAVE_SBIN_LAUNCHD),1)
|
||||
./build_tools/install_subst contrib/scripts/safe_asterisk "$(DESTDIR)$(ASTSBINDIR)/safe_asterisk";
|
||||
endif
|
||||
|
||||
ifneq ($(DISABLE_XMLDOC),yes)
|
||||
$(INSTALL) -m 644 doc/core-*.xml "$(DESTDIR)$(ASTDATADIR)/documentation"
|
||||
|
@ -1119,7 +1119,8 @@ ifeq ($(PYTHON),:)
|
|||
else
|
||||
@$(INSTALL) -d doc/rest-api
|
||||
$(PYTHON) rest-api-templates/make_ari_stubs.py \
|
||||
rest-api/resources.json .
|
||||
--resources rest-api/resources.json --source-dir $(ASTTOPDIR) \
|
||||
--dest-dir $(ASTTOPDIR)/doc/rest-api --docs-prefix ../
|
||||
endif
|
||||
|
||||
check-alembic: makeopts
|
||||
|
|
|
@ -213,10 +213,10 @@ endif
|
|||
# extern const size_t _binary_abc_def_xml_size;
|
||||
%.o: %.xml
|
||||
$(ECHO_PREFIX) echo " [LD] $^ -> $@"
|
||||
$(CMD_PREFIX) $(CC) -g -nostartfiles -nodefaultlibs -nostdlib -r -Wl,-b,binary -o $@ $^
|
||||
$(CMD_PREFIX) $(CC) -g -Wl,-znoexecstack -nostartfiles -nodefaultlibs -nostdlib -r -Wl,-b,binary -o $@ $^
|
||||
|
||||
%.o: %.xslt
|
||||
$(ECHO_PREFIX) echo " [LD] $^ -> $@"
|
||||
$(CMD_PREFIX) $(CC) -g -nostartfiles -nodefaultlibs -nostdlib -r -Wl,-b,binary -o $@ $^
|
||||
$(CMD_PREFIX) $(CC) -g -Wl,-znoexecstack -nostartfiles -nodefaultlibs -nostdlib -r -Wl,-b,binary -o $@ $^
|
||||
|
||||
dist-clean:: clean
|
||||
|
|
|
@ -377,9 +377,8 @@ is set to no.
|
|||
|
||||
In Asterisk 12 and later, live_dangerously defaults to no.
|
||||
|
||||
|
||||
[voip-security-webinar]: https://www.asterisk.org/security/webinar/
|
||||
[blog-sip-security]: http://blogs.digium.com/2009/03/28/sip-security/
|
||||
[voip-security-webinar]: https://docs.asterisk.org/Deployment/Important-Security-Considerations/Asterisk-Security-Webinars/
|
||||
[blog-sip-security]: https://web.archive.org/web/20171030134647/http://blogs.digium.com/2009/03/28/sip-security/
|
||||
[Strong Password Generator]: https://www.strongpasswordgenerator.com
|
||||
[Filtering Data]: #filtering-data
|
||||
[Proper Device Naming]: #proper-device-naming
|
||||
|
@ -387,4 +386,4 @@ In Asterisk 12 and later, live_dangerously defaults to no.
|
|||
[Reducing Pattern Match Typos]: #reducing-pattern-match-typos
|
||||
[Manager Class Authorizations]: #manager-class-authorizations
|
||||
[Avoid Privilege Escalations]: #avoid-privilege-escalations
|
||||
[Important Security Considerations]: https://wiki.asterisk.org/wiki/display/AST/Important+Security+Considerations
|
||||
[Important Security Considerations]: https://docs.asterisk.org/Deployment/Important-Security-Considerations/
|
||||
|
|
|
@ -20,7 +20,7 @@ more telephony interfaces than just Internet telephony. Asterisk also has a
|
|||
vast amount of support for traditional PSTN telephony, as well.
|
||||
|
||||
For more information on the project itself, please visit the Asterisk
|
||||
[home page] and the official [wiki]. In addition you'll find lots
|
||||
[home page] and the official [documentation]. In addition you'll find lots
|
||||
of information compiled by the Asterisk community at [voip-info.org].
|
||||
|
||||
There is a book on Asterisk published by O'Reilly under the Creative Commons
|
||||
|
@ -48,7 +48,7 @@ ANY special hardware, not even a sound card) to install and run Asterisk.
|
|||
|
||||
Supported telephony hardware includes:
|
||||
* All Analog and Digital Interface cards from [Sangoma]
|
||||
* QuickNet Internet PhoneJack and LineJack (http://www.quicknet.net)
|
||||
* QuickNet Internet PhoneJack and LineJack
|
||||
* any full duplex sound card supported by ALSA, OSS, or PortAudio
|
||||
* any ISDN card supported by mISDN on Linux
|
||||
* The Xorcom Astribank channel bank
|
||||
|
@ -258,7 +258,7 @@ Asterisk is a trademark of Sangoma Technologies Corporation
|
|||
|
||||
[home page]: https://www.asterisk.org
|
||||
[support]: https://www.asterisk.org/support
|
||||
[wiki]: https://wiki.asterisk.org/
|
||||
[documentation]: https://docs.asterisk.org/
|
||||
[mailing list]: http://lists.digium.com/mailman/listinfo/asterisk-users
|
||||
[chan_dahdi.conf]: configs/samples/chan_dahdi.conf.sample
|
||||
[voip-info.org]: http://www.voip-info.org/wiki-Asterisk
|
||||
|
@ -269,4 +269,4 @@ Asterisk is a trademark of Sangoma Technologies Corporation
|
|||
[CHANGES]: CHANGES
|
||||
[configs]: configs
|
||||
[doc]: doc
|
||||
[Important Security Considerations]: https://wiki.asterisk.org/wiki/display/AST/Important+Security+Considerations
|
||||
[Important Security Considerations]: https://docs.asterisk.org/Deployment/Important-Security-Considerations/
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
The Asterisk project maintains a [documentation page](https://docs.asterisk.org/About-the-Project/Asterisk-Versions/) of releases. Each version is listed with its release date, security fix only date, and end of life date. Consult this wiki page to see if the version of Asterisk you are reporting a security vulnerability against is still supported.
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
To report a vulnerability use the "Report a vulnerability" button under the "Security" tab of this project.
|
2986
UPGRADE.txt
2986
UPGRADE.txt
File diff suppressed because it is too large
Load Diff
|
@ -192,11 +192,13 @@ EXTERN int ooQ931Decode
|
|||
screening indicators ;-) */
|
||||
if(ie->discriminator == Q931CallingPartyNumberIE)
|
||||
{
|
||||
int numoffset=1;
|
||||
OOTRACEDBGB1(" CallingPartyNumber IE = {\n");
|
||||
if(ie->length < OO_MAX_NUMBER_LENGTH)
|
||||
if(!(0x80 & ie->data[0])) numoffset = 2;
|
||||
|
||||
if( (ie->length >= numoffset) &&
|
||||
(ie->length < OO_MAX_NUMBER_LENGTH) )
|
||||
{
|
||||
int numoffset=1;
|
||||
if(!(0x80 & ie->data[0])) numoffset = 2;
|
||||
memcpy(number, ie->data+numoffset,ie->length-numoffset);
|
||||
number[ie->length-numoffset]='\0';
|
||||
OOTRACEDBGB2(" %s\n", number);
|
||||
|
@ -204,7 +206,7 @@ EXTERN int ooQ931Decode
|
|||
ooCallSetCallingPartyNumber(call, number);
|
||||
}
|
||||
else{
|
||||
OOTRACEERR3("Error:Calling party number too long. (%s, %s)\n",
|
||||
OOTRACEERR3("Error:Calling party number outside range. (%s, %s)\n",
|
||||
call->callType, call->callToken);
|
||||
}
|
||||
OOTRACEDBGB1(" }\n");
|
||||
|
@ -214,7 +216,8 @@ EXTERN int ooQ931Decode
|
|||
if(ie->discriminator == Q931CalledPartyNumberIE)
|
||||
{
|
||||
OOTRACEDBGB1(" CalledPartyNumber IE = {\n");
|
||||
if(ie->length < OO_MAX_NUMBER_LENGTH)
|
||||
if( (ie->length >= 1) &&
|
||||
(ie->length < OO_MAX_NUMBER_LENGTH) )
|
||||
{
|
||||
memcpy(number, ie->data+1,ie->length-1);
|
||||
number[ie->length-1]='\0';
|
||||
|
@ -223,7 +226,7 @@ EXTERN int ooQ931Decode
|
|||
ooCallSetCalledPartyNumber(call, number);
|
||||
}
|
||||
else{
|
||||
OOTRACEERR3("Error:Calling party number too long. (%s, %s)\n",
|
||||
OOTRACEERR3("Error:Calling party number outside range. (%s, %s)\n",
|
||||
call->callType, call->callToken);
|
||||
}
|
||||
OOTRACEDBGB1(" }\n");
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
ami_test_client
|
|
@ -0,0 +1,339 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
|
@ -0,0 +1,20 @@
|
|||
CC = gcc
|
||||
CFLAGS = -Wall -ggdb -Ilibc-jss
|
||||
LDFLAGS = -lev -lm -lcrypto
|
||||
|
||||
OBJ=ami.o originate.o libc-jss/netsocket.o libc-jss/logger.o libc-jss/misc.o milenage.o
|
||||
PROGS=ami_test_client
|
||||
|
||||
.PHONY: all
|
||||
all: $(patsubst %, %.o, $(PROGS)) $(OBJ) $(PROGS)
|
||||
|
||||
%: %.o $(OBJ)
|
||||
gcc $(CFLAGS) -o $@ $< $(OBJ) $(LDFLAGS)
|
||||
|
||||
clean:
|
||||
rm -f *.o $(OBJ) $(PROGS)
|
||||
|
||||
volcon.o: volcon.c volcon_config.h
|
||||
|
||||
install: compile
|
||||
install -s volcon /usr/local/bin
|
|
@ -0,0 +1,69 @@
|
|||
BUGOK:
|
||||
- Asterisk 1.4 esetén az originate.c rossz Hangup-cause kódot ad vissza, ha Zap
|
||||
csatornán indítjuk a hívást. Rendre 19-et ad vissza. Nem az originate.c
|
||||
hibája, mert az AMI dumpban is 19 látszódik. Local csatornán rendben működik.
|
||||
|
||||
TODO:
|
||||
-első körben tesztelni kéne az ami.c-t a test_ami.c -vel. Írni valami kis célprogramot! pl. mellék állapot listázás
|
||||
-ami.c-ben ami_event_list_t átnevezése valami kultúráltabb típusnévre, mert ez az API-ban megjelenik
|
||||
-időzítőt betenni, hogy ha megszakad a kapcsolat az Asteriskkel, akkor ping timeout legyen
|
||||
-időzítőt betenni, ami törlődik a sikeres authentikációnál
|
||||
-Asterisk Call Manager/1.1 fejléc megérkezése előtt senki nem írhat az AMI socketre, mert ez lesz:
|
||||
Asterisk Call Manager/1.1
|
||||
Response: Error
|
||||
ActionID: 1
|
||||
Message: Missing action in request
|
||||
-CLI response és az olyan több csomagos válaszok, mint pl. a DongleShowDevices kezelése
|
||||
-ami_action-t ne lehessen regisztrálni, amíg nincs connected állapot
|
||||
(vigyázni a beépített authentication ami_action-re!)
|
||||
-ami_connect legyen hatástlan, ha már épp kapcsolódik vagy kapcsolódva van
|
||||
-ami_event_unregister megírása
|
||||
-ami dump events: response kulonvalasztasa
|
||||
-event es response kulonvalasztasa keresesnel
|
||||
-megvizsgálni, hogy az originate.c egyszerűbben működhet -e a linkedid változóval?
|
||||
-Asterisk 1.4-et dobni, mert nem kell!
|
||||
|
||||
CLI formátum:
|
||||
action: command
|
||||
command: sip show domains
|
||||
|
||||
Response: Follows
|
||||
Privilege: Command
|
||||
SIP Domain support not enabled.
|
||||
|
||||
--END COMMAND--
|
||||
|
||||
|
||||
SMS küldése
|
||||
action: DongleSendPDU
|
||||
ActionID: 59
|
||||
Device: dongle0
|
||||
PDU: 0031000B816002660304F000000010C8329BFD061DA74DD0F52D679343
|
||||
|
||||
Válasz a várakozósorból
|
||||
Response: Success
|
||||
ActionID: 59
|
||||
Message: [dongle0] SMS queued for send
|
||||
ID: 0x5e13c0
|
||||
|
||||
Elküldve
|
||||
Event: DongleSMSStatus
|
||||
Privilege: call,all
|
||||
Device: dongle0
|
||||
ID: 0x5e13c0
|
||||
Status: Sent
|
||||
|
||||
Nincs elküldve
|
||||
Event: DongleSMSStatus
|
||||
Privilege: call,all
|
||||
Device: dongle0
|
||||
ID: 0x5c0888
|
||||
Status: NotSent
|
||||
|
||||
|
||||
JEGYZETEK
|
||||
=========
|
||||
|
||||
A linkedid változó, pl: ${CHANNEL(LinkedID)} hívásonként és nem csatornánként
|
||||
változik. Tehát a tovább kapcsolt, illetve Local channel által továbbvitt
|
||||
hívások ugyan azt a LinkedID-t kapják.
|
|
@ -0,0 +1,76 @@
|
|||
# Asterisk Manager Interface client C library
|
||||
|
||||
libamievent is an asynchronous event-driven client library for Asterisk Manager
|
||||
Interface written in C. It uses [libev](http://software.schmorp.de/pkg/libev.html) as event
|
||||
loop backend.
|
||||
|
||||
With the libamievent you can send AMI commands and you can subscribe for
|
||||
response to the command. When it arrives, the libamievent call the callback
|
||||
function, which specified at subscription. The callback function allows you to
|
||||
query AMI variables.
|
||||
|
||||
libamievent support AMI events. You can also specify a callback function of
|
||||
what the libamievent is called when events are received.
|
||||
|
||||
Huge advantage of the libamievent, that the AMI commands and event names are
|
||||
not hardcoded in the library. All commands, event names, parameters and
|
||||
variables must be defined by printf-style strings with variable substitution.
|
||||
|
||||
## Requirements
|
||||
|
||||
* libev
|
||||
|
||||
For Debian users:
|
||||
|
||||
apt-get install libev-dev
|
||||
|
||||
For Gentoo users:
|
||||
|
||||
emerge -av libev
|
||||
|
||||
## Install
|
||||
|
||||
Currently, the Makefile is not prepared to carry out normal library. But, you
|
||||
can build the example codes.
|
||||
|
||||
Clone the libamievent repo with all submodules.
|
||||
|
||||
git clone --recursive git://github.com/andrewjsi/libamievent
|
||||
|
||||
Compile the source, test and install:
|
||||
|
||||
make
|
||||
|
||||
## Using library
|
||||
|
||||
Sorry, the documentation still needs work, but in the meantime check out the sample
|
||||
programs.
|
||||
|
||||
## Todo, Future
|
||||
|
||||
* more stability
|
||||
* more examples
|
||||
* build static and dynamic library
|
||||
* well-written documentation
|
||||
* the ability to be integrated with other systems as easy as possible
|
||||
|
||||
## Source code
|
||||
|
||||
The source code is well written as far as possible. We do not use tabs, instead
|
||||
of 4 spaces is indented. All identifiers, including variables, function names
|
||||
and macros written in English, but some comments and commits in Hungarian is,
|
||||
because we are speaking and thinking in Hungarian. Nevertheless, we try to
|
||||
write everything in English in the future.
|
||||
|
||||
## Contribution
|
||||
|
||||
It is an open source project, which is to be better and better. If you have any
|
||||
ideas or find an error, or get stuck, you can contact us, please file a bug
|
||||
report or send a pull-request!
|
||||
|
||||
## License
|
||||
|
||||
[_GPL2_](https://www.gnu.org/licenses/gpl-2.0.html)
|
||||
|
||||
(C) Copyright 2010-2014 Andras Jeszenszky, [JSS & Hayer
|
||||
IT](http://www.jsshayer.hu) All Rights Reserved.
|
|
@ -0,0 +1,864 @@
|
|||
/* ami.c
|
||||
* Copyright © 2014, Andras Jeszenszky, JSS & Hayer IT - http://www.jsshayer.hu
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
// debug infók (kommentezd, ha nem kell)
|
||||
// #define CON_DEBUG
|
||||
|
||||
// csomagok dumpolása stdout-ra (kommentezd, ha nem kell)
|
||||
// #define AMI_DEBUG_PACKET_DUMP
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <ev.h>
|
||||
#include <stdio.h> // TODO: kell ez?
|
||||
#include <stdarg.h>
|
||||
#include <sys/time.h> // gettimeofday()
|
||||
|
||||
#include "ami.h"
|
||||
#include "debug.h"
|
||||
#include "utlist.h"
|
||||
#include "misc.h"
|
||||
#include "logger.h"
|
||||
|
||||
// event rögzítése
|
||||
void put_event (ami_event_t *event) {
|
||||
ami_event_t *event_copy = (ami_event_t*)malloc(sizeof(ami_event_t));
|
||||
if (!event_copy) {
|
||||
conft("can't allocate event: %s, event lost", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
//~ event tartalmának másolása az új event_copy számára lefoglalt területre.
|
||||
//~ Emiatt lesz thread-safe a várakozó sor és a callback hívás.
|
||||
memcpy(event_copy, event, sizeof(ami_event_t));
|
||||
|
||||
// bedobjuk a listába az új eseményt
|
||||
DL_APPEND(event->ami->event_head, event_copy);
|
||||
|
||||
//~ Esedékessé tesszük az azonnali (0 sec) időzítőt, aminek hatására az event
|
||||
//~ loop a callback futtatások után azonnal meghívja az invoke_events()
|
||||
//~ függvényt, ami meghivogatja a sorban álló eventekhez tartozó callback
|
||||
//~ eljárásokat. Majd a multithread fejlesztésénél ezen a ponton az
|
||||
//~ ev_timer_start() helyett az ev_async() függvénnyel kell jelezni a másik
|
||||
//~ szálban futó event loop-nak, hogy dolog van.
|
||||
ev_timer_start(event->ami->loop, &event->ami->need_event_processing);
|
||||
}
|
||||
|
||||
/* Felépítjük az event->field string tömböt, amiben az Asterisk által
|
||||
küldött "változó: érték" párokat mentjük el úgy, hogy "változó", "érték",
|
||||
"változó", "érték", ... A tömböt az ami->inbuf mutatókkal való
|
||||
feldarabolásával és NULL byteok elhelyezésével kapjuk.
|
||||
|
||||
A sorvégeket lezárhatja \r\n és \n is egyaránt.
|
||||
A legutolsó sor végét nem kötelező lezárni.
|
||||
|
||||
Ha az ami->inbuf tartalma:
|
||||
Response: Success
|
||||
Message: Authentication accepted
|
||||
|
||||
Akkor az ami->field:
|
||||
{"Respone","Success","Message","Authentication accepted"}
|
||||
|
||||
field string tömb
|
||||
max_field_size maximum ennyi darab string rakható a field tömbbe
|
||||
field_len annyi lesz az értéke, ahány elem bekerült a field tömbbe
|
||||
data innen olvassuk az adatokat és ezt a buffert daraboljuk fel és zárjuk le NULL-al
|
||||
data_size data mérete
|
||||
*/
|
||||
|
||||
//~ TODO: Hibás a függvény működése, ha a **field tömbünk mérete kicsi és a
|
||||
//~ feldarabolás során nem férnek el benne a tokenek. Nincs segfault meg
|
||||
//~ memóriahiba, hanem csak annyi történik, hogy az utolsó változó-érték pár
|
||||
//~ értéke megkapja sortörésekkel együtt a maradék buffert. Ezt úgy lehetne
|
||||
//~ megoldani, hogy a függvény nem bal-jobb oldalt vizsgál, hanem egy for ciklus
|
||||
//~ NULL-ra állítja a ": " és a "\r" és "\n" karaktereket a teljes data-ban, majd
|
||||
//~ csak ezután következne a feldarabolás mutatókkal.
|
||||
//~
|
||||
//~ aug 21: A fent leirt hiba sz'tem nem hiba.
|
||||
//~
|
||||
//~ aug 29: mi lenne, ha az utolsó változó-érték pár nem kapná meg a teljes buffert?
|
||||
//~ vagy eleve netsocket_disconnect és feltakarítás kellene ide?
|
||||
//~
|
||||
//~ A függvény nem kezeli azt az esetet, amikor az AMI változó-érték párnak nincs
|
||||
//~ értéke és nincs a változó utáni kettőspont után szóköz, hanem egyből újsor
|
||||
//~ karakter. Ilyen eset áll fenn az RTCPSent esemény ReportBlock változójában.
|
||||
void tokenize_field (int *field, int max_field_size, int *field_len, char *data, int data_size) {
|
||||
enum {
|
||||
LEFT,
|
||||
RIGHT,
|
||||
} inexpr = LEFT;
|
||||
|
||||
int len = 0; // visszatéréskor ezt mentjük el a *field_len -be
|
||||
field[len++] = 0; // első pozíció a data legeleje, tehát 0
|
||||
int i;
|
||||
|
||||
// összes \r karakter nullázása
|
||||
for (i = 0; i < data_size; i++)
|
||||
if (data[i] == '\r')
|
||||
data[i] = '\0';
|
||||
|
||||
for (i = 0; i < data_size && len < max_field_size; i++) {
|
||||
if (inexpr == LEFT) { // ": " bal oldalán vagyunk, változó
|
||||
if (data[i] == ':' && data[i+1] == ' ') {
|
||||
data[i] = '\0';
|
||||
data[i+1] = '\0';
|
||||
i += 2;
|
||||
field[len++] = i;
|
||||
inexpr = RIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
if (inexpr == RIGHT) { // ": " jobb oldalán vagyunk, érték
|
||||
if (data[i] == '\n') {
|
||||
data[i] = '\0';
|
||||
i += 1;
|
||||
field[len++] = i;
|
||||
inexpr = LEFT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (inexpr == LEFT)
|
||||
len--;
|
||||
|
||||
*field_len = len;
|
||||
|
||||
// AMI bal és jobb értékek dumpolása
|
||||
#ifdef AMI_DEBUG_PACKET_DUMP
|
||||
int z;
|
||||
for (z = 0; z < len; z++)
|
||||
printf("tokenize_field ### %d - (%s)\n", z, &data[field[z]]);
|
||||
printf("\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
static char *type2name (enum ami_event_type type) {
|
||||
switch (type) {
|
||||
case AMI_EVENT: return "EVENT" ; break;
|
||||
case AMI_RESPONSE: return "RESPONSE" ; break;
|
||||
case AMI_CLIRESPONSE: return "CLIRESPONSE" ; break;
|
||||
case AMI_CONNECT: return "CONNECT" ; break;
|
||||
case AMI_DISCONNECT: return "DISCONNECT" ; break;
|
||||
default: return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
// belső esemény kiváltása (AMI_CONNECT, AMI_DISCONNECT, stb...)
|
||||
static void generate_local_event (ami_t *ami, enum ami_event_type type, const char *fmt, ...) {
|
||||
ami_event_t event_tmp; // ideiglenes event // TODO: ha működik, akkor bevezetni az ami->event_tmp helyett lent is
|
||||
ami_event_t *event = &event_tmp;
|
||||
bzero(event, sizeof(*event));
|
||||
|
||||
//~ char buf[AMI_BUFSIZ];
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(event->data, sizeof(event->data), fmt, ap);
|
||||
va_end(ap);
|
||||
event->data[AMI_BUFSIZ-1] = '\0'; // védelem // TODO: kell ez?
|
||||
event->data_size = strlen(event->data);
|
||||
|
||||
//~ printf("~~~ %s ~~~\n", event->data);
|
||||
|
||||
tokenize_field(
|
||||
event->field,
|
||||
sizeof(event->field) / sizeof(char*) - 1,
|
||||
&event->field_size,
|
||||
event->data,
|
||||
event->data_size
|
||||
);
|
||||
|
||||
ami_event_list_t *el = NULL;
|
||||
// végigmegyünk a regisztrált eseményeken
|
||||
DL_FOREACH(ami->ami_event_list_head, el) {
|
||||
if (el->type == type) {
|
||||
event->callback = el->callback;
|
||||
event->userdata = el->userdata;
|
||||
event->regby_file = el->regby_file;
|
||||
event->regby_line = el->regby_line;
|
||||
event->regby_function = el->regby_function;
|
||||
event->regby_cbname = el->regby_cbname;
|
||||
event->regby_udname = el->regby_udname;
|
||||
event->ami = ami;
|
||||
event->type = el->type;
|
||||
put_event(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_cliresponse (ami_t *ami, int actionid, char *buf, int size) {
|
||||
printf("***** CLI RESPONSE START *****\n");
|
||||
printf("***** ActionID = %d\n", actionid);
|
||||
int i;
|
||||
for (i = 0; i < size; i++) {
|
||||
putchar(buf[i]);
|
||||
}
|
||||
printf("***** CLI RESPONSE END *****\n\n");
|
||||
}
|
||||
|
||||
// bejövő Response es Event feldolgozása
|
||||
static void parse_input (ami_t *ami, char *buf, int size) {
|
||||
ami_event_t *event = &ami->event_tmp;
|
||||
bzero(event, sizeof(*event));
|
||||
|
||||
memcpy(event->data, buf, size);
|
||||
event->data_size = size;
|
||||
|
||||
tokenize_field(
|
||||
event->field,
|
||||
sizeof(event->field) / sizeof(char*) - 1,
|
||||
&event->field_size,
|
||||
event->data,
|
||||
size
|
||||
);
|
||||
|
||||
char *var_response = ami_getvar(event, "Response");
|
||||
char *var_event = ami_getvar(event, "Event");
|
||||
/* * * RESPONSE * * */
|
||||
if (!strlen(var_event)) {
|
||||
char *action_id_str = ami_getvar(event, "ActionID");
|
||||
if (action_id_str == NULL) {
|
||||
con_debug("Missing ActionID in Response!");
|
||||
return;
|
||||
}
|
||||
event->action_id = atoi(action_id_str);
|
||||
|
||||
if (!strcmp(var_response, "Success")) {
|
||||
event->success = 1;
|
||||
} else if (!strcmp(var_response, "Error")) {
|
||||
event->success = 0;
|
||||
} else {
|
||||
con_debug("Unknown Response value: %s", var_response);
|
||||
return;
|
||||
}
|
||||
|
||||
con_debug("RESPONSE - success = %d, action_id = %d", event->success, event->action_id);
|
||||
|
||||
ami_event_list_t *el = NULL;
|
||||
ami_event_list_t *eltmp = NULL;
|
||||
DL_FOREACH_SAFE(ami->ami_event_list_head, el, eltmp) {
|
||||
if (el->type != AMI_RESPONSE) // csak az AMI_RESPONSE típusú eseményeket vizsgáljuk
|
||||
continue;
|
||||
// event->action_id - Asterisktől érkezett ActionID
|
||||
// el->action_id - adatbázisban szereplő ActionID
|
||||
if (event->action_id == el->action_id) {
|
||||
event->callback = el->callback;
|
||||
event->userdata = el->userdata;
|
||||
event->regby_file = el->regby_file;
|
||||
event->regby_line = el->regby_line;
|
||||
event->regby_function = el->regby_function;
|
||||
event->regby_cbname = el->regby_cbname;
|
||||
event->regby_udname = el->regby_udname;
|
||||
event->ami = ami;
|
||||
event->type = AMI_RESPONSE;
|
||||
put_event(event);
|
||||
DL_DELETE(ami->ami_event_list_head, el);
|
||||
free(el);
|
||||
return;
|
||||
}
|
||||
}
|
||||
con_debug("Received ActionID=%d, but %d not found in ami_event_list_head!", event->action_id, event->action_id);
|
||||
|
||||
/* * * EVENT * * */
|
||||
} else {
|
||||
//~ printf("##### PARSE_INPUT EVENT #####\n");
|
||||
ami_event_list_t *el;
|
||||
// végigmegyünk a regisztrált eseményeken
|
||||
DL_FOREACH(ami->ami_event_list_head, el) {
|
||||
if (el->type != AMI_EVENT) // csak az AMI_EVENT típusú eseményeket vizsgáljuk
|
||||
continue;
|
||||
// regisztrációban definiált változó=érték párok száma
|
||||
int need_found = el->field_size / 2; // minden találatnál dekrementálva lesz
|
||||
//~ printf(" REG need_found=%d allevents=%d by %s:%d\n", need_found, el->allevents, el->regby_file, el->regby_line);
|
||||
if (need_found || el->allevents) { // ha van mit keresnünk
|
||||
int n, i;
|
||||
// végigmegyünk a regisztráció változó=érték párjain
|
||||
for (n = 0; n < el->field_size; n += 2) {
|
||||
//~ printf(" _reg_ %s=%s\n", &el->data[el->field[n]], &el->data[el->field[n+1]]);
|
||||
// végigmegyünk a bejövő csomag változó=érték párjain
|
||||
for (i = 0; i < event->field_size; i += 2) {
|
||||
//~ printf(" _eve_ %s=%s\n", &event->data[event->field[i]], &event->data[event->field[i+1]]);
|
||||
// ha egyezik a regisztrált változó neve a csomag változó nevével
|
||||
if (!strcmp(&el->data[el->field[n]], &event->data[event->field[i]])) {
|
||||
// ha egyezik a regisztrált változó értéke a csomag változó értékével
|
||||
if (!strcmp(&el->data[el->field[n+1]], &event->data[event->field[i+1]])) {
|
||||
//~ printf(" !found\n");
|
||||
need_found--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//~ printf(" FIN need_found=%d\n", need_found);
|
||||
// ha minden változó megtalálható volt és mindegyik értéke egyezett
|
||||
// vagy "*" volt megadva a regisztrációnál (allevents)
|
||||
if (need_found == 0 || el->allevents) {
|
||||
event->callback = el->callback;
|
||||
event->userdata = el->userdata;
|
||||
event->regby_file = el->regby_file;
|
||||
event->regby_line = el->regby_line;
|
||||
event->regby_function = el->regby_function;
|
||||
event->regby_cbname = el->regby_cbname;
|
||||
event->regby_udname = el->regby_udname;
|
||||
event->type = AMI_EVENT;
|
||||
event->ami = ami;
|
||||
put_event(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ami_disconnect (ami_t *ami, const char *fmt, ...) {
|
||||
char reason_text[AMI_BUFSIZ];
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(reason_text, sizeof(reason_text), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (netsocket_is_connected(ami->netsocket))
|
||||
netsocket_disconnect_withevent(ami->netsocket, reason_text);
|
||||
}
|
||||
|
||||
static void response_login (ami_event_t *response) {
|
||||
ami_t *ami = response->ami;
|
||||
|
||||
con_debug("auth reply: success=%d %s (by %s() %s:%d)",
|
||||
response->success,
|
||||
ami_getvar(response, "Message"),
|
||||
response->regby_function,
|
||||
response->regby_file,
|
||||
response->regby_line
|
||||
);
|
||||
|
||||
if (!response->ami->authenticated) {
|
||||
if (response->success) { // AUTH accepted
|
||||
response->ami->authenticated = 1;
|
||||
// TODO: itt kell a connect timeout időzítőt törölni
|
||||
generate_local_event(ami,
|
||||
AMI_CONNECT,
|
||||
"Host: %s\nIP: %s\nPort: %d",
|
||||
ami->host,
|
||||
ami->netsocket->ip,
|
||||
ami->port);
|
||||
} else { // AUTH failed
|
||||
netsocket_disconnect_withevent(response->ami->netsocket, "Authentication failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void process_input (ami_t *ami) {
|
||||
#ifdef AMI_DEBUG_PACKET_DUMP
|
||||
int pdi;
|
||||
printf("----- NETSOCKET INBUF START -----\n");
|
||||
for (pdi = 0; pdi < ami->netsocket->inbuf_len; pdi++)
|
||||
putchar(ami->netsocket->inbuf[pdi]);
|
||||
printf("----- NETSOCKET INBUF END -----\n");
|
||||
#endif
|
||||
|
||||
/*
|
||||
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
||||
E v e n t : D i a l \r \n \r \n A c t i o n
|
||||
\r \n \r \n
|
||||
|
||||
"Response: Follows\r\nPrivilege: Command\r\nActionID: %d\r\n"
|
||||
"--END COMMAND--\r\n\r\n"
|
||||
*/
|
||||
|
||||
// byte-onként végigmegyünk a netsocket bufferen
|
||||
int i;
|
||||
for (i = 0; i < ami->netsocket->inbuf_len; i++) {
|
||||
// buffer overflow védelem
|
||||
if (ami->inbuf_pos >= sizeof(ami->inbuf) - 1) {
|
||||
printf("ELFOGYOTT A BUFFER!!!\n"); // TODO: netsocket_disconnect és feltakarítás
|
||||
break;
|
||||
}
|
||||
|
||||
// byte másolása netsocketből ami->inbuf -ba
|
||||
ami->inbuf[ami->inbuf_pos] = ami->netsocket->inbuf[i];
|
||||
|
||||
/* AMI header vizsgalata. Biztonsagi okokbol ha mar authentikalt
|
||||
allapotban vagyunk, akkor ezt a vizsgalatot kihagyjuk */
|
||||
|
||||
// TODO. lekezelni azt az esetet, amikor kezdésnek nem ezt a fejlécet kapjuk!
|
||||
if (!ami->authenticated &&
|
||||
(!strcmp(ami->inbuf, "Asterisk Call Manager/1.1\r\n") ||
|
||||
!strcmp(ami->inbuf, "Asterisk Call Manager/1.0\r\n") ||
|
||||
!strcmp(ami->inbuf, "Asterisk Call Manager/1.2\r\n") ||
|
||||
!strcmp(ami->inbuf, "Asterisk Call Manager/1.3\r\n")))
|
||||
{
|
||||
bzero(ami->inbuf, sizeof(ami->inbuf));
|
||||
ami->inbuf_pos = 0;
|
||||
con_debug("Received \"Asterisk Call Manager\" header, sending auth...");
|
||||
ami_action(ami, response_login, NULL,
|
||||
"Action: Login\nUsername: %s\nSecret: %s\n",
|
||||
ami->username, ami->secret);
|
||||
bzero(ami->inbuf, sizeof(ami->inbuf));
|
||||
ami->inbuf_pos = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// ha épp egy "Response: Follows" belsejében vagyunk
|
||||
if (ami->cli_actionid > 0) {
|
||||
// keressük a csomag végét
|
||||
#define Q "--END COMMAND--\r\n\r\n"
|
||||
#define QSIZE 19
|
||||
if (ami->inbuf_pos >= QSIZE - 1) {
|
||||
if (!strncmp(Q, &ami->inbuf[ami->inbuf_pos - (QSIZE - 1)], QSIZE)) {
|
||||
// megtaláltuk, mehet a feldolgozóba
|
||||
parse_cliresponse(ami, ami->cli_actionid, ami->inbuf, ami->inbuf_pos - 18);
|
||||
bzero(ami->inbuf, sizeof(ami->inbuf));
|
||||
ami->inbuf_pos = 0;
|
||||
ami->cli_actionid = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#undef Q
|
||||
#undef QSIZE
|
||||
|
||||
// folytatjuk tovább a beolvasást
|
||||
ami->inbuf_pos++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Egy "Action: Command" csomagra (ami_cli() okozza) egy "Response:
|
||||
Follows" válaszcsomag érkezik. Az ilyen csomagoknak speciális
|
||||
formátuma van, ezért ezeket teljesen külön kell kezelni. Ezek a
|
||||
csomagok a parse_input() helyett a parse_cliresponse() függvénynek
|
||||
kerülnek át feldolgozásra. Az alábbi sscanf() megoldás megvizsgálja,
|
||||
hogy az éppen beolvasás alatt álló csomag ilyen speciális "Response:
|
||||
Follows" csomag lesz -e, illetve kiszedi belőle az ActionID-t. A
|
||||
sscanf() az ami->inbuf baloldali illeszkedését vizsgálja és ha
|
||||
tudja, akkor az ami->cli_actionid változóba menti el a kapott
|
||||
ActionID-t. */
|
||||
if (sscanf(ami->inbuf, "Response: Follows\r\nPrivilege: Command\r\nActionID: %d\r\n", &ami->cli_actionid) > 0) {
|
||||
// az ami->inbuf jobboldali illeszkedését az strncmp()-vel vizsgáljuk
|
||||
#define Q "\r\n"
|
||||
#define QSIZE 2 // Q mérete
|
||||
if (ami->inbuf_pos >= QSIZE - 1) {
|
||||
// ha illeszkedik jobbról a \r\n, akkor tovább olvassuk az adatokat
|
||||
if (!strncmp(Q, &ami->inbuf[ami->inbuf_pos - (QSIZE - 1)], QSIZE)) {
|
||||
bzero(ami->inbuf, sizeof(ami->inbuf));
|
||||
ami->inbuf_pos = 0;
|
||||
continue; // ezen a ponton az ami->cli_actionid -ben ott figyel az ActionID
|
||||
}
|
||||
}
|
||||
#undef Q
|
||||
#undef QSIZE
|
||||
|
||||
/* Ide akkor kerülünk, ha a sscanf() (bal oldal) illeszkedett, de az
|
||||
strncmp() (jobb oldal) nem. Ebben az esetben elképzelhető, hogy
|
||||
a sscanf() hibásan kiolvassa az ActionID egy töredékét, ezért
|
||||
biztos ami biztos, kinullázzuk. ezen a ponton lehetséges, hogy a
|
||||
sscanf() az ActinID csak egy töredékét szedte ki, ezért nullázunk. */
|
||||
ami->cli_actionid = 0;
|
||||
|
||||
// folytatjuk tovább a beolvasást
|
||||
ami->inbuf_pos++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Ha van elég adat, hogy az ami->inbuf -ban 3 byte-ot visszaléphessünk,
|
||||
akkor megvizsgáljuk, hogy vajon éppen egy csomag lezárásánál állunk
|
||||
-e, azaz az ami->inbuf legutolsó 4 byte-ja megegyezik ezzel:
|
||||
"\r\n\r\n". Ha igen, akkor az azt jelenti, hogy az ami->inbuf pont
|
||||
egy teljes csomagot tartalmaz, amit elküldünk a parse_input()-nak,
|
||||
majd kinullázzuk a teljes ami->inbuf buffert és az ami->inbuf_pos
|
||||
pozicionáló változót. Ezután folytatjuk a következő csomag byte-
|
||||
onkénti olvasását. Ha már nincs a netsocket->inbuf -ban feldolgozandó
|
||||
cucc, akkor a for ciklus kilép és majd a következő körben
|
||||
folytatódik az olvasás. */
|
||||
|
||||
/* TODO: Logikailag nem korrekt ez a megoldás! Segfault veszély
|
||||
ami_event_unregister() után. A process_input() és parse_input()
|
||||
páros a teljes netsocket->inbuf -ban lévő cuccot egyetlen egy körben
|
||||
feldolgozza. Ebben egyszerre több csomag is lehet. Az érdekes
|
||||
eseményeket a put_event() a saját listájába tolja és csak a
|
||||
következő körben lesz callback hívás. Tegyük fel, hogy egyszerre 2
|
||||
csomag érkezik. Az első csomagban lévő esemény callback függvénye
|
||||
megrendel egy új eseményt, amire történetesen pont a második csomag
|
||||
illeszkedne. De mivel a megrendelés előtt már megtörtént az
|
||||
összehasonlítás, szűrés és a futtatandó események kiválasztása,
|
||||
ezért erről a második eseményről le fog maradni a hívó. Másképpen
|
||||
szólva egy-egy megrendelésnek (vagy lemondásnak) csak a teljes
|
||||
put_event() által karbantartott lista (callback lista) lefuttatása
|
||||
után lesz hatása. Ez eseményről való lemaradást okozhat, illetve
|
||||
lemondásnál segfaultot is, ugyanis ha történik egy
|
||||
ami_event_unregister() akkor ezután még a put_event() által
|
||||
karbantartott listából lefuthat a (már lemondott) callback. Ötlet:
|
||||
valami olyan megoldás kéne, hogy még itt a process_input /
|
||||
parse_input szintjén ha fennakad a szűrőn egy esemény, akkor a
|
||||
put_event() regisztráció után álljon le a parse_input() és az event
|
||||
loop hívja meg a need_event_processing-et. És majd csak ezután
|
||||
folytatódjon a parse_input() vizsgálódása. Vaaagy... egy merészebb
|
||||
ötlet. A bejövő AMI buffer visszamenőleg addig legyen eltárolva,
|
||||
amíg az invoke_events még foglalkozik a callback hívásokkal.
|
||||
Multithread környezetben az invoke_events a megrendelő szálában fog
|
||||
futni. Elképzelhető, hogy az invoke_events-ből kellene vizsgálni
|
||||
azt, hogy az éppen bejövő AMI eseményt kell -e futtatni. */
|
||||
|
||||
#define Q "\r\n\r\n"
|
||||
#define QSIZE 4
|
||||
if (ami->inbuf_pos >= QSIZE - 1) {
|
||||
if (!strncmp(Q, &ami->inbuf[ami->inbuf_pos - (QSIZE - 1)], QSIZE)) {
|
||||
parse_input(ami, ami->inbuf, ami->inbuf_pos - 1); // -1 azért, hogy ne menjen át a legutolsó \r\n-ből az \r (érthető?)
|
||||
bzero(ami->inbuf, sizeof(ami->inbuf));
|
||||
ami->inbuf_pos = 0;
|
||||
continue; // ne jusson el az ami->inbuf_pos++ -ig :)
|
||||
}
|
||||
}
|
||||
#undef Q
|
||||
#undef QSIZE
|
||||
ami->inbuf_pos++;
|
||||
}
|
||||
}
|
||||
|
||||
static void netsocket_callback (netsocket_t *netsocket, int event) {
|
||||
ami_t *ami = netsocket->userdata;
|
||||
int was_authenticated = 0;
|
||||
|
||||
switch (event) {
|
||||
case NETSOCKET_EVENT_CONNECT:
|
||||
con_debug("Connected to %s (%s) port %d",
|
||||
netsocket->host,
|
||||
netsocket->ip,
|
||||
netsocket->port
|
||||
);
|
||||
break;
|
||||
|
||||
case NETSOCKET_EVENT_DISCONNECT:
|
||||
was_authenticated = ami->authenticated;
|
||||
|
||||
// TODO: itt kell alaphelyzetbe állítani az ami-t.
|
||||
// disconnect esemény szétkűrtölése előtt
|
||||
ami->authenticated = 0;
|
||||
|
||||
generate_local_event(ami,
|
||||
AMI_DISCONNECT,
|
||||
"Host: %s\nIP: %s\nPort: %d\nReason: %s\nWasAuthenticated: %d",
|
||||
netsocket->host,
|
||||
(netsocket->ip) ? netsocket->ip : "",
|
||||
netsocket->port,
|
||||
netsocket->disconnect_reason,
|
||||
was_authenticated
|
||||
);
|
||||
|
||||
if (netsocket->connected) {
|
||||
con_debug("Disconnected from %s: %s",
|
||||
netsocket->host,
|
||||
netsocket->disconnect_reason
|
||||
);
|
||||
} else {
|
||||
con_debug("Can't connect to %s[%s]:%d %s",
|
||||
netsocket->host,
|
||||
(netsocket->ip) ? netsocket->ip : "",
|
||||
netsocket->port,
|
||||
netsocket->disconnect_reason
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case NETSOCKET_EVENT_READ:
|
||||
process_input(ami);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// hívja az ami->need_event_processing azonnali időzítő
|
||||
static void invoke_events (EV_P_ ev_io *w, int revents) {
|
||||
ami_t *ami = w->data;
|
||||
|
||||
ami_event_t *event, *tmp;
|
||||
DL_FOREACH_SAFE(ami->event_head, event, tmp) {
|
||||
if (event->callback != NULL) {
|
||||
con_debug("call %s()", event->regby_cbname);
|
||||
event->callback(event);
|
||||
con_debug("end %s()", event->regby_cbname);
|
||||
}
|
||||
DL_DELETE(ami->event_head, event);
|
||||
free(event);
|
||||
}
|
||||
}
|
||||
|
||||
// 6 byte-os random hexa stringet masol az ami->uuid bufferbe
|
||||
// TODO: egy rendes, unique ID-t visszaado fuggvenyt irni ehelyett a random vacak helyett
|
||||
// pl. az util-linux-ng csomagban levo libuuid segitsegevel
|
||||
static void generate_uuid (char *dst, size_t size) {
|
||||
struct timeval tv;
|
||||
int num;
|
||||
char tmp[16];
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
srand(tv.tv_usec * tv.tv_sec);
|
||||
num = rand();
|
||||
snprintf(tmp, sizeof(tmp), "%x", num);
|
||||
tmp[6] = '\0';
|
||||
strncpy(dst, tmp, size);
|
||||
}
|
||||
|
||||
void connect_delayed (EV_P_ ev_io *w, int revents) {
|
||||
ami_t *ami = w->data;
|
||||
con_debug("invoked connect by timer");
|
||||
ev_timer_stop(ami->loop, &ami->t_connect_delayed);
|
||||
ami_connect(ami);
|
||||
}
|
||||
|
||||
// delay: millisec
|
||||
void ami_connect_delayed (ami_t *ami, int delay) {
|
||||
con_debug("connect after %d ms ...", delay);
|
||||
ev_timer_stop(ami->loop, &ami->t_connect_delayed);
|
||||
ev_timer_set(&ami->t_connect_delayed, (float)((float)delay / (float)1000), 0);
|
||||
ev_timer_start(ami->loop, &ami->t_connect_delayed);
|
||||
}
|
||||
|
||||
ami_t *ami_new (struct ev_loop *loop) {
|
||||
ami_t *ami = malloc(sizeof(*ami));
|
||||
if (ami == NULL) {
|
||||
con_debug("ami_new() returned NULL");
|
||||
return NULL;
|
||||
}
|
||||
bzero(ami, sizeof(*ami)); // minden NULL
|
||||
|
||||
// AMI UUID
|
||||
generate_uuid(ami->uuid, sizeof(ami->uuid));
|
||||
|
||||
// ha meg van adva a loop paraméter, akkor azt használjuk eseménykezelőnek
|
||||
// ellenkező esetben az alapértelmezett eseménykezelőt
|
||||
ami->loop = (loop != NULL) ? loop : ev_default_loop(0);
|
||||
|
||||
// default értékek
|
||||
strncpy(ami->host, AMI_DEFAULT_HOST, sizeof(ami->host) - 1);
|
||||
ami->port = AMI_DEFAULT_PORT;
|
||||
|
||||
if (!(ami->netsocket = netsocket_new(netsocket_callback, ami, ami->loop))) {
|
||||
con_debug("netsocket_new returned NULL");
|
||||
}
|
||||
netsocket_host(ami->netsocket, AMI_DEFAULT_HOST);
|
||||
netsocket_port(ami->netsocket, AMI_DEFAULT_PORT);
|
||||
|
||||
ami->need_event_processing.data = ami; // ami objektum így kerül az invoke_events-be
|
||||
ev_timer_init(&ami->need_event_processing, (void*)invoke_events, 0, 0);
|
||||
|
||||
ami->t_connect_delayed.data = ami;
|
||||
ev_timer_init(&ami->t_connect_delayed, (void*)connect_delayed, 0, 0);
|
||||
|
||||
return ami;
|
||||
}
|
||||
|
||||
void ami_destroy(ami_t *ami) {
|
||||
netsocket_destroy(ami->netsocket);
|
||||
}
|
||||
|
||||
void ami_credentials (ami_t *ami, const char *username, const char *secret, const char *host, const char *port) {
|
||||
if (username != NULL)
|
||||
strncpy(ami->username, username, sizeof(ami->username) - 1);
|
||||
|
||||
if (secret != NULL)
|
||||
strncpy(ami->secret, secret, sizeof(ami->secret) - 1);
|
||||
|
||||
if (host != NULL)
|
||||
strncpy(ami->host, host, sizeof(ami->host) - 1);
|
||||
|
||||
if (port != NULL) {
|
||||
int port_tmp = atoi(port);
|
||||
if (port_tmp > 0 || port_tmp < 65536)
|
||||
ami->port = port_tmp;
|
||||
}
|
||||
}
|
||||
|
||||
void ami_connect (ami_t *ami) {
|
||||
netsocket_host(ami->netsocket, ami->host);
|
||||
netsocket_port(ami->netsocket, ami->port);
|
||||
netsocket_connect(ami->netsocket);
|
||||
}
|
||||
|
||||
int ami_printf (ami_t *ami, const char *fmt, ...) {
|
||||
char buf[AMI_BUFSIZ];
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
int field[AMI_FIELD_SIZE];
|
||||
int field_size;
|
||||
tokenize_field(
|
||||
field,
|
||||
sizeof(field) / sizeof(char*) - 1,
|
||||
&field_size,
|
||||
buf,
|
||||
strlen(buf)
|
||||
);
|
||||
|
||||
char packet[AMI_BUFSIZ];
|
||||
int i;
|
||||
strcpy(packet, "");
|
||||
for (i = 0; i < field_size; i += 2)
|
||||
concatf(packet, "%s: %s\r\n", &buf[field[i]], &buf[field[i+1]]);
|
||||
concat(packet, "\r\n");
|
||||
|
||||
if (ami->netsocket != NULL) {
|
||||
#ifdef AMI_DEBUG_PACKET_DUMP
|
||||
printf("----- NETSOCKET WRITE START ------\n");
|
||||
printf("%s", packet);
|
||||
printf("----- NETSOCKET WRITE END ------\n");
|
||||
#endif
|
||||
return netsocket_printf(ami->netsocket, "%s", packet);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
ami_event_list_t *_ami_action (ami_t *ami, void *callback, void *userdata, char *file, int line, const char *function, const char *cbname, const char *udname, const char *fmt, ...) {
|
||||
char buf[AMI_BUFSIZ];
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
va_end(ap);
|
||||
buf[AMI_BUFSIZ-1] = '\0'; // védelem
|
||||
|
||||
if (callback != NULL) {
|
||||
ami_event_list_t *el = malloc(sizeof(ami_event_list_t));
|
||||
bzero(el, sizeof(*el)); // NULL, NULL, NULL :)
|
||||
el->callback = callback;
|
||||
el->userdata = userdata;
|
||||
el->type = AMI_RESPONSE;
|
||||
el->regby_file = file;
|
||||
el->regby_line = line;
|
||||
el->regby_function = function;
|
||||
el->regby_cbname = cbname;
|
||||
el->regby_udname = udname;
|
||||
ami->action_id++; // új ActionID
|
||||
el->action_id = ami->action_id;
|
||||
ami_printf(ami, "ActionID: %d\n%s", ami->action_id, buf);
|
||||
con_debug("registered action #%d, callback: %s()", el->action_id, el->regby_cbname);
|
||||
DL_APPEND(ami->ami_event_list_head, el);
|
||||
return el;
|
||||
} else {
|
||||
ami_printf(ami, "%s", buf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
ami_event_list_t *_ami_event_register (ami_t *ami, void *callback, void *userdata, char *file, int line, const char *function, const char *cbname, const char *udname, const char *fmt, ...) {
|
||||
ami_event_list_t *el = malloc(sizeof(ami_event_list_t));
|
||||
bzero(el, sizeof(*el)); // NULL, NULL, NULL :)
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(el->data, sizeof(el->data), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
el->callback = callback;
|
||||
el->userdata = userdata;
|
||||
el->regby_file = file;
|
||||
el->regby_line = line;
|
||||
el->regby_function = function;
|
||||
el->regby_cbname = cbname;
|
||||
el->regby_udname = udname;
|
||||
|
||||
// belső esemény: Connect
|
||||
if (!strcmp(el->data, "Connect")) {
|
||||
el->type = AMI_CONNECT;
|
||||
|
||||
// belső esemény: Disconnect
|
||||
} else if (!strcmp(el->data, "Disconnect")) {
|
||||
el->type = AMI_DISCONNECT;
|
||||
|
||||
// Minden Asterisk esemény szűrés nélkül
|
||||
} else if (!strcmp(el->data, "*")) {
|
||||
el->type = AMI_EVENT;
|
||||
el->allevents = 1;
|
||||
|
||||
// Asterisk esemény, feltételek feldarabolása
|
||||
} else {
|
||||
el->type = AMI_EVENT;
|
||||
tokenize_field(
|
||||
el->field,
|
||||
sizeof(el->field) / sizeof(char*) - 1,
|
||||
&el->field_size,
|
||||
el->data,
|
||||
sizeof(el->data)
|
||||
);
|
||||
}
|
||||
|
||||
DL_APPEND(ami->ami_event_list_head, el);
|
||||
con_debug("EVENT registered, callback: %s by %s() in %s line %d",
|
||||
el->regby_cbname, el->regby_function, el->regby_file, el->regby_line);
|
||||
|
||||
return el;
|
||||
}
|
||||
|
||||
void ami_event_unregister(ami_t *ami, ami_event_list_t *el) {
|
||||
if (el == NULL) {
|
||||
con_debug("attempting to unregister NULL pointer event!");
|
||||
return;
|
||||
}
|
||||
con_debug("EVENT unregistered, callback: %s()", el->regby_cbname);
|
||||
DL_DELETE(ami->ami_event_list_head, el);
|
||||
free(el);
|
||||
}
|
||||
|
||||
void ami_event_dump (ami_event_t *event) {
|
||||
printf(
|
||||
"Incoming %s /0x%lx/\n"
|
||||
" Registered by %s() in %s line %d\n"
|
||||
" Callback: %s() /0x%lx/, Userdata: %s /0x%lx/\n"
|
||||
" success=%d action_id=%d data_size=%d field_size=%d\n"
|
||||
, type2name(event->type), (unsigned long)event
|
||||
, event->regby_function, event->regby_file, event->regby_line
|
||||
, event->regby_cbname, (unsigned long)event->callback, event->regby_udname, (unsigned long)event->userdata
|
||||
, event->success, event->action_id, event->data_size, event->field_size
|
||||
);
|
||||
int i;
|
||||
for (i = 0; i < event->field_size; i += 2)
|
||||
printf(" %-16s %s\n", &event->data[event->field[i]], &event->data[event->field[i+1]]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void ami_dump_event_list_element (ami_event_list_t *el) {
|
||||
printf(
|
||||
"Registered %s /0x%lx/\n"
|
||||
" Registered by %s() in %s line %d\n"
|
||||
" Callback: %s() /0x%lx/, Userdata: %s /0x%lx/\n"
|
||||
" action_id=%d field_size=%d\n"
|
||||
, type2name(el->type), (unsigned long)el
|
||||
, el->regby_function, el->regby_file, el->regby_line
|
||||
, el->regby_cbname, (unsigned long)el->callback, el->regby_udname, (unsigned long)el->userdata
|
||||
, el->action_id, el->field_size
|
||||
);
|
||||
int i;
|
||||
for (i = 0; i < el->field_size; i += 2)
|
||||
printf(" %-16s %s\n", &el->data[el->field[i]], &el->data[el->field[i+1]]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void ami_dump_lists (ami_t *ami) {
|
||||
printf("** REGISTERED AMI EVENTS **\n");
|
||||
ami_event_list_t *el;
|
||||
DL_FOREACH(ami->ami_event_list_head, el)
|
||||
ami_dump_event_list_element(el);
|
||||
}
|
||||
|
||||
char *ami_getvar (ami_event_t *event, char *var) {
|
||||
int i;
|
||||
for (i = 0; i < event->field_size; i += 2) {
|
||||
if (!strcmp(&event->data[event->field[i]], var)) {
|
||||
if (&event->data[event->field[i+1]] != NULL) {
|
||||
return &event->data[event->field[i+1]];
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void ami_strncpy (ami_event_t *event, char *dest, char *var, size_t maxsize) {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
/* ami.h
|
||||
* Copyright © 2014, Andras Jeszenszky, JSS & Hayer IT - http://www.jsshayer.hu
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef AMI_H_INCLUDED
|
||||
#define AMI_H_INCLUDED
|
||||
|
||||
#include "netsocket.h"
|
||||
|
||||
// TODO: doksiba AMI_DEBUG_PACKET_DUMP
|
||||
|
||||
#ifndef AMI_DEFAULT_HOST
|
||||
#define AMI_DEFAULT_HOST "localhost"
|
||||
#endif
|
||||
|
||||
#ifndef AMI_DEFAULT_PORT
|
||||
#define AMI_DEFAULT_PORT 5038
|
||||
#endif
|
||||
|
||||
#ifndef AMI_BUFSIZ
|
||||
#define AMI_BUFSIZ 4096
|
||||
#endif
|
||||
|
||||
#ifndef AMI_FIELD_SIZE
|
||||
#define AMI_FIELD_SIZE 300
|
||||
#endif
|
||||
|
||||
enum ami_event_type {
|
||||
AMI_EVENT = 1,
|
||||
AMI_RESPONSE,
|
||||
AMI_CLIRESPONSE,
|
||||
AMI_CONNECT,
|
||||
AMI_DISCONNECT,
|
||||
};
|
||||
|
||||
// ha változik, akkor egyeztess az ami.c ami_dump_lists() függvénnyel!
|
||||
typedef struct ami_event_list_t {
|
||||
struct ami_event_list_t *prev;
|
||||
struct ami_event_list_t *next;
|
||||
void (*callback)(void*);
|
||||
void *userdata;
|
||||
int field[AMI_FIELD_SIZE];
|
||||
int field_size;
|
||||
char data[AMI_BUFSIZ];
|
||||
char *regby_file;
|
||||
int regby_line;
|
||||
const char *regby_function;
|
||||
const char *regby_cbname;
|
||||
const char *regby_udname;
|
||||
unsigned int action_id;
|
||||
enum ami_event_type type;
|
||||
int allevents; // 1 lesz, ha a megrendelo szures nelkul az osszes AMI esemenyt keri
|
||||
} ami_event_list_t;
|
||||
|
||||
typedef struct ami_event_t {
|
||||
struct ami_event_t *prev;
|
||||
struct ami_event_t *next;
|
||||
struct ami_t *ami;
|
||||
int success; // csak "Response: Success" esetén lesz egy, tehát biztos hogy volt Response és az értéke Success volt
|
||||
int field[AMI_FIELD_SIZE];
|
||||
int field_size;
|
||||
char data[AMI_BUFSIZ];
|
||||
int data_size;
|
||||
void (*callback)(void*);
|
||||
void *userdata;
|
||||
unsigned int action_id;
|
||||
char *regby_file;
|
||||
int regby_line;
|
||||
const char *regby_function;
|
||||
const char *regby_cbname;
|
||||
const char *regby_udname;
|
||||
enum ami_event_type type;
|
||||
} ami_event_t;
|
||||
|
||||
typedef struct ami_t {
|
||||
char host[64]; // Asterisk host
|
||||
int port; // Asterisk Manager Interface port
|
||||
char username[32]; // AMI User
|
||||
char secret[32]; // AMI Password
|
||||
netsocket_t *netsocket; // Netsocket objektum
|
||||
char disconnect_reason[64]; // ???
|
||||
ami_event_list_t *ami_event_list_head; // megrendelt események
|
||||
struct ev_loop *loop; // eseményhurok
|
||||
ev_timer need_event_processing; // azonnali időzítő az események kiküldéséhez
|
||||
ev_timer t_connect_delayed; // késleltetett connect időzítő
|
||||
char inbuf[AMI_BUFSIZ]; // bejövő buffer
|
||||
int inbuf_pos; // bejövő buffer pozíciója
|
||||
struct ami_event_t *event_head; // esemény várakozósor
|
||||
struct ami_event_t event_tmp; // itt készítünk új eseményt, amit aztán a várakozósorba másolunk
|
||||
int authenticated; // 1 lesz sikeres login után
|
||||
unsigned int action_id; // soron következő használható ActionID
|
||||
char uuid[16]; // AMI sajat belso ID
|
||||
int cli_actionid; // process_input() itt jegyzi meg a Response: Follows ActionID-t
|
||||
} ami_t;
|
||||
|
||||
ami_t *ami_new (struct ev_loop *loop);
|
||||
|
||||
void ami_credentials (ami_t *ami, const char *username, const char *secret, const char *host, const char *port);
|
||||
|
||||
void ami_destroy(ami_t *ami);
|
||||
|
||||
void ami_connect (ami_t *ami);
|
||||
|
||||
void ami_connect_delayed (ami_t *ami, int delay);
|
||||
|
||||
int ami_printf (ami_t *ami, const char *fmt, ...);
|
||||
|
||||
#define ami_action(ami, callback, userdata, ...) \
|
||||
_ami_action(ami, callback, userdata, __FILE__, __LINE__, __FUNCTION__, #callback, #userdata, __VA_ARGS__)
|
||||
ami_event_list_t *_ami_action (ami_t *ami, void *callback, void *userdata, char *file, int line, const char *function, const char *cbname, const char *udname, const char *fmt, ...);
|
||||
|
||||
#define ami_event_register(ami, callback, userdata, ...) \
|
||||
_ami_event_register(ami, callback, userdata, __FILE__, __LINE__, __FUNCTION__, #callback, #userdata, __VA_ARGS__)
|
||||
ami_event_list_t *_ami_event_register (ami_t *ami, void *callback, void *userdata, char *file, int line, const char *function, const char *cbname, const char *udname, const char *fmt, ...);
|
||||
|
||||
void ami_event_unregister(ami_t *ami, ami_event_list_t *el);
|
||||
|
||||
char *ami_getvar (ami_event_t *event, char *var);
|
||||
|
||||
#define ami_strcpy(event,dest,var) ami_strncpy(event,dest,var,sizeof(dest))
|
||||
|
||||
void ami_strncpy (ami_event_t *event, char *dest, char *var, size_t maxsize);
|
||||
|
||||
void ami_dump_lists (ami_t *ami);
|
||||
|
||||
void ami_event_dump (ami_event_t *el);
|
||||
|
||||
void ami_disconnect (ami_t *ami, const char *fmt, ...);
|
||||
|
||||
#endif // #ifndef AMI_H_INCLUDED
|
||||
|
|
@ -0,0 +1,298 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ev.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "ami.h"
|
||||
#include "debug.h"
|
||||
#include "utlist.h"
|
||||
|
||||
#define CON_DEBUG
|
||||
#include "logger.h"
|
||||
|
||||
#include "milenage.h"
|
||||
|
||||
ev_timer timer;
|
||||
ev_timer timer_reconnect;
|
||||
|
||||
ami_t *ami;
|
||||
int dstatus_n = 2;
|
||||
|
||||
//~ static void ami_event_callback (ami_event_t *ame) {
|
||||
//~ char *userdata = (char*)ame->userdata;
|
||||
//~ char *status = ami_getvar(ame, "Status");
|
||||
//~
|
||||
//~ char status2[64];
|
||||
//~ strncpy(status2, ami_getvar(ame, "Status"), 64);
|
||||
//~ ami_strncpy(ame, status2, "Status", 64);
|
||||
//~
|
||||
//~ ami_event_unregister(ame);
|
||||
//~ }
|
||||
|
||||
void utproba () {
|
||||
typedef struct st {
|
||||
struct st *prev;
|
||||
struct st *next;
|
||||
char str[32];
|
||||
} st;
|
||||
|
||||
st *head = NULL;
|
||||
st *el;
|
||||
st *x10, *x15;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < 20; i++) {
|
||||
el = (st*)malloc(sizeof(*el));
|
||||
bzero(el, sizeof(*el));
|
||||
|
||||
sprintf(el->str, "str %d", i);
|
||||
if (i == 10)
|
||||
x10 = el;
|
||||
if (i == 15)
|
||||
x15 = el;
|
||||
DL_APPEND(head, el);
|
||||
}
|
||||
|
||||
st *eltmp;
|
||||
DL_FOREACH_SAFE(head, el, eltmp) {
|
||||
if (el == x10) {
|
||||
st *csere = (st*)malloc(sizeof(st));
|
||||
strcpy(csere->str, "csere1");
|
||||
DL_APPEND(head, csere);
|
||||
csere = (st*)malloc(sizeof(st));
|
||||
strcpy(csere->str, "csere2");
|
||||
DL_APPEND(head, csere);
|
||||
|
||||
DL_DELETE(head, el);
|
||||
free(el);
|
||||
}
|
||||
|
||||
if (el == x15) {
|
||||
DL_DELETE(head, el);
|
||||
free(el);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DL_FOREACH_SAFE(head, el, eltmp) {
|
||||
printf("s %s s\n", el->str);
|
||||
DL_DELETE(head, el);
|
||||
free(el);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int do_register = 0;
|
||||
|
||||
void event_response (ami_event_t *event) {
|
||||
const char *message_str = ami_getvar(event, "Message");
|
||||
|
||||
printf("response: %s\n", message_str);
|
||||
}
|
||||
|
||||
void event_fullybooted (ami_event_t *event) {
|
||||
printf("*** Fully booted ***\n");
|
||||
if (do_register)
|
||||
return;
|
||||
do_register = 1;
|
||||
ami_action(ami, event_response, NULL, "Action: PJSIPRegister\nRegistration: volte_ims");
|
||||
ami_action(ami, event_response, NULL, "Action: PJSIPAccessNetworkInfo\nRegistration: volte_ims\nInfo: hello");
|
||||
}
|
||||
|
||||
int hex_to_octet_string(const char *name, const char *input, uint8_t *output, size_t output_size)
|
||||
{
|
||||
int i, n;
|
||||
|
||||
if (!input || !input[0]) {
|
||||
printf("Missing value for hex string '%s'.\n", name);
|
||||
return -1;
|
||||
}
|
||||
i = n = 0;
|
||||
while (*input) {
|
||||
if (i == output_size) {
|
||||
printf("Value for hex string '%s' too long, expecting %zu bytes.\n", name,
|
||||
output_size);
|
||||
return -1;
|
||||
}
|
||||
if (*input >= '0' && *input <= '9')
|
||||
output[i] = (output[i] << 4) | (*input - '0');
|
||||
else if (*input >= 'a' && *input <= 'f')
|
||||
output[i] = (output[i] << 4) | (*input - 'a' + 10);
|
||||
else if (*input >= 'A' && *input <= 'F')
|
||||
output[i] = (output[i] << 4) | (*input - 'A' + 10);
|
||||
else {
|
||||
printf("Value for hex string '%s' has invalid character '%c'.\n", name, *input);
|
||||
return -1;
|
||||
}
|
||||
if (++n == 2) {
|
||||
n = 0;
|
||||
i++;
|
||||
}
|
||||
input++;
|
||||
}
|
||||
if (i < output_size) {
|
||||
printf("Value for hex string '%s' too short, expecting %zu bytes.\n", name, output_size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void octest_string_to_hex(uint8_t *input, size_t input_size, char *output)
|
||||
{
|
||||
while(input_size) {
|
||||
sprintf(output, "%02x", *input);
|
||||
input++;
|
||||
input_size--;
|
||||
output += 2;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *usim_opc = "775A1F887D2AD66F9719C2C79F847B50";
|
||||
static const char *usim_k = "D534E07854B75E475C667A856AA31F9C";
|
||||
static const char *usim_sqn = "000000011000";
|
||||
|
||||
void event_authrequest (ami_event_t *event) {
|
||||
const char *rand_str, *autn_str;
|
||||
uint8_t opc[16], k[16], sqn[6], rand[16], autn[16], res[8], ik[16], ck[16], auts[14];
|
||||
char res_str[256], ik_str[256], ck_str[256], auts_str[256];
|
||||
size_t res_len = 8;
|
||||
rand_str = ami_getvar(event, "RAND");
|
||||
autn_str = ami_getvar(event, "AUTN");
|
||||
int rc;
|
||||
|
||||
if (!rand_str || !autn_str) {
|
||||
printf("Missing parameters in AuthRequest\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (hex_to_octet_string("RAND", rand_str, rand, sizeof(rand))) {
|
||||
printf("Invalid RAND parameter in AuthRequest\n");
|
||||
return;
|
||||
}
|
||||
if (hex_to_octet_string("AUTN", autn_str, autn, sizeof(autn))) {
|
||||
printf("Invalid AUTN parameter in AuthRequest\n");
|
||||
return;
|
||||
}
|
||||
if (hex_to_octet_string("OPC", usim_opc, opc, sizeof(opc))) {
|
||||
printf("Invalid OPC parameter in AuthRequest\n");
|
||||
return;
|
||||
}
|
||||
if (hex_to_octet_string("K", usim_k, k, sizeof(k))) {
|
||||
printf("Invalid K parameter in AuthRequest\n");
|
||||
return;
|
||||
}
|
||||
if (hex_to_octet_string("SQN", usim_sqn, sqn, sizeof(sqn))) {
|
||||
printf("Invalid SQN parameter in AuthRequest\n");
|
||||
return;
|
||||
}
|
||||
rc = milenage_check(opc, k, sqn, rand, autn, ik, ck, res, &res_len, auts);
|
||||
octest_string_to_hex(res, sizeof(res), res_str);
|
||||
octest_string_to_hex(ik, sizeof(ik), ik_str);
|
||||
octest_string_to_hex(ck, sizeof(ck), ck_str);
|
||||
octest_string_to_hex(auts, sizeof(auts), auts_str);
|
||||
if (rc == -2) {
|
||||
printf("*** Sending AuthResponse with authentication token ***\n");
|
||||
ami_action(ami, NULL, NULL, "Action: AuthResponse\nRegistration: volte_ims\nAUTS: %s", auts_str);
|
||||
} else if (!rc) {
|
||||
printf("*** Sending AuthResponse with authentication result and keys ***\n");
|
||||
ami_action(ami, NULL, NULL, "Action: AuthResponse\nRegistration: volte_ims\nRES: %s\nCK: %s\nIK: %s", res_str, ck_str, ik_str);
|
||||
} else {
|
||||
printf("*** Sending AuthResponse with authentication error\n");
|
||||
ami_action(ami, NULL, NULL, "Action: AuthResponse\nRegistration: volte_ims");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void reconnect_ami (ami_event_t *event) {
|
||||
printf("*** Reconnecting... ***\n");
|
||||
ev_timer_stop(EV_DEFAULT, &timer_reconnect);
|
||||
ami_connect(ami);
|
||||
}
|
||||
|
||||
void event_connect (ami_event_t *event) {
|
||||
printf("*** CONNECTED ***\n");
|
||||
printf(" semmi = %s\n host = %s\n ip = %s\n port = %s\n",
|
||||
ami_getvar(event, "semmi"),
|
||||
ami_getvar(event, "Host"),
|
||||
ami_getvar(event, "IP"),
|
||||
ami_getvar(event, "Port"));
|
||||
}
|
||||
|
||||
void event_disconnect (ami_event_t *event) {
|
||||
printf("*** DISCONNECTED ***\n");
|
||||
printf(" reason = %s\n host = %s\n ip = %s\n port = %s\n",
|
||||
ami_getvar(event, "Reason"),
|
||||
ami_getvar(event, "Host"),
|
||||
ami_getvar(event, "IP"),
|
||||
ami_getvar(event, "Port"));
|
||||
ev_timer_again(EV_DEFAULT, &timer_reconnect);
|
||||
ev_timer_start(EV_DEFAULT, &timer_reconnect);
|
||||
}
|
||||
|
||||
static int registered=0;
|
||||
|
||||
void event_registry (ami_event_t *event) {
|
||||
const char *status_str;
|
||||
status_str = ami_getvar(event, "Status");
|
||||
|
||||
printf("registry-status=%s\n", status_str);
|
||||
|
||||
if (!strcasecmp(status_str, "Registered")) {
|
||||
if (!registered) {
|
||||
registered = 1;
|
||||
ami_action(ami, event_response, NULL, "Action: PJSIPUnregister\nRegistration: volte_ims");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[]) {
|
||||
ami = ami_new(EV_DEFAULT);
|
||||
if (ami == NULL) {
|
||||
con_debug("ami_new() returned NULL");
|
||||
return 1;
|
||||
}
|
||||
|
||||
char host[128];
|
||||
|
||||
if (argc < 2) {
|
||||
//~ printf("usage: %s <host>\n", argv[0]);
|
||||
printf("Default host used!\n");
|
||||
strcpy(host, "127.0.0.1");
|
||||
} else {
|
||||
strcpy(host, argv[1]);
|
||||
}
|
||||
|
||||
printf("Connecting to %s ...\n", host);
|
||||
ami_credentials(ami, "jolly", "svenja", host, "5038");
|
||||
ami_connect(ami);
|
||||
|
||||
ami_event_register(ami, event_fullybooted, NULL, "Event: FullyBooted");
|
||||
|
||||
ev_timer_init(&timer_reconnect, (void*)reconnect_ami, 3, 3);
|
||||
//~ ev_timer_start(EV_DEFAULT, &timer_reconnect);
|
||||
|
||||
ami_event_register(ami, event_connect, NULL, "Connect");
|
||||
ami_event_register(ami, event_disconnect, NULL, "Disconnect");
|
||||
|
||||
ami_event_register(ami, event_authrequest, NULL, "Event: AuthRequest");
|
||||
|
||||
ami_event_register(ami, event_registry, NULL, "Event: Registry");
|
||||
|
||||
printf("\n");
|
||||
ami_dump_lists(ami);
|
||||
|
||||
ami_action(ami, NULL, NULL, "Action: Login\nUsername: jolly\nSecret: svenja");
|
||||
|
||||
ev_loop(EV_DEFAULT, 0);
|
||||
|
||||
ami_destroy(ami);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
2013-09-17 - netsocket
|
||||
==========
|
||||
|
||||
A netsocket mostantól nem fogad el kívülről értékeket, tehát nem szabad
|
||||
közvetlenül a programból manipulálni a netsocket_t objektumot. A host, lhost,
|
||||
port, lport értékeket az alábbi függvények segítségével lehet beállítani. Ennek
|
||||
oka az, hogy eddig a netsocket_t mutatókban tárolta a host és lhost stringeket,
|
||||
ami azt okozta, hogy ha a főprogramban megváltoztattuk a hostot, akkor a
|
||||
netsocket-ben is megváltozott, hisz ugyan arra mutattak. Mostantól a
|
||||
netsocket_t saját char[] tömbben tárolja ezeket az értékeket, így nem lesz
|
||||
hatással semmilyen külső változtatás, illetve nem fog összekeveredni.
|
||||
|
||||
Eddig így kellett hívni:
|
||||
|
||||
netsocket->host = host;
|
||||
netsocket->port = port;
|
||||
netsocket->lhost = lhost;
|
||||
netsocket->lport = lport;
|
||||
|
||||
Mostantól pedig így kell:
|
||||
|
||||
netsocket_host(netsocket, host);
|
||||
netsocket_port(netsocket, port);
|
||||
netsocket_lhost(netsocket, lhost);
|
||||
netsocket_lport(netsocket, lport);
|
||||
|
||||
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,339 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
CC = gcc
|
||||
CFLAGS = -Wall
|
||||
LIBS = -lcrypto -lev
|
||||
OBJ=pipe.o netsocket.o
|
||||
BIN=pipe
|
||||
|
||||
all: logger pipe fmtsub_test
|
||||
|
||||
pipe: $(OBJ)
|
||||
$(CC) $(CFLAGS) -o $(BIN) $(OBJ) $(EXTOBJ) $(LIBS)
|
||||
|
||||
logger: logger.o logger_test.o misc.o
|
||||
$(CC) $(CFLAGS) -o logger logger.o logger_test.o misc.o
|
||||
|
||||
fmtsub_test: misc.o fmtsub_test.o
|
||||
$(CC) $(CFLAGS) -o fmtsub_test misc.o fmtsub_test.o
|
||||
|
||||
doc:
|
||||
doxygen
|
||||
@echo ""
|
||||
@echo "DOC URL: file://"`pwd`"/html/index.html"
|
||||
@echo ""
|
||||
|
||||
clean:
|
||||
rm -rf $(OBJ) $(BIN) logger fmtsub_test core *.o html/ latex/ man/
|
||||
|
||||
# Függőségek
|
||||
#policy.o: server.h
|
|
@ -0,0 +1,15 @@
|
|||
Ring Bufferrel megoldhato a mem logging?
|
||||
http://en.wikipedia.org/wiki/Circular_buffer
|
||||
|
||||
|
||||
LIBEV STRICT ALIASING
|
||||
=====================
|
||||
|
||||
netsocket.c -ben a libev örjöng:
|
||||
|
||||
* libjsi/netsocket.c: In function ‘netsocket_connect’:
|
||||
* libjsi/netsocket.c:264: warning: dereferencing type-punned pointer will break strict-aliasing rules
|
||||
|
||||
A megoldás egyelőre az, hogy -fno-strict-aliasing CFLAGS-et használjuk.
|
||||
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
# JSS C Library
|
||||
|
||||
This library contains the C functions and macros, which are often used in our
|
||||
projects. In the future, this will be a stand-alone library with unit tests and
|
||||
documentation.
|
||||
|
||||
[AMISMS](https://github.com/andrewjsi/amisms) and [libamievent](https://github.com/andrewjsi/libamievent) uses this library.
|
||||
|
||||
## Source code
|
||||
|
||||
The source code is well written as far as possible. We do not use tabs, instead
|
||||
of 4 spaces is indented. All identifiers, including variables, function names
|
||||
and macros written in English, but some comments and commits in Hungarian is,
|
||||
because we are speaking and thinking in Hungarian. Nevertheless, we try to
|
||||
write everything in English in the future.
|
||||
|
||||
## Contribution
|
||||
|
||||
It is an open source project, which is to be better and better. If you have any
|
||||
ideas or find an error, or get stuck, you can contact us, please file a bug
|
||||
report or send a pull-request!
|
||||
|
||||
## License
|
||||
|
||||
[_GPL2_](https://www.gnu.org/licenses/gpl-2.0.html)
|
||||
|
||||
(C) Copyright 2010-2014 Andras Jeszenszky, [JSS & Hayer
|
||||
IT](http://www.jsshayer.hu) All Rights Reserved.
|
|
@ -0,0 +1,19 @@
|
|||
CC = gcc
|
||||
CFLAGS = -Wall -ggdb -I..
|
||||
CFLAGS += -DCON_DEBUG
|
||||
|
||||
LIBS = -lev -lm -lmysqlclient -lpthread
|
||||
OBJ=amysql.o ../logger.o ../misc.o
|
||||
|
||||
all: test_amysql test_sync_amysql
|
||||
|
||||
test_amysql: test_amysql.o $(OBJ)
|
||||
$(CC) $(CFLAGS) -o test_amysql test_amysql.o $(OBJ) $(LIBS)
|
||||
|
||||
test_sync_amysql: test_sync_amysql.o $(OBJ)
|
||||
$(CC) $(CFLAGS) -o test_sync_amysql test_sync_amysql.o $(OBJ) $(LIBS)
|
||||
|
||||
clean:
|
||||
rm -f $(OBJ) *.o test_amysql test_sync_amysql
|
||||
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
libzdb - http://www.tildeslash.com/libzdb/
|
||||
A small, easy to use Open Source Database Connection Pool Library with the
|
||||
following features:
|
||||
-Thread safe Database Connection Pool
|
||||
-Connect to multiple database systems
|
||||
-Zero runtime configuration, connect using a URL scheme
|
||||
-Supports MySQL, PostgreSQL, SQLite and Oracle
|
||||
|
||||
MySQL C Library API Reference:
|
||||
http://dev.mysql.com/doc/refman/5.1/en/c-api-functions.html
|
||||
|
||||
MySQL C API Tutorial:
|
||||
http://zetcode.com/tutorials/mysqlcapitutorial/
|
||||
|
||||
MySQL szerverben trigger - adding a New User-Defined Function
|
||||
http://dev.mysql.com/doc/refman/5.5/en/adding-udf.html
|
||||
|
||||
|
||||
|
||||
http://jan.kneschke.de/2008/9/9/async-mysql-queries-with-c-api/
|
||||
|
||||
tömör leírás az async elvről:
|
||||
http://betterlogic.com/roger/2008/08/gdb-says-asynchronous-mysql-c-api/
|
||||
|
||||
http://stackoverflow.com/questions/11313686/using-libmysqlclient-in-multi-threaded-application
|
||||
|
||||
http://www.linuxtopia.org/online_books/database_guides/mysql_5.1_database_reference_guide/threaded-clients.html
|
||||
|
||||
http://dev.mysql.com/doc/refman/5.1/en/threaded-clients.html
|
||||
|
|
@ -0,0 +1,321 @@
|
|||
/* amysql.c
|
||||
* Copyright © 2014, Andras Jeszenszky, JSS & Hayer IT - http://www.jsshayer.hu
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/* TODO: megvizsgálni a libzdb-t, mert ismeri a MySQL-t, PostgreSQL-t és az
|
||||
Oracle-t is. A libzdb tudtommal nem aszinkron, viszont az amysql.c mintájára
|
||||
aszinkronná lehetne tenni:) */
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <mysql/mysql.h>
|
||||
#include <ev.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "logger.h"
|
||||
|
||||
#define FIELDBUFSIZE 8192
|
||||
#define FIELDVSIZE 32
|
||||
#define QUERYBUFSIZE 4096
|
||||
|
||||
MYSQL *db;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
int busy = 0;
|
||||
void (*callback)(int, char**, char*);
|
||||
|
||||
int fieldc; // result mezők száma
|
||||
char *fieldv[FIELDVSIZE]; // result mező elemek
|
||||
char fieldbuf[FIELDBUFSIZE]; // result buffer (ide mutatnak a fieldv elemek)
|
||||
char querybuf[QUERYBUFSIZE]; // itt tároljuk el a query-t
|
||||
char error_str[256];
|
||||
int error_num;
|
||||
|
||||
struct option_t {
|
||||
char host[64];
|
||||
char user[64];
|
||||
char password[64];
|
||||
char database[64];
|
||||
char charset[16];
|
||||
int connect_timeout;
|
||||
int data_timeout;
|
||||
} option = {
|
||||
.host = "localhost",
|
||||
.user = "",
|
||||
.password = "",
|
||||
.database = "",
|
||||
.charset = "", // alapértelmezetten nem piszkáljuk a charset-et
|
||||
.connect_timeout = 10, // TODO: prod környezetben ezeket magasra venni!
|
||||
.data_timeout = 20, /* Each attempt uses this timeout value and there
|
||||
are retries if necessary, so the total effective
|
||||
timeout value is three times the option value. */
|
||||
};
|
||||
|
||||
static ev_async evasync_main;
|
||||
static ev_async evasync_thread;
|
||||
|
||||
static struct ev_loop *loop_main; // főprogram event loopja (kapja az amysql_init())
|
||||
static struct ev_loop *loop_thread; // thread event loopja
|
||||
|
||||
pthread_t thread_id;
|
||||
|
||||
void amysql_option_host (const char *host) {
|
||||
strncpy(option.host, host, sizeof(option.host) - 1);
|
||||
}
|
||||
|
||||
void amysql_option_user (const char *user) {
|
||||
strncpy(option.user, user, sizeof(option.user) - 1);
|
||||
}
|
||||
|
||||
void amysql_option_password (const char *password) {
|
||||
strncpy(option.password, password, sizeof(option.password) - 1);
|
||||
}
|
||||
|
||||
void amysql_option_database (const char *database) {
|
||||
strncpy(option.database, database, sizeof(option.database) - 1);
|
||||
}
|
||||
|
||||
void amysql_option_charset (const char *charset) {
|
||||
strncpy(option.charset, charset, sizeof(option.charset) - 1);
|
||||
}
|
||||
|
||||
void amysql_option_connect_timeout (int connect_timeout) {
|
||||
option.connect_timeout = connect_timeout;
|
||||
}
|
||||
|
||||
void amysql_option_data_timeout (int data_timeout) {
|
||||
option.data_timeout = data_timeout;
|
||||
}
|
||||
|
||||
// thread: AMYSQL, ha amysql_query() hívás volt
|
||||
// thread: nincs definiálva, ha amysql_sync_query() hívás volt
|
||||
// Függvény a következőket csinálja:
|
||||
// reset, init, config, connect, query, fetch, save, disconnect, free
|
||||
static void query () {
|
||||
con_debug("send query: %s", querybuf);
|
||||
//** Buffer reset **//
|
||||
memset(fieldbuf, 0, sizeof(fieldbuf));
|
||||
memset(fieldv, 0, sizeof(fieldv));
|
||||
memset(error_str, 0, sizeof(error_str));
|
||||
fieldc = 0;
|
||||
db = NULL;
|
||||
result = NULL;
|
||||
|
||||
//** Init **//
|
||||
db = mysql_init(NULL);
|
||||
if (db == NULL) {
|
||||
con_debug("mysql_init() returned NULL");
|
||||
char *errmsg = "mysql_init(): Can't allocate memory";
|
||||
strncpy(error_str, errmsg, sizeof(error_str));
|
||||
error_num = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
//** Config **//
|
||||
mysql_options(db, MYSQL_OPT_CONNECT_TIMEOUT, &option.connect_timeout);
|
||||
mysql_options(db, MYSQL_OPT_READ_TIMEOUT, &option.data_timeout);
|
||||
mysql_options(db, MYSQL_OPT_WRITE_TIMEOUT, &option.data_timeout);
|
||||
|
||||
//** Connect **//
|
||||
if (!mysql_real_connect(db, option.host, option.user, option.password, option.database, 0, NULL, 0)) {
|
||||
con_debug("Can't connect to MySQL server: %s", mysql_error(db));
|
||||
strncpy(error_str, mysql_error(db), sizeof(error_str));
|
||||
error_num = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (option.charset && strlen(option.charset)) {
|
||||
if (mysql_set_character_set(db, option.charset)) {
|
||||
strncpy(error_str, mysql_error(db), sizeof(error_str));
|
||||
error_num = -1;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
//** Query **//
|
||||
if (mysql_query(db, querybuf)) {;
|
||||
con_debug("query failed: %s", mysql_error(db));
|
||||
strncpy(error_str, mysql_error(db), sizeof(error_str));
|
||||
error_num = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
//** Result **//
|
||||
result = mysql_store_result(db);
|
||||
if (result == NULL) { // INSERT INTO sikeres
|
||||
con_debug("INSERT or UPDATE OK: result = NULL");
|
||||
error_num = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
//** Fetch only ONE row **//
|
||||
int num_fields = mysql_num_fields(result);
|
||||
row = mysql_fetch_row(result);
|
||||
if (row == NULL) { // SELECT-ben a WHERE nem illeszkedett semmire
|
||||
con_debug("SELECT empty: row = NULL");
|
||||
error_num = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Az alábbi for ciklus a következőket csinálja: Egyetlen row mezőinek
|
||||
másolása fieldbuf bufferbe és feldarabolása fieldv-be. A fieldbuf-ba
|
||||
folyamatosan bemásoljuk a row-ból kiolvasott byteokat. Ezzel a
|
||||
folytonossággal helyet spórolunk meg, mert nem kell minden mezőnek fix
|
||||
méretet lefoglalni. A fieldv mutató tömbbe pedig az egyes mezők
|
||||
kezdőcimeit mentjük el, ami a fieldbuf azon indexére mutat, ahol az
|
||||
adott mező kezdődik. Az argc és *argv[] pároshoz hasonlóan a fieldc
|
||||
változóba kerül a fieldv tömb mérete. Ha elegendő volt a FIELDBUFSIZE és
|
||||
a FIELDVSIZE, akkor ez megegyezik a MySQL által visszaadott
|
||||
mysql_num_fields() értékével. Ellenkező esetben annyi lesz, amennyit
|
||||
sikerült kigyűjteni, tehát amennyit biztonsággal ki lehet olvasni. */
|
||||
|
||||
//** Save **//
|
||||
int rpos = 0;
|
||||
for (fieldc = 0; fieldc < num_fields && fieldc < FIELDVSIZE; fieldc++) {
|
||||
if (row[fieldc] == NULL) {
|
||||
fieldv[fieldc] = NULL;
|
||||
} else {
|
||||
fieldv[fieldc] = &fieldbuf[rpos];
|
||||
int i;
|
||||
for (i = 0; row[fieldc][i] != 0; i++) {
|
||||
fieldbuf[rpos] = row[fieldc][i];
|
||||
rpos++;
|
||||
if (rpos > FIELDBUFSIZE - 2) { // ne szaladjunk túl a fieldbuf méretén
|
||||
fieldc++;
|
||||
error_num = 0;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
fieldbuf[rpos] = 0;
|
||||
rpos++;
|
||||
if (rpos > FIELDBUFSIZE - 2) { // ne szaladjunk túl a fieldbuf méretén
|
||||
fieldc++;
|
||||
error_num = 0;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
//~ int k; for (k = 0; k < fieldc; k++) printf("%d s %s s\n", k, fieldv[k]); printf("\n");
|
||||
|
||||
done:
|
||||
//** Free & Disconnect **//
|
||||
if (result != NULL)
|
||||
mysql_free_result(result);
|
||||
if (db != NULL)
|
||||
mysql_close(db);
|
||||
|
||||
// TODO: strerror üzenetét hozzácsapni az errstr-hez, az err != 0
|
||||
// ha 4-es hiba (interrupted system call) jön, akkor azt a mysql_connect()
|
||||
// timeout okozza. Vajon ez hogy van megoldva? SIGALRM??? Az bebaszna!
|
||||
//perror("strerror()");
|
||||
|
||||
}
|
||||
|
||||
void query_and_evasync () {
|
||||
query();
|
||||
|
||||
con_debug("ev_async: AMYSQL -> MAIN");
|
||||
ev_async_send(loop_main, &evasync_main);
|
||||
}
|
||||
|
||||
// thread: MAIN
|
||||
int amysql_is_busy () {
|
||||
return busy;
|
||||
}
|
||||
|
||||
// thread: MAIN
|
||||
int amysql_query (void *cb, const char *fmt, ...) {
|
||||
if (busy) {
|
||||
con_debug("amysql is BUSY");
|
||||
return -1;
|
||||
}
|
||||
busy = 1;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(querybuf, sizeof(querybuf) - 1, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
callback = cb;
|
||||
|
||||
con_debug("ev_async: MAIN -> AMYSQL");
|
||||
ev_async_send(loop_thread, &evasync_thread);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// thread: MAIN
|
||||
static void invoke_callback (EV_P_ ev_async *w, int revents) {
|
||||
/* callback hívás közben már lehet új amysql_query() függvényt hívni,
|
||||
mert féligmeddig biztonságos. Lehetőség szerint a callback függvény
|
||||
legvégén legyen új amysql_query() hívás, mert az amysql thread felül
|
||||
fogja írni a fieldc/fieldv és error_num/error_str változókat. */
|
||||
busy = 0;
|
||||
|
||||
callback(fieldc, fieldv, (error_num) ? error_str : NULL);
|
||||
}
|
||||
|
||||
// thread: AMYSQL
|
||||
static void *infinite_loop () {
|
||||
/* Itt lehet inicializálni az AMYSQL thread saját event watchereit */
|
||||
|
||||
ev_loop(loop_thread, 0);
|
||||
con_debug("FATAL: amysql event loop exited! ");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// thread: MAIN
|
||||
int amysql_init (struct ev_loop *loop) {
|
||||
busy = 0;
|
||||
|
||||
loop_main = loop;
|
||||
loop_thread = ev_loop_new(EVFLAG_AUTO);
|
||||
|
||||
ev_async_init(&evasync_main, (void*)invoke_callback);
|
||||
ev_async_init(&evasync_thread, (void*)query_and_evasync);
|
||||
|
||||
/* A mostani kezdetleges thread tapasztalataim alapján, szerintem az
|
||||
ev_async watchereket itt, még a pthread_create() előtt kell indítani.
|
||||
Azaz még a hívó thread kontextusában. Mert ha az új thread-be
|
||||
indítanánk, akkor elképzelhető, hogy visszatérés után a hívó függvény
|
||||
egyből egy ev_async_send() hívással folytatja a futást és lehet, hogy az
|
||||
új thread még nem járna az ev_async_init()-nél és ev_async_start()-nál.
|
||||
Ez pedig ugye nem jó, mert azelőtt hívnánk meg valamit, mint hogy
|
||||
inicializáltuk volna. A többi, (a thread-re nézve saját) event watcher,
|
||||
io, időzítő, stb.. inicializálását már végezheti a thread saját maga,
|
||||
tehát mehet a pthread_create() által meghívott függvénybe. */
|
||||
ev_async_start(loop_main, &evasync_main);
|
||||
ev_async_start(loop_thread, &evasync_thread);
|
||||
|
||||
int err;
|
||||
err = pthread_create(&thread_id, NULL, infinite_loop, NULL);
|
||||
if (err)
|
||||
con_debug("thread creating error: (%d) %s", err, strerror(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
int amysql_sync_query (int *parc, char **parv[], const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(querybuf, sizeof(querybuf) - 1, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
query();
|
||||
|
||||
if (parc)
|
||||
*parc = fieldc;
|
||||
if (parv)
|
||||
*parv = fieldv;
|
||||
|
||||
return error_num;
|
||||
}
|
||||
|
||||
const char *amysql_strerror () {
|
||||
return (error_num) ? error_str : NULL;
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/* amysql.h
|
||||
* Copyright © 2014, Andras Jeszenszky, JSS & Hayer IT - http://www.jsshayer.hu
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
#include <ev.h>
|
||||
|
||||
/* Azért kell a loop paraméter, mert innen tudja az amysql, hogy melyik
|
||||
event loop-ban kell majd meghívni a callback-et.*/
|
||||
|
||||
int amysql_init (struct ev_loop *loop);
|
||||
|
||||
/* Az amysql_query() azonnal visszaadja a vezérlést, és a háttérben egy
|
||||
másik szálon megkezdi a paraméterben megadott lekérdezést az adatbázis
|
||||
szerver felé. Amikor megjön a válasz, akkor lezárja a szerverrel a
|
||||
kapcsolatot és meghívja a paraméterben megadott callback függvényt.
|
||||
|
||||
Figyelem! A callback függvény végén, de tényleg a legvégén lehetőség van új
|
||||
amysql_query() függvény hívására. Hatására a fieldc/fieldv és a hibaváltozók
|
||||
törlődni fognak, amiket a callback függvény is kapott.*/
|
||||
|
||||
int amysql_query (void *cb, const char *fmt, ...);
|
||||
|
||||
|
||||
/* Konfigurációs függvények */
|
||||
|
||||
// default: localhost
|
||||
void amysql_option_host (const char *host);
|
||||
|
||||
void amysql_option_user (const char *user);
|
||||
|
||||
void amysql_option_password (const char *password);
|
||||
|
||||
void amysql_option_database (const char *database);
|
||||
|
||||
// default: nem hívja meg a mysql_set_character_set() függvényt
|
||||
void amysql_option_charset (const char *charset);
|
||||
|
||||
// default: 10
|
||||
void amysql_option_connect_timeout (int connect_timeout);
|
||||
|
||||
// default: 20
|
||||
void amysql_option_data_timeout (int data_timeout);
|
||||
|
||||
|
||||
// visszaadja a hiba szövegét vagy NULL-t, ha nem volt hiba
|
||||
const char *amysql_strerror ();
|
||||
|
||||
// nem-aszinkron lekérdezés. A lekérdezés erejéig az amysql_sync_query() hívás
|
||||
// blokkol. Az eredményt a parc és a parv-be menti el.
|
||||
int amysql_sync_query (int *parc, char **parv[], const char *fmt, ...);
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
/* test_amysql.c
|
||||
* Copyright © 2014, Andras Jeszenszky, JSS & Hayer IT - http://www.jsshayer.hu
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ev.h>
|
||||
|
||||
#include "amysql.h"
|
||||
#include "debug.h"
|
||||
|
||||
static struct ev_loop *loop;
|
||||
static ev_timer timeout_watcher;
|
||||
|
||||
static void cbtest (int fc, char *fv[], char *e);
|
||||
|
||||
static void q () {
|
||||
amysql_query(cbtest, "select * from smsout where sent='0' order by RAND()");
|
||||
}
|
||||
|
||||
static void cbtest (int fc, char *fv[], char *e) {
|
||||
debi(fc);
|
||||
printf("e=%s\n", e);
|
||||
int i;
|
||||
for (i = 0; i < fc; i++) {
|
||||
printf("%d --- %s\n", i, fv[i]);
|
||||
}
|
||||
|
||||
// 3 másodperc múlva q() futtatása
|
||||
ev_once(loop, -1, -1, 3, q, 0);
|
||||
}
|
||||
|
||||
static void timeout_cb (EV_P_ ev_timer *w, int revents) {
|
||||
printf("timeout\n");
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[]) {
|
||||
loop = ev_default_loop (0);
|
||||
|
||||
ev_timer_init (&timeout_watcher, timeout_cb, 0, 0.5);
|
||||
ev_timer_start (loop, &timeout_watcher);
|
||||
|
||||
amysql_init(loop);
|
||||
|
||||
q(); // berúgjuk a mocit:)
|
||||
|
||||
ev_loop (loop, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/* test_sync_amysql.c
|
||||
* Copyright © 2014, Andras Jeszenszky, JSS & Hayer IT - http://www.jsshayer.hu
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "amysql.h"
|
||||
#include "debug.h"
|
||||
|
||||
int main (int argc, char *argv[]) {
|
||||
amysql_option_user ("proba");
|
||||
amysql_option_password ("proba");
|
||||
amysql_option_database ("proba");
|
||||
amysql_option_charset ("utf8");
|
||||
|
||||
// if (amysql_sync_query(NULL, NULL, "INSERT INTO proba (name, comment) VALUES ('%s', '%s')", "egy", "kettő")) {
|
||||
// printf("ERROR: %s\n", amysql_strerror());
|
||||
// }
|
||||
|
||||
int parc;
|
||||
char **parv;
|
||||
if (amysql_sync_query(&parc, &parv, "select * from proba order by RAND()")) {
|
||||
printf("ERROR: %s\n", amysql_strerror());
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 0; i < parc; i++) {
|
||||
printf("%d --- %s\n", i, parv[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
/* debug.h
|
||||
* Copyright © 2014, Andras Jeszenszky, JSS & Hayer IT - http://www.jsshayer.hu
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
#define debi(x) printf(#x " = %d\n", ((int)(x)))
|
||||
#define debf(x) printf(#x " = %f\n", (x))
|
||||
#define debs(x) printf(#x " = %s\n", (x))
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/* fmtsub_test.c
|
||||
* Copyright © 2014, Andras Jeszenszky, JSS & Hayer IT - http://www.jsshayer.hu
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "misc.h"
|
||||
|
||||
/*
|
||||
const char *args[][2] = {
|
||||
{"%n", "2463434"},
|
||||
{"%v", "0.9.6-rc2"},
|
||||
{"%n", "Jekusa Poromeck"},
|
||||
{0}
|
||||
};
|
||||
*/
|
||||
//~ void prob (const char *args[][2]) {
|
||||
//~ int i;
|
||||
//~ for (i = 0; afmt[i][0] != 0; i++) {
|
||||
//~ printf("hello %s --- %s\n", afmt[i][0], afmt[i][1]);
|
||||
//~
|
||||
//~ }
|
||||
//~ }
|
||||
|
||||
int main (int argc, char **argv) {
|
||||
char buf2[32];
|
||||
char buf[64];
|
||||
|
||||
char *pattern = argv[1];
|
||||
|
||||
char proba[64];
|
||||
strcpy(proba, "PROBA");
|
||||
|
||||
const char *args[][2] = {
|
||||
{"%n", NULL},
|
||||
{"", "URES_STRING"},
|
||||
{"%v", "0.9.6-rc2"},
|
||||
{"%a", "Jekusa Poromeck"},
|
||||
{"%p", proba},
|
||||
{"Windows", "Linux"},
|
||||
{"\\%", "%"},
|
||||
{0}
|
||||
};
|
||||
|
||||
if (fmtsub(buf, sizeof(buf), pattern, args)) {
|
||||
printf("fmtsub() hibaval tert vissza!\n");
|
||||
}
|
||||
|
||||
printf("%d s %s s\n", (int)strlen(buf), buf);
|
||||
|
||||
strncpy(buf2, buf, sizeof(buf2)-1);
|
||||
printf("%d s %s s\n", (int)strlen(buf2), buf2);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
CC = gcc
|
||||
CFLAGS = -Wall -I.. -ggdb
|
||||
LDFLAGS = -lpthread
|
||||
|
||||
all: test_htclient
|
||||
|
||||
test_htclient: test_htclient.o htclient.o url_parser.o
|
||||
$(CC) $(CFLAGS) -o test_htclient test_htclient.o htclient.o url_parser.o $(LDFLAGS)
|
||||
|
||||
clean:
|
||||
rm -f test_htclient *.o
|
|
@ -0,0 +1,235 @@
|
|||
/* htclient.c
|
||||
* Copyright © 2014, Andras Jeszenszky, JSS & Hayer IT - http://www.jsshayer.hu
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "htclient.h"
|
||||
#include "debug.h"
|
||||
#include "url_parser.h"
|
||||
|
||||
/* void ERR(...)
|
||||
*
|
||||
* A paraméterül átadott VA_ARGS formátumú hibaüzenetet bemásolja a req->error
|
||||
* -ba, majd visszatér return -1 -el. Figyelni kell a blokkos szerkezeteknél:
|
||||
* Mindenképp használni kell a { } zárójeleket, mivel ez a makró két utasítást
|
||||
* tartalmaz. A { } elhagyásával logikai hiba keletkezhet a programban.
|
||||
*/
|
||||
#define ERR(...) snprintf(htc->error, sizeof(htc->error), __VA_ARGS__); return -1
|
||||
|
||||
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
|
||||
|
||||
void htclient_dump (htclient_t *htc) {
|
||||
#define HTCLIENT_DUMPS(s) printf("%13s = %s\n", #s, htc->s)
|
||||
#define HTCLIENT_DUMPI(i) printf("%13s = %d\n", #i, htc->i)
|
||||
HTCLIENT_DUMPS(url.full);
|
||||
HTCLIENT_DUMPS(url.scheme);
|
||||
HTCLIENT_DUMPS(url.host);
|
||||
HTCLIENT_DUMPS(url.port);
|
||||
HTCLIENT_DUMPS(url.path);
|
||||
HTCLIENT_DUMPS(url.query);
|
||||
HTCLIENT_DUMPS(url.fragment);
|
||||
HTCLIENT_DUMPS(url.username);
|
||||
HTCLIENT_DUMPS(url.password);
|
||||
HTCLIENT_DUMPS(request_data);
|
||||
HTCLIENT_DUMPS(response_data);
|
||||
HTCLIENT_DUMPI(num_headers);
|
||||
HTCLIENT_DUMPS(header_buf);
|
||||
HTCLIENT_DUMPS(error);
|
||||
}
|
||||
|
||||
// Skip the characters until one of the delimiters characters found.
|
||||
// 0-terminate resulting word. Skip the rest of the delimiters if any. Advance
|
||||
// pointer to buffer to the next word. Return found 0-terminated word.
|
||||
// (function from Mongoose project)
|
||||
static char *skip (char **buf, const char *delimiters) {
|
||||
char *p, *begin_word, *end_word, *end_delimiters;
|
||||
|
||||
begin_word = *buf;
|
||||
end_word = begin_word + strcspn(begin_word, delimiters);
|
||||
end_delimiters = end_word + strspn(end_word, delimiters);
|
||||
|
||||
for (p = end_word; p < end_delimiters; p++) {
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
*buf = end_delimiters;
|
||||
|
||||
return begin_word;
|
||||
}
|
||||
|
||||
// Parse HTTP headers from the given buffer, advance buffer to the point where
|
||||
// parsing stopped. (function from Mongoose project)
|
||||
static void parse_http_headers(char **buf, struct htclient_t *htc) {
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(htc->headers); i++) {
|
||||
htc->headers[i].name = skip(buf, ": ");
|
||||
htc->headers[i].value = skip(buf, "\r\n");
|
||||
if (htc->headers[i].name[0] == '\0')
|
||||
break;
|
||||
htc->num_headers = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
char *htclient_error (htclient_t *htc) {
|
||||
if (htc->error == NULL || !strlen(htc->error))
|
||||
return NULL;
|
||||
return htc->error;
|
||||
}
|
||||
|
||||
int htclient_url (htclient_t *htc, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(htc->url.full, sizeof(htc->url.full), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
struct parsed_url *pu = parse_url(htc->url.full);
|
||||
if (pu == NULL) {
|
||||
htc->url.set = 0;
|
||||
ERR("URL mismatch");
|
||||
}
|
||||
|
||||
htc->url.url_parser_ptr = pu;
|
||||
htc->url.scheme = pu->scheme;
|
||||
htc->url.host = pu->host;
|
||||
htc->url.port = pu->port;
|
||||
htc->url.path = pu->path;
|
||||
htc->url.query = pu->query;
|
||||
htc->url.fragment = pu->fragment;
|
||||
htc->url.username = pu->username;
|
||||
htc->url.password = pu->password;
|
||||
|
||||
// ha nincs megadva a port, akkor a scheme-ből megállapítjuk
|
||||
if (!htc->url.port && htc->url.scheme) {
|
||||
if (!strcmp(htc->url.scheme, "http")) {
|
||||
// TODO: az strdup() nem okoz memória szivárgást? Ha felszabadítjuk
|
||||
// az url_parser-t, akkor az felszabadítja ezt is?
|
||||
htc->url.port = strdup("80");
|
||||
} else if (!strcmp(htc->url.scheme, "https")) {
|
||||
htc->url.port = strdup("443");
|
||||
}
|
||||
}
|
||||
|
||||
// ha valamilyen oknál fogva ezen a ponton nincs
|
||||
// host vagy nincs port, akkor a további
|
||||
// grimbuszok elkerülése végett hivát dobunk:)
|
||||
if (!htc->url.host || !htc->url.port) {
|
||||
htc->url.set = 0;
|
||||
ERR("URL mismatch");
|
||||
}
|
||||
|
||||
htc->url.set = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int htclient_perform (htclient_t *htc) {
|
||||
struct sockaddr_in serv_addr;
|
||||
struct hostent *server;
|
||||
int port;
|
||||
int sockfd;
|
||||
int rv;
|
||||
|
||||
if (!htc->url.set) {
|
||||
ERR("URL not set or bogus");
|
||||
}
|
||||
|
||||
port = atoi(htc->url.port);
|
||||
|
||||
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sockfd < 0) {
|
||||
ERR("error opening socket: %s", strerror(errno));
|
||||
}
|
||||
|
||||
server = gethostbyname(htc->url.host);
|
||||
if (server == NULL) {
|
||||
close(sockfd);
|
||||
ERR("host not found: %s", htc->url.host);
|
||||
}
|
||||
|
||||
bzero((char *) &serv_addr, sizeof(serv_addr));
|
||||
serv_addr.sin_family = AF_INET;
|
||||
bcopy((char *)server->h_addr,
|
||||
(char *)&serv_addr.sin_addr.s_addr,
|
||||
server->h_length);
|
||||
serv_addr.sin_port = htons(port);
|
||||
if (connect(sockfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0) {
|
||||
close(sockfd);
|
||||
ERR("can't connect to %s:%d: %s", htc->url.host, port, strerror(errno));
|
||||
}
|
||||
|
||||
rv = write(sockfd, htc->request_data, strlen(htc->request_data));
|
||||
if (rv < 0) {
|
||||
close(sockfd);
|
||||
ERR("ERROR writing to socket");
|
||||
}
|
||||
|
||||
memset(htc->response_data, 0, sizeof(htc->response_data));
|
||||
rv = read(sockfd, htc->response_data, sizeof(htc->response_data) - 1);
|
||||
if (rv < 0) {
|
||||
close(sockfd);
|
||||
ERR("ERROR reading from socket");
|
||||
}
|
||||
|
||||
htc->header_buf = strdup(htc->response_data);
|
||||
char *buf = htc->header_buf;
|
||||
|
||||
parse_http_headers(&buf, htc);
|
||||
close(sockfd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *htclient_header_get (htclient_t *htc, const char *name) {
|
||||
int i;
|
||||
for (i = 0; i < htc->num_headers; i++) {
|
||||
if (htc->headers[i].name == NULL || htc->headers[i].value == NULL)
|
||||
continue;
|
||||
if (!strcmp(htc->headers[i].name, name))
|
||||
return htc->headers[i].value;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
htclient_t *htclient_new () {
|
||||
htclient_t *htc = malloc(sizeof(*htc));
|
||||
if (htc == NULL) {
|
||||
fprintf(stderr, "out of memory");
|
||||
return NULL;
|
||||
}
|
||||
memset(htc, 0, sizeof(*htc));
|
||||
return htc;
|
||||
}
|
||||
|
||||
void htclient_request_set (htclient_t *htc, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(htc->request_data, sizeof(htc->request_data), fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
|
||||
void htclient_destroy (htclient_t *htc) {
|
||||
if (htc == NULL)
|
||||
return;
|
||||
if (htc->header_buf != NULL) {
|
||||
free(htc->header_buf);
|
||||
htc->header_buf = NULL;
|
||||
}
|
||||
free(htc);
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
/* htclient.h
|
||||
* Copyright © 2014, Andras Jeszenszky, JSS & Hayer IT - http://www.jsshayer.hu
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
#define HTCLIENT_BUFSIZ 1024
|
||||
|
||||
// változás esetén módosítsd a htclient_dump() függvényt a htclient.c fájlban!
|
||||
typedef struct htclient_t {
|
||||
struct {
|
||||
void *url_parser_ptr; // url_parser.h -ban definiált pointer, ezt kell majd felszabadítani
|
||||
char full[HTCLIENT_BUFSIZ]; // http://jsi@jss.hu/auth?param=59
|
||||
char *scheme; // http
|
||||
char *host; // jss.hu
|
||||
char *port; // (null)
|
||||
char *path; // auth
|
||||
char *query; // param=59
|
||||
char *fragment; // (null)
|
||||
char *username; // jsi
|
||||
char *password; // (null)
|
||||
int set; // 1 lesz, ha rendben beállítottuk az URL-t
|
||||
} url;
|
||||
char request_data[HTCLIENT_BUFSIZ];
|
||||
char response_data[HTCLIENT_BUFSIZ];
|
||||
struct {
|
||||
char *name;
|
||||
char *value;
|
||||
} headers[16];
|
||||
int num_headers;
|
||||
char *header_buf;
|
||||
char error[128];
|
||||
} htclient_t;
|
||||
|
||||
// új htclient objektum
|
||||
htclient_t *htclient_new ();
|
||||
|
||||
// URL beállítása
|
||||
// Kezeli a scheme, host, port, path URL részeket. Tovább infó a
|
||||
// htclient_t->url struktúrában. Az URL path részét nem kezeli a
|
||||
// htclient_perform(), ezért azt külön el kell menteni a request-ben.
|
||||
//
|
||||
// például: http://jss.hu:3333/akarmi.jpg
|
||||
int htclient_url (htclient_t *htc, const char *fmt, ...);
|
||||
|
||||
// Beállítja a teljes HTTP request-et. Beleértve a fejléceket meg mindent.
|
||||
void htclient_request_set (htclient_t *htc, const char *fmt, ...);
|
||||
|
||||
// Végrehajtja a lekérdezést. A függvény addig blokkol, amíg nem érkezik meg a
|
||||
// válasz vagy valami hiba történik.
|
||||
int htclient_perform (htclient_t *htc);
|
||||
|
||||
// Visszaadja a válaszban szereplő header értékét. Ha a megadott header nem
|
||||
// létezik, akkor a visszatérési érték NULL.
|
||||
char *htclient_header_get (htclient_t *htc, const char *name);
|
||||
|
||||
// Felszabadítja a htclient objektumot
|
||||
void htclient_destroy (htclient_t *htc);
|
||||
|
||||
// Ha volt hiba, akkor visszaadja a hibastringet, ha nem, akkor NULL
|
||||
char *htclient_error (htclient_t *htc);
|
||||
|
||||
// htclient_t struktúra dumpolása
|
||||
void htclient_dump (htclient_t *htc);
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
/* test_htclient.c
|
||||
* Copyright © 2014, Andras Jeszenszky, JSS & Hayer IT - http://www.jsshayer.hu
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "htclient.h"
|
||||
#include "debug.h"
|
||||
#include "url_parser.h"
|
||||
|
||||
void url_test () {
|
||||
htclient_t *h = htclient_new();
|
||||
|
||||
htclient_url(h, "http://10.42.20.14:3000/akarmi.jpg");
|
||||
htclient_dump(h);
|
||||
|
||||
htclient_destroy(h);
|
||||
}
|
||||
|
||||
int main (int argc, const char *argv[]) {
|
||||
// url_test(); return(0);
|
||||
|
||||
htclient_t *h;
|
||||
h = htclient_new();
|
||||
if (h == NULL) {
|
||||
printf("out of memory\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
htclient_url(h, "http://10.42.20.14:3000/dovecheck");
|
||||
htclient_request_set(h,
|
||||
"GET /auth\r\n"
|
||||
"Auth-server: akarmi\r\n"
|
||||
"Auth-port: %d\r\n"
|
||||
"\r\n"
|
||||
, 5555
|
||||
);
|
||||
htclient_perform(h);
|
||||
|
||||
htclient_dump(h);
|
||||
if (htclient_error(h)) {
|
||||
printf("error: %s\n", htclient_error(h));
|
||||
goto err;
|
||||
}
|
||||
|
||||
char *hdr = htclient_header_get(h, "Auth-server");
|
||||
printf("Header vissza: %s\n", hdr);
|
||||
|
||||
printf("len = %s\n", htclient_header_get(h, "Content-Length"));
|
||||
|
||||
htclient_destroy(h);
|
||||
return 0;
|
||||
|
||||
err:
|
||||
htclient_destroy(h);
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -0,0 +1,329 @@
|
|||
/*_
|
||||
* Copyright 2010-2011 Scyphus Solutions Co. Ltd. All rights reserved.
|
||||
*
|
||||
* Authors:
|
||||
* Hirochika Asai
|
||||
*/
|
||||
|
||||
#include "url_parser.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/*
|
||||
* Prototype declarations
|
||||
*/
|
||||
static __inline__ int _is_scheme_char(int);
|
||||
|
||||
/*
|
||||
* Check whether the character is permitted in scheme string
|
||||
*/
|
||||
static __inline__ int
|
||||
_is_scheme_char(int c)
|
||||
{
|
||||
return (!isalpha(c) && '+' != c && '-' != c && '.' != c) ? 0 : 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* See RFC 1738, 3986
|
||||
*/
|
||||
struct parsed_url *
|
||||
parse_url(const char *url)
|
||||
{
|
||||
struct parsed_url *purl;
|
||||
const char *tmpstr;
|
||||
const char *curstr;
|
||||
int len;
|
||||
int i;
|
||||
int userpass_flag;
|
||||
int bracket_flag;
|
||||
|
||||
/* Allocate the parsed url storage */
|
||||
purl = malloc(sizeof(struct parsed_url));
|
||||
if ( NULL == purl ) {
|
||||
return NULL;
|
||||
}
|
||||
purl->scheme = NULL;
|
||||
purl->host = NULL;
|
||||
purl->port = NULL;
|
||||
purl->path = NULL;
|
||||
purl->query = NULL;
|
||||
purl->fragment = NULL;
|
||||
purl->username = NULL;
|
||||
purl->password = NULL;
|
||||
|
||||
curstr = url;
|
||||
|
||||
/*
|
||||
* <scheme>:<scheme-specific-part>
|
||||
* <scheme> := [a-z\+\-\.]+
|
||||
* upper case = lower case for resiliency
|
||||
*/
|
||||
/* Read scheme */
|
||||
tmpstr = strchr(curstr, ':');
|
||||
if ( NULL == tmpstr ) {
|
||||
/* Not found the character */
|
||||
parsed_url_free(purl);
|
||||
return NULL;
|
||||
}
|
||||
/* Get the scheme length */
|
||||
len = tmpstr - curstr;
|
||||
/* Check restrictions */
|
||||
for ( i = 0; i < len; i++ ) {
|
||||
if ( !_is_scheme_char(curstr[i]) ) {
|
||||
/* Invalid format */
|
||||
parsed_url_free(purl);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
/* Copy the scheme to the storage */
|
||||
purl->scheme = malloc(sizeof(char) * (len + 1));
|
||||
if ( NULL == purl->scheme ) {
|
||||
parsed_url_free(purl);
|
||||
return NULL;
|
||||
}
|
||||
(void)strncpy(purl->scheme, curstr, len);
|
||||
purl->scheme[len] = '\0';
|
||||
/* Make the character to lower if it is upper case. */
|
||||
for ( i = 0; i < len; i++ ) {
|
||||
purl->scheme[i] = tolower(purl->scheme[i]);
|
||||
}
|
||||
/* Skip ':' */
|
||||
tmpstr++;
|
||||
curstr = tmpstr;
|
||||
|
||||
/*
|
||||
* //<user>:<password>@<host>:<port>/<url-path>
|
||||
* Any ":", "@" and "/" must be encoded.
|
||||
*/
|
||||
/* Eat "//" */
|
||||
for ( i = 0; i < 2; i++ ) {
|
||||
if ( '/' != *curstr ) {
|
||||
parsed_url_free(purl);
|
||||
return NULL;
|
||||
}
|
||||
curstr++;
|
||||
}
|
||||
|
||||
/* Check if the user (and password) are specified. */
|
||||
userpass_flag = 0;
|
||||
tmpstr = curstr;
|
||||
while ( '\0' != *tmpstr ) {
|
||||
if ( '@' == *tmpstr ) {
|
||||
/* Username and password are specified */
|
||||
userpass_flag = 1;
|
||||
break;
|
||||
} else if ( '/' == *tmpstr ) {
|
||||
/* End of <host>:<port> specification */
|
||||
userpass_flag = 0;
|
||||
break;
|
||||
}
|
||||
tmpstr++;
|
||||
}
|
||||
|
||||
/* User and password specification */
|
||||
tmpstr = curstr;
|
||||
if ( userpass_flag ) {
|
||||
/* Read username */
|
||||
while ( '\0' != *tmpstr && ':' != *tmpstr && '@' != *tmpstr ) {
|
||||
tmpstr++;
|
||||
}
|
||||
len = tmpstr - curstr;
|
||||
purl->username = malloc(sizeof(char) * (len + 1));
|
||||
if ( NULL == purl->username ) {
|
||||
parsed_url_free(purl);
|
||||
return NULL;
|
||||
}
|
||||
(void)strncpy(purl->username, curstr, len);
|
||||
purl->username[len] = '\0';
|
||||
/* Proceed current pointer */
|
||||
curstr = tmpstr;
|
||||
if ( ':' == *curstr ) {
|
||||
/* Skip ':' */
|
||||
curstr++;
|
||||
/* Read password */
|
||||
tmpstr = curstr;
|
||||
while ( '\0' != *tmpstr && '@' != *tmpstr ) {
|
||||
tmpstr++;
|
||||
}
|
||||
len = tmpstr - curstr;
|
||||
purl->password = malloc(sizeof(char) * (len + 1));
|
||||
if ( NULL == purl->password ) {
|
||||
parsed_url_free(purl);
|
||||
return NULL;
|
||||
}
|
||||
(void)strncpy(purl->password, curstr, len);
|
||||
purl->password[len] = '\0';
|
||||
curstr = tmpstr;
|
||||
}
|
||||
/* Skip '@' */
|
||||
if ( '@' != *curstr ) {
|
||||
parsed_url_free(purl);
|
||||
return NULL;
|
||||
}
|
||||
curstr++;
|
||||
}
|
||||
|
||||
if ( '[' == *curstr ) {
|
||||
bracket_flag = 1;
|
||||
} else {
|
||||
bracket_flag = 0;
|
||||
}
|
||||
/* Proceed on by delimiters with reading host */
|
||||
tmpstr = curstr;
|
||||
while ( '\0' != *tmpstr ) {
|
||||
if ( bracket_flag && ']' == *tmpstr ) {
|
||||
/* End of IPv6 address. */
|
||||
tmpstr++;
|
||||
break;
|
||||
} else if ( !bracket_flag && (':' == *tmpstr || '/' == *tmpstr) ) {
|
||||
/* Port number is specified. */
|
||||
break;
|
||||
}
|
||||
tmpstr++;
|
||||
}
|
||||
len = tmpstr - curstr;
|
||||
purl->host = malloc(sizeof(char) * (len + 1));
|
||||
if ( NULL == purl->host || len <= 0 ) {
|
||||
parsed_url_free(purl);
|
||||
return NULL;
|
||||
}
|
||||
(void)strncpy(purl->host, curstr, len);
|
||||
purl->host[len] = '\0';
|
||||
curstr = tmpstr;
|
||||
|
||||
/* Is port number specified? */
|
||||
if ( ':' == *curstr ) {
|
||||
curstr++;
|
||||
/* Read port number */
|
||||
tmpstr = curstr;
|
||||
while ( '\0' != *tmpstr && '/' != *tmpstr ) {
|
||||
tmpstr++;
|
||||
}
|
||||
len = tmpstr - curstr;
|
||||
purl->port = malloc(sizeof(char) * (len + 1));
|
||||
if ( NULL == purl->port ) {
|
||||
parsed_url_free(purl);
|
||||
return NULL;
|
||||
}
|
||||
(void)strncpy(purl->port, curstr, len);
|
||||
purl->port[len] = '\0';
|
||||
curstr = tmpstr;
|
||||
}
|
||||
|
||||
/* End of the string */
|
||||
if ( '\0' == *curstr ) {
|
||||
return purl;
|
||||
}
|
||||
|
||||
/* Skip '/' */
|
||||
if ( '/' != *curstr ) {
|
||||
parsed_url_free(purl);
|
||||
return NULL;
|
||||
}
|
||||
curstr++;
|
||||
|
||||
/* Parse path */
|
||||
tmpstr = curstr;
|
||||
while ( '\0' != *tmpstr && '#' != *tmpstr && '?' != *tmpstr ) {
|
||||
tmpstr++;
|
||||
}
|
||||
len = tmpstr - curstr;
|
||||
purl->path = malloc(sizeof(char) * (len + 1));
|
||||
if ( NULL == purl->path ) {
|
||||
parsed_url_free(purl);
|
||||
return NULL;
|
||||
}
|
||||
(void)strncpy(purl->path, curstr, len);
|
||||
purl->path[len] = '\0';
|
||||
curstr = tmpstr;
|
||||
|
||||
/* Is query specified? */
|
||||
if ( '?' == *curstr ) {
|
||||
/* Skip '?' */
|
||||
curstr++;
|
||||
/* Read query */
|
||||
tmpstr = curstr;
|
||||
while ( '\0' != *tmpstr && '#' != *tmpstr ) {
|
||||
tmpstr++;
|
||||
}
|
||||
len = tmpstr - curstr;
|
||||
purl->query = malloc(sizeof(char) * (len + 1));
|
||||
if ( NULL == purl->query ) {
|
||||
parsed_url_free(purl);
|
||||
return NULL;
|
||||
}
|
||||
(void)strncpy(purl->query, curstr, len);
|
||||
purl->query[len] = '\0';
|
||||
curstr = tmpstr;
|
||||
}
|
||||
|
||||
/* Is fragment specified? */
|
||||
if ( '#' == *curstr ) {
|
||||
/* Skip '#' */
|
||||
curstr++;
|
||||
/* Read fragment */
|
||||
tmpstr = curstr;
|
||||
while ( '\0' != *tmpstr ) {
|
||||
tmpstr++;
|
||||
}
|
||||
len = tmpstr - curstr;
|
||||
purl->fragment = malloc(sizeof(char) * (len + 1));
|
||||
if ( NULL == purl->fragment ) {
|
||||
parsed_url_free(purl);
|
||||
return NULL;
|
||||
}
|
||||
(void)strncpy(purl->fragment, curstr, len);
|
||||
purl->fragment[len] = '\0';
|
||||
curstr = tmpstr;
|
||||
}
|
||||
|
||||
return purl;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free memory of parsed url
|
||||
*/
|
||||
void
|
||||
parsed_url_free(struct parsed_url *purl)
|
||||
{
|
||||
if ( NULL != purl ) {
|
||||
if ( NULL != purl->scheme ) {
|
||||
free(purl->scheme);
|
||||
}
|
||||
if ( NULL != purl->host ) {
|
||||
free(purl->host);
|
||||
}
|
||||
if ( NULL != purl->port ) {
|
||||
free(purl->port);
|
||||
}
|
||||
if ( NULL != purl->path ) {
|
||||
free(purl->path);
|
||||
}
|
||||
if ( NULL != purl->query ) {
|
||||
free(purl->query);
|
||||
}
|
||||
if ( NULL != purl->fragment ) {
|
||||
free(purl->fragment);
|
||||
}
|
||||
if ( NULL != purl->username ) {
|
||||
free(purl->username);
|
||||
}
|
||||
if ( NULL != purl->password ) {
|
||||
free(purl->password);
|
||||
}
|
||||
free(purl);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* tab-width: 4
|
||||
* c-basic-offset: 4
|
||||
* End:
|
||||
* vim600: sw=4 ts=4 fdm=marker
|
||||
* vim<600: sw=4 ts=4
|
||||
*/
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/*_
|
||||
* Copyright 2010 Scyphus Solutions Co. Ltd. All rights reserved.
|
||||
*
|
||||
* Authors:
|
||||
* Hirochika Asai
|
||||
*/
|
||||
|
||||
#ifndef _URL_PARSER_H
|
||||
#define _URL_PARSER_H
|
||||
|
||||
/*
|
||||
* URL storage
|
||||
*/
|
||||
struct parsed_url {
|
||||
char *scheme; /* mandatory */
|
||||
char *host; /* mandatory */
|
||||
char *port; /* optional */
|
||||
char *path; /* optional */
|
||||
char *query; /* optional */
|
||||
char *fragment; /* optional */
|
||||
char *username; /* optional */
|
||||
char *password; /* optional */
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Declaration of function prototypes
|
||||
*/
|
||||
struct parsed_url *parse_url (const char *);
|
||||
void parsed_url_free (struct parsed_url *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _URL_PARSER_H */
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* tab-width: 4
|
||||
* c-basic-offset: 4
|
||||
* End:
|
||||
* vim600: sw=4 ts=4 fdm=marker
|
||||
* vim<600: sw=4 ts=4
|
||||
*/
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
|
||||
The "inih" library is distributed under the New BSD license:
|
||||
|
||||
Copyright (c) 2009, Brush Technology
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of Brush Technology nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY BRUSH TECHNOLOGY ''AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL BRUSH TECHNOLOGY BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,9 @@
|
|||
CFLAGS = -Wall
|
||||
|
||||
all: test_ini
|
||||
|
||||
test_ini: ini.o test_ini.o
|
||||
gcc -o test_ini $(CFLAGS) test_ini.o ini.o
|
||||
|
||||
clean:
|
||||
rm -f test_ini *.o
|
|
@ -0,0 +1,5 @@
|
|||
|
||||
inih is a simple .INI file parser written in C, released under the New BSD
|
||||
license (see LICENSE.txt). Go to the project home page for more info:
|
||||
|
||||
http://code.google.com/p/inih/
|
|
@ -0,0 +1,76 @@
|
|||
// Read an INI file into easy-to-access name/value pairs.
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cstdlib>
|
||||
#include "../ini.h"
|
||||
#include "INIReader.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
INIReader::INIReader(string filename)
|
||||
{
|
||||
_error = ini_parse(filename.c_str(), ValueHandler, this);
|
||||
}
|
||||
|
||||
int INIReader::ParseError()
|
||||
{
|
||||
return _error;
|
||||
}
|
||||
|
||||
string INIReader::Get(string section, string name, string default_value)
|
||||
{
|
||||
string key = MakeKey(section, name);
|
||||
return _values.count(key) ? _values[key] : default_value;
|
||||
}
|
||||
|
||||
long INIReader::GetInteger(string section, string name, long default_value)
|
||||
{
|
||||
string valstr = Get(section, name, "");
|
||||
const char* value = valstr.c_str();
|
||||
char* end;
|
||||
// This parses "1234" (decimal) and also "0x4D2" (hex)
|
||||
long n = strtol(value, &end, 0);
|
||||
return end > value ? n : default_value;
|
||||
}
|
||||
|
||||
double INIReader::GetReal(string section, string name, double default_value)
|
||||
{
|
||||
string valstr = Get(section, name, "");
|
||||
const char* value = valstr.c_str();
|
||||
char* end;
|
||||
double n = strtod(value, &end);
|
||||
return end > value ? n : default_value;
|
||||
}
|
||||
|
||||
bool INIReader::GetBoolean(string section, string name, bool default_value)
|
||||
{
|
||||
string valstr = Get(section, name, "");
|
||||
// Convert to lower case to make string comparisons case-insensitive
|
||||
std::transform(valstr.begin(), valstr.end(), valstr.begin(), ::tolower);
|
||||
if (valstr == "true" || valstr == "yes" || valstr == "on" || valstr == "1")
|
||||
return true;
|
||||
else if (valstr == "false" || valstr == "no" || valstr == "off" || valstr == "0")
|
||||
return false;
|
||||
else
|
||||
return default_value;
|
||||
}
|
||||
|
||||
string INIReader::MakeKey(string section, string name)
|
||||
{
|
||||
string key = section + "." + name;
|
||||
// Convert to lower case to make section/name lookups case-insensitive
|
||||
std::transform(key.begin(), key.end(), key.begin(), ::tolower);
|
||||
return key;
|
||||
}
|
||||
|
||||
int INIReader::ValueHandler(void* user, const char* section, const char* name,
|
||||
const char* value)
|
||||
{
|
||||
INIReader* reader = (INIReader*)user;
|
||||
string key = MakeKey(section, name);
|
||||
if (reader->_values[key].size() > 0)
|
||||
reader->_values[key] += "\n";
|
||||
reader->_values[key] += value;
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
// Read an INI file into easy-to-access name/value pairs.
|
||||
|
||||
// inih and INIReader are released under the New BSD license (see LICENSE.txt).
|
||||
// Go to the project home page for more info:
|
||||
//
|
||||
// http://code.google.com/p/inih/
|
||||
|
||||
#ifndef __INIREADER_H__
|
||||
#define __INIREADER_H__
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
// Read an INI file into easy-to-access name/value pairs. (Note that I've gone
|
||||
// for simplicity here rather than speed, but it should be pretty decent.)
|
||||
class INIReader
|
||||
{
|
||||
public:
|
||||
// Construct INIReader and parse given filename. See ini.h for more info
|
||||
// about the parsing.
|
||||
INIReader(std::string filename);
|
||||
|
||||
// Return the result of ini_parse(), i.e., 0 on success, line number of
|
||||
// first error on parse error, or -1 on file open error.
|
||||
int ParseError();
|
||||
|
||||
// Get a string value from INI file, returning default_value if not found.
|
||||
std::string Get(std::string section, std::string name,
|
||||
std::string default_value);
|
||||
|
||||
// Get an integer (long) value from INI file, returning default_value if
|
||||
// not found or not a valid integer (decimal "1234", "-1234", or hex "0x4d2").
|
||||
long GetInteger(std::string section, std::string name, long default_value);
|
||||
|
||||
// Get a real (floating point double) value from INI file, returning
|
||||
// default_value if not found or not a valid floating point value
|
||||
// according to strtod().
|
||||
double GetReal(std::string section, std::string name, double default_value);
|
||||
|
||||
// Get a boolean value from INI file, returning default_value if not found or if
|
||||
// not a valid true/false value. Valid true values are "true", "yes", "on", "1",
|
||||
// and valid false values are "false", "no", "off", "0" (not case sensitive).
|
||||
bool GetBoolean(std::string section, std::string name, bool default_value);
|
||||
|
||||
private:
|
||||
int _error;
|
||||
std::map<std::string, std::string> _values;
|
||||
static std::string MakeKey(std::string section, std::string name);
|
||||
static int ValueHandler(void* user, const char* section, const char* name,
|
||||
const char* value);
|
||||
};
|
||||
|
||||
#endif // __INIREADER_H__
|
|
@ -0,0 +1,21 @@
|
|||
// Example that shows simple usage of the INIReader class
|
||||
|
||||
#include <iostream>
|
||||
#include "INIReader.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
INIReader reader("../examples/test.ini");
|
||||
|
||||
if (reader.ParseError() < 0) {
|
||||
std::cout << "Can't load 'test.ini'\n";
|
||||
return 1;
|
||||
}
|
||||
std::cout << "Config loaded from 'test.ini': version="
|
||||
<< reader.GetInteger("protocol", "version", -1) << ", name="
|
||||
<< reader.Get("user", "name", "UNKNOWN") << ", email="
|
||||
<< reader.Get("user", "email", "UNKNOWN") << ", pi="
|
||||
<< reader.GetReal("user", "pi", -1) << ", active="
|
||||
<< reader.GetBoolean("user", "active", true) << "\n";
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
// CFG(section, name, default)
|
||||
|
||||
CFG(protocol, version, "0")
|
||||
|
||||
CFG(user, name, "Fatty Lumpkin")
|
||||
CFG(user, email, "fatty@lumpkin.com")
|
||||
|
||||
#undef CFG
|
|
@ -0,0 +1,40 @@
|
|||
/* ini.h example that simply dumps an INI file without comments */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "../ini.h"
|
||||
|
||||
static int dumper(void* user, const char* section, const char* name,
|
||||
const char* value)
|
||||
{
|
||||
static char prev_section[50] = "";
|
||||
|
||||
if (strcmp(section, prev_section)) {
|
||||
printf("%s[%s]\n", (prev_section[0] ? "\n" : ""), section);
|
||||
strncpy(prev_section, section, sizeof(prev_section));
|
||||
prev_section[sizeof(prev_section) - 1] = '\0';
|
||||
}
|
||||
printf("%s = %s\n", name, value);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int error;
|
||||
|
||||
if (argc <= 1) {
|
||||
printf("Usage: ini_dump filename.ini\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
error = ini_parse(argv[1], dumper, NULL);
|
||||
if (error < 0) {
|
||||
printf("Can't read '%s'!\n", argv[1]);
|
||||
return 2;
|
||||
}
|
||||
else if (error) {
|
||||
printf("Bad config file (first error on line %d)!\n", error);
|
||||
return 3;
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/* Example: parse a simple configuration file */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "../ini.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int version;
|
||||
const char* name;
|
||||
const char* email;
|
||||
} configuration;
|
||||
|
||||
static int handler(void* user, const char* section, const char* name,
|
||||
const char* value)
|
||||
{
|
||||
configuration* pconfig = (configuration*)user;
|
||||
|
||||
#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
|
||||
if (MATCH("protocol", "version")) {
|
||||
pconfig->version = atoi(value);
|
||||
} else if (MATCH("user", "name")) {
|
||||
pconfig->name = strdup(value);
|
||||
} else if (MATCH("user", "email")) {
|
||||
pconfig->email = strdup(value);
|
||||
} else {
|
||||
return 0; /* unknown section/name, error */
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
configuration config;
|
||||
|
||||
if (ini_parse("test.ini", handler, &config) < 0) {
|
||||
printf("Can't load 'test.ini'\n");
|
||||
return 1;
|
||||
}
|
||||
printf("Config loaded from 'test.ini': version=%d, name=%s, email=%s\n",
|
||||
config.version, config.name, config.email);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/* Parse a configuration file into a struct using X-Macros */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "../ini.h"
|
||||
|
||||
/* define the config struct type */
|
||||
typedef struct {
|
||||
#define CFG(s, n, default) char *s##_##n;
|
||||
#include "config.def"
|
||||
} config;
|
||||
|
||||
/* create one and fill in its default values */
|
||||
config Config = {
|
||||
#define CFG(s, n, default) default,
|
||||
#include "config.def"
|
||||
};
|
||||
|
||||
/* process a line of the INI file, storing valid values into config struct */
|
||||
int handler(void *user, const char *section, const char *name,
|
||||
const char *value)
|
||||
{
|
||||
config *cfg = (config *)user;
|
||||
|
||||
if (0) ;
|
||||
#define CFG(s, n, default) else if (strcmp(section, #s)==0 && \
|
||||
strcmp(name, #n)==0) cfg->s##_##n = strdup(value);
|
||||
#include "config.def"
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* print all the variables in the config, one per line */
|
||||
void dump_config(config *cfg)
|
||||
{
|
||||
#define CFG(s, n, default) printf("%s_%s = %s\n", #s, #n, cfg->s##_##n);
|
||||
#include "config.def"
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if (ini_parse("test.ini", handler, &Config) < 0)
|
||||
printf("Can't load 'test.ini', using defaults\n");
|
||||
dump_config(&Config);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
; Test config file for ini_example.c and INIReaderTest.cpp
|
||||
|
||||
[protocol] ; Protocol configuration
|
||||
version=6 ; IPv6
|
||||
|
||||
[user]
|
||||
name = Bob Smith ; Spaces around '=' are stripped
|
||||
email = bob@smith.com ; And comments (like this) ignored
|
||||
active = true ; Test a boolean
|
||||
pi = 3.14159 ; Test a floating point number
|
|
@ -0,0 +1,19 @@
|
|||
# Simple makefile to build inih as a static library using g++
|
||||
|
||||
SRC = ../ini.c
|
||||
OBJ = $(SRC:.c=.o)
|
||||
OUT = libinih.a
|
||||
INCLUDES = -I..
|
||||
CCFLAGS = -g -O2
|
||||
CC = g++
|
||||
|
||||
default: $(OUT)
|
||||
|
||||
.c.o:
|
||||
$(CC) $(INCLUDES) $(CCFLAGS) $(EXTRACCFLAGS) -c $< -o $@
|
||||
|
||||
$(OUT): $(OBJ)
|
||||
ar rcs $(OUT) $(OBJ) $(EXTRAARFLAGS)
|
||||
|
||||
clean:
|
||||
rm -f $(OBJ) $(OUT)
|
|
@ -0,0 +1,176 @@
|
|||
/* inih -- simple .INI file parser
|
||||
|
||||
inih is released under the New BSD license (see LICENSE.txt). Go to the project
|
||||
home page for more info:
|
||||
|
||||
http://code.google.com/p/inih/
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ini.h"
|
||||
|
||||
#if !INI_USE_STACK
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#define MAX_SECTION 50
|
||||
#define MAX_NAME 50
|
||||
|
||||
/* Strip whitespace chars off end of given string, in place. Return s. */
|
||||
static char* rstrip(char* s)
|
||||
{
|
||||
char* p = s + strlen(s);
|
||||
while (p > s && isspace((unsigned char)(*--p)))
|
||||
*p = '\0';
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Return pointer to first non-whitespace char in given string. */
|
||||
static char* lskip(const char* s)
|
||||
{
|
||||
while (*s && isspace((unsigned char)(*s)))
|
||||
s++;
|
||||
return (char*)s;
|
||||
}
|
||||
|
||||
/* Return pointer to first char c or ';' comment in given string, or pointer to
|
||||
null at end of string if neither found. ';' must be prefixed by a whitespace
|
||||
character to register as a comment. */
|
||||
static char* find_char_or_comment(const char* s, char c)
|
||||
{
|
||||
int was_whitespace = 0;
|
||||
while (*s && *s != c && !(was_whitespace && *s == ';')) {
|
||||
was_whitespace = isspace((unsigned char)(*s));
|
||||
s++;
|
||||
}
|
||||
return (char*)s;
|
||||
}
|
||||
|
||||
/* Version of strncpy that ensures dest (size bytes) is null-terminated. */
|
||||
static char* strncpy0(char* dest, const char* src, size_t size)
|
||||
{
|
||||
strncpy(dest, src, size);
|
||||
dest[size - 1] = '\0';
|
||||
return dest;
|
||||
}
|
||||
|
||||
/* See documentation in header file. */
|
||||
int ini_parse_file(FILE* file,
|
||||
int (*handler)(void*, const char*, const char*,
|
||||
const char*),
|
||||
void* user)
|
||||
{
|
||||
/* Uses a fair bit of stack (use heap instead if you need to) */
|
||||
#if INI_USE_STACK
|
||||
char line[INI_MAX_LINE];
|
||||
#else
|
||||
char* line;
|
||||
#endif
|
||||
char section[MAX_SECTION] = "";
|
||||
char prev_name[MAX_NAME] = "";
|
||||
|
||||
char* start;
|
||||
char* end;
|
||||
char* name;
|
||||
char* value;
|
||||
int lineno = 0;
|
||||
int error = 0;
|
||||
|
||||
#if !INI_USE_STACK
|
||||
line = (char*)malloc(INI_MAX_LINE);
|
||||
if (!line) {
|
||||
return -2;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Scan through file line by line */
|
||||
while (fgets(line, INI_MAX_LINE, file) != NULL) {
|
||||
lineno++;
|
||||
|
||||
start = line;
|
||||
#if INI_ALLOW_BOM
|
||||
if (lineno == 1 && (unsigned char)start[0] == 0xEF &&
|
||||
(unsigned char)start[1] == 0xBB &&
|
||||
(unsigned char)start[2] == 0xBF) {
|
||||
start += 3;
|
||||
}
|
||||
#endif
|
||||
start = lskip(rstrip(start));
|
||||
|
||||
if (*start == ';' || *start == '#') {
|
||||
/* Per Python ConfigParser, allow '#' comments at start of line */
|
||||
}
|
||||
#if INI_ALLOW_MULTILINE
|
||||
else if (*prev_name && *start && start > line) {
|
||||
/* Non-black line with leading whitespace, treat as continuation
|
||||
of previous name's value (as per Python ConfigParser). */
|
||||
if (!handler(user, section, prev_name, start) && !error)
|
||||
error = lineno;
|
||||
}
|
||||
#endif
|
||||
else if (*start == '[') {
|
||||
/* A "[section]" line */
|
||||
end = find_char_or_comment(start + 1, ']');
|
||||
if (*end == ']') {
|
||||
*end = '\0';
|
||||
strncpy0(section, start + 1, sizeof(section));
|
||||
*prev_name = '\0';
|
||||
}
|
||||
else if (!error) {
|
||||
/* No ']' found on section line */
|
||||
error = lineno;
|
||||
}
|
||||
}
|
||||
else if (*start && *start != ';') {
|
||||
/* Not a comment, must be a name[=:]value pair */
|
||||
end = find_char_or_comment(start, '=');
|
||||
if (*end != '=') {
|
||||
end = find_char_or_comment(start, ':');
|
||||
}
|
||||
if (*end == '=' || *end == ':') {
|
||||
*end = '\0';
|
||||
name = rstrip(start);
|
||||
value = lskip(end + 1);
|
||||
end = find_char_or_comment(value, '\0');
|
||||
if (*end == ';')
|
||||
*end = '\0';
|
||||
rstrip(value);
|
||||
|
||||
/* Valid name[=:]value pair found, call handler */
|
||||
strncpy0(prev_name, name, sizeof(prev_name));
|
||||
if (!handler(user, section, name, value) && !error)
|
||||
error = lineno;
|
||||
}
|
||||
else if (!error) {
|
||||
/* No '=' or ':' found on name[=:]value line */
|
||||
error = lineno;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !INI_USE_STACK
|
||||
free(line);
|
||||
#endif
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/* See documentation in header file. */
|
||||
int ini_parse(const char* filename,
|
||||
int (*handler)(void*, const char*, const char*, const char*),
|
||||
void* user)
|
||||
{
|
||||
FILE* file;
|
||||
int error;
|
||||
|
||||
file = fopen(filename, "r");
|
||||
if (!file)
|
||||
return -1;
|
||||
error = ini_parse_file(file, handler, user);
|
||||
fclose(file);
|
||||
return error;
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
/* inih -- simple .INI file parser
|
||||
|
||||
inih is released under the New BSD license (see LICENSE.txt). Go to the project
|
||||
home page for more info:
|
||||
|
||||
http://code.google.com/p/inih/
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __INI_H__
|
||||
#define __INI_H__
|
||||
|
||||
/* Make this header file easier to include in C++ code */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* Parse given INI-style file. May have [section]s, name=value pairs
|
||||
(whitespace stripped), and comments starting with ';' (semicolon). Section
|
||||
is "" if name=value pair parsed before any section heading. name:value
|
||||
pairs are also supported as a concession to Python's ConfigParser.
|
||||
|
||||
For each name=value pair parsed, call handler function with given user
|
||||
pointer as well as section, name, and value (data only valid for duration
|
||||
of handler call). Handler should return nonzero on success, zero on error.
|
||||
|
||||
Returns 0 on success, line number of first error on parse error (doesn't
|
||||
stop on first error), -1 on file open error, or -2 on memory allocation
|
||||
error (only when INI_USE_STACK is zero).
|
||||
*/
|
||||
int ini_parse(const char* filename,
|
||||
int (*handler)(void* user, const char* section,
|
||||
const char* name, const char* value),
|
||||
void* user);
|
||||
|
||||
/* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't
|
||||
close the file when it's finished -- the caller must do that. */
|
||||
int ini_parse_file(FILE* file,
|
||||
int (*handler)(void* user, const char* section,
|
||||
const char* name, const char* value),
|
||||
void* user);
|
||||
|
||||
/* Nonzero to allow multi-line value parsing, in the style of Python's
|
||||
ConfigParser. If allowed, ini_parse() will call the handler with the same
|
||||
name for each subsequent line parsed. */
|
||||
#ifndef INI_ALLOW_MULTILINE
|
||||
#define INI_ALLOW_MULTILINE 1
|
||||
#endif
|
||||
|
||||
/* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of
|
||||
the file. See http://code.google.com/p/inih/issues/detail?id=21 */
|
||||
#ifndef INI_ALLOW_BOM
|
||||
#define INI_ALLOW_BOM 1
|
||||
#endif
|
||||
|
||||
/* Nonzero to use stack, zero to use heap (malloc/free). */
|
||||
#ifndef INI_USE_STACK
|
||||
#define INI_USE_STACK 1
|
||||
#endif
|
||||
|
||||
/* Maximum line length for any line in INI file. */
|
||||
#ifndef INI_MAX_LINE
|
||||
#define INI_MAX_LINE 200
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __INI_H__ */
|
|
@ -0,0 +1,6 @@
|
|||
[protocol]
|
||||
version = 5 ; próba komment
|
||||
|
||||
[user]
|
||||
name = Gipsz Jakab ; comment
|
||||
email = gip@szja.kab ; comment
|
|
@ -0,0 +1,45 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ini.h"
|
||||
|
||||
typedef struct {
|
||||
int version;
|
||||
const char* name;
|
||||
const char* email;
|
||||
} configuration;
|
||||
|
||||
static int handler(void* user, const char* section, const char* name,
|
||||
const char* value)
|
||||
{
|
||||
configuration *pconfig = (configuration*)user;
|
||||
|
||||
#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
|
||||
if (MATCH("protocol", "version")) {
|
||||
pconfig->version = atoi(value);
|
||||
} else if (MATCH("user", "name")) {
|
||||
pconfig->name = strdup(value);
|
||||
} else if (MATCH("user", "email")) {
|
||||
pconfig->email = strdup(value);
|
||||
} else {
|
||||
return 0; /* unknown section/name, error */
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main (int argc, char* argv[]) {
|
||||
configuration config;
|
||||
|
||||
if (ini_parse("test.ini", handler, &config) < 0) {
|
||||
printf("Can't load 'test.ini'\n");
|
||||
return 1;
|
||||
}
|
||||
printf("Config loaded from 'test.ini': version=%d, name=%s, email=%s\n",
|
||||
config.version, config.name, config.email);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1 @@
|
|||
This is an error
|
|
@ -0,0 +1 @@
|
|||
indented
|
|
@ -0,0 +1,5 @@
|
|||
[section1]
|
||||
name1=value1
|
||||
[section2
|
||||
[section3 ; comment ]
|
||||
name2=value2
|
|
@ -0,0 +1,47 @@
|
|||
no_file.ini: e=-1 user=0
|
||||
... [section1]
|
||||
... one=This is a test;
|
||||
... two=1234;
|
||||
... [ section 2 ]
|
||||
... happy=4;
|
||||
... sad=;
|
||||
... [comment_test]
|
||||
... test1=1;2;3;
|
||||
... test2=2;3;4;this won't be a comment, needs whitespace before ';';
|
||||
... test;3=345;
|
||||
... test4=4#5#6;
|
||||
... [colon_tests]
|
||||
... Content-Type=text/html;
|
||||
... foo=bar;
|
||||
... adams=42;
|
||||
normal.ini: e=0 user=101
|
||||
... [section1]
|
||||
... name1=value1;
|
||||
... name2=value2;
|
||||
bad_section.ini: e=3 user=102
|
||||
bad_comment.ini: e=1 user=102
|
||||
... [section]
|
||||
... a=b;
|
||||
... user=parse_error;
|
||||
... c=d;
|
||||
user_error.ini: e=3 user=104
|
||||
... [section1]
|
||||
... single1=abc;
|
||||
... multi=this is a;
|
||||
... multi=multi-line value;
|
||||
... single2=xyz;
|
||||
... [section2]
|
||||
... multi=a;
|
||||
... multi=b;
|
||||
... multi=c;
|
||||
... [section3]
|
||||
... single=ghi;
|
||||
... multi=the quick;
|
||||
... multi=brown fox;
|
||||
... name=bob smith;
|
||||
multi_line.ini: e=0 user=105
|
||||
bad_multi.ini: e=1 user=105
|
||||
... [bom_section]
|
||||
... bom_name=bom_value;
|
||||
... key“=value“;
|
||||
bom.ini: e=0 user=107
|
|
@ -0,0 +1,43 @@
|
|||
no_file.ini: e=-1 user=0
|
||||
... [section1]
|
||||
... one=This is a test;
|
||||
... two=1234;
|
||||
... [ section 2 ]
|
||||
... happy=4;
|
||||
... sad=;
|
||||
... [comment_test]
|
||||
... test1=1;2;3;
|
||||
... test2=2;3;4;this won't be a comment, needs whitespace before ';';
|
||||
... test;3=345;
|
||||
... test4=4#5#6;
|
||||
... [colon_tests]
|
||||
... Content-Type=text/html;
|
||||
... foo=bar;
|
||||
... adams=42;
|
||||
normal.ini: e=0 user=101
|
||||
... [section1]
|
||||
... name1=value1;
|
||||
... name2=value2;
|
||||
bad_section.ini: e=3 user=102
|
||||
bad_comment.ini: e=1 user=102
|
||||
... [section]
|
||||
... a=b;
|
||||
... user=parse_error;
|
||||
... c=d;
|
||||
user_error.ini: e=3 user=104
|
||||
... [section1]
|
||||
... single1=abc;
|
||||
... multi=this is a;
|
||||
... single2=xyz;
|
||||
... [section2]
|
||||
... multi=a;
|
||||
... [section3]
|
||||
... single=ghi;
|
||||
... multi=the quick;
|
||||
... name=bob smith;
|
||||
multi_line.ini: e=4 user=105
|
||||
bad_multi.ini: e=1 user=105
|
||||
... [bom_section]
|
||||
... bom_name=bom_value;
|
||||
... key“=value“;
|
||||
bom.ini: e=0 user=107
|
|
@ -0,0 +1,3 @@
|
|||
[bom_section]
|
||||
bom_name=bom_value
|
||||
key“ = value“
|
|
@ -0,0 +1,15 @@
|
|||
[section1]
|
||||
single1 = abc
|
||||
multi = this is a
|
||||
multi-line value
|
||||
single2 = xyz
|
||||
[section2]
|
||||
multi = a
|
||||
b
|
||||
c
|
||||
[section3]
|
||||
single: ghi
|
||||
multi: the quick
|
||||
brown fox
|
||||
name = bob smith ; comment line 1
|
||||
; comment line 2
|
|
@ -0,0 +1,25 @@
|
|||
; This is an INI file
|
||||
[section1] ; section comment
|
||||
one=This is a test ; name=value comment
|
||||
two = 1234
|
||||
; x=y
|
||||
|
||||
[ section 2 ]
|
||||
happy = 4
|
||||
sad =
|
||||
|
||||
[empty]
|
||||
; do nothing
|
||||
|
||||
[comment_test]
|
||||
test1 = 1;2;3 ; only this will be a comment
|
||||
test2 = 2;3;4;this won't be a comment, needs whitespace before ';'
|
||||
test;3 = 345 ; key should be "test;3"
|
||||
test4 = 4#5#6 ; '#' only starts a comment at start of line
|
||||
#test5 = 567 ; entire line commented
|
||||
# test6 = 678 ; entire line commented, except in MULTILINE mode
|
||||
|
||||
[colon_tests]
|
||||
Content-Type: text/html
|
||||
foo:bar
|
||||
adams : 42
|
|
@ -0,0 +1,2 @@
|
|||
@call tcc ..\ini.c -I..\ -run unittest.c > baseline_multi.txt
|
||||
@call tcc ..\ini.c -I..\ -DINI_ALLOW_MULTILINE=0 -run unittest.c > baseline_single.txt
|
|
@ -0,0 +1,58 @@
|
|||
/* inih -- unit tests
|
||||
|
||||
This works simply by dumping a bunch of info to standard output, which is
|
||||
redirected to an output file (baseline_*.txt) and checked into the Subversion
|
||||
repository. This baseline file is the test output, so the idea is to check it
|
||||
once, and if it changes -- look at the diff and see which tests failed.
|
||||
|
||||
Here's how I produced the two baseline files (with Tiny C Compiler):
|
||||
|
||||
tcc -DINI_ALLOW_MULTILINE=1 ../ini.c -run unittest.c > baseline_multi.txt
|
||||
tcc -DINI_ALLOW_MULTILINE=0 ../ini.c -run unittest.c > baseline_single.txt
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "../ini.h"
|
||||
|
||||
int User;
|
||||
char Prev_section[50];
|
||||
|
||||
int dumper(void* user, const char* section, const char* name,
|
||||
const char* value)
|
||||
{
|
||||
User = (int)user;
|
||||
if (strcmp(section, Prev_section)) {
|
||||
printf("... [%s]\n", section);
|
||||
strncpy(Prev_section, section, sizeof(Prev_section));
|
||||
Prev_section[sizeof(Prev_section) - 1] = '\0';
|
||||
}
|
||||
printf("... %s=%s;\n", name, value);
|
||||
|
||||
return strcmp(name, "user")==0 && strcmp(value, "parse_error")==0 ? 0 : 1;
|
||||
}
|
||||
|
||||
void parse(const char* fname) {
|
||||
static int u = 100;
|
||||
int e;
|
||||
|
||||
*Prev_section = '\0';
|
||||
e = ini_parse(fname, dumper, (void*)u);
|
||||
printf("%s: e=%d user=%d\n", fname, e, User);
|
||||
u++;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
parse("no_file.ini");
|
||||
parse("normal.ini");
|
||||
parse("bad_section.ini");
|
||||
parse("bad_comment.ini");
|
||||
parse("user_error.ini");
|
||||
parse("multi_line.ini");
|
||||
parse("bad_multi.ini");
|
||||
parse("bom.ini");
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
[section]
|
||||
a = b
|
||||
user = parse_error
|
||||
c = d
|
|
@ -0,0 +1,165 @@
|
|||
/* logger.c
|
||||
* Copyright © 2014, Andras Jeszenszky, JSS & Hayer IT - http://www.jsshayer.hu
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "logger.h"
|
||||
#include "debug.h"
|
||||
#include "misc.h"
|
||||
|
||||
#include "utlist.h"
|
||||
#include "misc.h"
|
||||
|
||||
//~ #define concat(dst, src) strncat((dst), (src), ((sizeof(dst)) - strlen(dst) - 1))
|
||||
//~ #define concatf(dst, ...) snprintf((dst) + strlen((dst)), sizeof((dst)) - strlen((dst)), __VA_ARGS__)
|
||||
|
||||
static char *logfile = NULL;
|
||||
static char logfile_buf[128];
|
||||
|
||||
/* TODO: rendbe tenni ezt a marhaságot valami kultúrált megoldással úgy,
|
||||
hogy a hívó függvény által átadott stringet lemásoljuk és helyben a
|
||||
másolatot kezeljük. Azért, hogy a hívó utána a saját mutatójával azt
|
||||
csinálhasson, amit csak akar. Kezelni a NULL-t, a default értékeket és
|
||||
valami kultúrált köntöst adni neki, ne ezt a három változós izét. */
|
||||
static char *timestamp_format_default = "%a %H:%M:%S";
|
||||
static char *timestamp_format = "%a %H:%M:%S";
|
||||
static char timestamp_format_buf[128];
|
||||
|
||||
static int initialised = 0;
|
||||
struct timeval first_time = {0, 0};
|
||||
char ela[16];
|
||||
|
||||
typedef struct el {
|
||||
struct timeval tm;
|
||||
char *line;
|
||||
struct el *prev; /* needed for a doubly-linked list only */
|
||||
struct el *next; /* needed for singly- or doubly-linked lists */
|
||||
} el;
|
||||
|
||||
/* Ha a tv (első paraméter) meg van adva, akkor nincs gettimeofday hívás, hanem
|
||||
* a tv-ben beállított idő lesz a mérvadó. Ha a tv értéke NULL, akkor a
|
||||
* jelenlegi idővel (gettimeofday) számolunk. Ha meg van adva a ptm, akkor az is
|
||||
* be lesz állítva. Ha az elapsed nem NULL, akkor kiszámolja az indítástól
|
||||
* eltelt időt, és visszaad egy mutatót, ami a kiszámolt érték ssss.mmmu
|
||||
* formátumú stringre mutat.
|
||||
*/
|
||||
static struct timeval get_time (struct timeval *tv, struct tm **ptm, char *elapsed) {
|
||||
struct timeval mytv;
|
||||
|
||||
if (tv == NULL) {
|
||||
gettimeofday(&mytv, NULL);
|
||||
} else {
|
||||
mytv.tv_sec = tv->tv_sec;
|
||||
mytv.tv_usec = tv->tv_usec;
|
||||
}
|
||||
|
||||
if (tv)
|
||||
*tv = mytv;
|
||||
|
||||
if (ptm)
|
||||
*ptm = localtime(&mytv.tv_sec); // thread safe?
|
||||
|
||||
if (elapsed) {
|
||||
long int delta = ((mytv.tv_sec * 1000000) + mytv.tv_usec) - ((first_time.tv_sec * 1000000) + first_time.tv_usec);
|
||||
snprintf(elapsed, 8, "%3.3f", (float)delta / 1000000);
|
||||
}
|
||||
|
||||
return mytv;
|
||||
}
|
||||
|
||||
void con_init () {
|
||||
if (initialised)
|
||||
return;
|
||||
first_time = get_time(NULL, NULL, NULL);
|
||||
initialised = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
void con_logfile (const char *file) {
|
||||
if (file == NULL) {
|
||||
logfile = NULL;
|
||||
return;
|
||||
}
|
||||
strncpy(logfile_buf, file, sizeof(logfile_buf));
|
||||
logfile = logfile_buf;
|
||||
}
|
||||
|
||||
void con_timestamp_format (const char *format) {
|
||||
if (format == NULL) {
|
||||
timestamp_format = timestamp_format_default;
|
||||
return;
|
||||
}
|
||||
strncpy(timestamp_format_buf, format, sizeof(timestamp_format_buf));
|
||||
timestamp_format = timestamp_format_buf;
|
||||
}
|
||||
|
||||
// gány, memóriazabáló függvény :)
|
||||
void _con_writef (enum con_callmode cm, char *file, int line, const char *function, const char *fmt, ...) {
|
||||
if (!initialised)
|
||||
con_init();
|
||||
|
||||
// botrányos deklarációk
|
||||
char tmp[1024] = {0}; // ide kerül a végeredmény
|
||||
char tmp2[1024]; // va_arg szöveges kimenete
|
||||
char timestamp[64]; // timestamp
|
||||
char elapsed[64]; // elapsed
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(tmp2, sizeof(tmp2), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
// TODO: ezt az idő lekérdezős részt külön függvénybe kell rakni!
|
||||
struct timeval tv;
|
||||
struct tm *ptm;
|
||||
tv = get_time(NULL, &ptm, NULL); // idő, ami alapján a továbbiakban számolunk
|
||||
strftime(timestamp, sizeof(timestamp), timestamp_format, ptm); // szöveges timestamp
|
||||
get_time(&tv, &ptm, elapsed); // elapsed lekérdezése TODO: ez borzalmas, átírni!!!
|
||||
|
||||
switch (cm) {
|
||||
case CON_CALLMODE_CONFT:
|
||||
case CON_CALLMODE_CONFTN:
|
||||
concatf(tmp, "%s %s", timestamp, tmp2);
|
||||
break;
|
||||
|
||||
case CON_CALLMODE_CONF:
|
||||
case CON_CALLMODE_CONFN:
|
||||
strncpy(tmp, tmp2, sizeof(tmp) - 1);
|
||||
break;
|
||||
|
||||
case CON_CALLMODE_DEBUG:
|
||||
concatf(tmp, "%s /%s/ [%s:%d %s]: %s", timestamp, elapsed, file, line, function, tmp2);
|
||||
break;
|
||||
}
|
||||
|
||||
chomp(tmp);
|
||||
|
||||
// Kiiratás
|
||||
printf("%s", tmp);
|
||||
if (cm != CON_CALLMODE_CONFTN && cm != CON_CALLMODE_CONFN)
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
|
||||
if (logfile) {
|
||||
FILE *f = fopen(logfile, "a");
|
||||
if (f != NULL) {
|
||||
fprintf(f, "%s", tmp);
|
||||
if (cm != CON_CALLMODE_CONFTN && cm != CON_CALLMODE_CONFN)
|
||||
fprintf(f, "\n");
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
/* logger.h
|
||||
* Copyright © 2014, Andras Jeszenszky, JSS & Hayer IT - http://www.jsshayer.hu
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*
|
||||
conf(...) kiírás időbélyeg nélkül, újsorral
|
||||
confn(...) kiírás időbélyeg nélkül, újsor nélkül
|
||||
conft(...) kiírás időbélyeggel, újsorral
|
||||
conftn(...) kiírás időbélyeggel, újsor nélkül
|
||||
*/
|
||||
|
||||
enum con_callmode {
|
||||
CON_CALLMODE_CONF,
|
||||
CON_CALLMODE_CONFN,
|
||||
CON_CALLMODE_CONFT,
|
||||
CON_CALLMODE_CONFTN,
|
||||
CON_CALLMODE_DEBUG,
|
||||
};
|
||||
|
||||
#ifndef LOGGER_H_LOADED
|
||||
#define LOGGER_H_LOADED
|
||||
void con_init ();
|
||||
//~ void conft (const char *fmt, ...);
|
||||
void con_logfile (const char *file);
|
||||
void con_timestamp_format (const char *format);
|
||||
void _con_writef (enum con_callmode cm, char *file, int line, const char *function, const char *fmt, ...);
|
||||
#endif
|
||||
|
||||
|
||||
// ha a DEBUG makró 1, akkor a debug() makrók életbe lépnek,
|
||||
// ellenkező esetben a kódba sem kerül bele :)
|
||||
#ifdef CON_DEBUG
|
||||
#define con_debug(...) _con_writef(CON_CALLMODE_DEBUG, __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__)
|
||||
#else
|
||||
#define con_debug(...)
|
||||
#endif
|
||||
|
||||
#define conf(...) _con_writef(CON_CALLMODE_CONF, NULL, 0, NULL, __VA_ARGS__)
|
||||
#define confn(...) _con_writef(CON_CALLMODE_CONFN, NULL, 0, NULL, __VA_ARGS__)
|
||||
#define conft(...) _con_writef(CON_CALLMODE_CONFT, NULL, 0, NULL, __VA_ARGS__)
|
||||
#define conftn(...) _con_writef(CON_CALLMODE_CONFTN, NULL, 0, NULL, __VA_ARGS__)
|
|
@ -0,0 +1,43 @@
|
|||
/* logger_test.c
|
||||
* Copyright © 2014, Andras Jeszenszky, JSS & Hayer IT - http://www.jsshayer.hu
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
#define CON_DEBUG
|
||||
|
||||
#include "logger.h"
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
int main () {
|
||||
|
||||
con_logfile("logger_test.log");
|
||||
con_timestamp_format("%a %H:%M:%S");
|
||||
|
||||
conft("zsiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiir");
|
||||
conft("yeahhhh");
|
||||
conft("ok");
|
||||
|
||||
FILE *f;
|
||||
if (!(f = fopen("/proc/ioports", "r"))) {
|
||||
perror("fopen");
|
||||
return 1;
|
||||
}
|
||||
|
||||
char tmp[128];
|
||||
int i = 0;
|
||||
while (fgets(tmp, sizeof(tmp), f)) {
|
||||
con_debug("i=%d %s", i, tmp);
|
||||
i++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
fclose(f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,285 @@
|
|||
/* misc.c
|
||||
* Copyright © 2014, Andras Jeszenszky, JSS & Hayer IT - http://www.jsshayer.hu
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/* altalanos fuggvenyek */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <arpa/inet.h> // inet_pton() függvény
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
char *chomp (char *s) {
|
||||
if (s == NULL)
|
||||
return NULL;
|
||||
size_t len = strlen(s);
|
||||
|
||||
int n;
|
||||
for (n = len - 1; n >= 0; n--) {
|
||||
if (s[n] == '\n' || s[n] == '\r')
|
||||
s[n] = '\0';
|
||||
else
|
||||
return s;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
fmtsub - mintából, változó-érték párokból és készít stringet behelyettesítéssel
|
||||
|
||||
paraméterek:
|
||||
dest ebbe a stringbe menti el az eredményt
|
||||
size dest mérete
|
||||
pattern minta
|
||||
args változó-érték táblázat, nullával lezárva
|
||||
|
||||
visszatérési érték:
|
||||
0 sikerült a behelyettesítés
|
||||
-1 valamelyik mutató == NULL vagy a size == 0
|
||||
|
||||
A táblázat megadása:
|
||||
|
||||
const char *args[][2] = {
|
||||
{"%n", "2463434"},
|
||||
{"%v", "0.9.6-rc2"},
|
||||
{"version", "Linux 2.6.32"},
|
||||
{"boo", "baa"},
|
||||
{0}}; */
|
||||
int fmtsub (char *dest, size_t size, const char *pattern, const char *args[][2]) {
|
||||
char buf[4096];
|
||||
//~ debs(dest); debi(size); debs(pattern); debi(args);
|
||||
if (dest == NULL || pattern == NULL || args == NULL || size == 0)
|
||||
return -1;
|
||||
|
||||
// ha a pattern üres string, akkor üres stringet adunk vissza
|
||||
if (strlen(pattern) == 0) {
|
||||
strcpy(dest, "");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pospat, posbuf, a;
|
||||
int lenpat = strlen(pattern);
|
||||
buf[0] = '\0';
|
||||
// byteonként végigmegyünk a pattern stringen
|
||||
for (pospat = 0, posbuf = 0; pospat < lenpat && posbuf < sizeof(buf) - 1;) {
|
||||
const char *subpat = &pattern[pospat];
|
||||
int match = 0;
|
||||
|
||||
// végigmegyünk az args táblázaton
|
||||
for (a = 0; args[a][0] != 0; a++) {
|
||||
const char *var = args[a][0]; // "%n"
|
||||
const char *exp = args[a][1]; // "2463434"
|
||||
|
||||
// ha a változónév megtalálható a pattern jelenlegi pozíciójánál
|
||||
if (strlen(var) != 0 && !strncmp(subpat, var, strlen(var))) {
|
||||
if (exp != NULL) {
|
||||
// bemásoljuk a változó értékét a bufferbe
|
||||
strncat(buf, exp, sizeof(buf) - posbuf - 1);
|
||||
posbuf += strlen(exp);
|
||||
}
|
||||
|
||||
/* ezen a ponton a posbuf nagyobb lehet, mint a buf, ami
|
||||
igen kellemetlenül érintené a lenti buf[posbuf] = '\0'
|
||||
értékadást, ezért a posbuf pozícionálót beállítjuk a buf
|
||||
utolsó byte-jára. ide fog kerülni a NULL. */
|
||||
if (posbuf >= sizeof(buf) - 1)
|
||||
posbuf = sizeof(buf) - 1;
|
||||
|
||||
// pattern pozícióját a változónév utáni karakterre állítjuk
|
||||
pospat += strlen(var);
|
||||
|
||||
// kihagyjuk a lenti if-et
|
||||
match = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 1 bájt másolása pattern-ből buf-ba
|
||||
if (!match) {
|
||||
buf[posbuf] = pattern[pospat];
|
||||
buf[posbuf+1] = '\0';
|
||||
pospat++;
|
||||
posbuf++;
|
||||
}
|
||||
}
|
||||
|
||||
buf[posbuf] = '\0'; // lezáró NULL
|
||||
strncpy(dest, buf, size - 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// http://en.wikipedia.org/wiki/ROT13
|
||||
// paraméter az a string, amit módosítani kell
|
||||
// visszatérés ugyan az, mint a paraméter kompatibilitási izé miatt
|
||||
char *encode_rot13 (char *s) {
|
||||
if (s == NULL)
|
||||
return NULL;
|
||||
|
||||
int i;
|
||||
for (i = 0; s[i]; i++) {
|
||||
if (s[i] >= 'a' && s[i] <= 'm') { s[i] += 13; continue; }
|
||||
if (s[i] >= 'A' && s[i] <= 'M') { s[i] += 13; continue; }
|
||||
if (s[i] >= 'n' && s[i] <= 'z') { s[i] -= 13; continue; }
|
||||
if (s[i] >= 'N' && s[i] <= 'Z') { s[i] -= 13; continue; }
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
// szóközöket és tabokat vág le a megadott string bal és/vagy jobb oldaláról
|
||||
// trim - mindkét oldalról vág
|
||||
// ltrim - bal oldalról vág
|
||||
// rtrim - jobb oldalról vág
|
||||
char *_trim (char *s, int trim_from_left, int trim_from_right) {
|
||||
if (s == NULL)
|
||||
return NULL;
|
||||
|
||||
int n, i;
|
||||
size_t len = strlen(s);
|
||||
|
||||
if (trim_from_right) {
|
||||
for (n = len - 1; n >= 0; n--) {
|
||||
if (s[n] == 32 || s[n] == '\t') {
|
||||
s[n] = '\0';
|
||||
len--;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (trim_from_left) {
|
||||
for (n = 0; n < len; n++)
|
||||
if (s[n] != 32 && s[n] != '\t')
|
||||
break;
|
||||
|
||||
if (n > 0) {
|
||||
for (i = n; i < len; i++)
|
||||
s[i-n] = s[i];
|
||||
|
||||
for (i = len - n; i < len; i++)
|
||||
s[i] = '\0';
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/* megszámlálja a <delimeter> elemeket */
|
||||
static int split_get_size (char *buffer, int delimeter) {
|
||||
int c = 0, i = 0;
|
||||
if (buffer[ 0 ] == 0)
|
||||
return 0;
|
||||
while (buffer[i] != 0) {
|
||||
if (buffer[i] == delimeter)
|
||||
c++;
|
||||
i++;
|
||||
}
|
||||
/* egyet hozzáadok, mert a "hello" is értéknek számít, hiába nincs benne ';' */
|
||||
return c + 1;
|
||||
}
|
||||
|
||||
/* visszatér egy pointer tömbbel, ami az elemekre mutat, a tömböt 0 pointerrel zárja */
|
||||
char **split (char *buffer, int delimeter) {
|
||||
int size = split_get_size(buffer, delimeter);
|
||||
/* helyfoglalás a pointer tömbnek */
|
||||
char **res = (char **)malloc(sizeof(char *) * (size + 1));
|
||||
int i=0;
|
||||
int p=0;
|
||||
while (buffer[i] != 0) {
|
||||
/* a sor elejét eltárolom */
|
||||
res[p++] = buffer + i;
|
||||
/* a sor végét megkeresem */
|
||||
do {
|
||||
i++;
|
||||
} while (buffer[i] != 0 && buffer[i] != delimeter);
|
||||
/* felülírjuk a ';'-t 0-val */
|
||||
if (buffer[i] != 0) {
|
||||
buffer[i] = 0;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
/* null pointerrel zárjuk */
|
||||
res[p] = 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
// 1-et ad vissza, ha érvényes a kapott IP cím
|
||||
// 0-át ha nem
|
||||
int is_valid_ip (const char *ip) {
|
||||
struct sockaddr_in sa;
|
||||
int result = inet_pton(AF_INET, ip, &(sa.sin_addr));
|
||||
return result != 0;
|
||||
}
|
||||
|
||||
void die (const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
void read_lines_from_stdin (char *dst, int size) {
|
||||
char *line = NULL; // ideiglenes buffer a getline-nak
|
||||
size_t len = 0;
|
||||
ssize_t read;
|
||||
int remaining_size; // dst stringbe még ennyi byte fér el
|
||||
|
||||
remaining_size = size - 1;
|
||||
|
||||
while ((read = getline(&line, &len, stdin)) != -1) {
|
||||
strncat(dst, line, remaining_size);
|
||||
remaining_size -= read;
|
||||
if (remaining_size <= 0)
|
||||
break;
|
||||
}
|
||||
chomp(dst); // utolsó \n karakter chompolása
|
||||
free(line);
|
||||
}
|
||||
|
||||
char *strcutpbrk (char *str, const char *accept) {
|
||||
if (str == NULL)
|
||||
return NULL;
|
||||
|
||||
if (accept == NULL)
|
||||
return str;
|
||||
|
||||
char *at = strpbrk(str, accept);
|
||||
if (at != NULL)
|
||||
*at = '\0';
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
char *strdelchars (char *str, const char *dels) {
|
||||
if (!str)
|
||||
return NULL;
|
||||
|
||||
if (!dels)
|
||||
return str;
|
||||
|
||||
int len_str = strlen(str);
|
||||
int len_dels = strlen(dels);
|
||||
|
||||
if (!len_str || !len_dels)
|
||||
return str;
|
||||
|
||||
int i, j, k = 0;
|
||||
for (i = 0; i < len_str; i++) {
|
||||
for (j = 0; j < len_dels; j++)
|
||||
if (str[i] == dels[j])
|
||||
break;
|
||||
if (j == len_dels) // ha nem volt break
|
||||
str[k++] = str[i];
|
||||
}
|
||||
str[k] = '\0';
|
||||
return str;
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
/* misc.h
|
||||
* Copyright © 2014, Andras Jeszenszky, JSS & Hayer IT - http://www.jsshayer.hu
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
char *chomp (char *str);
|
||||
|
||||
#define scpy(dst, src) strncpy((dst), (src), (sizeof(dst)) - 1)
|
||||
|
||||
#define concat(dst, src) strncat((dst), (src), ((sizeof(dst)) - strlen(dst) - 1))
|
||||
#define concatf(dst, ...) snprintf((dst) + strlen((dst)), sizeof((dst)) - strlen((dst)), __VA_ARGS__)
|
||||
int fmtsub (char *dest, size_t size, const char *pattern, const char *args[][2]);
|
||||
char *encode_rot13 (char *s);
|
||||
|
||||
char *_trim (char *s, int trim_from_left, int trim_from_right);
|
||||
#define trim(s) _trim(s, 1, 1)
|
||||
#define ltrim(s) _trim(s, 1, 0)
|
||||
#define rtrim(s) _trim(s, 0, 1)
|
||||
|
||||
// Az str stringet levágja ott, ahol az accept stringben felsorolt első
|
||||
// karakterrel találkozik. A levágást úgy oldja meg, hogy az str string
|
||||
// megfelelő byte-ját átírja 0-ra. A visszatérési érték az str string. Ha az
|
||||
// accept == NULL, akkor nem piszkálja az str stringet. Ha az str == NULL,
|
||||
// akkor a visszatérési érték NULL. Például ha az str "Bandi" és az accept
|
||||
// "cde", akkor az eredmény "Ban" lesz.
|
||||
char *strcutpbrk (char *str, const char *accept);
|
||||
|
||||
// Nincs még doksi, ezért ide írom...
|
||||
// A chomp, trim, encode_rot13, strcutpbrk függvények használhatok beágyazva is, tehát:
|
||||
// char buf[64];
|
||||
// encode_rot13(trim(chomp(buf)));
|
||||
|
||||
// visszatér egy pointer tömbbel, ami az elemekre mutat, a tömböt 0 pointerrel zárja. A függvény felülírja a buffer stringben lévő delimetereket. Magyarul módosítja a kapott stringet, ami nem biztos, hogy jó dolog. Pl. char *x = "hello" változóknál segfault.
|
||||
char **split (char *buffer, int delimeter);
|
||||
|
||||
// 1-et ad vissza, ha érvényes a kapott IP cím
|
||||
// 0-át ha nem
|
||||
int is_valid_ip (const char *ip);
|
||||
|
||||
// mint Perl-ben:)
|
||||
void die (const char *fmt, ...);
|
||||
|
||||
// STDIN-ről beolvasás EOF-ig. A sorokat összefűzi és a dst stringbe menti,
|
||||
// vigyázva a lezáró NULL karakterre és a dst string hosszára, amit a size-ben
|
||||
// kell átadni. Az utolsó \n karakterek le lesznek csípve.
|
||||
void read_lines_from_stdin (char *dst, int size);
|
||||
|
||||
// Az str stringből eltávolítja a dels stringben megtalálható karaktereket. Az
|
||||
// eltávolítás folyamán az str stringben a byteokat fokozatosan balra rendezi.
|
||||
// A művelet végén elhelyezi a stringet lezáró NULL karaktert. Az eredmény
|
||||
// ugyan akkora vagy kisebb méretű string. A visszatérési érték az str string.
|
||||
// Ha az str NULL, akkor a visszatérési érték NULL. Ha a dels NULL, akkor a
|
||||
// visszatérési érték az str string.
|
||||
char *strdelchars (char *str, const char *dels);
|
||||
|
|
@ -0,0 +1,524 @@
|
|||
/* netsocket.c
|
||||
* Copyright © 2014, Andras Jeszenszky, JSS & Hayer IT - http://www.jsshayer.hu
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
// TODO: datapipe-nál jól látható, hogy a connect előtt bejött adatok
|
||||
// nem kerülnek kiküldésre. Valami buffer megoldást kéne alkalmazni. vagy mégsem?
|
||||
// ... végülis a Centauri nézőpontja szerint connect előtt miért küldenénk adatokat?
|
||||
|
||||
// TODO: gethostbyaddr és gethostbyname függvényeket lecserélni getaddrinfo és
|
||||
// getnameinfo függvényekre
|
||||
//
|
||||
// Figyelem! Amelyik függvényben invoke_callback van, annak a legaljára kell
|
||||
// destroy_netsocket. Na meg ezt a kommentet átfogalmazni, mert valószínűleg
|
||||
// baromira nem fogom érteni két hét múlva, hogy mi a szar is akar ez lenni
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <resolv.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "netsocket.h"
|
||||
#include "debug.h"
|
||||
|
||||
static void dummy_callback (netsocket_t *obj, int event) {
|
||||
printf("dummy_callback called at %s:%d\n", __FILE__, __LINE__);
|
||||
printf(" event = %d\n mode = %s\n host = %s\n port = %d\n lhost = %s\n lport = %d\n",
|
||||
event,
|
||||
(obj->mode == NETSOCKET_SERVER) ? "server" : "client",
|
||||
obj->host,
|
||||
obj->port,
|
||||
obj->lhost,
|
||||
obj->lport
|
||||
);
|
||||
}
|
||||
|
||||
static void sock_close (netsocket_t *obj) {
|
||||
if (!obj->sock)
|
||||
return;
|
||||
ev_io_stop(obj->loop, &obj->w_in);
|
||||
ev_io_stop(obj->loop, &obj->w_out);
|
||||
ev_timer_stop(obj->loop, &obj->w_connect_timeout);
|
||||
close(obj->sock);
|
||||
obj->sock = 0;
|
||||
}
|
||||
|
||||
static void invoke_callback (netsocket_t *obj, int event) {
|
||||
obj->in_callback++;
|
||||
obj->callback(obj, event);
|
||||
obj->in_callback--;
|
||||
|
||||
// késleltetett destroy
|
||||
if (obj->destroy_request) {
|
||||
if (!obj->in_callback) {
|
||||
netsocket_destroy(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void disconnect (netsocket_t *obj, char *reason, int ignore_callback) {
|
||||
if (obj == NULL)
|
||||
return;
|
||||
|
||||
sock_close(obj);
|
||||
if (reason != NULL)
|
||||
strncpy(obj->disconnect_reason, reason, sizeof(obj->disconnect_reason) - 1);
|
||||
|
||||
if (!ignore_callback)
|
||||
invoke_callback(obj, NETSOCKET_EVENT_DISCONNECT);
|
||||
|
||||
//~ if (!obj->connected)
|
||||
//~ return;
|
||||
obj->connected = 0;
|
||||
|
||||
// automatikusan felszabaditjuk a gyermek objektumot abban az esetben, ha
|
||||
// az obj kliens modban van es bejovo kapcsolatrol van szo, maskeppen mondva
|
||||
// akkor, ha egy szerver objektum gyermek objektuma szakad meg
|
||||
// ilyen objektumot a sock_accept allokal malloccal
|
||||
|
||||
//~ if (obj->mode == NETSOCKET_CLIENT && obj->direction == NETSOCKET_IN)
|
||||
//~ netsocket_destroy(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disconnect from peer, close socket
|
||||
* @param obj the netsocket object
|
||||
* @param reason description of disconnect reason
|
||||
*
|
||||
* If connection in progress, abort the connection and close the socket.
|
||||
* If connection was established, disconnect from peer, close socket and
|
||||
* detach from event loop. Call the callback with NETSOCKET_EVENT_DISCONNECT
|
||||
* event. Save the "reason" to obj->reason.
|
||||
*/
|
||||
void netsocket_disconnect (netsocket_t *obj, char *reason) {
|
||||
disconnect(obj, reason, 1); // 1 jelzi, hogy nem kérünk callback hívást
|
||||
}
|
||||
|
||||
void netsocket_disconnect_withevent (netsocket_t *obj, char *reason) {
|
||||
disconnect(obj, reason, 0); // 0 jelzi, hogy kérünk callback hívást
|
||||
}
|
||||
|
||||
// ha ezt meghívjuk, akkor a bejövő kapcsolatoknál nem kérdezzük meg
|
||||
// a kliens IP címének nevét a DNS szervertől
|
||||
void netsocket_disable_lookup_on_accept (netsocket_t *obj) {
|
||||
obj->disable_lookup_on_accept = 1;
|
||||
}
|
||||
|
||||
static int sock_accept (netsocket_t *parent) {
|
||||
netsocket_t *obj = netsocket_new(dummy_callback, NULL, parent->loop);
|
||||
|
||||
obj->mode = NETSOCKET_CLIENT;
|
||||
obj->direction = NETSOCKET_IN;
|
||||
|
||||
socklen_t addrlen = sizeof(obj->addr);
|
||||
obj->sock = accept(parent->sock, (struct sockaddr *) &obj->addr, &addrlen);
|
||||
if (obj->sock < 0) { // TODO rendes hibakezelés, memória felszabadítás
|
||||
perror("accept"); // például: Too many open files
|
||||
netsocket_destroy(obj);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// kliens IP cím lekérdezése, ha nincs beállítva a "disable_lookup_on_accept"
|
||||
if (!parent->disable_lookup_on_accept)
|
||||
obj->hostent = gethostbyaddr(&obj->addr.sin_addr, sizeof(&obj->addr.sin_addr), AF_INET);
|
||||
|
||||
// ha nincs hostja az IP-nek, akkor a hostent NULL lesz
|
||||
if (obj->hostent != NULL)
|
||||
strncpy(obj->host, obj->hostent->h_name, sizeof(obj->host) - 1);
|
||||
|
||||
// IP cím tárolása szöveges formátumban
|
||||
strncpy(obj->ip, inet_ntoa(obj->addr.sin_addr), sizeof(obj->ip) - 1);
|
||||
|
||||
// ha nincs hostja az IP-nek, akkor az IP lesz a host
|
||||
if (!strlen(obj->host))
|
||||
strncpy(obj->host, obj->ip, sizeof(obj->host) - 1);
|
||||
|
||||
// Kliens portja
|
||||
obj->port = ntohs(obj->addr.sin_port);
|
||||
|
||||
ev_io_set(&obj->w_in, obj->sock, EV_READ);
|
||||
ev_io_set(&obj->w_out, obj->sock, EV_WRITE);
|
||||
|
||||
ev_io_start(obj->loop, &obj->w_in);
|
||||
ev_io_start(obj->loop, &obj->w_out);
|
||||
|
||||
obj->parent = parent;
|
||||
obj->callback = parent->callback;
|
||||
obj->userdata = parent->userdata;
|
||||
strncpy(obj->lhost, parent->lhost, sizeof(obj->lhost));
|
||||
obj->lport = parent->lport;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void w_connect_timeout_cb (EV_P_ ev_io *w, int revents) {
|
||||
netsocket_t *obj = w->data;
|
||||
disconnect(obj, "Connection timed out", 0);
|
||||
}
|
||||
|
||||
static void w_in_cb (EV_P_ ev_io *w, int revents) {
|
||||
netsocket_t *obj = w->data;
|
||||
int i;
|
||||
|
||||
// ha a szerver portra csatlakozott új kliens
|
||||
if (obj->mode == NETSOCKET_SERVER) {
|
||||
sock_accept(obj);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Ide akkor kerülünk, amikor egy kliensről adat érkezik.
|
||||
* A NETSOCKET_EVENT_CONNECT eseményt és az obj->connected 1-re állítását
|
||||
* a w_out_cb() függvény okozza, de az valójában a sock_accept() függvényben
|
||||
* lenne esedékes. Szervernél, amikor várjuk a klienseket, normális esetben
|
||||
* nincs ezzel semmmi gond, de ha valgrind-el fut, akkor valamiért
|
||||
* összekeveredik az event loop-ban a sorrend és előbb hívódik meg az
|
||||
* új kliens objektummal a NETSOCKET_EVENT_READ, mint a NETSOCKET_EVENT_CONNECT.
|
||||
* Ez a hívó kódjában okozhat kollóziót (és okozott is), ezért ha nincs
|
||||
* beállítva az obj->connected, de mégis adatot akarnánk beolvasni, akkor
|
||||
* egyszerűen csak "elnapoljuk" a feladatot. Ekkor az event loop megteszi
|
||||
* prevenciós körét a w_out_cb() függvényben is, ahol megtörténik a
|
||||
* NETSOCKET_EVENT_CONNECT és utána ismét visszatér ide. Ezzel kényszerítjük
|
||||
* ki a helyes sorrendet.
|
||||
*/
|
||||
if (!obj->connected)
|
||||
return;
|
||||
|
||||
// adat beolvasása a kliensről
|
||||
i = read(obj->sock, obj->inbuf, sizeof(obj->inbuf));
|
||||
if (i < 1) {
|
||||
disconnect(obj, (i == 0) ? "Connection reset by peer" : strerror(errno), 0);
|
||||
} else {
|
||||
obj->inbuf_len = i;
|
||||
invoke_callback(obj, NETSOCKET_EVENT_READ);
|
||||
}
|
||||
}
|
||||
|
||||
static int sockerr (int sock) {
|
||||
int optval = 0;
|
||||
int err;
|
||||
socklen_t optlen = sizeof(optval);
|
||||
err = getsockopt(sock, SOL_SOCKET, SO_ERROR, &optval, &optlen);
|
||||
if (err) return err;
|
||||
return optval;
|
||||
}
|
||||
|
||||
static void w_out_cb (EV_P_ ev_io *w, int revents) {
|
||||
netsocket_t *obj = w->data;
|
||||
//~ printf("Can't connect to %s: %s\n", obj->host, strerror(sockerr(obj->sock)));
|
||||
obj->err = sockerr(obj->sock);
|
||||
ev_io_stop(EV_A_ w);
|
||||
if (obj->err) {
|
||||
disconnect(obj, strerror(obj->err), 0);
|
||||
} else {
|
||||
obj->connected = 1;
|
||||
ev_timer_stop(obj->loop, &obj->w_connect_timeout);
|
||||
invoke_callback(obj, NETSOCKET_EVENT_CONNECT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Make outgoing connection to remote host
|
||||
* @param obj the netsocket object
|
||||
* @returns 0 if everything ok, otherwise -1
|
||||
*
|
||||
* Use netsocket as client. The function check the syntax of the "host" and "port" variable and
|
||||
* lookup the host. If the host resolved successfully, then create an
|
||||
* non-blocking outgoing socket, call connect(3) and add the socket to
|
||||
* the event loop. In case of problem, close socket and call callback
|
||||
* with event NETSOCKET_EVENT_DISCONNECT.
|
||||
*/
|
||||
int netsocket_connect (netsocket_t *obj) {
|
||||
obj->mode = NETSOCKET_CLIENT;
|
||||
obj->direction = NETSOCKET_OUT;
|
||||
|
||||
if (obj->host == NULL) {
|
||||
disconnect(obj, "Invalid host", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (obj->port < 1 || obj->port > 65535) {
|
||||
disconnect(obj, "Invalid port", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// TODO aszinkronná tenni a host lookup-ot
|
||||
if ((obj->hostent = gethostbyname(obj->host)) == NULL) {
|
||||
disconnect(obj, "Host not found", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct in_addr **pptr;
|
||||
pptr = (struct in_addr **)obj->hostent->h_addr_list;
|
||||
strncpy(obj->ip, inet_ntoa(**(pptr++)), sizeof(obj->ip));
|
||||
obj->sock = socket(PF_INET, SOCK_STREAM, 0);
|
||||
|
||||
ev_io_set(&obj->w_in, obj->sock, EV_READ);
|
||||
ev_io_set(&obj->w_out, obj->sock, EV_WRITE);
|
||||
ev_timer_set(&obj->w_connect_timeout, (float)obj->connect_timeout / 1000, 0);
|
||||
|
||||
ev_io_start(obj->loop, &obj->w_in);
|
||||
ev_io_start(obj->loop, &obj->w_out);
|
||||
ev_timer_start(obj->loop, &obj->w_connect_timeout);
|
||||
|
||||
// socket non-block
|
||||
fcntl(obj->sock, F_SETFL, fcntl(obj->sock, F_GETFL, 0) | O_NONBLOCK);
|
||||
|
||||
bzero(&obj->addr, sizeof(obj->addr));
|
||||
obj->addr.sin_family = AF_INET;
|
||||
obj->addr.sin_port = htons(obj->port);
|
||||
obj->addr.sin_addr.s_addr = *(long*)(obj->hostent->h_addr);
|
||||
|
||||
connect(obj->sock, (struct sockaddr*)&obj->addr, sizeof(obj->addr));
|
||||
if (errno != EINPROGRESS) {
|
||||
netsocket_disconnect(obj, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Listening for incoming connections
|
||||
* @param obj the netsocket object
|
||||
* @returns 0 if everything ok, otherwise -1
|
||||
*
|
||||
* Use netsocket as server. The function check the syntax of
|
||||
* the "lhost" and "lport" variable and
|
||||
* lookup the lhost. If the host resolved successfully, then create an
|
||||
* non-blocking incoming socket, bind to lhost, and add the socket to
|
||||
* the event loop. If "lhost" is NULL, then "0.0.0.0" is assumed.
|
||||
*
|
||||
* When a peer connects to the listening port, create a new netsocket object and inherit
|
||||
* lhost, lport, userdata and callback variables from the server object.
|
||||
* Accept the incoming connection,
|
||||
* add them to the event loop and call the callback with NETSOCKET_EVENT_CONNECT event.
|
||||
* The callback's object parameter is the newly created client object. The server object's
|
||||
* address is in obj->parent pointer. For each incoming connection make individually a
|
||||
* new netsocket object.
|
||||
*/
|
||||
int netsocket_listen (netsocket_t *obj) {
|
||||
obj->mode = NETSOCKET_SERVER;
|
||||
|
||||
if (!strlen(obj->lhost))
|
||||
strcpy(obj->lhost, "0.0.0.0");
|
||||
|
||||
if (obj->lport < 1 || obj->lport > 65535) {
|
||||
disconnect(obj, "Invalid local port", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// TODO aszinkronná tenni a host lookup-ot
|
||||
if ((obj->hostent = gethostbyname(obj->lhost)) == NULL) {
|
||||
disconnect(obj, "Local host not found", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct in_addr **pptr;
|
||||
pptr = (struct in_addr **)obj->hostent->h_addr_list;
|
||||
strncpy(obj->ip, inet_ntoa(**(pptr++)), sizeof(obj->ip));
|
||||
|
||||
// TODO: socket függvény hibájának csekkolása
|
||||
obj->sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
fcntl(obj->sock, F_SETFL, fcntl(obj->sock, F_GETFL, 0) | O_NONBLOCK);
|
||||
|
||||
int optval = 1;
|
||||
if (setsockopt(obj->sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1) {
|
||||
perror("setsockopt"); // TODO normális hibakezelés
|
||||
return -1;
|
||||
}
|
||||
|
||||
bzero(&obj->addr, sizeof(obj->addr));
|
||||
obj->addr.sin_family = AF_INET;
|
||||
obj->addr.sin_port = htons(obj->lport);
|
||||
obj->addr.sin_addr.s_addr = *(long*)(obj->hostent->h_addr);
|
||||
|
||||
if (bind(obj->sock, (struct sockaddr *) &obj->addr, sizeof(obj->addr)) < 0) {
|
||||
disconnect(obj, "Error on bind()", 0); // TODO rendes hibaüzenet
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (listen(obj->sock, 5)) {
|
||||
disconnect(obj, "Error on listen()", 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ev_io_set(&obj->w_in, obj->sock, EV_READ);
|
||||
ev_io_set(&obj->w_out, obj->sock, EV_WRITE);
|
||||
//~ ev_timer_set(&obj->w_connect_timeout, (float)obj->connect_timeout / 1000, 0);
|
||||
|
||||
ev_io_start(obj->loop, &obj->w_in);
|
||||
ev_io_start(obj->loop, &obj->w_out);
|
||||
//~ ev_timer_start(EV_DEFAULT, &obj->w_connect_timeout);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief write data to netsocket socket
|
||||
* @param obj the netsocket object
|
||||
* @param data data string
|
||||
* @param length length of data string
|
||||
* @returns length of written data
|
||||
*
|
||||
* Write data to socket. O yeahhh:)
|
||||
*/
|
||||
int netsocket_write (netsocket_t *obj, const char *data, int length) {
|
||||
int i = 0;
|
||||
if (!obj->sock) return 0; // véletlenül sem írunk az stdout-ra :)
|
||||
|
||||
/* Úgy néz ki, hogy Linux alatt a send() az igazi. Az MSG_NOSIGNAL nélkül a
|
||||
rendszer PIPE szignállal kinyírja a szervert abban az esetben, ha "Broken
|
||||
pipe" állapot lép fel, tehát a socket bezárult (kliens megszakadt) de a
|
||||
szerver még írni akar rá. Az MSG_NOSIGNAL állítólag csak Linux alatt
|
||||
létezik. BSD alatt pl. az a megoldás, hogy a setsockopt függvénnyel be kell
|
||||
állítani az adott socketen a SO_NOSIGPIPE flag-et, majd write() vagy más
|
||||
függvénnyel lehet a socketre irkálni. További probléma a netsocket
|
||||
szerkezetéből adódik, ahová mindig eljutok, amikor aszinkron rendszerben
|
||||
meghívódik egy callback és a callback-en belül van törölve az az objektum,
|
||||
ami a callback-et meghívta. Ez ugye paradoxon, avagy magad alatt vágod a
|
||||
fát, C-ben pedig csúnya segfault vagy még rosszabb. Jelen esetben itt a
|
||||
send() függvény visszatérési értékénél kellene ellenőrizni a "Broken pipe"
|
||||
esetet és ha bekövetkezik, akkor a netsocket_disconnect() függvénnyel
|
||||
megszakítani a kapcsolatot és hátrahagyni a "Broken pipe" üzenetet. Ebben az
|
||||
esetben a netsocket_disconnect meghívja a sock_close függvényt, ami törli a
|
||||
netsocket objektumot, majd visszatér ide. Ezen a ponton már a netsocket
|
||||
objektum, amivel eddig dolgoztunk, nem létezik és elképzelhető, hogy érkezik
|
||||
még egy netsocket_write függvényhívás vagy eleve mivel callback-ben vagyunk,
|
||||
más is történik a netsocket-tel, ami már végzetes egy nem létező objektumon.
|
||||
Erre kell kitalálni valami megoldást! Két ötlet van: vagy hardcore módon
|
||||
minden netsocket függvény a meghívásnál leellenőrzi, hogy a paraméterül
|
||||
átadott netsocket objektum létezik, írható, stb., és ha nem, akkor visszatér
|
||||
hibával. A másik módszer pedig, hogy aszinkron módon történik a netsocket
|
||||
objektumok törlése. A netsocket_disconnect megrendeli a törlést, és majd a
|
||||
callback lefutása után ténylegesen le is lesz törölve. Ezt az aszinkron
|
||||
megoldást már csináltam Perl-ben és jól működött, de valahogyan most ezt a
|
||||
kommentet fogalmazva, a hardcore verzió tűnik a legjobbnak, tehát: minden
|
||||
azonnal történjen meg, semmi ne blokkolódjon, ha már nem létezik az adott
|
||||
objektum, akkor hibával térjünk vissza és ne folytassuk a műveletet. Ezt
|
||||
minden olyan helyen ellenőrizni kell, ahol az objektummal munka van. Ez a
|
||||
koncepció talán a szálaknál is alkalmazható egy-egy mutex lock körzet alatt.
|
||||
Végiggondolni a szitut úgy, hogy egy callback-ből hívott netsocket_write
|
||||
hívja meg a netsocket_disconnect-et:) Praktikusan az, ami miatt ezt a
|
||||
litániát megírtam. */
|
||||
|
||||
/* Ötlet. Az aszinkron megoldást végiggondolni jobban! A netsocket_destroy()
|
||||
meghívására ne törlődjön azonnal a netsocket. Ha callback-ben van éppen,
|
||||
akkor a callback után történjen a felszabadítás. Vagy dupla mutatót használni
|
||||
és ellenőrizni a NULL értéket? Faszság:) */
|
||||
|
||||
// i = write(obj->sock, data, length); // nem szignál-biztos
|
||||
i = send(obj->sock, data, length, MSG_NOSIGNAL);
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a new netsocket object
|
||||
* @param callback callback function pointer
|
||||
* @param userdata user defined pointer
|
||||
* @param loop event loop
|
||||
* @returns a new netsocket object
|
||||
*
|
||||
* Create and return a malloc'ed netsocket object. Save callback and userdata
|
||||
* in the netsocket structure. Callback will be called when an event occur. Userdata
|
||||
* is an user defined pointer. If the optional loop parameter is given, then tell
|
||||
* the netsocket to use this event loop for async operations. This is useful in
|
||||
* multithreading environment. If the loop is NULL, then the default event loop
|
||||
* will be used.
|
||||
*/
|
||||
netsocket_t *netsocket_new (void *callback, void *userdata, struct ev_loop *loop) {
|
||||
netsocket_t *obj = malloc(sizeof(*obj));
|
||||
if (obj == NULL)
|
||||
return NULL;
|
||||
|
||||
//~ printf("netsocket object size = %d\n", sizeof(*obj));
|
||||
bzero(obj, sizeof(*obj)); // mindent nullázunk
|
||||
|
||||
// ha meg van adva a loop paraméter, akkor azt használjuk eseménykezelőnek
|
||||
// ellenkező esetben az alapértelmezett eseménykezelőt
|
||||
obj->loop = (loop != NULL) ? loop : ev_default_loop(0);
|
||||
|
||||
// default értékek
|
||||
obj->connect_timeout = 5000; // 5000 millisec
|
||||
|
||||
obj->callback = callback;
|
||||
obj->userdata = userdata;
|
||||
|
||||
obj->w_in.data = obj;
|
||||
obj->w_out.data = obj;
|
||||
obj->w_connect_timeout.data = obj;
|
||||
ev_init(&obj->w_in, (void*)w_in_cb);
|
||||
ev_init(&obj->w_out, (void*)w_out_cb);
|
||||
ev_init(&obj->w_connect_timeout, (void*)w_connect_timeout_cb);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief destroy the netsocket object
|
||||
* @param obj the netsocket object
|
||||
*
|
||||
* Disconnect from peer(s) without call the callback, close sockets,
|
||||
* free all resources and destroy the netsocket object.
|
||||
*/
|
||||
// TODO ha a szerver netsocket-et szabadítjuk fel, akkor az összes hozzá tartozó
|
||||
// kliens is menjen a levesbe
|
||||
void netsocket_destroy (netsocket_t *obj) {
|
||||
// ha nincs objektum, akkor lófaszjóska
|
||||
if (obj == NULL)
|
||||
return;
|
||||
|
||||
if (obj->in_callback > 0) {
|
||||
obj->destroy_request = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
disconnect(obj, NULL, 1);
|
||||
free(obj);
|
||||
}
|
||||
|
||||
// formázott konzol üzenet kiírása időbélyeggel
|
||||
int netsocket_printf (netsocket_t *obj, const char *fmt, ...) {
|
||||
char tmp[8192];
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(tmp, sizeof(tmp) - 1, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return netsocket_write(obj, tmp, strlen(tmp));
|
||||
}
|
||||
|
||||
void netsocket_host (netsocket_t *obj, const char *host) {
|
||||
if (host != NULL)
|
||||
strncpy(obj->host, host, sizeof(obj->host) - 1);
|
||||
}
|
||||
|
||||
void netsocket_lhost (netsocket_t *obj, const char *lhost) {
|
||||
if (lhost != NULL)
|
||||
strncpy(obj->lhost, lhost, sizeof(obj->lhost) - 1);
|
||||
}
|
||||
|
||||
void netsocket_port (netsocket_t *obj, int port) {
|
||||
obj->port = port;
|
||||
}
|
||||
|
||||
void netsocket_lport (netsocket_t *obj, int lport) {
|
||||
obj->lport = lport;
|
||||
}
|
||||
|
||||
int netsocket_is_connected (netsocket_t *obj) {
|
||||
return obj->connected;
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
/* netsocket.h
|
||||
* Copyright © 2014, Andras Jeszenszky, JSS & Hayer IT - http://www.jsshayer.hu
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef NETSOCKET_H_INCLUDED
|
||||
#define NETSOCKET_H_INCLUDED
|
||||
|
||||
#include <netdb.h>
|
||||
#include <ev.h>
|
||||
|
||||
#define NETSOCKET_IN 1
|
||||
#define NETSOCKET_OUT 2
|
||||
|
||||
#define NETSOCKET_CLIENT 1
|
||||
#define NETSOCKET_SERVER 2
|
||||
|
||||
#define NETSOCKET_TCP 1
|
||||
#define NETSOCKET_UNIX 2
|
||||
|
||||
#define NETSOCKET_STATE_RESOLVING 1
|
||||
#define NETSOCKET_STATE_CONNECTING 2
|
||||
#define NETSOCKET_STATE_CONNECTED 3
|
||||
|
||||
#define NETSOCKET_EVENT_ERROR 1
|
||||
#define NETSOCKET_EVENT_CONNECT 2
|
||||
#define NETSOCKET_EVENT_READ 3
|
||||
#define NETSOCKET_EVENT_DISCONNECT 4
|
||||
|
||||
typedef struct netsocket_t {
|
||||
char host[128];
|
||||
int port;
|
||||
char lhost[128];
|
||||
int lport;
|
||||
int connect_timeout;
|
||||
char ip[20];
|
||||
int sock;
|
||||
struct hostent *hostent;
|
||||
struct sockaddr_in addr;
|
||||
char inbuf[1024];
|
||||
int inbuf_len;
|
||||
ev_io w_out;
|
||||
ev_io w_in;
|
||||
ev_timer w_connect_timeout;
|
||||
void (*callback)(void*, int);
|
||||
void *userdata; // user data
|
||||
int err;
|
||||
int event;
|
||||
char disconnect_reason[128];
|
||||
int connected;
|
||||
int mode;
|
||||
struct netsocket_t *parent;
|
||||
int direction;
|
||||
int destroy_request;
|
||||
int in_callback;
|
||||
int disable_lookup_on_accept;
|
||||
struct ev_loop *loop;
|
||||
} netsocket_t;
|
||||
|
||||
netsocket_t *netsocket_new (void *callback, void *userdata, struct ev_loop *loop);
|
||||
void netsocket_destroy (netsocket_t *obj);
|
||||
int netsocket_connect (netsocket_t *obj);
|
||||
int netsocket_listen (netsocket_t *obj);
|
||||
void netsocket_disconnect (netsocket_t *obj, char *reason);
|
||||
void netsocket_disconnect_withevent (netsocket_t *obj, char *reason);
|
||||
int netsocket_write (netsocket_t *obj, const char *data, int length);
|
||||
int netsocket_printf (netsocket_t *obj, const char *fmt, ...);
|
||||
void netsocket_disable_lookup_on_accept (netsocket_t *obj);
|
||||
void netsocket_host (netsocket_t *obj, const char *host);
|
||||
void netsocket_lhost (netsocket_t *obj, const char *host);
|
||||
void netsocket_port (netsocket_t *obj, int port);
|
||||
void netsocket_lport (netsocket_t *obj, int port);
|
||||
int netsocket_is_connected (netsocket_t *obj);
|
||||
|
||||
#endif // #ifndef NETSOCKET_H_INCLUDED
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue