├── .github ├── dependabot.yml └── workflows │ └── ci.yaml ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── composer.json ├── etc ├── editorconfig.txt ├── phpstan.neon ├── phpunit.xml.dist └── psalm.xml ├── examples ├── 01-parse-request.php ├── 02-render-request.php ├── 03-parse-response.php ├── 04-render-response.php ├── 05-stream-parse.php └── 99-crude-benchmark.php ├── src ├── Auth │ ├── Digest │ │ ├── AbstractParams.php │ │ ├── ChallengeParams.php │ │ └── ResponseParams.php │ ├── OpaqueParams.php │ └── ParamsInterface.php ├── Exception │ ├── AuthException.php │ ├── InvalidBodyLengthException.php │ ├── InvalidCSeqValueException.php │ ├── InvalidDuplicateHeaderException.php │ ├── InvalidHeaderLineException.php │ ├── InvalidHeaderParameterException.php │ ├── InvalidHeaderSectionException.php │ ├── InvalidHeaderValueException.php │ ├── InvalidMessageStartLineException.php │ ├── InvalidProtocolVersionException.php │ ├── InvalidRequestMethodException.php │ ├── InvalidRequestURIException.php │ ├── InvalidScalarValueException.php │ ├── InvalidStatusCodeException.php │ ├── InvalidURIException.php │ └── SIPException.php ├── Header │ ├── AbstractAuthHeader.php │ ├── AuthValue.php │ ├── AuthenticateHeader.php │ ├── AuthorizationHeader.php │ ├── CSeqHeader.php │ ├── CallIdHeader.php │ ├── ContactHeader.php │ ├── ContactValue.php │ ├── FromHeader.php │ ├── Header.php │ ├── MaxForwardsHeader.php │ ├── MultiValueHeader.php │ ├── MultiValueWithParamsHeader.php │ ├── NameAddrHeader.php │ ├── RAckHeader.php │ ├── ScalarHeader.php │ ├── SingleValueWithParamsHeader.php │ ├── ValueWithParams.php │ ├── ViaHeader.php │ └── ViaValue.php ├── Message.php ├── Request.php ├── Response.php ├── StreamParser.php └── URI.php └── tests ├── Auth └── Digest │ └── ResponseParamsTest.php ├── Header ├── AuthenticateHeaderTest.php ├── AuthorizationHeaderTest.php ├── CSeqHeaderTest.php ├── CallIdHeaderTest.php ├── ContactHeaderTest.php ├── FromHeaderTest.php ├── HeaderTest.php ├── MultiValueHeaderTest.php ├── MultiValueWithParamsHeaderTest.php ├── NameAddrHeaderTest.php ├── RAckHeaderTest.php ├── ScalarHeaderTest.php ├── SingleValueWithParamsHeaderTest.php └── ViaHeaderTest.php ├── MessageTest.php ├── MiscTest.php ├── ProtosTest.php ├── RFC4475 ├── RFC4475Case.php ├── S31101Test.php ├── S31102Test.php ├── S31103Test.php ├── S31104Test.php ├── S31105Test.php ├── S31106Test.php ├── S31107Test.php ├── S31108Test.php ├── S31109Test.php ├── S31110Test.php ├── S31111Test.php ├── S31112Test.php ├── S31113Test.php ├── S31201Test.php ├── S31202Test.php ├── S31203Test.php ├── S31204Test.php ├── S31205Test.php ├── S31206Test.php ├── S31207Test.php ├── S31208Test.php ├── S31209Test.php ├── S31210Test.php ├── S31211Test.php ├── S31212Test.php ├── S31213Test.php ├── S31214Test.php ├── S31215Test.php ├── S31216Test.php ├── S31217Test.php ├── S31218Test.php ├── S31219Test.php ├── S32010Test.php ├── S33010Test.php ├── S33020Test.php ├── S33030Test.php ├── S33040Test.php ├── S33050Test.php ├── S33060Test.php ├── S33070Test.php ├── S33080Test.php ├── S33090Test.php ├── S33100Test.php ├── S33110Test.php ├── S33120Test.php ├── S33130Test.php ├── S33140Test.php ├── S33150Test.php └── S34010Test.php ├── RequestTest.php ├── ResponseTest.php ├── StreamParserTest.php ├── URITest.php └── fixtures ├── misc ├── gh-21.yaml ├── rfc3327 │ ├── 5.5.1_example-of-mechanism-in-register-transaction.yaml │ └── 5.5.2_example-of-mechanism-in-invite-transaction.yaml ├── rfc3515 │ ├── 4.1_prototypical-refer-callflow.yaml │ └── 4.2_multiple-refers-in-a-dialog.yaml ├── rfc3665 │ ├── 2.01_sip-client-new-registration.yaml │ ├── 2.02_update-of-contact-list.yaml │ ├── 2.03_request-for-current-contact-list.yaml │ ├── 2.04_cancellation-of-registration.yaml │ ├── 2.05_unsuccessful-registration.yaml │ ├── 3.01_successful-session-establishment.yaml │ ├── 3.02_session-establishment-through-two-proxies.yaml │ ├── 3.03_session-with-multiple-proxy-authentication.yaml │ ├── 3.04_successful-session-with-proxy-failure.yaml │ ├── 3.05_session-through-a-sip-alg.yaml │ ├── 3.06_session-via-redirect-and-proxy-servers-with-sdp-in-ack.yaml │ ├── 3.07_session-with-re-invite-ip-address-change.yaml │ ├── 3.08_unsuccessful-no-answer.yaml │ ├── 3.09_unsuccessful-busy.orig │ ├── 3.09_unsuccessful-busy.yaml │ ├── 3.10_unsuccessful-no-response-from-user-agent.yaml │ └── 3.11_unsuccessful-temporarily-unavailable.yaml ├── rfc4916 │ ├── 5.1_sending-connected-identity-after-answering-a-call.yaml │ └── 5.2_sending-revised-connected-identity-during-a-call.yaml └── rfc5626 │ ├── 3.2_single-registrar-and-ua.yaml │ ├── 9.1_subscription-to-configuration-package.yaml │ ├── 9.2_registration.yaml │ ├── 9.3_incoming_call_and_proxy_crash.yaml │ ├── 9.4_re-registration.yaml │ └── 9.5_outgoing_call.yaml ├── rfc4475 ├── badaspec.dat ├── badbranch.dat ├── baddate.dat ├── baddn.dat ├── badinv01.dat ├── badvers.dat ├── bcast.dat ├── bext01.dat ├── bigcode.dat ├── clerr.dat ├── cparam01.dat ├── cparam02.dat ├── dblreq.dat ├── esc01.dat ├── esc02.dat ├── escnull.dat ├── escruri.dat ├── insuf.dat ├── intmeth.dat ├── inv2543.dat ├── invut.dat ├── longreq.dat ├── ltgtruri.dat ├── lwsdisp.dat ├── lwsruri.dat ├── lwsstart.dat ├── mcl01.dat ├── mismatch01.dat ├── mismatch02.dat ├── mpart01.dat ├── multi01.dat ├── ncl.dat ├── noreason.dat ├── novelsc.dat ├── quotbal.dat ├── regaut01.dat ├── regbadct.dat ├── regescrt.dat ├── scalar02.dat ├── scalarlg.dat ├── sdp01.dat ├── semiuri.dat ├── test.dat ├── transports.dat ├── trws.dat ├── unkscm.dat ├── unksm2.dat ├── unreason.dat ├── wsinv.dat └── zeromf.dat └── stream ├── generic.txt └── lioneagle-sipparser.txt /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "composer" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | pull_request: 6 | 7 | jobs: 8 | StaticAnalysis: 9 | name: StaticAnalysis (PHP ${{ matrix.php }} on ${{ matrix.os }}) 10 | runs-on: ${{ matrix.os }} 11 | strategy: 12 | matrix: 13 | os: 14 | - ubuntu-20.04 15 | php: 16 | - 7.4 17 | - 8.0 18 | - 8.1 19 | - 8.2 20 | steps: 21 | - uses: actions/checkout@v2 22 | - uses: shivammathur/setup-php@v2 23 | with: 24 | php-version: ${{ matrix.php }} 25 | - run: composer install 26 | - run: composer phpstan 27 | - run: composer psalm -- --output-format=github --shepherd 28 | 29 | Coverage: 30 | name: Coverage (PHP ${{ matrix.php }} on ${{ matrix.os }}) 31 | runs-on: ${{ matrix.os }} 32 | strategy: 33 | matrix: 34 | os: 35 | - ubuntu-20.04 36 | php: 37 | - 7.4 38 | - 8.0 39 | - 8.1 40 | - 8.2 41 | steps: 42 | - uses: actions/checkout@v2 43 | - uses: shivammathur/setup-php@v2 44 | with: 45 | php-version: ${{ matrix.php }} 46 | - run: composer install 47 | - uses: paambaati/codeclimate-action@v4.0.0 48 | env: 49 | CC_TEST_REPORTER_ID: ${{secrets.CC_TEST_REPORTER_ID}} 50 | with: 51 | coverageCommand: php -d memory_limit=-1 ./vendor/bin/phpunit -c ./etc/phpunit.xml.dist --coverage-clover clover.xml 52 | coverageLocations: clover.xml:clover 53 | debug: true 54 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .editorconfig 2 | .phpunit.result.cache 3 | reports 4 | vendor 5 | composer.lock 6 | tests/fixtures/protos 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | env: 2 | global: 3 | - GIT_COMMITTED_AT=$(if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then git log -1 --pretty=format:%ct; else git log -1 --skip 1 --pretty=format:%ct; fi) 4 | 5 | language: php 6 | 7 | php: 8 | - '7.4' 9 | - nightly 10 | 11 | before_script: 12 | - composer install 13 | - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter 14 | - chmod +x ./cc-test-reporter 15 | - ./cc-test-reporter before-build 16 | - echo "xdebug.mode=coverage" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini 17 | 18 | script: 19 | - php -d memory_limit=-1 ./vendor/bin/phpstan analyse -c ./etc/phpstan.neon -n -vvv --ansi --level=max src 20 | - php -d memory_limit=-1 ./vendor/bin/psalm --config=./etc/psalm.xml --show-info=true 21 | - php -d memory_limit=-1 ./vendor/bin/phpunit -c ./etc/phpunit.xml.dist --coverage-text --coverage-clover build/logs/clover.xml 22 | - if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT; fi 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Ciprian Dosoftei 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rtckit/sip", 3 | "description": "SIP protocol implementation written in PHP", 4 | "version": "0.7.1", 5 | "type": "library", 6 | "keywords": [ 7 | "sip", 8 | "session initiation protocol", 9 | "voip", 10 | "rfc 3261", 11 | "telephony", 12 | "telco" 13 | ], 14 | "homepage": "https://github.com/rtckit/php-sip", 15 | "license": "MIT", 16 | "authors": [ 17 | { 18 | "name": "Ciprian Dosoftei" 19 | } 20 | ], 21 | "support": { 22 | "email": "hello@rtckit.io", 23 | "issues": "https://github.com/rtckit/php-sip/issues" 24 | }, 25 | "require": { 26 | "php": ">=7.4.0", 27 | "ext-ctype": "*" 28 | }, 29 | "require-dev": { 30 | "phpstan/phpstan": "^1.10", 31 | "phpunit/phpunit": "^9.5", 32 | "symfony/yaml": "^5.3", 33 | "vimeo/psalm": "^5.11" 34 | }, 35 | "suggest": { 36 | "ext-hash": "Enables RFC 8760 authentication via SHA(-512)-256 hashing" 37 | }, 38 | "autoload": { 39 | "psr-4": { 40 | "RTCKit\\SIP\\": "src/" 41 | } 42 | }, 43 | "autoload-dev": { 44 | "psr-4": { 45 | "RTCKit\\SIP\\": "tests/" 46 | } 47 | }, 48 | "config": { 49 | "allow-plugins": false, 50 | "platform": { 51 | "php": "7.4" 52 | } 53 | }, 54 | "scripts": { 55 | "phpstan": "php -d memory_limit=-1 ./vendor/bin/phpstan analyse -c ./etc/phpstan.neon -n -vvv --ansi --level=max src", 56 | "psalm": "php -d memory_limit=-1 ./vendor/bin/psalm --config=./etc/psalm.xml", 57 | "test": "php -d memory_limit=-1 ./vendor/bin/phpunit -c ./etc/phpunit.xml.dist --debug", 58 | "coverage": "php -d extension=pcov -d memory_limit=-1 ./vendor/bin/phpunit -c ./etc/phpunit.xml.dist --coverage-text --coverage-html=reports/coverage", 59 | "profile": "php -d memory_limit=-1 ./examples/99-crude-benchmark.php" 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /etc/phpstan.neon: -------------------------------------------------------------------------------- 1 | includes: 2 | - ../vendor/phpstan/phpstan/conf/bleedingEdge.neon 3 | -------------------------------------------------------------------------------- /etc/phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | ../tests/ 12 | 13 | 14 | 15 | 16 | ../src/ 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /etc/psalm.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /examples/01-parse-request.php: -------------------------------------------------------------------------------- 1 | ;tag=SFJbQ2oWh' . "\r\n" . 19 | 'To: sip:buzz@192.168.0.1' . "\r\n" . 20 | 'CSeq: 20 REGISTER' . "\r\n" . 21 | 'Call-ID: ob0EYyuyC0' . "\r\n" . 22 | 'Max-Forwards: 70' . "\r\n" . 23 | 'Supported: replaces, outbound' . "\r\n" . 24 | 'Accept: application/sdp' . "\r\n" . 25 | 'Accept: text/plain' . "\r\n" . 26 | 'Accept: application/vnd.gsma.rcs-ft-http+xml' . "\r\n" . 27 | 'Contact: ' . "\r\n" . 28 | ' ;q=0.7; expires=3600' . "\r\n" . 29 | ' ;+sip.instance=""' . "\r\n" . 30 | 'Contact: ;reg-id=1;expires=3600' . "\r\n" . 31 | ' ;+sip.instance=""' . "\r\n" . 32 | 'Contact: ;reg-id=2;expires=3600' . "\r\n" . 33 | ' ;+sip.instance=""' . "\r\n" . 34 | 'Expires: 3600' . "\r\n" . 35 | 'User-Agent: MyDeskPhone/1.0.0' . "\r\n" . 36 | "\r\n"; 37 | 38 | $request = Message::parse($text); 39 | 40 | printf("Message type: %s" . PHP_EOL, (get_class($request) === Request::class) ? 'SIP Request' : 'BOGUS!!!'); 41 | printf("Protocol version: %s" . PHP_EOL, $request->version); 42 | printf("Request method: %s" . PHP_EOL, $request->method); 43 | printf("Request URI scheme: %s" . PHP_EOL, $request->uri->scheme); 44 | printf("Request URI host: %s" . PHP_EOL, $request->uri->host); 45 | printf("Via: %s" . PHP_EOL, $request->via->values[0]->host); 46 | printf("Via branch: %s" . PHP_EOL, $request->via->values[0]->branch); 47 | printf("From scheme: %s" . PHP_EOL, $request->from->uri->scheme); 48 | printf("From user: %s" . PHP_EOL, $request->from->uri->user); 49 | printf("From host: %s" . PHP_EOL, $request->from->uri->host); 50 | printf("From tag: %s" . PHP_EOL, $request->from->tag); 51 | printf("To scheme: %s" . PHP_EOL, $request->to->uri->scheme); 52 | printf("To user: %s" . PHP_EOL, $request->to->uri->user); 53 | printf("To host: %s" . PHP_EOL, $request->to->uri->host); 54 | printf("CSeq: %s" . PHP_EOL, $request->cSeq->sequence); 55 | printf("Call ID: %s" . PHP_EOL, $request->callId->value); 56 | printf("Max forwards: %d" . PHP_EOL, $request->maxForwards->value); 57 | 58 | printf("Supported: "); 59 | 60 | foreach ($request->supported->values as $key => $val) { 61 | if ($key) { 62 | printf(" "); 63 | } 64 | 65 | printf("- %s" . PHP_EOL, $val); 66 | } 67 | 68 | printf("Accept: "); 69 | 70 | foreach ($request->accept->values as $key => $val) { 71 | if ($key) { 72 | printf(" "); 73 | } 74 | 75 | printf("- %s" . PHP_EOL, $val->value); 76 | } 77 | 78 | printf("Contact scheme: %s" . PHP_EOL, $request->contact->values[0]->uri->scheme); 79 | printf("Contact user: %s" . PHP_EOL, $request->contact->values[0]->uri->user); 80 | printf("Contact host: %s" . PHP_EOL, $request->contact->values[0]->uri->host); 81 | printf("Contact transport: %s" . PHP_EOL, $request->contact->values[0]->uri->transport); 82 | printf("Contact q-value: %s" . PHP_EOL, $request->contact->values[0]->q); 83 | printf("Contact expires: %s" . PHP_EOL, $request->contact->values[0]->expires); 84 | printf("Contact instance: %s" . PHP_EOL, $request->contact->values[0]->params['+sip.instance']); 85 | printf("Expires: %s" . PHP_EOL, $request->expires->value); 86 | printf("User agent: %s" . PHP_EOL, $request->userAgent->values[0]); 87 | -------------------------------------------------------------------------------- /examples/02-render-request.php: -------------------------------------------------------------------------------- 1 | version = 'SIP/2.0'; 25 | $request->method = 'REGISTER'; 26 | $request->uri = new URI; 27 | $request->uri->scheme = 'sip'; 28 | $request->uri->host = '192.168.0.1'; 29 | 30 | $request->via = new ViaHeader; 31 | $request->via->values[0] = new ViaValue; 32 | $request->via->values[0]->protocol = 'SIP'; 33 | $request->via->values[0]->version = '2.0'; 34 | $request->via->values[0]->transport = 'UDP'; 35 | $request->via->values[0]->host = '192.168.0.2:5050'; 36 | $request->via->values[0]->branch = 'z9hG4bK.eAV4o0nXr'; 37 | 38 | $request->from = new NameAddrHeader; 39 | $request->from->uri = new URI; 40 | $request->from->uri->scheme = 'sip'; 41 | $request->from->uri->user = 'buzz'; 42 | $request->from->uri->host = '192.168.0.1'; 43 | $request->from->tag = 'SFJbQ2oWh'; 44 | 45 | $request->to = new NameAddrHeader; 46 | $request->to->uri = new URI; 47 | $request->to->uri->scheme = 'sip'; 48 | $request->to->uri->user = 'buzz'; 49 | $request->to->uri->host = '192.168.0.1'; 50 | 51 | $request->cSeq = new CSeqHeader; 52 | $request->cSeq->sequence = 20; 53 | $request->cSeq->method = $request->method; 54 | 55 | $request->callId = new CallIdHeader; 56 | $request->callId->value = 'ob0EYyuyC0'; 57 | 58 | $request->maxForwards = new ScalarHeader; 59 | $request->maxForwards->value = 70; 60 | 61 | $request->contact = new ContactHeader; 62 | $request->contact->values[0] = new ContactValue; 63 | $request->contact->values[0]->uri = new URI; 64 | $request->contact->values[0]->uri->scheme = 'sip'; 65 | $request->contact->values[0]->uri->user = 'buzz'; 66 | $request->contact->values[0]->uri->host = '192.168.0.2'; 67 | $request->contact->values[0]->uri->port = 5050; 68 | $request->contact->values[0]->uri->transport = 'udp'; 69 | $request->contact->values[0]->q = 0.7; 70 | $request->contact->values[0]->expires = 3600; 71 | $request->contact->values[0]->params['+sip.instance'] = '""'; 72 | 73 | $request->userAgent = new Header; 74 | $request->userAgent->values[0] = 'MyDeskPhone/1.0.0'; 75 | 76 | echo $request->render(); 77 | -------------------------------------------------------------------------------- /examples/03-parse-response.php: -------------------------------------------------------------------------------- 1 | ;tag=8734a29d0ba1b4b0a195a091c7233452-6e53' . "\r\n" . 19 | 'To: ;tag=8cQtUyH6N5N9K' . "\r\n" . 20 | 'Call-ID: 5a3202932ab4128f-23935' . "\r\n" . 21 | 'User-Agent: MyDeskPhone/1.0.0' . "\r\n" . 22 | 'CSeq: 10 OPTIONS' . "\r\n" . 23 | 'Contact: ' . "\r\n" . 24 | 'Accept: application/sdp' . "\r\n" . 25 | 'Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, INFO, UPDATE, REGISTER, REFER, NOTIFY' . "\r\n" . 26 | 'Supported: timer' . "\r\n" . 27 | 'Supported: path' . "\r\n" . 28 | 'Supported: replaces' . "\r\n" . 29 | 'Allow-Events: talk' . "\r\n" . 30 | 'Content-Length: 0' . "\r\n" . 31 | "\r\n"; 32 | 33 | $response = Message::parse($text); 34 | 35 | printf("Message type: %s" . PHP_EOL, (get_class($response) === Response::class) ? 'SIP Response' : 'BOGUS!!!'); 36 | printf("Protocol version: %s" . PHP_EOL, $response->version); 37 | printf("Response code: %s" . PHP_EOL, $response->code); 38 | printf("Response reason: %s" . PHP_EOL, $response->reason); 39 | printf("Via: %s" . PHP_EOL, $response->via->values[0]->host); 40 | printf("Via branch: %s" . PHP_EOL, $response->via->values[0]->branch); 41 | printf("From scheme: %s" . PHP_EOL, $response->from->uri->scheme); 42 | printf("From user: %s" . PHP_EOL, $response->from->uri->user); 43 | printf("From host: %s" . PHP_EOL, $response->from->uri->host); 44 | printf("From tag: %s" . PHP_EOL, $response->from->tag); 45 | printf("To scheme: %s" . PHP_EOL, $response->to->uri->scheme); 46 | printf("To host: %s" . PHP_EOL, $response->to->uri->host); 47 | printf("To tag: %s" . PHP_EOL, $response->to->tag); 48 | printf("Call ID: %s" . PHP_EOL, $response->callId->value); 49 | printf("User agent: %s" . PHP_EOL, $response->userAgent->values[0]); 50 | printf("CSeq: %s" . PHP_EOL, $response->cSeq->sequence); 51 | printf("Contact scheme: %s" . PHP_EOL, $response->contact->values[0]->uri->scheme); 52 | printf("Contact user: %s" . PHP_EOL, $response->contact->values[0]->uri->user); 53 | printf("Contact host: %s" . PHP_EOL, $response->contact->values[0]->uri->host); 54 | printf("Contact port: %s" . PHP_EOL, $response->contact->values[0]->uri->port); 55 | printf("Contact transport: %s" . PHP_EOL, $response->contact->values[0]->uri->transport); 56 | 57 | printf("Accept: "); 58 | 59 | foreach ($response->accept->values as $key => $val) { 60 | if ($key) { 61 | printf(" "); 62 | } 63 | 64 | printf("- %s" . PHP_EOL, $val->value); 65 | } 66 | 67 | printf("Allow: "); 68 | 69 | foreach ($response->allow->values as $key => $val) { 70 | if ($key) { 71 | printf(" "); 72 | } 73 | 74 | printf("- %s" . PHP_EOL, $val); 75 | } 76 | 77 | printf("Supported: "); 78 | 79 | foreach ($response->supported->values as $key => $val) { 80 | if ($key) { 81 | printf(" "); 82 | } 83 | 84 | printf("- %s" . PHP_EOL, $val); 85 | } 86 | 87 | printf("Allow events: "); 88 | 89 | foreach ($response->allowEvents->values as $key => $val) { 90 | if ($key) { 91 | printf(" "); 92 | } 93 | 94 | printf("- %s" . PHP_EOL, $val); 95 | } 96 | 97 | printf("Content length: %s" . PHP_EOL, $response->contentLength->value); 98 | -------------------------------------------------------------------------------- /examples/04-render-response.php: -------------------------------------------------------------------------------- 1 | version = 'SIP/2.0'; 25 | $response->code = 200; 26 | 27 | $response->via = new ViaHeader; 28 | $response->via->values[0] = new ViaValue; 29 | $response->via->values[0]->protocol = 'SIP'; 30 | $response->via->values[0]->version = '2.0'; 31 | $response->via->values[0]->transport = 'UDP'; 32 | $response->via->values[0]->host = '192.168.0.2:5050'; 33 | $response->via->values[0]->branch = 'z9hG4bK.eAV4o0nXr'; 34 | 35 | $response->from = new NameAddrHeader; 36 | $response->from->uri = new URI; 37 | $response->from->uri->scheme = 'sip'; 38 | $response->from->uri->user = 'buzz'; 39 | $response->from->uri->host = '192.168.0.1'; 40 | $response->from->tag = 'SFJbQ2oWh'; 41 | 42 | $response->to = new NameAddrHeader; 43 | $response->to->uri = new URI; 44 | $response->to->uri->scheme = 'sip'; 45 | $response->to->uri->user = 'buzz'; 46 | $response->to->uri->host = '192.168.0.1'; 47 | $response->to->tag = '8cQtUyH6N5N9K'; 48 | 49 | $response->cSeq = new CSeqHeader; 50 | $response->cSeq->sequence = 20; 51 | $response->cSeq->method = 'REGISTER'; 52 | 53 | $response->callId = new CallIdHeader; 54 | $response->callId->value = 'ob0EYyuyC0'; 55 | 56 | $response->maxForwards = new ScalarHeader; 57 | $response->maxForwards->value = 70; 58 | 59 | $response->contact = new ContactHeader; 60 | $response->contact->values[0] = new ContactValue; 61 | $response->contact->values[0]->uri = new URI; 62 | $response->contact->values[0]->uri->scheme = 'sip'; 63 | $response->contact->values[0]->uri->user = 'buzz'; 64 | $response->contact->values[0]->uri->host = '192.168.0.2'; 65 | $response->contact->values[0]->uri->port = 5050; 66 | $response->contact->values[0]->uri->transport = 'udp'; 67 | $response->contact->values[0]->q = 0.7; 68 | $response->contact->values[0]->expires = 3600; 69 | $response->contact->values[0]->params['+sip.instance'] = '""'; 70 | 71 | $response->userAgent = new Header; 72 | $response->userAgent->values[0] = 'MyDeskPhone/1.0.0'; 73 | 74 | echo $response->render(); 75 | -------------------------------------------------------------------------------- /examples/05-stream-parse.php: -------------------------------------------------------------------------------- 1 | process($bytes, $messages) === StreamParser::SUCCESS) { 23 | foreach($messages as $message) { 24 | /* Consume messages ... */ 25 | if ($message instanceof Request) { 26 | printf( 27 | "Request %10s %30s %30s %40s" . PHP_EOL, 28 | $message->method, 29 | substr($message->from->uri->user, 0, 30), 30 | substr($message->to->uri->user, 0, 30), 31 | substr($message->callId->value, 0, 40) 32 | ); 33 | } else { 34 | printf( 35 | "Response %10s %30s %30s %40s %03d %s" . PHP_EOL, 36 | $message->cSeq->method, 37 | substr($message->from->uri->user, 0, 30), 38 | substr($message->to->uri->user, 0, 30), 39 | substr($message->callId->value, 0, 40), 40 | $message->code, 41 | $message->reason 42 | ); 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Auth/Digest/ChallengeParams.php: -------------------------------------------------------------------------------- 1 | Quality of protection options */ 21 | public array $qop = []; 22 | } 23 | -------------------------------------------------------------------------------- /src/Auth/OpaqueParams.php: -------------------------------------------------------------------------------- 1 | verbatim = $input; 27 | 28 | return $params; 29 | } 30 | 31 | /** 32 | * Renders opaque authentication scheme parameters as string 33 | * 34 | * @return string Opaque authentication parameters 35 | */ 36 | public function render(): string 37 | { 38 | return $this->verbatim; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Auth/ParamsInterface.php: -------------------------------------------------------------------------------- 1 | stub = $stub; 29 | } 30 | 31 | /** 32 | * Retrieve's exception's stub, if any 33 | * 34 | * @return ?Message Partial message 35 | */ 36 | public function getStub(): ?Message 37 | { 38 | return $this->stub; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Header/AbstractAuthHeader.php: -------------------------------------------------------------------------------- 1 | Authentication/Authorization value(s) */ 23 | public array $values = []; 24 | 25 | final public function __construct() {} 26 | 27 | /** 28 | * Authentication/Authorization field value parser 29 | * 30 | * @param list $hbody Header body 31 | * @throws InvalidHeaderLineException 32 | * @throws InvalidHeaderParameterException 33 | * @return AbstractAuthHeader 34 | */ 35 | public static function parse(array $hbody): AbstractAuthHeader 36 | { 37 | $ret = new static; 38 | $challenge = static::class === AuthenticateHeader::class; 39 | 40 | foreach ($hbody as $hline) { 41 | $hparts = explode(' ', trim($hline), 2); 42 | 43 | if (count($hparts) !== 2) { 44 | throw new InvalidHeaderLineException('Invalid Auth header, missing scheme', Response::BAD_REQUEST); 45 | } 46 | 47 | $val = new AuthValue; 48 | $val->scheme = strtolower($hparts[0]); 49 | 50 | $params = ltrim($hparts[1]); 51 | 52 | switch ($val->scheme) { 53 | case DigestChallengeParams::SCHEME_NAME: 54 | if ($challenge) { 55 | $val->params = DigestChallengeParams::parse($params); 56 | } else { 57 | $val->params = DigestResponseParams::parse($params); 58 | } 59 | break; 60 | 61 | default: 62 | $val->params = OpaqueParams::parse($params); 63 | break; 64 | } 65 | 66 | $ret->values[] = $val; 67 | } 68 | 69 | return $ret; 70 | } 71 | 72 | /** 73 | * Authentication/Authorization header field value renderer 74 | * 75 | * @param string $hname Header field name 76 | * @throws InvalidHeaderValueException 77 | * @return string 78 | */ 79 | public function render(string $hname): string 80 | { 81 | $ret = ''; 82 | 83 | foreach ($this->values as $key => $value) { 84 | if (!isset($value->scheme, $value->params)) { 85 | throw new InvalidHeaderValueException('Malformed auth header, missing scheme and/or parameters'); 86 | } 87 | 88 | $ret .= "{$hname}: {$value->scheme} " . $value->params->render() . "\r\n"; 89 | } 90 | 91 | return $ret; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/Header/AuthValue.php: -------------------------------------------------------------------------------- 1 | $hbody Header body 32 | * @throws InvalidDuplicateHeaderException 33 | * @throws InvalidHeaderLineException 34 | * @throws InvalidScalarValueException 35 | * @return CSeqHeader 36 | */ 37 | public static function parse(array $hbody): CSeqHeader 38 | { 39 | if (isset($hbody[1])) { 40 | throw new InvalidDuplicateHeaderException('Cannot have more than one CSeq header', Response::BAD_REQUEST); 41 | } 42 | 43 | $cseq = trim($hbody[0]); 44 | $delimPos = strpos($cseq, ' '); 45 | 46 | if ($delimPos === false) { 47 | throw new InvalidHeaderLineException('Invalid CSeq header', Response::BAD_REQUEST); 48 | } 49 | 50 | $ret = new static; 51 | $ret->sequence = (int) substr($cseq, 0, $delimPos); 52 | 53 | if (($ret->sequence < 0) || ($ret->sequence > ScalarHeader::MAX_VALUE)) { 54 | throw new InvalidScalarValueException('CSeq sequence number out of bounds', Response::BAD_REQUEST); 55 | } 56 | 57 | $ret->method = ltrim(substr($cseq, $delimPos)); 58 | 59 | return $ret; 60 | } 61 | 62 | /** 63 | * CSeq header value renderer 64 | * 65 | * @param string $hname Header field name 66 | * @throws InvalidHeaderValueException 67 | * @return string 68 | */ 69 | public function render(string $hname): string 70 | { 71 | if (!isset($this->sequence, $this->method[0])) { 72 | throw new InvalidHeaderValueException('Missing Sequence/Method for CSeq header field value'); 73 | } 74 | 75 | return "{$hname}: {$this->sequence} {$this->method}\r\n"; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/Header/CallIdHeader.php: -------------------------------------------------------------------------------- 1 | $hbody Header body 27 | * @throws InvalidDuplicateHeaderException 28 | * @return CallIdHeader 29 | */ 30 | public static function parse(array $hbody): CallIdHeader 31 | { 32 | if (isset($hbody[1])) { 33 | throw new InvalidDuplicateHeaderException('Cannot have more than one Call-ID header', Response::BAD_REQUEST); 34 | } 35 | 36 | $ret = new static; 37 | $ret->value = trim($hbody[0]); 38 | 39 | return $ret; 40 | } 41 | 42 | /** 43 | * Call-ID header value renderer 44 | * 45 | * @param string $hname Header field name 46 | * @throws InvalidHeaderValueException 47 | * @return string 48 | */ 49 | public function render(string $hname): string 50 | { 51 | if (!isset($this->value[0])) { 52 | throw new InvalidHeaderValueException('Missing Call-ID header value'); 53 | } 54 | 55 | return "{$hname}: {$this->value}\r\n"; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/Header/ContactValue.php: -------------------------------------------------------------------------------- 1 | Additional/extension parameters */ 29 | public array $params = []; 30 | } 31 | -------------------------------------------------------------------------------- /src/Header/FromHeader.php: -------------------------------------------------------------------------------- 1 | $hbody Header body 21 | * @throws InvalidHeaderParameterException 22 | * @return NameAddrHeader 23 | */ 24 | public static function parse(array $hbody): NameAddrHeader 25 | { 26 | $ret = parent::parse($hbody); 27 | 28 | if (!isset($ret->tag[0])) { 29 | throw new InvalidHeaderParameterException('Missing/empty tag parameter in From header field value', Response::BAD_REQUEST); 30 | } 31 | 32 | return $ret; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Header/Header.php: -------------------------------------------------------------------------------- 1 | Generic header field values */ 15 | public array $values = []; 16 | 17 | final public function __construct() {} 18 | 19 | /** 20 | * Generic header value parser 21 | * 22 | * @param list $hbody Header body 23 | * @return Header 24 | */ 25 | public static function parse(array $hbody): Header 26 | { 27 | $ret = new static; 28 | 29 | foreach ($hbody as $hline) { 30 | $ret->values[] = trim($hline); 31 | } 32 | 33 | return $ret; 34 | } 35 | 36 | /** 37 | * Generic header value renderer 38 | * 39 | * @param string $hname Header field name 40 | * @return string 41 | */ 42 | public function render(string $hname): string 43 | { 44 | $ret = ''; 45 | 46 | foreach ($this->values as $value) { 47 | $ret .= "{$hname}: {$value}\r\n"; 48 | } 49 | 50 | return $ret; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Header/MaxForwardsHeader.php: -------------------------------------------------------------------------------- 1 | Header field values */ 15 | public array $values = []; 16 | 17 | final public function __construct() {} 18 | 19 | /** 20 | * Multpiple value header parser (no parameters) 21 | * 22 | * @param list $hbody Header body 23 | * @return MultiValueHeader 24 | */ 25 | public static function parse(array $hbody): MultiValueHeader 26 | { 27 | $ret = new static; 28 | 29 | foreach ($hbody as $hline) { 30 | $hvalues = explode(',', $hline); 31 | 32 | foreach ($hvalues as $hvalue) { 33 | $ret->values[] = trim($hvalue); 34 | } 35 | } 36 | 37 | return $ret; 38 | } 39 | 40 | /** 41 | * Multiple value header renderer 42 | * 43 | * @param string $hname Header field name 44 | * @return string 45 | */ 46 | public function render(string $hname): string 47 | { 48 | return "{$hname}: " . implode(', ', $this->values) . "\r\n"; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Header/MultiValueWithParamsHeader.php: -------------------------------------------------------------------------------- 1 | Header value(s) */ 20 | public array $values = []; 21 | 22 | final public function __construct() {} 23 | 24 | /** 25 | * Multiple value header parser, with optional parameters 26 | * 27 | * @param list $hbody Header body 28 | * @throws InvalidHeaderLineException 29 | * @throws InvalidHeaderParameterException 30 | * @return MultiValueWithParamsHeader 31 | */ 32 | public static function parse(array $hbody): MultiValueWithParamsHeader 33 | { 34 | $ret = new static; 35 | 36 | foreach ($hbody as $hline) { 37 | $hvalues = explode(',', $hline); 38 | 39 | foreach ($hvalues as $hvalue) { 40 | $tok = strtok(trim($hvalue), ';'); 41 | 42 | if ($tok === false) { 43 | throw new InvalidHeaderLineException('Empty header value', Response::BAD_REQUEST); 44 | } 45 | 46 | $val = new ValueWithParams; 47 | $val->value = $tok; 48 | 49 | while (($tok = strtok(';')) !== false) { 50 | $p = explode('=', $tok); 51 | $p[0] = trim($p[0]); 52 | 53 | if (!isset($p[0][0])) { 54 | throw new InvalidHeaderParameterException('Empty header parameters', Response::BAD_REQUEST); 55 | } 56 | 57 | $val->params[$p[0]] = isset($p[1]) ? trim($p[1]) : ''; 58 | } 59 | 60 | $ret->values[] = $val; 61 | } 62 | } 63 | 64 | return $ret; 65 | } 66 | 67 | /** 68 | * Multiple value header renderer, with optional parameters 69 | * 70 | * @param string $hname Header field name 71 | * @throws InvalidHeaderValueException 72 | * @return string 73 | */ 74 | public function render(string $hname): string 75 | { 76 | $ret = "{$hname}: "; 77 | 78 | foreach ($this->values as $key => $value) { 79 | if (!isset($value->value)) { 80 | throw new InvalidHeaderValueException('Malformed header, missing value'); 81 | } 82 | 83 | if ($key) { 84 | $ret .= ', '; 85 | } 86 | 87 | $ret .= $value->value; 88 | 89 | foreach ($value->params as $pk => $pv) { 90 | if (!isset($pk[0])) { 91 | throw new InvalidHeaderValueException('Malformed header, invalid parameter key for header ' . $hname); 92 | } 93 | 94 | $ret .= ';' . $pk . (!isset($pv[0]) ? '' : "={$pv}"); 95 | } 96 | } 97 | 98 | $ret .= "\r\n"; 99 | 100 | return $ret; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/Header/RAckHeader.php: -------------------------------------------------------------------------------- 1 | $hbody Header body 37 | * @throws InvalidDuplicateHeaderException 38 | * @throws InvalidHeaderLineException 39 | * @throws InvalidScalarValueException 40 | * @return RAckHeader 41 | */ 42 | public static function parse(array $hbody): RAckHeader 43 | { 44 | if (isset($hbody[1])) { 45 | throw new InvalidDuplicateHeaderException('Cannot have more than one RAck header', Response::BAD_REQUEST); 46 | } 47 | 48 | $rack = preg_split('/\s+/', trim($hbody[0]), -1, PREG_SPLIT_NO_EMPTY); 49 | 50 | if (!is_array($rack) || (count($rack) != 3)) { 51 | throw new InvalidHeaderLineException('Invalid RAck header', Response::BAD_REQUEST); 52 | } 53 | 54 | $ret = new static; 55 | $ret->rSequence = (int) $rack[0]; 56 | 57 | if (($ret->rSequence < 0) || ($ret->rSequence > ScalarHeader::MAX_VALUE)) { 58 | throw new InvalidScalarValueException('RAck provisional sequence number out of bounds', Response::BAD_REQUEST); 59 | } 60 | 61 | $ret->cSequence = (int) $rack[1]; 62 | 63 | if (($ret->cSequence < 0) || ($ret->cSequence > ScalarHeader::MAX_VALUE)) { 64 | throw new InvalidScalarValueException('RAck sequence number out of bounds', Response::BAD_REQUEST); 65 | } 66 | 67 | $ret->method = $rack[2]; 68 | 69 | return $ret; 70 | } 71 | 72 | /** 73 | * RAck header value renderer 74 | * 75 | * @param string $hname Header field name 76 | * @throws InvalidHeaderValueException 77 | * @return string 78 | */ 79 | public function render(string $hname): string 80 | { 81 | if (!isset($this->rSequence, $this->cSequence, $this->method[0])) { 82 | throw new InvalidHeaderValueException('Missing Sequence(s)/Method for RAck header field value'); 83 | } 84 | 85 | return "{$hname}: {$this->rSequence} {$this->cSequence} {$this->method}\r\n"; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/Header/ScalarHeader.php: -------------------------------------------------------------------------------- 1 | $hbody Header body 31 | * @throws InvalidDuplicateHeaderException 32 | * @throws InvalidScalarValueException 33 | * @return ScalarHeader 34 | */ 35 | public static function parse(array $hbody): ScalarHeader 36 | { 37 | if (isset($hbody[1])) { 38 | throw new InvalidDuplicateHeaderException('Scalar header fields can only have one value', Response::BAD_REQUEST); 39 | } 40 | 41 | $val = (int) $hbody[0]; 42 | 43 | if ($val > static::MAX_VALUE) { 44 | throw new InvalidScalarValueException('Scalar header field value out of bounds, > ' . static::MAX_VALUE, Response::BAD_REQUEST); 45 | } 46 | 47 | if ($val < 0) { 48 | throw new InvalidScalarValueException('Scalar header field value out of bounds (negative)', Response::BAD_REQUEST); 49 | } 50 | 51 | $ret = new static; 52 | $ret->value = $val; 53 | 54 | return $ret; 55 | } 56 | 57 | /** 58 | * Scalar header value renderer 59 | * 60 | * @param string $hname Header field name 61 | * @throws InvalidHeaderValueException 62 | * @return string 63 | */ 64 | public function render(string $hname): string 65 | { 66 | if (!isset($this->value)) { 67 | throw new InvalidHeaderValueException('Missing scalar header value'); 68 | } 69 | 70 | return "{$hname}: {$this->value}\r\n"; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/Header/SingleValueWithParamsHeader.php: -------------------------------------------------------------------------------- 1 | Parameters */ 24 | public array $params = []; 25 | 26 | final public function __construct() {} 27 | 28 | /** 29 | * Single value header field parser, with parameters 30 | * 31 | * @param list $hbody Header body 32 | * @throws InvalidDuplicateHeaderException 33 | * @throws InvalidHeaderLineException 34 | * @throws InvalidHeaderParameterException 35 | * @return SingleValueWithParamsHeader 36 | */ 37 | public static function parse(array $hbody): SingleValueWithParamsHeader 38 | { 39 | if (isset($hbody[1])) { 40 | throw new InvalidDuplicateHeaderException('Cannot have multiple single value headers', Response::BAD_REQUEST); 41 | } 42 | 43 | $tok = strtok(trim($hbody[0]), ';'); 44 | 45 | if ($tok === false) { 46 | throw new InvalidHeaderLineException('Empty header value', Response::BAD_REQUEST); 47 | } 48 | 49 | $ret = new static; 50 | $ret->value = $tok; 51 | 52 | while (($tok = strtok(';')) !== false) { 53 | $p = explode('=', $tok); 54 | $p[0] = trim($p[0]); 55 | 56 | if (!isset($p[0][0])) { 57 | throw new InvalidHeaderParameterException('Empty header parameters', Response::BAD_REQUEST); 58 | } 59 | 60 | $ret->params[$p[0]] = isset($p[1]) ? trim($p[1]) : ''; 61 | } 62 | 63 | return $ret; 64 | } 65 | 66 | /** 67 | * Single value header renderer, with optional parameters 68 | * 69 | * @param string $hname Header field name 70 | * @throws InvalidHeaderValueException 71 | * @return string 72 | */ 73 | public function render(string $hname): string 74 | { 75 | if (!isset($this->value[0])) { 76 | throw new InvalidHeaderValueException('Missing header field value for header: ' . $hname); 77 | } 78 | 79 | $ret = "{$hname}: {$this->value}"; 80 | 81 | foreach ($this->params as $pk => $pv) { 82 | if (!isset($pk[0]) && !is_numeric($pk)) { 83 | throw new InvalidHeaderValueException('Malformed header, invalid parameter key for header ' . $hname); 84 | } 85 | 86 | $ret .= ';' . $pk . (!isset($pv[0]) ? '' : "={$pv}"); 87 | } 88 | 89 | $ret .= "\r\n"; 90 | 91 | return $ret; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/Header/ValueWithParams.php: -------------------------------------------------------------------------------- 1 | Parameters */ 18 | public array $params = []; 19 | } 20 | -------------------------------------------------------------------------------- /src/Header/ViaValue.php: -------------------------------------------------------------------------------- 1 | Additional parameters */ 36 | public array $params = []; 37 | } 38 | -------------------------------------------------------------------------------- /src/Request.php: -------------------------------------------------------------------------------- 1 | request URIs', Response::BAD_REQUEST); 47 | } 48 | 49 | if ($rqstLine[2] !== Message::SIP_VERSION) { 50 | throw new InvalidProtocolVersionException('Unsupported SIP version: ' . $rqstLine[2], Response::VERSION_NOT_SUPPORTED); 51 | } 52 | 53 | $this->version = $rqstLine[2]; 54 | $this->method = $rqstLine[0]; 55 | $this->uri = URI::parse($rqstLine[1]); 56 | 57 | if (count($this->uri->headers)) { 58 | /* 59 | * https://datatracker.ietf.org/doc/html/rfc3261#page-152 60 | * 61 | * We interpret this that, as a UAS, we should ignore any headers in Request-URIs. 62 | * 63 | * Also, relevant to RFC 4475 3.1.2.11: 64 | * https://datatracker.ietf.org/doc/html/rfc4475#section-3.1.2.11 65 | */ 66 | $this->uri->headers = []; 67 | } 68 | } 69 | 70 | /** 71 | * SIP Response Renderer 72 | * 73 | * @param bool $compact Whether to output compact headers or not 74 | * @throws InvalidRequestMethodException 75 | * @throws InvalidRequestURIException 76 | * @return string SIP response as text 77 | */ 78 | public function render(bool $compact = false): string 79 | { 80 | if (!isset($this->method[0])) { 81 | throw new InvalidRequestMethodException('Missing request method'); 82 | } 83 | 84 | if (!isset($this->uri, $this->uri->scheme, $this->uri->host)) { 85 | throw new InvalidRequestURIException('Missing/invalid request URI'); 86 | } 87 | 88 | if (count($this->uri->headers)) { 89 | /* 90 | * https://datatracker.ietf.org/doc/html/rfc3261#page-152 91 | * 92 | * We interpret this that, as a UAC, we should never issue headers in Request-URIs. 93 | */ 94 | throw new InvalidRequestURIException('Headers present in request URI'); 95 | } 96 | 97 | $uriStr = $this->uri->render(); 98 | $this->version ??= Message::SIP_VERSION; 99 | $this->body ??= ''; 100 | $headers = $this->renderHeaders($compact); 101 | 102 | return "{$this->method} {$uriStr} {$this->version}\r\n{$headers}\r\n{$this->body}"; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/StreamParser.php: -------------------------------------------------------------------------------- 1 | $messages Resulting messages, if any 31 | * @psalm-suppress ReferenceConstraintViolation Doesn't make a lot of sense here 32 | * @return int Execution status 33 | */ 34 | public function process(string $chunk, ?array &$messages): int 35 | { 36 | if (!isset($this->buffer[0])) { 37 | $this->buffer = ltrim($chunk); 38 | 39 | if (!isset($this->buffer[0])) { 40 | /* Nothing to process! */ 41 | return self::READY; 42 | } 43 | } else { 44 | $this->buffer .= $chunk; 45 | } 46 | 47 | $status = self::READY; 48 | $messages = []; 49 | 50 | do { 51 | if (!isset($this->message)) { 52 | /* We're waiting for new messages */ 53 | $blocks = explode("\r\n\r\n", $this->buffer, 2); 54 | 55 | if (count($blocks) === 1) { 56 | /* We don't have a whole message just yet */ 57 | $status = self::WAIT_MESSAGE; 58 | 59 | break; 60 | } 61 | 62 | assert(count($blocks) === 2); 63 | 64 | $this->message = Message::parse($this->buffer, true); 65 | $this->buffer = $blocks[1]; 66 | } else { 67 | /* We are waiting for the remainder of the body of the current message */ 68 | } 69 | 70 | $bodyLength = strlen($this->buffer); 71 | 72 | if (isset($this->message->contentLength)) { 73 | if ($bodyLength < $this->message->contentLength->value) { 74 | /* We need to wait for more body bytes */ 75 | $status = self::WAIT_BODY; 76 | 77 | break; 78 | } else if ($bodyLength > $this->message->contentLength->value) { 79 | /* Move the remainder of bytes into the buffer and save the body */ 80 | $this->message->body = substr($this->buffer, 0, $this->message->contentLength->value); 81 | $this->buffer = ltrim(substr($this->buffer, $this->message->contentLength->value)); 82 | } else { 83 | /* We're all set! */ 84 | $this->message->body = $this->buffer; 85 | $this->buffer = ''; 86 | } 87 | } else { 88 | $this->message->body = ''; 89 | } 90 | 91 | $messages[] = $this->message; 92 | 93 | unset($this->message); 94 | 95 | $status = self::SUCCESS; 96 | } while (true); 97 | 98 | return (isset($messages[0])) 99 | ? self::SUCCESS 100 | : $status; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /tests/Header/AuthorizationHeaderTest.php: -------------------------------------------------------------------------------- 1 | assertNotNull($auth); 26 | $this->assertInstanceOf(AuthorizationHeader::class, $auth); 27 | $this->assertCount(2, $auth->values); 28 | $this->assertEquals('digest', $auth->values[0]->scheme); 29 | $this->assertEquals('sip.domain.net', $auth->values[0]->params->realm); 30 | $this->assertEquals('xPgHm7ito95w8je2FGvPS-', $auth->values[0]->params->nonce); 31 | $this->assertEquals('jdudlKi/EjqLMlSgUFIFyQ', $auth->values[0]->params->cnonce); 32 | $this->assertEquals('MD5', $auth->values[0]->params->algorithm); 33 | $this->assertEquals('sip:sip.domain.net:5566;transport=udp', $auth->values[0]->params->uri); 34 | $this->assertEquals('d1ffd656b679aa3a0ace1c648b36ab7d', $auth->values[0]->params->response); 35 | $this->assertEquals('auth', $auth->values[0]->params->qop); 36 | $this->assertEquals('00000001', $auth->values[0]->params->nc); 37 | 38 | /* Basic authentication scheme has been obsoleted by RFC 3261, now it's handled as an opaque scheme */ 39 | $this->assertEquals('basic', $auth->values[1]->scheme); 40 | $this->assertEquals('d1ffd656b679aa3a0ace1c648b36ab7d', $auth->values[1]->params->verbatim); 41 | } 42 | 43 | public function testShouldParseEnclosedCharacters() 44 | { 45 | $auth = AuthorizationHeader::parse([ 46 | 'Digest username="QWxhZGRpbjpvcGVuIHNlc2FtZQ=="', 47 | 'Digest username="enclosed\"quotes\"test"', 48 | ]); 49 | 50 | $this->assertEquals('QWxhZGRpbjpvcGVuIHNlc2FtZQ==', $auth->values[0]->params->username); 51 | $this->assertEquals('enclosed"quotes"test', $auth->values[1]->params->username); 52 | } 53 | 54 | public function testShouldNotParseAlphaNcValues() 55 | { 56 | $this->expectException(InvalidHeaderParameterException::class); 57 | AuthorizationHeader::parse(['Digest nc=fortytwo']); 58 | } 59 | 60 | public function testShouldNotParseMixedNcValues() 61 | { 62 | $this->expectException(InvalidHeaderParameterException::class); 63 | AuthorizationHeader::parse(['Digest nc=O042']); 64 | } 65 | 66 | public function testShouldNotParseNonHexResponseValues() 67 | { 68 | $this->expectException(InvalidHeaderParameterException::class); 69 | AuthorizationHeader::parse(['Digest response="deadbeef_-~"']); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /tests/Header/CSeqHeaderTest.php: -------------------------------------------------------------------------------- 1 | assertNotNull($cseq); 22 | $this->assertInstanceOf(CSeqHeader::class, $cseq); 23 | $this->assertEquals(7, $cseq->sequence); 24 | $this->assertEquals('METHOD', $cseq->method); 25 | } 26 | 27 | public function testShouldNotParseMultiValue() 28 | { 29 | $this->expectException(InvalidDuplicateHeaderException::class); 30 | CSeqHeader::parse([ 31 | '7 METHOD', 32 | '9 INVITE', 33 | ]); 34 | } 35 | 36 | public function testShouldNotParseNondelimitedComponents() 37 | { 38 | $this->expectException(InvalidHeaderLineException::class); 39 | CSeqHeader::parse(['7METHOD']); 40 | } 41 | 42 | public function testShouldNotParseNegativeSequence() 43 | { 44 | $this->expectException(InvalidScalarValueException::class); 45 | CSeqHeader::parse(['-7 METHOD']); 46 | } 47 | 48 | public function testShouldNotParseOutOfBoundsSequence() 49 | { 50 | $this->expectException(InvalidScalarValueException::class); 51 | CSeqHeader::parse(['42949672950 METHOD']); 52 | } 53 | 54 | public function testShouldNotParseMissingMethod() 55 | { 56 | $this->expectException(InvalidHeaderLineException::class); 57 | CSeqHeader::parse(['7 ']); 58 | } 59 | 60 | public function testShouldRenderWellFormedValue() 61 | { 62 | $cseq = new CSeqHeader; 63 | $cseq->sequence = 7; 64 | $cseq->method = 'METHOD'; 65 | 66 | $rendered = $cseq->render('CSeq'); 67 | 68 | $this->assertNotNull($rendered); 69 | $this->assertIsString($rendered); 70 | $this->assertEquals("CSeq: 7 METHOD\r\n", $rendered); 71 | } 72 | 73 | public function testShouldNotRenderMissingSequence() 74 | { 75 | $cseq = new CSeqHeader; 76 | $cseq->method = 'METHOD'; 77 | 78 | $this->expectException(InvalidHeaderValueException::class); 79 | $cseq->render('CSeq'); 80 | } 81 | 82 | public function testShouldNotRenderMissingMethod() 83 | { 84 | $cseq = new CSeqHeader; 85 | $cseq->sequence = 7; 86 | 87 | $this->expectException(InvalidHeaderValueException::class); 88 | $cseq->render('CSeq'); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /tests/Header/CallIdHeaderTest.php: -------------------------------------------------------------------------------- 1 | assertNotNull($callId); 20 | $this->assertInstanceOf(CallIdHeader::class, $callId); 21 | $this->assertEquals('65465496', $callId->value); 22 | } 23 | 24 | public function testShouldNotParseMultiValue() 25 | { 26 | $this->expectException(InvalidDuplicateHeaderException::class); 27 | CallIdHeader::parse([ 28 | '78', 29 | '99', 30 | ]); 31 | } 32 | 33 | public function testShouldRenderWellFormedValue() 34 | { 35 | $callId = new CallIdHeader; 36 | $callId->value = '42'; 37 | 38 | $rendered = $callId->render('Call-ID'); 39 | 40 | $this->assertNotNull($rendered); 41 | $this->assertIsString($rendered); 42 | $this->assertEquals("Call-ID: 42\r\n", $rendered); 43 | } 44 | 45 | public function testShouldNotRenderMissingValue() 46 | { 47 | $callId = new CallIdHeader; 48 | 49 | $this->expectException(InvalidHeaderValueException::class); 50 | $callId->render('Call-ID'); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /tests/Header/FromHeaderTest.php: -------------------------------------------------------------------------------- 1 | ;tag=4294967295;custom=parameter', 19 | ]); 20 | 21 | $this->assertNotNull($from); 22 | $this->assertInstanceOf(NameAddrHeader::class, $from); 23 | $this->assertEquals('Bob', $from->name); 24 | $this->assertEquals('sips:bob@biloxi.example.com', $from->uri->render()); 25 | $this->assertEquals('4294967295', $from->tag); 26 | $this->assertEquals('parameter', $from->params['custom']); 27 | } 28 | 29 | public function testShouldNotParseMissingTagParameter() 30 | { 31 | $this->expectException(InvalidHeaderParameterException::class); 32 | FromHeader::parse(['Bob ']); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tests/Header/HeaderTest.php: -------------------------------------------------------------------------------- 1 | assertNotNull($header); 18 | $this->assertInstanceOf(Header::class, $header); 19 | $this->assertCount(1, $header->values); 20 | $this->assertEquals('Mysterious value', $header->values[0]); 21 | } 22 | 23 | public function testShouldRenderWellFormedValue() 24 | { 25 | $header = new Header; 26 | $header->values = [ 27 | 'Something useful', 28 | 'Something else', 29 | ]; 30 | 31 | $rendered = $header->render('X-Extra'); 32 | 33 | $this->assertNotNull($rendered); 34 | $this->assertIsString($rendered); 35 | $this->assertEquals( 36 | 'X-Extra: Something useful' . "\r\n" . 37 | 'X-Extra: Something else' . "\r\n", 38 | $rendered 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/Header/MultiValueHeaderTest.php: -------------------------------------------------------------------------------- 1 | assertNotNull($header); 18 | $this->assertInstanceOf(MultiValueHeader::class, $header); 19 | $this->assertCount(2, $header->values); 20 | $this->assertEquals('gzip', $header->values[0]); 21 | $this->assertEquals('compressed', $header->values[1]); 22 | } 23 | 24 | public function testShouldRenderWellFormedValue() 25 | { 26 | $header = new MultiValueHeader; 27 | $header->values = [ 28 | 'compressed', 29 | 'gzip', 30 | ]; 31 | 32 | $rendered = $header->render('Accept-Encoding'); 33 | 34 | $this->assertNotNull($rendered); 35 | $this->assertIsString($rendered); 36 | $this->assertEquals("Accept-Encoding: compressed, gzip\r\n", $rendered); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /tests/Header/MultiValueWithParamsHeaderTest.php: -------------------------------------------------------------------------------- 1 | assertNotNull($header); 22 | $this->assertInstanceOf(MultiValueWithParamsHeader::class, $header); 23 | $this->assertCount(2, $header->values); 24 | $this->assertEquals('text/plain', $header->values[0]->value); 25 | $this->assertEquals('utf-8', $header->values[0]->params['charset']); 26 | $this->assertEquals('application/sdp', $header->values[1]->value); 27 | $this->assertEquals('something', $header->values[1]->params['custom']); 28 | } 29 | 30 | public function testShouldNotParseMissingHeaderValue() 31 | { 32 | $this->expectException(InvalidHeaderLineException::class); 33 | MultiValueWithParamsHeader::parse([', application/sdp;custom=something']); 34 | } 35 | 36 | public function testShouldNotParseMissingHeaderParameterName() 37 | { 38 | $this->expectException(InvalidHeaderParameterException::class); 39 | MultiValueWithParamsHeader::parse(['text/plain;=utf-8, application/sdp;custom=something']); 40 | } 41 | 42 | public function testShouldRenderWellFormedValue() 43 | { 44 | $header = new MultiValueWithParamsHeader; 45 | $header->values[0] = new ValueWithParams; 46 | $header->values[0]->value = 'text/plain'; 47 | $header->values[0]->params['charset'] = 'utf-8'; 48 | $header->values[1] = new ValueWithParams; 49 | $header->values[1]->value = 'application/sdp'; 50 | $header->values[1]->params['custom'] = 'something'; 51 | 52 | $rendered = $header->render('Accept'); 53 | 54 | $this->assertNotNull($rendered); 55 | $this->assertIsString($rendered); 56 | $this->assertEquals("Accept: text/plain;charset=utf-8, application/sdp;custom=something\r\n", $rendered); 57 | } 58 | 59 | public function testShouldNotRenderMissingHeaderValue() 60 | { 61 | $header = new MultiValueWithParamsHeader; 62 | $header->values[0] = new ValueWithParams; 63 | 64 | $this->expectException(InvalidHeaderValueException::class); 65 | $header->render('Accept'); 66 | } 67 | 68 | public function testShouldNotRenderMissingHeaderParameterName() 69 | { 70 | $header = new MultiValueWithParamsHeader; 71 | $header->values[0] = new ValueWithParams; 72 | $header->values[0]->value = 'text/plain'; 73 | $header->values[0]->params[''] = 'utf-8'; 74 | 75 | $this->expectException(InvalidHeaderValueException::class); 76 | $header->render('Accept'); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /tests/Header/ScalarHeaderTest.php: -------------------------------------------------------------------------------- 1 | assertNotNull($scalar); 21 | $this->assertInstanceOf(ScalarHeader::class, $scalar); 22 | $this->assertEquals(65465496, $scalar->value); 23 | } 24 | 25 | public function testShouldNotParseMultiValue() 26 | { 27 | $this->expectException(InvalidDuplicateHeaderException::class); 28 | ScalarHeader::parse([ 29 | '78', 30 | '99', 31 | ]); 32 | } 33 | 34 | public function testShouldNotParseNegativeValue() 35 | { 36 | $this->expectException(InvalidScalarValueException::class); 37 | ScalarHeader::parse(['-1969']); 38 | } 39 | 40 | public function testShouldNotParseOutOfBoundsValue() 41 | { 42 | $this->expectException(InvalidScalarValueException::class); 43 | ScalarHeader::parse(['42949672950']); 44 | } 45 | 46 | public function testShouldRenderWellFormedValue() 47 | { 48 | $scalar = new ScalarHeader; 49 | $scalar->value = 42; 50 | 51 | $rendered = $scalar->render('Max-Forwards'); 52 | 53 | $this->assertNotNull($rendered); 54 | $this->assertIsString($rendered); 55 | $this->assertEquals("Max-Forwards: 42\r\n", $rendered); 56 | } 57 | 58 | public function testShouldNotRenderMissingValue() 59 | { 60 | $scalar = new ScalarHeader; 61 | 62 | $this->expectException(InvalidHeaderValueException::class); 63 | $scalar->render('Max-Forwards'); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /tests/Header/SingleValueWithParamsHeaderTest.php: -------------------------------------------------------------------------------- 1 | assertNotNull($header); 22 | $this->assertInstanceOf(SingleValueWithParamsHeader::class, $header); 23 | $this->assertEquals('text/plain', $header->value); 24 | $this->assertEquals('utf-8', $header->params['charset']); 25 | $this->assertEquals('something', $header->params['custom']); 26 | } 27 | 28 | public function testShouldNotParseMissingValue() 29 | { 30 | $this->expectException(InvalidHeaderLineException::class); 31 | SingleValueWithParamsHeader::parse(['']); 32 | } 33 | 34 | public function testShouldNotParseMultiValue() 35 | { 36 | $this->expectException(InvalidDuplicateHeaderException::class); 37 | SingleValueWithParamsHeader::parse(['text/plain;charset=utf-8;custom=something', 'application/sdp']); 38 | } 39 | 40 | public function testShouldNotParseMissingHeaderParameterName() 41 | { 42 | $this->expectException(InvalidHeaderParameterException::class); 43 | SingleValueWithParamsHeader::parse(['text/plain;charset=utf-8;=something']); 44 | } 45 | 46 | public function testShouldRenderWellFormedValue() 47 | { 48 | $header = new SingleValueWithParamsHeader; 49 | $header->value = 'text/plain'; 50 | $header->params['charset'] = 'utf-8'; 51 | $header->params['custom'] = 'something'; 52 | 53 | $rendered = $header->render('Content-Type'); 54 | 55 | $this->assertNotNull($rendered); 56 | $this->assertIsString($rendered); 57 | $this->assertEquals("Content-Type: text/plain;charset=utf-8;custom=something\r\n", $rendered); 58 | } 59 | 60 | public function testShouldNotRenderMissingHeaderValue() 61 | { 62 | $header = new SingleValueWithParamsHeader; 63 | 64 | $this->expectException(InvalidHeaderValueException::class); 65 | $header->render('Accept'); 66 | } 67 | 68 | public function testShouldNotRenderMissingHeaderParameterName() 69 | { 70 | $header = new SingleValueWithParamsHeader; 71 | $header->value = 'text/plain'; 72 | $header->params[''] = 'utf-8'; 73 | 74 | $this->expectException(InvalidHeaderValueException::class); 75 | $header->render('Accept'); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /tests/MiscTest.php: -------------------------------------------------------------------------------- 1 | flows[$file] = Yaml::parse(file_get_contents($dir . '/' . $file)); 39 | $this->flows[$file] = preg_replace('~\R~u', "\r\n", $this->flows[$file]); 40 | } catch (\Throwable $t) { 41 | echo $t->getMessage() . ' in flow ' . $file . "\n"; 42 | 43 | throw $t; 44 | } 45 | } 46 | } 47 | } 48 | 49 | public function testMisc() 50 | { 51 | foreach ($this->flows as $name => $flow) { 52 | foreach ($flow as $i => $text) { 53 | try { 54 | $message = Message::parse($text); 55 | } catch (\Throwable $t) { 56 | echo $t->getMessage() . ' in flow ' . $name . "\n"; 57 | 58 | throw $t; 59 | } 60 | 61 | /* Message could be parsed, no exceptions to be thrown */ 62 | $this->assertInstanceOf(Message::class, $message); 63 | 64 | try { 65 | $reassembled = $message->render(); 66 | } catch (\Throwable $t) { 67 | echo $t->getMessage() . ' in flow ' . $name . "\n"; 68 | 69 | throw $t; 70 | } 71 | 72 | /* Resulting message can be rendered, no exceptions to be thrown */ 73 | $this->assertIsString($reassembled); 74 | 75 | try { 76 | $reparsed = Message::parse($reassembled); 77 | } catch (\Throwable $t) { 78 | echo $t->getMessage() . ' in flow ' . $name . "\n"; 79 | 80 | throw $t; 81 | } 82 | 83 | /* Reassembled message's message to be identical to the original message */ 84 | $this->assertEquals($message, $reparsed, "In flow {$name}[{$i}]"); 85 | } 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /tests/RFC4475/RFC4475Case.php: -------------------------------------------------------------------------------- 1 | loadFixture('wsinv'); 19 | 20 | $msg = Message::parse($pdu); 21 | 22 | $this->assertInstanceOf(Request::class, $msg); 23 | 24 | /* unknown Request-URI parameter */ 25 | $this->assertNotNull($msg->uri->params['unknownparam']); 26 | 27 | /* tag From/To header value parameters */ 28 | $this->assertEquals("1918181833n", $msg->to->tag); 29 | $this->assertEquals("98asjd8", $msg->from->tag); 30 | 31 | /* escaped characters within quotes */ 32 | $this->assertEquals("J Rosenberg \\\\\"", $msg->from->name); 33 | $this->assertEquals('Quoted string \\"\\"', $msg->contact->values[0]->name); 34 | 35 | /* an empty subject */ 36 | $this->assertCount(0, $msg->subject->values); 37 | 38 | /* both comma separated and separately listed header field values */ 39 | /* a mix of short and long form for the same header field name */ 40 | $this->assertCount(3, $msg->via->values); 41 | 42 | $this->assertEquals('390skdjuw', $msg->via->values['0']->branch); 43 | $this->assertEquals('z9hG4bK9ikj8', $msg->via->values['1']->branch); 44 | $this->assertEquals('z9hG4bK30239', $msg->via->values['2']->branch); 45 | 46 | /* unknown header fields */ 47 | $this->assertNotNull($msg->extraHeaders['newfangledheader']->values[0]); 48 | $this->assertNotNull($msg->extraHeaders['unknownheaderwithunusualvalue']->values[0]); 49 | 50 | /* an unknown header field with a value that would be syntactically invalid if it were defined in terms of generic-param */ 51 | $this->assertEquals(';;,,;;,;', $msg->extraHeaders['unknownheaderwithunusualvalue']->values[0]); 52 | 53 | /* unknown parameters of a known header field */ 54 | $this->assertEquals('newvalue', $msg->contact->values[0]->params['newparam']); 55 | 56 | /* a header parameter with no value */ 57 | $this->assertEquals('', $msg->contact->values[0]->params['secondparam']); 58 | 59 | /* integer fields (Max-Forwards and CSeq) with leading zeros */ 60 | $this->assertIsNumeric($msg->maxForwards->value); 61 | $this->assertEquals(68, $msg->maxForwards->value); 62 | $this->assertIsNumeric($msg->cSeq->sequence); 63 | $this->assertEquals(9, $msg->cSeq->sequence); 64 | $this->assertIsString($msg->cSeq->method); 65 | $this->assertEquals('INVITE', $msg->cSeq->method); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /tests/RFC4475/S31102Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('intmeth'); 19 | 20 | $msg = Message::parse($pdu); 21 | 22 | $this->assertInstanceOf(Request::class, $msg); 23 | 24 | /* The Method contains non-alpha characters from token */ 25 | $this->assertEquals('!interesting-Method0123456789_*+`.%indeed\'~', $msg->method); 26 | 27 | /* The Request-URI contains unusual, but legal, characters */ 28 | $this->assertEquals('sip', $msg->uri->scheme); 29 | $this->assertEquals("1_unusual.URI~(to-be!sure)&isn't+it$/crazy?,/;;*", $msg->uri->user); 30 | $this->assertEquals("&it+has=1,weird!*pas\$wo~d_too.(doesn't-it)", $msg->uri->password); 31 | $this->assertEquals('example.com', $msg->uri->host); 32 | 33 | /* A branch parameter contains all non-alphanum characters from token */ 34 | $this->assertEquals('z9hG4bK-.!%66*_+`\'~', $msg->via->values[0]->branch); 35 | 36 | /* The To header field value's quoted string contains quoted-pair expansions, including a quoted NULL character */ 37 | $this->assertEquals('BEL:\\' . "\x07" . ' NUL:\\' . "\x00" . ' DEL:\\' . "\x7f", $msg->to->name); 38 | 39 | /* The name part of name-addr in the From header field value contains 40 | multiple tokens (instead of a quoted string) with all non-alphanum 41 | characters from the token production rule. */ 42 | $this->assertEquals('token1~` token2\'+_ token3*%!.-', $msg->from->name); 43 | 44 | /* That value also has an unknown header parameter whose name contains the non-alphanum 45 | token characters and whose value is a non-ascii range UTF-8 encoded string. */ 46 | $this->assertNotNull($msg->from->params['fromParam\'\'~+*_!.-%']); 47 | $this->assertEquals( 48 | "\"\xD1\x80\xD0\xB0\xD0\xB1\xD0\xBE\xD1\x82\xD0\xB0\xD1\x8E\xD1\x89\xD0\xB8\xD0\xB9\"", 49 | $msg->from->params['fromParam\'\'~+*_!.-%'] 50 | ); 51 | 52 | /* The tag parameter on this value contains the non-alphanum token characters. */ 53 | $this->assertEquals('_token~1\'+`*%!-.', $msg->from->tag); 54 | 55 | /* The Call-ID header field value contains the non-alphanum characters from word */ 56 | $this->assertEquals('intmeth.word%ZK-!.*_+\'@word`~)(><:\\/"][?}{', $msg->callId->value); 57 | 58 | /* There is an unknown header field (matching extension-header) with 59 | non-alphanum token characters in its name and a UTF8-NONASCII value. */ 60 | $this->assertEquals( 61 | "\xEF\xBB\xBF\xE5\xA4\xA7\xE5\x81\x9C\xE9\x9B\xBB", 62 | $msg->extraHeaders['extensionheader-!.%*+_`\'~']->values[0] 63 | ); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /tests/RFC4475/S31103Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('esc01'); 19 | 20 | $msg = Message::parse($pdu); 21 | 22 | $this->assertInstanceOf(Request::class, $msg); 23 | 24 | /* The request-URI has sips:user@example.com embedded in its 25 | userpart. What that might mean to example.net is beyond the scope 26 | of this document. */ 27 | $this->assertEquals('sip', $msg->uri->scheme); 28 | $this->assertEquals('sips:user@example.com', $msg->uri->user); 29 | $this->assertEquals('example.net', $msg->uri->host); 30 | $this->assertFalse(isset($msg->uri->password)); 31 | 32 | /* The From and To URIs have escaped characters in their userparts. */ 33 | $this->assertEquals('sip', $msg->from->uri->scheme); 34 | $this->assertEquals('I have spaces', $msg->from->uri->user); 35 | $this->assertEquals('example.net', $msg->from->uri->host); 36 | $this->assertFalse(isset($msg->from->uri->password)); 37 | 38 | $this->assertEquals('sip', $msg->to->uri->scheme); 39 | $this->assertEquals('user', $msg->to->uri->user); 40 | $this->assertEquals('example.com', $msg->to->uri->host); 41 | $this->assertFalse(isset($msg->to->uri->password)); 42 | 43 | /* The Contact URI has escaped characters in the URI parameters. 44 | Note that the "name" uri-parameter has a value of "value%41", 45 | which is NOT equivalent to "valueA". */ 46 | $this->assertEquals('sip', $msg->contact->values[0]->uri->scheme); 47 | $this->assertEquals('caller', $msg->contact->values[0]->uri->user); 48 | $this->assertEquals('host5.example.net', $msg->contact->values[0]->uri->host); 49 | $this->assertFalse(isset($msg->contact->values[0]->uri->password)); 50 | $this->assertEquals('', $msg->contact->values[0]->uri->lr); 51 | $this->assertEquals('value%41', $msg->contact->values[0]->uri->params['name']); 52 | $this->assertNotEquals('valueA', $msg->contact->values[0]->uri->params['name']); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /tests/RFC4475/S31104Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('escnull'); 20 | 21 | $msg = Message::parse($pdu); 22 | 23 | $this->assertInstanceOf(Request::class, $msg); 24 | 25 | /* This register request contains several URIs with nulls in the 26 | userpart. The message is well formed - parsers must accept this 27 | message. Implementations must take special care when unescaping the 28 | Address-of-Record (AOR) in this request so as to not prematurely 29 | shorten the username. This request registers two distinct contact 30 | URIs. */ 31 | $this->assertEquals(URI::unescape('null-%00-null'), $msg->to->uri->user); 32 | $this->assertEquals(0x00, ord($msg->to->uri->user[5])); 33 | $this->assertEquals(URI::escape(URI::unescape('null-%00-null')), 'null-%00-null'); 34 | $this->assertEquals(URI::unescape('null-%00-null'), $msg->from->uri->user); 35 | $this->assertEquals(0x00, ord($msg->from->uri->user[5])); 36 | $this->assertEquals('839923423', $msg->from->tag); 37 | $this->assertEquals(chr(0x00), $msg->contact->values[0]->uri->user); 38 | $this->assertEquals(1, strlen($msg->contact->values[0]->uri->user)); 39 | $this->assertEquals(chr(0x00) . chr(0x00), $msg->contact->values[1]->uri->user); 40 | $this->assertEquals(2, strlen($msg->contact->values[1]->uri->user)); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tests/RFC4475/S31105Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('esc02'); 19 | 20 | $msg = Message::parse($pdu); 21 | 22 | $this->assertInstanceOf(Request::class, $msg); 23 | 24 | /* The request method is unknown. It is NOT equivalent to REGISTER. */ 25 | $this->assertEquals('RE%47IST%45R', $msg->method); 26 | 27 | /* The display name portion of the To and From header fields is 28 | "%Z%45". Note that this is not the same as %ZE. */ 29 | $this->assertEquals('%Z%45', $msg->to->name); 30 | $this->assertEquals('%Z%45', $msg->from->name); 31 | 32 | /* This message has two Contact header field values, not three. 33 | is a C%6Fntact header field value. */ 34 | $this->assertCount(2, $msg->contact->values); 35 | $this->assertEquals('sip:alias1@host1.example.com', $msg->contact->values[0]->uri->render()); 36 | $this->assertEquals('sip:alias3@host3.example.com', $msg->contact->values[1]->uri->render()); 37 | $this->assertEquals('', $msg->extraHeaders['c%6fntact']->values[0]); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tests/RFC4475/S31106Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('lwsdisp'); 19 | 20 | $msg = Message::parse($pdu); 21 | 22 | $this->assertInstanceOf(Request::class, $msg); 23 | 24 | $this->assertEquals('OPTIONS', $msg->method); 25 | 26 | /* This OPTIONS request is not valid per the grammar in RFC 3261 since 27 | there is no LWS between the token in the display name and < in the 28 | From header field value. This has been identified as a specification 29 | bug that will be removed when RFC 3261 is revised. Elements should 30 | accept this request as well formed. */ 31 | $this->assertEquals('sip', $msg->from->uri->scheme); 32 | $this->assertEquals('caller', $msg->from->uri->user); 33 | $this->assertEquals('example.com', $msg->from->uri->host); 34 | $this->assertEquals('caller', $msg->from->name); 35 | $this->assertEquals('323', $msg->from->tag); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tests/RFC4475/S31107Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('longreq'); 19 | 20 | $msg = Message::parse($pdu); 21 | 22 | $this->assertInstanceOf(Request::class, $msg); 23 | 24 | /* The To header field has a long display name, and long uri parameter names and values. */ 25 | $this->assertEquals('sip', $msg->to->uri->scheme); 26 | $this->assertEquals('user', $msg->to->uri->user); 27 | $this->assertEquals('example.com', $msg->to->uri->host); 28 | $this->assertEquals(6000, $msg->to->uri->port); 29 | $this->assertEquals('very' . str_repeat('long', 20) . 'value', $msg->to->uri->params['unknownparam1']); 30 | $this->assertEquals('shortvalue', $msg->to->uri->params['longparam' . str_repeat('name', 25)]); 31 | $this->assertEquals('', $msg->to->uri->params['very' . str_repeat('long', 25) . 'parameternamewithnovalue']); 32 | $this->assertEquals('I have a user name of ' . str_repeat('extreme', 10) . ' proportion', $msg->to->name); 33 | 34 | /* The From header field has long header parameter names and values, in particular, a very long tag. */ 35 | $this->assertEquals('sip', $msg->from->uri->scheme); 36 | $this->assertEquals(str_repeat('amazinglylongcallername', 5), $msg->from->uri->user); 37 | $this->assertEquals('example.net', $msg->from->uri->host); 38 | $this->assertEquals('12' . str_repeat('982', 50) . '424', $msg->from->tag); 39 | $this->assertEquals( 40 | 'unknowheaderparam' . str_repeat('value', 15), 41 | $msg->from->params['unknownheaderparam' . str_repeat('name', 20)] 42 | ); 43 | $this->assertEquals('', $msg->from->params['unknownValueless' . str_repeat('paramname', 10)]); 44 | 45 | /* The Call-ID is one long token */ 46 | $this->assertEquals('longreq.one' . str_repeat('really', 20) . 'longcallid', $msg->callId->value); 47 | 48 | /* Other cases */ 49 | $this->assertEquals( 50 | 'unknown-' . 51 | str_repeat('long', 20) . 52 | '-value; unknown-' . 53 | str_repeat('long', 20) . 54 | '-parameter-name = unknown-' . 55 | str_repeat('long', 20) . 56 | '-parameter-value', 57 | $msg->extraHeaders['unknown-' . str_repeat('long', 20) . '-name']->values[0] 58 | ); 59 | $this->assertCount(34, $msg->via->values); 60 | $this->assertEquals( 61 | 'very' . str_repeat('long', 50) . 'branchvalue', 62 | $msg->via->values[33]->branch 63 | ); 64 | $this->assertEquals(str_repeat('amazinglylongcallername', 5), $msg->contact->values[0]->uri->user); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /tests/RFC4475/S31108Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('dblreq'); 19 | 20 | $msg = Message::parse($pdu); 21 | 22 | $this->assertInstanceOf(Request::class, $msg); 23 | 24 | /* A SIP element receiving this datagram would handle the REGISTER 25 | request normally and ignore the extra bits that look like an INVITE 26 | request. If the element is a proxy choosing to forward the REGISTER, 27 | the INVITE octets would not appear in the forwarded request. */ 28 | $this->assertEquals('REGISTER', $msg->method); 29 | $this->assertEquals(0, $msg->contentLength->value); 30 | $this->assertEquals('', $msg->body); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/RFC4475/S31109Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('semiuri'); 19 | 20 | $msg = Message::parse($pdu); 21 | 22 | $this->assertInstanceOf(Request::class, $msg); 23 | 24 | /* The Request-URI will parse so that the user part is "user;par=u@example.net" */ 25 | $this->assertEquals('user;par=u@example.net', $msg->uri->user); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/RFC4475/S31110Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('transports'); 19 | 20 | $msg = Message::parse($pdu); 21 | 22 | $this->assertInstanceOf(Request::class, $msg); 23 | 24 | /* This request contains Via header field values with all known 25 | transport types and exercises the transport extension mechanism. 26 | Parsers must accept this message as well formed. Elements receiving 27 | this message would process it exactly as if the 2nd and subsequent 28 | header field values specified UDP (or other transport). */ 29 | $this->assertEquals('UDP', $msg->via->values[0]->transport); 30 | $this->assertEquals('SCTP', $msg->via->values[1]->transport); 31 | $this->assertEquals('TLS', $msg->via->values[2]->transport); 32 | $this->assertEquals('UNKNOWN', $msg->via->values[3]->transport); 33 | $this->assertEquals('TCP', $msg->via->values[4]->transport); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/RFC4475/S31111Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('mpart01'); 19 | 20 | $msg = Message::parse($pdu); 21 | 22 | $this->assertInstanceOf(Request::class, $msg); 23 | 24 | /* This MESSAGE request contains two body parts. The second part is 25 | binary encoded and contains null (0x00) characters. Receivers must 26 | take care to frame the received message properly. */ 27 | $this->assertEquals('MESSAGE', $msg->method); 28 | $this->assertEquals(553, $msg->contentLength->value); 29 | $this->assertEquals(553, strlen($msg->body)); 30 | $this->assertEquals( 31 | "--7a9cbec02ceef655" . "\r\n" . 32 | "Content-Type: text/plain" . "\r\n" . 33 | "Content-Transfer-Encoding: binary" . "\r\n" . 34 | "\r\n" . 35 | "Hello" . "\r\n" . 36 | "--7a9cbec02ceef655" . "\r\n" . 37 | "Content-Type: application/octet-stream" . "\r\n" . 38 | "Content-Transfer-Encoding: binary" . "\r\n" . 39 | "\r\n" . 40 | "\x30\x82\x01\x52\x06\x09\x2A\x86" . 41 | "\x48\x86\xF7\x0D\x01\x07\x02\xA0\x82\x01\x43\x30\x82\x01\x3F\x02" . 42 | "\x01\x01\x31\x09\x30\x07\x06\x05\x2B\x0E\x03\x02\x1A\x30\x0B\x06" . 43 | "\x09\x2A\x86\x48\x86\xF7\x0D\x01\x07\x01\x31\x82\x01\x20\x30\x82" . 44 | "\x01\x1C\x02\x01\x01\x30\x7C\x30\x70\x31\x0B\x30\x09\x06\x03\x55" . 45 | "\x04\x06\x13\x02\x55\x53\x31\x13\x30\x11\x06\x03\x55\x04\x08\x13" . 46 | "\x0A\x43\x61\x6C\x69\x66\x6F\x72\x6E\x69\x61\x31\x11\x30\x0F\x06" . 47 | "\x03\x55\x04\x07\x13\x08\x53\x61\x6E\x20\x4A\x6F\x73\x65\x31\x0E" . 48 | "\x30\x0C\x06\x03\x55\x04\x0A\x13\x05\x73\x69\x70\x69\x74\x31\x29" . 49 | "\x30\x27\x06\x03\x55\x04\x0B\x13\x20\x53\x69\x70\x69\x74\x20\x54" . 50 | "\x65\x73\x74\x20\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x65\x20" . 51 | "\x41\x75\x74\x68\x6F\x72\x69\x74\x79\x02\x08\x01\x95\x00\x71\x02" . 52 | "\x33\x01\x13\x30\x07\x06\x05\x2B\x0E\x03\x02\x1A\x30\x0D\x06\x09" . 53 | "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01\x05\x00\x04\x81\x80\x8E\xF4" . 54 | "\x66\xF9\x48\xF0\x52\x2D\xD2\xE5\x97\x8E\x9D\x95\xAA\xE9\xF2\xFE" . 55 | "\x15\xA0\x66\x59\x71\x62\x92\xE8\xDA\x2A\xA8\xD8\x35\x0A\x68\xCE" . 56 | "\xFF\xAE\x3C\xBD\x2B\xFF\x16\x75\xDD\xD5\x64\x8E\x59\x3D\xD6\x47" . 57 | "\x28\xF2\x62\x20\xF7\xE9\x41\x74\x9E\x33\x0D\x9A\x15\xED\xAB\xDB" . 58 | "\x93\xD1\x0C\x42\x10\x2E\x7B\x72\x89\xD2\x9C\xC0\xC9\xAE\x2E\xFB" . 59 | "\xC7\xC0\xCF\xF9\x17\x2F\x3B\x02\x7E\x4F\xC0\x27\xE1\x54\x6D\xE4" . 60 | "\xB6\xAA\x3A\xBB\x3E\x66\xCC\xCB\x5D\xD6\xC6\x4B\x83\x83\x14\x9C" . 61 | "\xB8\xE6\xFF\x18\x2D\x94\x4F\xE5\x7B\x65\xBC\x99\xD0\x05" . "\r\n" . 62 | "--7a9cbec02ceef655--" . "\r\n", 63 | $msg->body 64 | ); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /tests/RFC4475/S31112Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('unreason'); 19 | 20 | $msg = Message::parse($pdu); 21 | 22 | $this->assertInstanceOf(Response::class, $msg); 23 | 24 | /* This particular response contains unreserved and non-ascii UTF-8 25 | characters. This response is well formed. A parser must accept this 26 | message */ 27 | $this->assertEquals( 28 | '= 2**3 * 5**2 ' . 29 | "\xD0\xBD\xD0\xBE\x20\xD1\x81\xD1\x82" . 30 | "\xD0\xBE\x20\xD0\xB4\xD0\xB5\xD0\xB2\xD1\x8F\xD0\xBD\xD0\xBE\xD1\x81\xD1\x82\xD0\xBE\x20\xD0\xB4" . 31 | "\xD0\xB5\xD0\xB2\xD1\x8F\xD1\x82\xD1\x8C\x20\x2D\x20\xD0\xBF\xD1\x80\xD0\xBE\xD1\x81\xD1\x82\xD0" . 32 | "\xBE\xD0\xB5", 33 | $msg->reason 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tests/RFC4475/S31113Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('noreason'); 19 | 20 | $msg = Message::parse($pdu); 21 | 22 | $this->assertInstanceOf(Response::class, $msg); 23 | 24 | /* This well-formed response contains no reason phrase. A parser must 25 | accept this message. The space character after the reason code is 26 | required. If it were not present, this message could be rejected as 27 | invalid (a liberal receiver would accept it anyway). */ 28 | $this->assertEquals('', $msg->reason); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tests/RFC4475/S31201Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('badinv01'); 19 | 20 | // Throws InvalidHeaderParameterException for blank Via and Contact parameters 21 | $this->expectException(InvalidHeaderParameterException::class); 22 | Message::parse($pdu); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/RFC4475/S31202Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('clerr'); 19 | 20 | // Throws InvalidBodyLengthException for length mismatch 21 | $this->expectException(InvalidBodyLengthException::class); 22 | Message::parse($pdu); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/RFC4475/S31203Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('ncl'); 19 | 20 | // Throws InvalidScalarValueException for length mismatch 21 | $this->expectException(InvalidScalarValueException::class); 22 | Message::parse($pdu); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/RFC4475/S31204Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('scalar02'); 19 | 20 | // Throws InvalidScalarValueException for aberrant values 21 | $this->expectException(InvalidScalarValueException::class); 22 | Message::parse($pdu); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/RFC4475/S31205Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('scalarlg'); 19 | 20 | // Throws InvalidScalarValueException for aberrant values 21 | $this->expectException(InvalidScalarValueException::class); 22 | Message::parse($pdu); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/RFC4475/S31206Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('quotbal'); 19 | 20 | // Throws InvalidHeaderLineException for unmatched quotes 21 | $this->expectException(InvalidHeaderLineException::class); 22 | Message::parse($pdu); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/RFC4475/S31207Test.php: -------------------------------------------------------------------------------- 1 | Enclosing Request-URI 13 | */ 14 | class S31207Test extends RFC4475Case 15 | { 16 | public function testShouldNotParse() 17 | { 18 | $pdu = $this->loadFixture('ltgtruri'); 19 | 20 | // Throws InvalidRequestURIException for escaped request URIs 21 | $this->expectException(InvalidRequestURIException::class); 22 | Message::parse($pdu); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/RFC4475/S31208Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('lwsruri'); 19 | 20 | // Throws InvalidMessageStartLineException for malformed request URI 21 | $this->expectException(InvalidMessageStartLineException::class); 22 | Message::parse($pdu); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/RFC4475/S31209Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('lwsstart'); 19 | 20 | // Throws InvalidMessageStartLineException for malformed request URI 21 | $this->expectException(InvalidMessageStartLineException::class); 22 | Message::parse($pdu); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/RFC4475/S31210Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('trws'); 19 | 20 | // Throws InvalidMessageStartLineException for malformed request URI 21 | $this->expectException(InvalidMessageStartLineException::class); 22 | Message::parse($pdu); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/RFC4475/S31211Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('escruri'); 22 | 23 | $msg = Message::parse($pdu); 24 | 25 | $this->assertInstanceOf(Request::class, $msg); 26 | $this->assertEquals([], $msg->uri->headers); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tests/RFC4475/S31212Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('baddate'); 19 | 20 | $msg = Message::parse($pdu); 21 | 22 | $this->assertInstanceOf(Request::class, $msg); 23 | 24 | $this->assertEquals('Fri, 01 Jan 2010 16:00:00 EST', $msg->date->values[0]); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/RFC4475/S31213Test.php: -------------------------------------------------------------------------------- 1 | 13 | * 14 | * As an UAS, this implementation will take the liberal route and accept 15 | * unenclosed SIP name-addr URIs 16 | */ 17 | class S31213Test extends RFC4475Case 18 | { 19 | public function testShouldParse() 20 | { 21 | $pdu = $this->loadFixture('regbadct'); 22 | 23 | $msg = Message::parse($pdu); 24 | 25 | $this->assertInstanceOf(Request::class, $msg); 26 | $this->assertEquals('', $msg->contact->values[0]->uri->headers['Route']); 27 | 28 | /* However, as an UAC, this implementation will always enclose SIP name-addr URIs */ 29 | $this->assertEquals( 30 | "Contact: \r\n", 31 | $msg->contact->render('Contact') 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tests/RFC4475/S31214Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('badaspec'); 22 | 23 | $msg = Message::parse($pdu); 24 | 25 | $this->assertInstanceOf(Request::class, $msg); 26 | 27 | $this->assertEquals('sip', $msg->to->uri->scheme); 28 | $this->assertEquals('t.watson', $msg->to->uri->user); 29 | $this->assertEquals('example.org', $msg->to->uri->host); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/RFC4475/S31215Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('baddn'); 22 | 23 | $msg = Message::parse($pdu); 24 | 25 | $this->assertInstanceOf(Request::class, $msg); 26 | 27 | $this->assertEquals('sip', $msg->to->uri->scheme); 28 | $this->assertEquals('t.watson', $msg->to->uri->user); 29 | $this->assertEquals('example.org', $msg->to->uri->host); 30 | $this->assertEquals('Watson, Thomas', $msg->to->name); 31 | $this->assertEquals('sip', $msg->from->uri->scheme); 32 | $this->assertEquals('a.g.bell', $msg->from->uri->user); 33 | $this->assertEquals('example.com', $msg->from->uri->host); 34 | $this->assertEquals('Bell, Alexander', $msg->from->name); 35 | $this->assertEquals('43', $msg->from->tag); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tests/RFC4475/S31216Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('badvers'); 19 | 20 | // Throws InvalidProtocolVersionException for bogus version 21 | $this->expectException(InvalidProtocolVersionException::class); 22 | Message::parse($pdu); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/RFC4475/S31217Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('mismatch01'); 19 | 20 | // Throws InvalidCSeqValueException for bogus mismatched request methods 21 | $this->expectException(InvalidCSeqValueException::class); 22 | Message::parse($pdu); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/RFC4475/S31218Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('mismatch02'); 19 | 20 | // Throws InvalidCSeqValueException for bogus mismatched request methods 21 | $this->expectException(InvalidCSeqValueException::class); 22 | Message::parse($pdu); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/RFC4475/S31219Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('bigcode'); 19 | 20 | // Throws InvalidStatusCodeException for bogus response codes 21 | $this->expectException(InvalidStatusCodeException::class); 22 | Message::parse($pdu); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/RFC4475/S32010Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('badbranch'); 20 | 21 | $msg = Message::parse($pdu); 22 | 23 | $this->assertInstanceOf(Request::class, $msg); 24 | 25 | /* Make sure via branch tag is readable; application must be able to tell 26 | only the prefix was sent over, no identifier. */ 27 | $this->assertEquals('z9hG4bK', $msg->via->values[0]->branch); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tests/RFC4475/S33010Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('insuf'); 20 | 21 | $msg = Message::parse($pdu); 22 | 23 | $this->assertInstanceOf(Request::class, $msg); 24 | 25 | /* Make sure the application has enough visibility to determine 26 | Call-ID, From, or To headers are missing */ 27 | $this->assertFalse(isset($msg->callId)); 28 | $this->assertFalse(isset($msg->from)); 29 | $this->assertFalse(isset($msg->to)); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/RFC4475/S33020Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('unkscm'); 19 | 20 | $msg = Message::parse($pdu); 21 | 22 | $this->assertInstanceOf(Request::class, $msg); 23 | 24 | /* Make sure the application has enough visibility to work 25 | with the request URI scheme as it wishes */ 26 | $this->assertEquals('nobodyknowsthisscheme', $msg->uri->scheme); 27 | $this->assertEquals('totallyopaquecontent', $msg->uri->host); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tests/RFC4475/S33030Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('novelsc'); 19 | 20 | $msg = Message::parse($pdu); 21 | 22 | $this->assertInstanceOf(Request::class, $msg); 23 | 24 | /* Make sure the application has enough visibility to work 25 | with the request URI scheme as it wishes */ 26 | $this->assertEquals('soap.beep', $msg->uri->scheme); 27 | $this->assertEquals('192.0.2.103', $msg->uri->host); 28 | $this->assertEquals(3002, $msg->uri->port); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tests/RFC4475/S33040Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('unksm2'); 19 | 20 | $msg = Message::parse($pdu); 21 | 22 | $this->assertInstanceOf(Request::class, $msg); 23 | 24 | /* Make sure the application has enough visibility to work 25 | with the To header field value scheme as it wishes */ 26 | $this->assertEquals('isbn', $msg->to->uri->scheme); 27 | $this->assertEquals('2983792873', $msg->to->uri->host); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tests/RFC4475/S33050Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('bext01'); 20 | 21 | $msg = Message::parse($pdu); 22 | 23 | $this->assertInstanceOf(Request::class, $msg); 24 | 25 | /* Make sure the application has enough visibility to read *Require header fields */ 26 | $this->assertEquals('nothingSupportsThis', $msg->require->values[0]); 27 | $this->assertEquals('nothingSupportsThisEither', $msg->require->values[1]); 28 | $this->assertEquals('noProxiesSupportThis', $msg->proxyRequire->values[0]); 29 | $this->assertEquals('norDoAnyProxiesSupportThis', $msg->proxyRequire->values[1]); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/RFC4475/S33060Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('invut'); 20 | 21 | $msg = Message::parse($pdu); 22 | 23 | $this->assertInstanceOf(Request::class, $msg); 24 | 25 | /* Make sure the application has enough visibility read the content's type */ 26 | $this->assertEquals('application/unknownformat', $msg->contentType->value); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tests/RFC4475/S33070Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('regaut01'); 20 | 21 | $msg = Message::parse($pdu); 22 | 23 | $this->assertInstanceOf(Request::class, $msg); 24 | 25 | /* Make sure the application has enough visibility read the authorization */ 26 | $this->assertEquals('nooneknowsthisscheme', $msg->authorization->values[0]->scheme); 27 | $this->assertEquals('opaque-data=here', $msg->authorization->values[0]->params->verbatim); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tests/RFC4475/S33080Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('multi01'); 19 | 20 | // Throws InvalidDuplicateHeaderException for duplicate header fields 21 | $this->expectException(InvalidDuplicateHeaderException::class); 22 | Message::parse($pdu); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/RFC4475/S33090Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('mcl01'); 19 | 20 | // Throws InvalidDuplicateHeaderException for duplicate header fields 21 | $this->expectException(InvalidDuplicateHeaderException::class); 22 | Message::parse($pdu); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/RFC4475/S33100Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('bcast'); 20 | 21 | $msg = Message::parse($pdu); 22 | 23 | $this->assertInstanceOf(Response::class, $msg); 24 | 25 | /* Make sure the application has enough visibility to read the broadcast address */ 26 | $this->assertEquals('255.255.255.255', $msg->via->values[1]->host); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tests/RFC4475/S33110Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('zeromf'); 20 | 21 | $msg = Message::parse($pdu); 22 | 23 | $this->assertInstanceOf(Request::class, $msg); 24 | 25 | /* Make sure the application has enough visibility to read the Max-Forwards header value */ 26 | $this->assertNotNull($msg->maxForwards->value); 27 | $this->assertEquals(0, $msg->maxForwards->value); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tests/RFC4475/S33120Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('cparam01'); 19 | 20 | $msg = Message::parse($pdu); 21 | 22 | $this->assertInstanceOf(Request::class, $msg); 23 | 24 | /* Make sure the application has enough visibility to 25 | determine this is a REGISTER request with a contact 26 | header parameter (not URI parameter!) */ 27 | $this->assertEquals('REGISTER', $msg->method); 28 | $this->assertEquals('sip', $msg->contact->values[0]->uri->scheme); 29 | $this->assertEquals('+19725552222', $msg->contact->values[0]->uri->user); 30 | $this->assertEquals('gw1.example.net', $msg->contact->values[0]->uri->host); 31 | $this->assertEquals('', $msg->contact->values[0]->params['unknownparam']); 32 | $this->assertTrue(!isset($msg->contact->values[0]->uri->params['unknownparam'])); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tests/RFC4475/S33130Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('cparam02'); 19 | 20 | $msg = Message::parse($pdu); 21 | 22 | $this->assertInstanceOf(Request::class, $msg); 23 | 24 | /* Make sure the application has enough visibility to 25 | determine this is a REGISTER request with a URI 26 | parameter (not a contact parameter!) */ 27 | $this->assertEquals('REGISTER', $msg->method); 28 | $this->assertEquals('sip', $msg->contact->values[0]->uri->scheme); 29 | $this->assertEquals('+19725552222', $msg->contact->values[0]->uri->user); 30 | $this->assertEquals('gw1.example.net', $msg->contact->values[0]->uri->host); 31 | $this->assertEquals('', $msg->contact->values[0]->uri->params['unknownparam']); 32 | $this->assertTrue(!isset($msg->contact->values[0]->params['unknownparam'])); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tests/RFC4475/S33140Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('regescrt'); 19 | 20 | $msg = Message::parse($pdu); 21 | 22 | $this->assertInstanceOf(Request::class, $msg); 23 | 24 | /* Make sure the application has enough visibility to 25 | determine this is a REGISTER request with a URI 26 | parameter (escaped header, not a contact parameter!) */ 27 | $this->assertEquals('REGISTER', $msg->method); 28 | $this->assertEquals('', $msg->contact->values[0]->uri->headers['Route']); 29 | $this->assertTrue(!isset($msg->contact->values[0]->params['Route'])); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/RFC4475/S33150Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('sdp01'); 20 | 21 | $msg = Message::parse($pdu); 22 | 23 | $this->assertInstanceOf(Request::class, $msg); 24 | 25 | /* Make sure the application has enough visibility to 26 | read the Accept reader */ 27 | $this->assertEquals('text/nobodyKnowsThis', $msg->accept->values[0]->value); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tests/RFC4475/S34010Test.php: -------------------------------------------------------------------------------- 1 | loadFixture('inv2543'); 19 | 20 | // Throws InvalidHeaderParameterException for missing From header value tag parameter 21 | $this->expectException(InvalidHeaderParameterException::class); 22 | Message::parse($pdu); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/RequestTest.php: -------------------------------------------------------------------------------- 1 | assertNotNull($request); 25 | $this->assertInstanceOf(Request::class, $request); 26 | } 27 | 28 | public function testShouldInstantiateWithCorrectStartLine() 29 | { 30 | $request = new Request('INVITE sip:something.com SIP/2.0'); 31 | 32 | $this->assertNotNull($request); 33 | $this->assertInstanceOf(Request::class, $request); 34 | } 35 | 36 | public function testShouldFailWithoutVersion() 37 | { 38 | // Throws InvalidMessageStartLineException 39 | $this->expectException(InvalidMessageStartLineException::class); 40 | $request = new Request('INVITE sip:something.com'); 41 | } 42 | 43 | public function testShouldFailWithBadVersion() 44 | { 45 | // Throws InvalidProtocolVersionException 46 | $this->expectException(InvalidProtocolVersionException::class); 47 | $request = new Request('INVITE sip:something.com SIP/7.0'); 48 | } 49 | 50 | public function testShouldFailWithBadURI() 51 | { 52 | // Throws InvalidRequestURIException 53 | $this->expectException(InvalidRequestURIException::class); 54 | $request = new Request('INVITE SIP/2.0'); 55 | } 56 | 57 | public function testShouldRender() 58 | { 59 | $request = new Request(); 60 | $request->method = 'REGISTER'; 61 | $request->uri = URI::parse('sip:user@domain.com'); 62 | $request->from = new NameAddrHeader; 63 | $request->from->uri = URI::parse('sip:user@domain.com'); 64 | $request->from->tag = 'rand0m'; 65 | $request->to = new NameAddrHeader; 66 | $request->to->uri = URI::parse('sip:user@domain.com'); 67 | 68 | $text = $request->render(); 69 | 70 | $this->assertNotNull($text); 71 | $this->assertIsString($text); 72 | $this->assertEquals( 73 | 'REGISTER sip:user@domain.com SIP/2.0' . "\r\n" . 74 | 'From: ;tag=rand0m' . "\r\n" . 75 | 'To: ' . "\r\n" . 76 | "\r\n", 77 | $text 78 | ); 79 | } 80 | 81 | public function testShouldNotRenderWithoutMethod() 82 | { 83 | $request = new Request(); 84 | $request->uri = URI::parse('sip:user@domain.com'); 85 | 86 | // Throws InvalidRequestMethodException 87 | $this->expectException(InvalidRequestMethodException::class); 88 | $request->render(); 89 | } 90 | 91 | public function testShouldNotRenderWithoutURI() 92 | { 93 | $request = new Request(); 94 | $request->method = 'REGISTER'; 95 | 96 | // Throws InvalidRequestURIException 97 | $this->expectException(InvalidRequestURIException::class); 98 | $request->render(); 99 | } 100 | 101 | public function testShouldNotRenderWithHeadersInURI() 102 | { 103 | $request = new Request(); 104 | $request->method = 'REGISTER'; 105 | $request->uri = new URI; 106 | $request->uri->scheme = 'sip'; 107 | $request->uri->user = 'user'; 108 | $request->uri->host = 'domain.com'; 109 | $request->uri->headers['Header'] = 'Value'; 110 | 111 | // Throws InvalidRequestURIException 112 | $this->expectException(InvalidRequestURIException::class); 113 | $request->render(); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /tests/fixtures/misc/gh-21.yaml: -------------------------------------------------------------------------------- 1 | # https://github.com/rtckit/php-sip/issues/21 2 | - |+ 3 | SIP/2.0 200 OK 4 | Via: SIP/2.0/TCP 192.0.2.15;branch=z9hG4bKnuiqisi 5 | From: Bob ;tag=7F94778B653B 6 | To: Bob ;tag=6AF99445E44A 7 | Call-ID: 16CB75F21C70 8 | CSeq: 1 REGISTER 9 | Supported: path, outbound 10 | Require: outbound 11 | Contact: ;expires=111;received="sip:e52@78.102.16.243:55497";reg-id=1;+sip.instance="",;expires=258;received="sip:e52@78.102.16.243:17127";reg-id=2;+sip.instance="<65be01c100f2ccd762df61057569f037bd46a367>" 12 | Path: 13 | Content-Length: 0 14 | -------------------------------------------------------------------------------- /tests/fixtures/misc/rfc3327/5.5.2_example-of-mechanism-in-invite-transaction.yaml: -------------------------------------------------------------------------------- 1 | # https://tools.ietf.org/html/rfc3327 2 | # 5.5.2 Example of Mechanism in INVITE Transaction 3 | # 4 | # UA1----P1---------P3-----REGISTRAR 5 | # | | 6 | # P2 | 7 | # | 8 | # UA2-------------------------- 9 | - |+ 10 | INVITE sip:UA1@EXAMPLEHOME.COM SIP/2.0 11 | Via: SIP/2.0/UDP 71.91.180.10:5060;branch=z9hG4bKe2i95c5st3R 12 | To: UA1 13 | From: UA2 ;tag=224497 14 | Call-ID: 48273181116@71.91.180.10 15 | CSeq: 29 INVITE 16 | Contact: 17 | 18 | - |+ 19 | INVITE sip:UA1@192.0.2.4 SIP/2.0 20 | Via: SIP/2.0/UDP 143.70.6.83:5060;branch=z9hG4bKlj25C107a7b176 21 | Via: SIP/2.0/UDP 71.91.180.10:5060;branch=z9hG4bKe2i95c5st3R 22 | To: UA1 23 | From: UA2 ;tag=224497 24 | Call-ID: 48273181116@71.91.180.10 25 | CSeq: 29 INVITE 26 | Contact: 27 | Route: , 28 | 29 | - |+ 30 | INVITE sip:UA1@192.0.2.4 SIP/2.0 31 | Via: SIP/2.0/UDP 19.31.97.3:5060;branch=z9hG4bKjasg7li7nc9e 32 | Via: SIP/2.0/UDP 143.70.6.83:5060;branch=z9hG4bKlj25C107a7b176 33 | Via: SIP/2.0/UDP 71.91.180.10:5060;branch=z9hG4bKe2i95c5st3R 34 | To: UA1 35 | From: UA2 ;tag=224497 36 | Call-ID: 48273181116@71.91.180.10 37 | CSeq: 29 INVITE 38 | Contact: 39 | Record-Route: 40 | Route: 41 | 42 | - |+ 43 | INVITE sip:UA1@192.0.2.4 SIP/2.0 44 | Via: SIP/2.0/UDP 112.68.155.4:5060;branch=z9hG4bKk5l1833o43p 45 | Via: SIP/2.0/UDP 19.31.97.3:5060;branch=z9hG4bKjasg7li7nc9e 46 | Via: SIP/2.0/UDP 143.70.6.83:5060;branch=z9hG4bKlj25C107a7b176 47 | Via: SIP/2.0/UDP 71.91.180.10:5060;branch=z9hG4bKe2i95c5st3R 48 | To: UA1 49 | From: UA2 ;tag=224497 50 | Call-ID: 48273181116@71.91.180.10 51 | CSeq: 29 INVITE 52 | Contact: 53 | Record-Route: 54 | Record-Route: 55 | -------------------------------------------------------------------------------- /tests/fixtures/misc/rfc3515/4.1_prototypical-refer-callflow.yaml: -------------------------------------------------------------------------------- 1 | # https://datatracker.ietf.org/doc/html/rfc3515 2 | # 4.1 Prototypical REFER callflow 3 | # 4 | # Agent A Agent B 5 | # | | 6 | # | F1 REFER | 7 | # |----------------------->| 8 | # | F2 202 Accepted | 9 | # |<-----------------------| 10 | # | F3 NOTIFY | 11 | # |<-----------------------| 12 | # | F4 200 OK | 13 | # |----------------------->| 14 | # | | 15 | # | | 16 | # | |-------> 17 | # | | (whatever) 18 | # | |<------ 19 | # | | 20 | # | F5 NOTIFY | 21 | # |<-----------------------| 22 | # | F6 200 OK | 23 | # |----------------------->| 24 | # | | 25 | # | | 26 | - |+ 27 | REFER sip:b@atlanta.example.com SIP/2.0 28 | Via: SIP/2.0/UDP agenta.atlanta.example.com;branch=z9hG4bK2293940223 29 | To: 30 | From: ;tag=193402342 31 | Call-ID: 898234234@agenta.atlanta.example.com 32 | CSeq: 93809823 REFER 33 | Max-Forwards: 70 34 | Refer-To: (whatever URI) 35 | Contact: sip:a@atlanta.example.com 36 | Content-Length: 0 37 | 38 | - |+ 39 | SIP/2.0 202 Accepted 40 | Via: SIP/2.0/UDP agenta.atlanta.example.com;branch=z9hG4bK2293940223 41 | To: ;tag=4992881234 42 | From: ;tag=193402342 43 | Call-ID: 898234234@agenta.atlanta.example.com 44 | CSeq: 93809823 REFER 45 | Contact: sip:b@atlanta.example.com 46 | Content-Length: 0 47 | 48 | - |+ 49 | NOTIFY sip:a@atlanta.example.com SIP/2.0 50 | Via: SIP/2.0/UDP agentb.atlanta.example.com;branch=z9hG4bK9922ef992-25 51 | To: ;tag=193402342 52 | From: ;tag=4992881234 53 | Call-ID: 898234234@agenta.atlanta.example.com 54 | CSeq: 1993402 NOTIFY 55 | Max-Forwards: 70 56 | Event: refer 57 | Subscription-State: active;expires=(depends on Refer-To URI) 58 | Contact: sip:b@atlanta.example.com 59 | Content-Type: message/sipfrag;version=2.0 60 | Content-Length: 20 61 | 62 | SIP/2.0 100 Trying 63 | 64 | - |+ 65 | SIP/2.0 200 OK 66 | Via: SIP/2.0/UDP agentb.atlanta.example.com;branch=z9hG4bK9922ef992-25 67 | To: ;tag=193402342 68 | From: ;tag=4992881234 69 | Call-ID: 898234234@agenta.atlanta.example.com 70 | CSeq: 1993402 NOTIFY 71 | Contact: sip:a@atlanta.example.com 72 | Content-Length: 0 73 | 74 | - |+ 75 | NOTIFY sip:a@atlanta.example.com SIP/2.0 76 | Via: SIP/2.0/UDP agentb.atlanta.example.com;branch=z9hG4bK9323394234 77 | To: ;tag=193402342 78 | From: ;tag=4992881234 79 | Call-ID: 898234234@agenta.atlanta.example.com 80 | CSeq: 1993403 NOTIFY 81 | Max-Forwards: 70 82 | Event: refer 83 | Subscription-State: terminated;reason=noresource 84 | Contact: sip:b@atlanta.example.com 85 | Content-Type: message/sipfrag;version=2.0 86 | Content-Length: 16 87 | 88 | SIP/2.0 200 OK 89 | 90 | - |+ 91 | SIP/2.0 200 OK 92 | Via: SIP/2.0/UDP agentb.atlanta.example.com;branch=z9hG4bK9323394234 93 | To: ;tag=193402342 94 | From: ;tag=4992881234 95 | Call-ID: 898234234@agenta.atlanta.example.com 96 | CSeq: 1993403 NOTIFY 97 | Contact: sip:a@atlanta.example.com 98 | Content-Length: 0 99 | -------------------------------------------------------------------------------- /tests/fixtures/misc/rfc3515/4.2_multiple-refers-in-a-dialog.yaml: -------------------------------------------------------------------------------- 1 | # https://datatracker.ietf.org/doc/html/rfc3515 2 | # 4.2 Multiple REFERs in a dialog 3 | # 4 | # Agent A Agent B 5 | # | | 6 | # | F7 REFER | 7 | # |----------------------->| 8 | # | F8 202 Accepted | 9 | # |<-----------------------| 10 | # | F9 NOTIFY | 11 | # |<-----------------------| 12 | # | F10 200 OK | 13 | # |----------------------->| 14 | # | |-------> 15 | # | | (something different) 16 | # | |<------ 17 | # | | 18 | # | F11 NOTIFY | 19 | # |<-----------------------| 20 | # | F12 200 OK | 21 | # |----------------------->| 22 | # | | 23 | # | | 24 | - |+ 25 | REFER sip:b@atlanta.example.com SIP/2.0 26 | Via: SIP/2.0/UDP agenta.atlanta.example.com;branch=z9hG4bK9390399231 27 | To: ;tag=4992881234 28 | From: ;tag=193402342 29 | Call-ID: 898234234@agenta.atlanta.example.com 30 | CSeq: 93809824 REFER 31 | Max-Forwards: 70 32 | Refer-To: (some different URI) 33 | Contact: sip:a@atlanta.example.com 34 | Content-Length: 0 35 | 36 | - |+ 37 | SIP/2.0 202 Accepted 38 | Via: SIP/2.0/UDP agenta.atlanta.example.com;branch=z9hG4bK9390399231 39 | To: ;tag=4992881234 40 | From: ;tag=193402342 41 | Call-ID: 898234234@agenta.atlanta.example.com 42 | CSeq: 93809824 REFER 43 | Contact: sip:b@atlanta.example.com 44 | Content-Length: 0 45 | 46 | - |+ 47 | NOTIFY sip:a@atlanta.example.com SIP/2.0 48 | Via: SIP/2.0/UDP agentb.atlanta.example.com;branch=z9hG4bK9320394238995 49 | To: ;tag=193402342 50 | From: ;tag=4992881234 51 | Call-ID: 898234234@agenta.atlanta.example.com 52 | CSeq: 1993404 NOTIFY 53 | Max-Forwards: 70 54 | Event: refer;id=93809824 55 | Subscription-State: active;expires=(depends on Refer-To URI) 56 | Contact: sip:b@atlanta.example.com 57 | Content-Type: message/sipfrag;version=2.0 58 | Content-Length: 20 59 | 60 | SIP/2.0 100 Trying 61 | 62 | - |+ 63 | SIP/2.0 200 OK 64 | Via: SIP/2.0/UDP agentb.atlanta.example.com;branch=z9hG4bK9320394238995 65 | To: ;tag=193402342 66 | From: ;tag=4992881234 67 | Call-ID: 898234234@agenta.atlanta.example.com 68 | CSeq: 1993404 NOTIFY 69 | Contact: sip:a@atlanta.example.com 70 | Content-Length: 0 71 | 72 | - |+ 73 | NOTIFY sip:a@atlanta.example.com SIP/2.0 74 | Via: SIP/2.0/UDP agentb.atlanta.example.com;branch=z9hG4bK2994a93eb-fe 75 | To: ;tag=193402342 76 | From: ;tag=4992881234 77 | Call-ID: 898234234@agenta.atlanta.example.com 78 | CSeq: 1993405 NOTIFY 79 | Max-Forwards: 70 80 | Event: refer;id=93809824 81 | Subscription-State: terminated;reason=noresource 82 | Contact: sip:b@atlanta.example.com 83 | Content-Type: message/sipfrag;version=2.0 84 | Content-Length: 16 85 | 86 | SIP/2.0 200 OK 87 | 88 | - |+ 89 | SIP/2.0 200 OK 90 | Via: SIP/2.0/UDP agentb.atlanta.example.com;branch=z9hG4bK2994a93eb-fe 91 | To: ;tag=193402342 92 | From: ;tag=4992881234 93 | Call-ID: 898234234@agenta.atlanta.example.com 94 | CSeq: 1993405 NOTIFY 95 | Contact: sip:a@atlanta.example.com 96 | Content-Length: 0 97 | -------------------------------------------------------------------------------- /tests/fixtures/misc/rfc3665/2.01_sip-client-new-registration.yaml: -------------------------------------------------------------------------------- 1 | # https://tools.ietf.org/html/rfc3665 2 | # 2.1. Successful New Registration 3 | # 4 | # Bob SIP Server 5 | # | | 6 | # | REGISTER F1 | 7 | # |------------------------------>| 8 | # | 401 Unauthorized F2 | 9 | # |<------------------------------| 10 | # | REGISTER F3 | 11 | # |------------------------------>| 12 | # | 200 OK F4 | 13 | # |<------------------------------| 14 | # | | 15 | - |+ 16 | REGISTER sips:ss2.biloxi.example.com SIP/2.0 17 | Via: SIP/2.0/TLS client.biloxi.example.com:5061;branch=z9hG4bKnashds7 18 | Max-Forwards: 70 19 | From: Bob ;tag=a73kszlfl 20 | To: Bob 21 | Call-ID: 1j9FpLxk3uxtm8tn@biloxi.example.com 22 | CSeq: 1 REGISTER 23 | Contact: 24 | Content-Length: 0 25 | 26 | - |+ 27 | SIP/2.0 401 Unauthorized 28 | Via: SIP/2.0/TLS client.biloxi.example.com:5061;branch=z9hG4bKnashds7 29 | ;received=192.0.2.201 30 | From: Bob ;tag=a73kszlfl 31 | To: Bob ;tag=1410948204 32 | Call-ID: 1j9FpLxk3uxtm8tn@biloxi.example.com 33 | CSeq: 1 REGISTER 34 | WWW-Authenticate: Digest realm="atlanta.example.com", qop="auth", 35 | nonce="ea9c8e88df84f1cec4341ae6cbe5a359", 36 | opaque="", stale=FALSE, algorithm=MD5 37 | Content-Length: 0 38 | 39 | - |+ 40 | REGISTER sips:ss2.biloxi.example.com SIP/2.0 41 | Via: SIP/2.0/TLS client.biloxi.example.com:5061;branch=z9hG4bKnashd92 42 | Max-Forwards: 70 43 | From: Bob ;tag=ja743ks76zlflH 44 | To: Bob 45 | Call-ID: 1j9FpLxk3uxtm8tn@biloxi.example.com 46 | CSeq: 2 REGISTER 47 | Contact: 48 | Authorization: Digest username="bob", realm="atlanta.example.com", 49 | nonce="ea9c8e88df84f1cec4341ae6cbe5a359", opaque="", 50 | uri="sips:ss2.biloxi.example.com", 51 | response="dfe56131d1958046689d83306477ecc" 52 | Content-Length: 0 53 | 54 | - |+ 55 | SIP/2.0 200 OK 56 | Via: SIP/2.0/TLS client.biloxi.example.com:5061;branch=z9hG4bKnashd92 57 | ;received=192.0.2.201 58 | From: Bob ;tag=ja743ks76zlflH 59 | To: Bob ;tag=37GkEhwl6 60 | Call-ID: 1j9FpLxk3uxtm8tn@biloxi.example.com 61 | CSeq: 2 REGISTER 62 | Contact: ;expires=3600 63 | Content-Length: 0 64 | -------------------------------------------------------------------------------- /tests/fixtures/misc/rfc3665/2.02_update-of-contact-list.yaml: -------------------------------------------------------------------------------- 1 | # https://tools.ietf.org/html/rfc3665 2 | # 2.2. Update of Contact List 3 | # 4 | # Bob SIP Server 5 | # | | 6 | # | REGISTER F1 | 7 | # |------------------------------>| 8 | # | 200 OK F2 | 9 | # |<------------------------------| 10 | # | | 11 | - |+ 12 | REGISTER sips:ss2.biloxi.example.com SIP/2.0 13 | Via: SIP/2.0/TLS client.biloxi.example.com:5061;branch=z9hG4bKnashds7 14 | Max-Forwards: 70 15 | From: Bob ;tag=a73kszlfl 16 | To: Bob 17 | Call-ID: 1j9FpLxk3uxtm8tn@biloxi.example.com 18 | CSeq: 1 REGISTER 19 | Contact: mailto:bob@biloxi.example.com 20 | Authorization: Digest username="bob", realm="atlanta.example.com", 21 | qop="auth", nonce="1cec4341ae6cbe5a359ea9c8e88df84f", opaque="", 22 | uri="sips:ss2.biloxi.example.com", 23 | response="71ba27c64bd01de719686aa4590d5824" 24 | Content-Length: 0 25 | 26 | - |+ 27 | SIP/2.0 200 OK 28 | Via: SIP/2.0/TLS client.biloxi.example.com:5061;branch=z9hG4bKnashds7 29 | ;received=192.0.2.201 30 | From: Bob ;tag=a73kszlfl 31 | To: Bob ;tag=34095828jh 32 | Call-ID: 1j9FpLxk3uxtm8tn@biloxi.example.com 33 | CSeq: 1 REGISTER 34 | Contact: ;expires=3600 35 | Contact: ;expires=4294967295 36 | Content-Length: 0 37 | 38 | -------------------------------------------------------------------------------- /tests/fixtures/misc/rfc3665/2.03_request-for-current-contact-list.yaml: -------------------------------------------------------------------------------- 1 | # https://tools.ietf.org/html/rfc3665 2 | # 2.3. Request for Current Contact List 3 | # 4 | # Bob SIP Server 5 | # | | 6 | # | REGISTER F1 | 7 | # |------------------------------>| 8 | # | 200 OK F2 | 9 | # |<------------------------------| 10 | # | | 11 | - |+ 12 | REGISTER sips:ss2.biloxi.example.com SIP/2.0 13 | Via: SIP/2.0/TLS client.biloxi.example.com:5061;branch=z9hG4bKnashds7 14 | Max-Forwards: 70 15 | From: Bob ;tag=a73kszlfl 16 | To: Bob 17 | Call-ID: 1j9FpLxk3uxtm8tn@biloxi.example.com 18 | CSeq: 1 REGISTER 19 | Authorization: Digest username="bob", realm="atlanta.example.com", 20 | nonce="df84f1cec4341ae6cbe5ap359a9c8e88", opaque="", 21 | uri="sips:ss2.biloxi.example.com", 22 | response="aa7ab4678258377c6f7d4be6087e2f60" 23 | Content-Length: 0 24 | 25 | - |+ 26 | SIP/2.0 200 OK 27 | Via: SIP/2.0/TLS client.biloxi.example.com:5061;branch=z9hG4bKnashds7 28 | ;received=192.0.2.201 29 | From: Bob ;tag=a73kszlfl 30 | To: Bob ;tag=jqoiweu75 31 | Call-ID: 1j9FpLxk3uxtm8tn@biloxi.example.com 32 | CSeq: 1 REGISTER 33 | Contact: ;expires=3600 34 | Contact: ;expires=4294967295 35 | Content-Length: 0 36 | 37 | -------------------------------------------------------------------------------- /tests/fixtures/misc/rfc3665/2.04_cancellation-of-registration.yaml: -------------------------------------------------------------------------------- 1 | # https://tools.ietf.org/html/rfc3665 2 | # 2.4. Cancellation of Registration 3 | # 4 | # Bob SIP Server 5 | # | | 6 | # | REGISTER F1 | 7 | # |------------------------------>| 8 | # | 200 OK F2 | 9 | # |<------------------------------| 10 | # | | 11 | - |+ 12 | REGISTER sips:ss2.biloxi.example.com SIP/2.0 13 | Via: SIP/2.0/TLS client.biloxi.example.com:5061;branch=z9hG4bKnashds7 14 | Max-Forwards: 70 15 | From: Bob ;tag=a73kszlfl 16 | To: Bob 17 | Call-ID: 1j9FpLxk3uxtm8tn@biloxi.example.com 18 | CSeq: 1 REGISTER 19 | Expires: 0 20 | Contact: * 21 | Authorization: Digest username="bob", realm="atlanta.example.com", 22 | nonce="88df84f1cac4341aea9c8ee6cbe5a359", opaque="", 23 | uri="sips:ss2.biloxi.example.com", 24 | response="ff0437c51696f9a76244f0cf1dbabbea" 25 | Content-Length: 0 26 | 27 | - |+ 28 | SIP/2.0 200 OK 29 | Via: SIP/2.0/TLS client.biloxi.example.com:5061;branch=z9hG4bKnashds7 30 | ;received=192.0.2.201 31 | From: Bob ;tag=a73kszlfl 32 | To: Bob ;tag=1418nmdsrf 33 | Call-ID: 1j9FpLxk3uxtm8tn@biloxi.example.com 34 | CSeq: 1 REGISTER 35 | Content-Length: 0 36 | 37 | -------------------------------------------------------------------------------- /tests/fixtures/misc/rfc3665/2.05_unsuccessful-registration.yaml: -------------------------------------------------------------------------------- 1 | # https://tools.ietf.org/html/rfc3665 2 | # 2.5. Unsuccessful Registration 3 | # 4 | # Bob SIP Server 5 | # | | 6 | # | REGISTER F1 | 7 | # |------------------------------>| 8 | # | 401 Unauthorized F2 | 9 | # |<------------------------------| 10 | # | REGISTER F3 | 11 | # |------------------------------>| 12 | # | 401 Unauthorized F4 | 13 | # |<------------------------------| 14 | # | | 15 | - |+ 16 | REGISTER sips:ss2.biloxi.example.com SIP/2.0 17 | Via: SIP/2.0/TLS client.biloxi.example.com:5061;branch=z9hG4bKnashds7 18 | ;received=192.0.2.201 19 | From: Bob ;tag=a73kszlfl 20 | To: Bob 21 | Call-ID: 1j9FpLxk3uxtm8tn@biloxi.example.com 22 | CSeq: 1 REGISTER 23 | Contact: 24 | Content-Length: 0 25 | 26 | - |+ 27 | SIP/2.0 401 Unauthorized 28 | Via: SIP/2.0/TLS client.biloxi.example.com:5061;branch=z9hG4bKnashds7 29 | ;received=192.0.2.201 30 | From: Bob ;tag=a73kszlfl 31 | To: Bob ;tag=1410948204 32 | Call-ID: 1j9FpLxk3uxtm8tn@biloxi.example.com 33 | CSeq: 1 REGISTER 34 | WWW-Authenticate: Digest realm="atlanta.example.com", qop="auth", 35 | nonce="f1cec4341ae6ca9c8e88df84be55a359", 36 | opaque="", stale=FALSE, algorithm=MD5 37 | Content-Length: 0 38 | 39 | - |+ 40 | REGISTER sips:ss2.biloxi.example.com SIP/2.0 41 | Via: SIP/2.0/TLS client.biloxi.example.com:5061;branch=z9hG4bKnashd92 42 | Max-Forwards: 70 43 | From: Bob ;tag=JueHGuidj28dfga 44 | To: Bob 45 | Call-ID: 1j9FpLxk3uxtm8tn@biloxi.example.com 46 | CSeq: 2 REGISTER 47 | Contact: 48 | Authorization: Digest username="bob", realm="atlanta.example.com", 49 | nonce="f1cec4341ae6ca9c8e88df84be55a359", opaque="", 50 | uri="sips:ss2.biloxi.example.com", 51 | response="61f8470ceb87d7ebf508220214ed438b" 52 | Content-Length: 0 53 | 54 | - |+ 55 | SIP/2.0 401 Unauthorized 56 | Via: SIP/2.0/TLS client.biloxi.example.com:5061;branch=z9hG4bKnashd92 57 | ;received=192.0.2.201 58 | From: Bob ;tag=JueHGuidj28dfga 59 | To: Bob ;tag=1410948204 60 | Call-ID: 1j9FpLxk3uxtm8tn@biloxi.example.com 61 | CSeq: 2 REGISTER 62 | WWW-Authenticate: Digest realm="atlanta.example.com", qop="auth", 63 | nonce="84f1c1ae6cbe5ua9c8e88dfa3ecm3459", 64 | opaque="", stale=FALSE, algorithm=MD5 65 | Content-Length: 0 66 | 67 | -------------------------------------------------------------------------------- /tests/fixtures/misc/rfc3665/3.01_successful-session-establishment.yaml: -------------------------------------------------------------------------------- 1 | # https://tools.ietf.org/html/rfc3665 2 | # 3.1. Successful Session Establishment 3 | # 4 | # Alice Bob 5 | # | | 6 | # | INVITE F1 | 7 | # |----------------------->| 8 | # | 180 Ringing F2 | 9 | # |<-----------------------| 10 | # | | 11 | # | 200 OK F3 | 12 | # |<-----------------------| 13 | # | ACK F4 | 14 | # |----------------------->| 15 | # | Both Way RTP Media | 16 | # |<======================>| 17 | # | | 18 | # | BYE F5 | 19 | # |<-----------------------| 20 | # | 200 OK F6 | 21 | # |----------------------->| 22 | # | | 23 | - |+ 24 | INVITE sip:bob@biloxi.example.com SIP/2.0 25 | Via: SIP/2.0/TCP client.atlanta.example.com:5060;branch=z9hG4bK74bf9 26 | Max-Forwards: 70 27 | From: Alice ;tag=9fxced76sl 28 | To: Bob 29 | Call-ID: 3848276298220188511@atlanta.example.com 30 | CSeq: 1 INVITE 31 | Contact: 32 | Content-Type: application/sdp 33 | Content-Length: 151 34 | 35 | v=0 36 | o=alice 2890844526 2890844526 IN IP4 client.atlanta.example.com 37 | s=- 38 | c=IN IP4 192.0.2.101 39 | t=0 0 40 | m=audio 49172 RTP/AVP 0 41 | a=rtpmap:0 PCMU/8000 42 | - |+ 43 | SIP/2.0 180 Ringing 44 | Via: SIP/2.0/TCP client.atlanta.example.com:5060;branch=z9hG4bK74bf9 45 | ;received=192.0.2.101 46 | From: Alice ;tag=9fxced76sl 47 | To: Bob ;tag=8321234356 48 | Call-ID: 3848276298220188511@atlanta.example.com 49 | CSeq: 1 INVITE 50 | Contact: 51 | Content-Length: 0 52 | 53 | - |+ 54 | SIP/2.0 200 OK 55 | Via: SIP/2.0/TCP client.atlanta.example.com:5060;branch=z9hG4bK74bf9 56 | ;received=192.0.2.101 57 | From: Alice ;tag=9fxced76sl 58 | To: Bob ;tag=8321234356 59 | Call-ID: 3848276298220188511@atlanta.example.com 60 | CSeq: 1 INVITE 61 | Contact: 62 | Content-Type: application/sdp 63 | Content-Length: 147 64 | 65 | v=0 66 | o=bob 2890844527 2890844527 IN IP4 client.biloxi.example.com 67 | s=- 68 | c=IN IP4 192.0.2.201 69 | t=0 0 70 | m=audio 3456 RTP/AVP 0 71 | a=rtpmap:0 PCMU/8000 72 | - |+ 73 | ACK sip:bob@client.biloxi.example.com SIP/2.0 74 | Via: SIP/2.0/TCP client.atlanta.example.com:5060;branch=z9hG4bK74bd5 75 | Max-Forwards: 70 76 | From: Alice ;tag=9fxced76sl 77 | To: Bob ;tag=8321234356 78 | Call-ID: 3848276298220188511@atlanta.example.com 79 | CSeq: 1 ACK 80 | Content-Length: 0 81 | 82 | - |+ 83 | BYE sip:alice@client.atlanta.example.com SIP/2.0 84 | Via: SIP/2.0/TCP client.biloxi.example.com:5060;branch=z9hG4bKnashds7 85 | Max-Forwards: 70 86 | From: Bob ;tag=8321234356 87 | To: Alice ;tag=9fxced76sl 88 | Call-ID: 3848276298220188511@atlanta.example.com 89 | CSeq: 1 BYE 90 | Content-Length: 0 91 | 92 | - |+ 93 | SIP/2.0 200 OK 94 | Via: SIP/2.0/TCP client.biloxi.example.com:5060;branch=z9hG4bKnashds7 95 | ;received=192.0.2.201 96 | From: Bob ;tag=8321234356 97 | To: Alice ;tag=9fxced76sl 98 | Call-ID: 3848276298220188511@atlanta.example.com 99 | CSeq: 1 BYE 100 | Content-Length: 0 101 | 102 | -------------------------------------------------------------------------------- /tests/fixtures/misc/rfc5626/3.2_single-registrar-and-ua.yaml: -------------------------------------------------------------------------------- 1 | # https://tools.ietf.org/html/rfc5626 2 | # 3.2. Single Registrar and UA 3 | # 4 | # +-----------+ 5 | # | Registrar | 6 | # | Proxy | 7 | # +-----+-----+ 8 | # | 9 | # | 10 | # +----+--+ 11 | # | User | 12 | # | Agent | 13 | # +-------+ 14 | # Note: this has been tampered with ... the semicolon after reg-id=1 was been removed 15 | # to comply with the general spec (also, demonstrated in https://tools.ietf.org/html/rfc4475#section-3.1.2.1) 16 | - |+ 17 | REGISTER sip:example.com SIP/2.0 18 | Via: SIP/2.0/TCP 192.0.2.2;branch=z9hG4bK-bad0ce-11-1036 19 | Max-Forwards: 70 20 | From: Bob ;tag=d879h76 21 | To: Bob 22 | Call-ID: 8921348ju72je840.204 23 | CSeq: 1 REGISTER 24 | Supported: path, outbound 25 | Contact: ; reg-id=1 26 | ;+sip.instance="" 27 | Content-Length: 0 28 | -------------------------------------------------------------------------------- /tests/fixtures/misc/rfc5626/9.1_subscription-to-configuration-package.yaml: -------------------------------------------------------------------------------- 1 | # https://tools.ietf.org/html/rfc5626 2 | # 9.1. Subscription to Configuration Package 3 | # 4 | # [----example.com domain-------------------------] 5 | # Bob EP1 EP2 Proxy Config 6 | # | | | | | 7 | # 1)|SUBSCRIBE->| | | | 8 | # 2)| |---SUBSCRIBE Event: ua-profile ->| 9 | # 3)| |<--200 OK -----------------------| 10 | # 4)|<--200 OK--| | | | 11 | # 5)| |<--NOTIFY------------------------| 12 | # 6)|<--NOTIFY--| | | | 13 | # 7)|---200 OK->| | | | 14 | # 8)| |---200 OK ---------------------->| 15 | # | | | | | 16 | - |+ 17 | SUBSCRIBE sip:00000000-0000-1000-8000-AABBCCDDEEFF@example.com SIP/2.0 18 | Via: SIP/2.0/TCP 192.0.2.2;branch=z9hG4bKnlsdkdj2 19 | Max-Forwards: 70 20 | From: ;tag=23324 21 | To: 22 | Call-ID: nSz1TWN54x7My0GvpEBj 23 | CSeq: 1 SUBSCRIBE 24 | Event: ua-profile ;profile-type=device 25 | ;vendor="example.com";model="uPhone";version="1.1" 26 | Expires: 0 27 | Supported: path, outbound 28 | Accept: message/external-body, application/x-uPhone-config 29 | Contact: 30 | ;+sip.instance="" 31 | Content-Length: 0 32 | 33 | - |+ 34 | NOTIFY sip:192.0.2.2;transport=tcp;ob SIP/2.0 35 | Via: SIP/2.0/TCP 192.0.2.5;branch=z9hG4bKn81dd2 36 | Max-Forwards: 70 37 | To: ;tag=23324 38 | From: ;tag=0983 39 | Call-ID: nSz1TWN54x7My0GvpEBj 40 | CSeq: 1 NOTIFY 41 | Route: 42 | Subscription-State: terminated;reason=timeout 43 | Event: ua-profile 44 | Content-Type: message/external-body; access-type="URL" 45 | ;expiration="Thu, 01 Jan 2009 09:00:00 UTC" 46 | ;URL="http://example.com/uPhone.cfg" 47 | ;size=9999;hash=10AB568E91245681AC1B 48 | Content-Length: 0 49 | -------------------------------------------------------------------------------- /tests/fixtures/misc/rfc5626/9.2_registration.yaml: -------------------------------------------------------------------------------- 1 | # https://tools.ietf.org/html/rfc5626 2 | # 9.2. Registration 3 | # 4 | # Bob EP1 EP2 Proxy Alice 5 | # | | | | | 6 | # 9)|-REGISTER->| | | | 7 | # 10)| |---REGISTER-->| | 8 | # 11)| |<----200 OK---| | 9 | # 12)|<-200 OK---| | | | 10 | # 13)|----REGISTER---->| | | 11 | # 14)| | |--REG-->| | 12 | # 15)| | |<-200---| | 13 | # 16)|<----200 OK------| | | 14 | # | | | | | 15 | # | about 120 seconds later... | 16 | # | | | | | 17 | # 17)|--2CRLF--->| | | | 18 | # 18)|<--CRLF----| | | | 19 | # 19)|------2CRLF----->| | | 20 | # 20)|<------CRLF------| | | 21 | # | | | | | 22 | - |+ 23 | REGISTER sip:example.com SIP/2.0 24 | Via: SIP/2.0/TCP 192.0.2.2;branch=z9hG4bKnashds7 25 | Max-Forwards: 70 26 | From: Bob ;tag=7F94778B653B 27 | To: Bob 28 | Call-ID: 16CB75F21C70 29 | CSeq: 1 REGISTER 30 | Supported: path, outbound 31 | Route: 32 | Contact: ;reg-id=1 33 | ;+sip.instance="" 34 | Content-Length: 0 35 | 36 | - |+ 37 | SIP/2.0 200 OK 38 | Via: SIP/2.0/TCP 192.0.2.15;branch=z9hG4bKnuiqisi 39 | Via: SIP/2.0/TCP 192.0.2.2;branch=z9hG4bKnashds7 40 | From: Bob ;tag=7F94778B653B 41 | To: Bob ;tag=6AF99445E44A 42 | Call-ID: 16CB75F21C70 43 | CSeq: 1 REGISTER 44 | Supported: path, outbound 45 | Require: outbound 46 | Contact: ;reg-id=1;expires=3600 47 | ;+sip.instance="" 48 | Path: 49 | Content-Length: 0 50 | 51 | - |+ 52 | REGISTER sip:example.com SIP/2.0 53 | Via: SIP/2.0/TCP 192.0.2.2;branch=z9hG4bKnqr9bym 54 | Max-Forwards: 70 55 | From: Bob ;tag=755285EABDE2 56 | To: Bob 57 | Call-ID: E05133BD26DD 58 | CSeq: 1 REGISTER 59 | Supported: path, outbound 60 | Route: 61 | Contact: ;reg-id=2 62 | ;+sip.instance="" 63 | Content-Length: 0 64 | 65 | - |+ 66 | SIP/2.0 200 OK 67 | Via: SIP/2.0/TCP 192.0.2.2;branch=z9hG4bKnqr9bym 68 | From: Bob ;tag=755285EABDE2 69 | To: Bob ;tag=49A9AD0B3F6A 70 | Call-ID: E05133BD26DD 71 | Supported: path, outbound 72 | Require: outbound 73 | CSeq: 1 REGISTER 74 | Contact: ;reg-id=1;expires=3600 75 | ;+sip.instance="" 76 | Contact: ;reg-id=2;expires=3600 77 | ;+sip.instance="" 78 | Path: 79 | Content-Length: 0 80 | -------------------------------------------------------------------------------- /tests/fixtures/misc/rfc5626/9.3_incoming_call_and_proxy_crash.yaml: -------------------------------------------------------------------------------- 1 | # https://tools.ietf.org/html/rfc5626 2 | # 9.3. Incoming Call and Proxy Crash 3 | # 4 | # Bob EP1 EP2 Proxy Alice 5 | # | | | | | 6 | # | CRASH X | | | 7 | # | Reboot | | | 8 | # | | | | | 9 | # 21)| | | |<-INVITE-| 10 | # 22)| |<---INVITE----| | 11 | # 23)| |----430------>| | 12 | # 24)| | |<-INVITE| | 13 | # 25)|<---INVITE-------| | | 14 | # 26)|----200 OK------>| | | 15 | # 27)| | |200 OK->| | 16 | # 28)| | | |-200 OK->| 17 | # 29)| | |<----------ACK----| 18 | # 30)|<---ACK----------| | | 19 | # | | | | | 20 | # 31)| | |<----------BYE----| 21 | # 32)|<---BYE----------| | | 22 | # 33)|----200 OK------>| | | 23 | # 34)| | |--------200 OK--->| 24 | # | | | | | 25 | - |+ 26 | INVITE sip:bob@example.com SIP/2.0 27 | To: Bob 28 | From: Alice ;tag=02935 29 | Call-ID: klmvCxVWGp6MxJp2T2mb 30 | CSeq: 1 INVITE 31 | 32 | - |+ 33 | INVITE sip:bob@192.0.2.2;transport=tcp SIP/2.0 34 | To: Bob 35 | From: Alice ;tag=02935 36 | Call-ID: klmvCxVWGp6MxJp2T2mb 37 | CSeq: 1 INVITE 38 | Route: 39 | 40 | - |+ 41 | SIP/2.0 430 Flow Failed 42 | To: Bob 43 | From: Alice ;tag=02935 44 | Call-ID: klmvCxVWGp6MxJp2T2mb 45 | CSeq: 1 INVITE 46 | 47 | - |+ 48 | INVITE sip:bob@192.0.2.2;transport=tcp SIP/2.0 49 | To: Bob 50 | From: Alice ;tag=02935 51 | Call-ID: klmvCxVWGp6MxJp2T2mb 52 | CSeq: 1 INVITE 53 | Route: 54 | 55 | - |+ 56 | INVITE sip:bob@192.0.2.2;transport=tcp SIP/2.0 57 | To: Bob 58 | From: Alice ;tag=02935 59 | Call-ID: klmvCxVWGp6MxJp2T2mb 60 | CSeq: 1 INVITE 61 | Record-Route: 62 | 63 | - |+ 64 | SIP/2.0 200 OK 65 | To: Bob ;tag=skduk2 66 | From: Alice ;tag=02935 67 | Call-ID: klmvCxVWGp6MxJp2T2mb 68 | CSeq: 1 INVITE 69 | Record-Route: 70 | 71 | - |+ 72 | ACK sip:bob@192.0.2.2;transport=tcp SIP/2.0 73 | To: Bob ;tag=skduk2 74 | From: Alice ;tag=02935 75 | Call-ID: klmvCxVWGp6MxJp2T2mb 76 | CSeq: 1 ACK 77 | Route: 78 | 79 | - |+ 80 | BYE sip:bob@192.0.2.2;transport=tcp SIP/2.0 81 | To: Bob ;tag=skduk2 82 | From: Alice ;tag=02935 83 | Call-ID: klmvCxVWGp6MxJp2T2mb 84 | CSeq: 2 BYE 85 | Route: 86 | -------------------------------------------------------------------------------- /tests/fixtures/misc/rfc5626/9.4_re-registration.yaml: -------------------------------------------------------------------------------- 1 | # https://tools.ietf.org/html/rfc5626 2 | # 9.4. Re-Registration 3 | # 4 | # Bob EP1 EP2 Proxy Alice 5 | # | | | | | 6 | # 35)|------2CRLF----->| | | 7 | # 36)|<------CRLF------| | | 8 | # 37)|--2CRLF->X | | | | 9 | # | | | | | 10 | # 38)|-REGISTER->| | | | 11 | # 39)| |---REGISTER-->| | 12 | # 40)| |<----200 OK---| | 13 | # 41)|<-200 OK---| | | | 14 | # | | | | | 15 | - |+ 16 | REGISTER sip:example.com SIP/2.0 17 | From: Bob ;tag=7F94778B653B 18 | To: Bob 19 | Call-ID: 16CB75F21C70 20 | CSeq: 2 REGISTER 21 | Supported: path, outbound 22 | Route: 23 | Contact: ;reg-id=1 24 | ;+sip.instance="" 25 | -------------------------------------------------------------------------------- /tests/fixtures/misc/rfc5626/9.5_outgoing_call.yaml: -------------------------------------------------------------------------------- 1 | # https://tools.ietf.org/html/rfc5626 2 | # 9.5. Outgoing Call 3 | # 4 | # Bob EP1 EP2 Proxy Alice 5 | # | | | | | 6 | # 42)|--INVITE-->| | | | 7 | # 43)| |---INVITE---->| | 8 | # 44)| | | |-INVITE->| 9 | # 45)| | | |<--200---| 10 | # 46)| |<----200 OK---| | 11 | # 47)|<-200 OK---| | | | 12 | # 48)|--ACK----->| | | | 13 | # 49)| |-----ACK--------------->| 14 | # | | | | | 15 | # 50)|-- BYE---->| | | | 16 | # 51)| |-----------BYE--------->| 17 | # 52)| |<----------200 OK-------| 18 | # 53)|<--200 OK--| | | | 19 | # | | | | | 20 | - |+ 21 | INVITE sip:alice@a.example SIP/2.0 22 | From: Bob ;tag=ldw22z 23 | To: Alice 24 | Call-ID: 95KGsk2V/Eis9LcpBYy3 25 | CSeq: 1 INVITE 26 | Route: 27 | Contact: 28 | 29 | - |+ 30 | BYE sip:alice@a.example SIP/2.0 31 | From: Bob ;tag=ldw22z 32 | To: Alice ;tag=plqus8 33 | Call-ID: 95KGsk2V/Eis9LcpBYy3 34 | CSeq: 2 BYE 35 | Route: 36 | Contact: 37 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/badaspec.dat: -------------------------------------------------------------------------------- 1 | OPTIONS sip:user@example.org SIP/2.0 2 | Via: SIP/2.0/UDP host4.example.com:5060;branch=z9hG4bKkdju43234 3 | Max-Forwards: 70 4 | From: "Bell, Alexander" ;tag=433423 5 | To: "Watson, Thomas" < sip:t.watson@example.org > 6 | Call-ID: badaspec.sdf0234n2nds0a099u23h3hnnw009cdkne3 7 | Accept: application/sdp 8 | CSeq: 3923239 OPTIONS 9 | l: 0 10 | 11 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/badbranch.dat: -------------------------------------------------------------------------------- 1 | OPTIONS sip:user@example.com SIP/2.0 2 | To: sip:user@example.com 3 | From: sip:caller@example.org;tag=33242 4 | Max-Forwards: 3 5 | Via: SIP/2.0/UDP 192.0.2.1;branch=z9hG4bK 6 | Accept: application/sdp 7 | Call-ID: badbranch.sadonfo23i420jv0as0derf3j3n 8 | CSeq: 8 OPTIONS 9 | l: 0 10 | 11 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/baddate.dat: -------------------------------------------------------------------------------- 1 | INVITE sip:user@example.com SIP/2.0 2 | To: sip:user@example.com 3 | From: sip:caller@example.net;tag=2234923 4 | Max-Forwards: 70 5 | Call-ID: baddate.239423mnsadf3j23lj42--sedfnm234 6 | CSeq: 1392934 INVITE 7 | Via: SIP/2.0/UDP host.example.com;branch=z9hG4bKkdjuw 8 | Date: Fri, 01 Jan 2010 16:00:00 EST 9 | Contact: 10 | Content-Type: application/sdp 11 | Content-Length: 150 12 | 13 | v=0 14 | o=mhandley 29739 7272939 IN IP4 192.0.2.5 15 | s=- 16 | c=IN IP4 192.0.2.5 17 | t=0 0 18 | m=audio 49217 RTP/AVP 0 12 19 | m=video 3227 RTP/AVP 31 20 | a=rtpmap:31 LPC 21 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/baddn.dat: -------------------------------------------------------------------------------- 1 | OPTIONS sip:t.watson@example.org SIP/2.0 2 | Via: SIP/2.0/UDP c.example.com:5060;branch=z9hG4bKkdjuw 3 | Max-Forwards: 70 4 | From: Bell, Alexander ;tag=43 5 | To: Watson, Thomas 6 | Call-ID: baddn.31415@c.example.com 7 | Accept: application/sdp 8 | CSeq: 3923239 OPTIONS 9 | l: 0 10 | 11 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/badinv01.dat: -------------------------------------------------------------------------------- 1 | INVITE sip:user@example.com SIP/2.0 2 | To: sip:j.user@example.com 3 | From: sip:caller@example.net;tag=134161461246 4 | Max-Forwards: 7 5 | Call-ID: badinv01.0ha0isndaksdjasdf3234nas 6 | CSeq: 8 INVITE 7 | Via: SIP/2.0/UDP 192.0.2.15;;,;,, 8 | Contact: "Joe" ;;;; 9 | Content-Length: 152 10 | Content-Type: application/sdp 11 | 12 | v=0 13 | o=mhandley 29739 7272939 IN IP4 192.0.2.15 14 | s=- 15 | c=IN IP4 192.0.2.15 16 | t=0 0 17 | m=audio 49217 RTP/AVP 0 12 18 | m=video 3227 RTP/AVP 31 19 | a=rtpmap:31 LPC 20 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/badvers.dat: -------------------------------------------------------------------------------- 1 | OPTIONS sip:t.watson@example.org SIP/7.0 2 | Via: SIP/7.0/UDP c.example.com;branch=z9hG4bKkdjuw 3 | Max-Forwards: 70 4 | From: A. Bell ;tag=qweoiqpe 5 | To: T. Watson 6 | Call-ID: badvers.31417@c.example.com 7 | CSeq: 1 OPTIONS 8 | l: 0 9 | 10 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/bcast.dat: -------------------------------------------------------------------------------- 1 | SIP/2.0 200 OK 2 | Via: SIP/2.0/UDP 192.0.2.198;branch=z9hG4bK1324923 3 | Via: SIP/2.0/UDP 255.255.255.255;branch=z9hG4bK1saber23 4 | Call-ID: bcast.0384840201234ksdfak3j2erwedfsASdf 5 | CSeq: 35 INVITE 6 | From: sip:user@example.com;tag=11141343 7 | To: sip:user@example.edu;tag=2229 8 | Content-Length: 154 9 | Content-Type: application/sdp 10 | Contact: 11 | 12 | v=0 13 | o=mhandley 29739 7272939 IN IP4 192.0.2.198 14 | s=- 15 | c=IN IP4 192.0.2.198 16 | t=0 0 17 | m=audio 49217 RTP/AVP 0 12 18 | m=video 3227 RTP/AVP 31 19 | a=rtpmap:31 LPC 20 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/bext01.dat: -------------------------------------------------------------------------------- 1 | OPTIONS sip:user@example.com SIP/2.0 2 | To: sip:j_user@example.com 3 | From: sip:caller@example.net;tag=242etr 4 | Max-Forwards: 6 5 | Call-ID: bext01.0ha0isndaksdj 6 | Require: nothingSupportsThis, nothingSupportsThisEither 7 | Proxy-Require: noProxiesSupportThis, norDoAnyProxiesSupportThis 8 | CSeq: 8 OPTIONS 9 | Via: SIP/2.0/TLS fold-and-staple.example.com;branch=z9hG4bKkdjuw 10 | Content-Length: 0 11 | 12 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/bigcode.dat: -------------------------------------------------------------------------------- 1 | SIP/2.0 4294967301 better not break the receiver 2 | Via: SIP/2.0/UDP 192.0.2.105;branch=z9hG4bK2398ndaoe 3 | Call-ID: bigcode.asdof3uj203asdnf3429uasdhfas3ehjasdfas9i 4 | CSeq: 353494 INVITE 5 | From: ;tag=39ansfi3 6 | To: ;tag=902jndnke3 7 | Content-Length: 0 8 | Contact: 9 | 10 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/clerr.dat: -------------------------------------------------------------------------------- 1 | INVITE sip:user@example.com SIP/2.0 2 | Max-Forwards: 80 3 | To: sip:j.user@example.com 4 | From: sip:caller@example.net;tag=93942939o2 5 | Contact: 6 | Call-ID: clerr.0ha0isndaksdjweiafasdk3 7 | CSeq: 8 INVITE 8 | Via: SIP/2.0/UDP host5.example.com;branch=z9hG4bK-39234-23523 9 | Content-Type: application/sdp 10 | Content-Length: 9999 11 | 12 | v=0 13 | o=mhandley 29739 7272939 IN IP4 192.0.2.155 14 | s=- 15 | c=IN IP4 192.0.2.155 16 | t=0 0 17 | m=audio 49217 RTP/AVP 0 12 18 | m=video 3227 RTP/AVP 31 19 | a=rtpmap:31 LPC 20 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/cparam01.dat: -------------------------------------------------------------------------------- 1 | REGISTER sip:example.com SIP/2.0 2 | Via: SIP/2.0/UDP saturn.example.com:5060;branch=z9hG4bKkdjuw 3 | Max-Forwards: 70 4 | From: sip:watson@example.com;tag=DkfVgjkrtMwaerKKpe 5 | To: sip:watson@example.com 6 | Call-ID: cparam01.70710@saturn.example.com 7 | CSeq: 2 REGISTER 8 | Contact: sip:+19725552222@gw1.example.net;unknownparam 9 | l: 0 10 | 11 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/cparam02.dat: -------------------------------------------------------------------------------- 1 | REGISTER sip:example.com SIP/2.0 2 | Via: SIP/2.0/UDP saturn.example.com:5060;branch=z9hG4bKkdjuw 3 | Max-Forwards: 70 4 | From: sip:watson@example.com;tag=838293 5 | To: sip:watson@example.com 6 | Call-ID: cparam02.70710@saturn.example.com 7 | CSeq: 3 REGISTER 8 | Contact: 9 | l: 0 10 | 11 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/dblreq.dat: -------------------------------------------------------------------------------- 1 | REGISTER sip:example.com SIP/2.0 2 | To: sip:j.user@example.com 3 | From: sip:j.user@example.com;tag=43251j3j324 4 | Max-Forwards: 8 5 | I: dblreq.0ha0isndaksdj99sdfafnl3lk233412 6 | Contact: sip:j.user@host.example.com 7 | CSeq: 8 REGISTER 8 | Via: SIP/2.0/UDP 192.0.2.125;branch=z9hG4bKkdjuw23492 9 | Content-Length: 0 10 | 11 | 12 | INVITE sip:joe@example.com SIP/2.0 13 | t: sip:joe@example.com 14 | From: sip:caller@example.net;tag=141334 15 | Max-Forwards: 8 16 | Call-ID: dblreq.0ha0isnda977644900765@192.0.2.15 17 | CSeq: 8 INVITE 18 | Via: SIP/2.0/UDP 192.0.2.15;branch=z9hG4bKkdjuw380234 19 | Content-Type: application/sdp 20 | Content-Length: 150 21 | 22 | v=0 23 | o=mhandley 29739 7272939 IN IP4 192.0.2.15 24 | s=- 25 | c=IN IP4 192.0.2.15 26 | t=0 0 27 | m=audio 49217 RTP/AVP 0 12 28 | m =video 3227 RTP/AVP 31 29 | a=rtpmap:31 LPC 30 | 31 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/esc01.dat: -------------------------------------------------------------------------------- 1 | INVITE sip:sips%3Auser%40example.com@example.net SIP/2.0 2 | To: sip:%75se%72@example.com 3 | From: ;tag=938 4 | Max-Forwards: 87 5 | i: esc01.239409asdfakjkn23onasd0-3234 6 | CSeq: 234234 INVITE 7 | Via: SIP/2.0/UDP host5.example.net;branch=z9hG4bKkdjuw 8 | C: application/sdp 9 | Contact: 10 | 11 | Content-Length: 150 12 | 13 | v=0 14 | o=mhandley 29739 7272939 IN IP4 192.0.2.1 15 | s=- 16 | c=IN IP4 192.0.2.1 17 | t=0 0 18 | m=audio 49217 RTP/AVP 0 12 19 | m=video 3227 RTP/AVP 31 20 | a=rtpmap:31 LPC 21 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/esc02.dat: -------------------------------------------------------------------------------- 1 | RE%47IST%45R sip:registrar.example.com SIP/2.0 2 | To: "%Z%45" 3 | From: "%Z%45" ;tag=f232jadfj23 4 | Call-ID: esc02.asdfnqwo34rq23i34jrjasdcnl23nrlknsdf 5 | Via: SIP/2.0/TCP host.example.com;branch=z9hG4bK209%fzsnel234 6 | CSeq: 29344 RE%47IST%45R 7 | Max-Forwards: 70 8 | Contact: 9 | C%6Fntact: 10 | Contact: 11 | l: 0 12 | 13 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/escnull.dat: -------------------------------------------------------------------------------- 1 | REGISTER sip:example.com SIP/2.0 2 | To: sip:null-%00-null@example.com 3 | From: sip:null-%00-null@example.com;tag=839923423 4 | Max-Forwards: 70 5 | Call-ID: escnull.39203ndfvkjdasfkq3w4otrq0adsfdfnavd 6 | CSeq: 14398234 REGISTER 7 | Via: SIP/2.0/UDP host5.example.com;branch=z9hG4bKkdjuw 8 | Contact: 9 | Contact: 10 | L:0 11 | 12 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/escruri.dat: -------------------------------------------------------------------------------- 1 | INVITE sip:user@example.com?Route=%3Csip:example.com%3E SIP/2.0 2 | To: sip:user@example.com 3 | From: sip:caller@example.net;tag=341518 4 | Max-Forwards: 7 5 | Contact: 6 | Call-ID: escruri.23940-asdfhj-aje3br-234q098w-fawerh2q-h4n5 7 | CSeq: 149209342 INVITE 8 | Via: SIP/2.0/UDP host-of-the-hour.example.com;branch=z9hG4bKkdjuw 9 | Content-Type: application/sdp 10 | Content-Length: 150 11 | 12 | v=0 13 | o=mhandley 29739 7272939 IN IP4 192.0.2.1 14 | s=- 15 | c=IN IP4 192.0.2.1 16 | t=0 0 17 | m=audio 49217 RTP/AVP 0 12 18 | m=video 3227 RTP/AVP 31 19 | a=rtpmap:31 LPC 20 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/insuf.dat: -------------------------------------------------------------------------------- 1 | INVITE sip:user@example.com SIP/2.0 2 | CSeq: 193942 INVITE 3 | Via: SIP/2.0/UDP 192.0.2.95;branch=z9hG4bKkdj.insuf 4 | Content-Type: application/sdp 5 | l: 152 6 | 7 | v=0 8 | o=mhandley 29739 7272939 IN IP4 192.0.2.95 9 | s=- 10 | c=IN IP4 192.0.2.95 11 | t=0 0 12 | m=audio 49217 RTP/AVP 0 12 13 | m=video 3227 RTP/AVP 31 14 | a=rtpmap:31 LPC 15 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/intmeth.dat: -------------------------------------------------------------------------------- 1 | !interesting-Method0123456789_*+`.%indeed'~ sip:1_unusual.URI~(to-be!sure)&isn't+it$/crazy?,/;;*:&it+has=1,weird!*pas$wo~d_too.(doesn't-it)@example.com SIP/2.0 2 | Via: SIP/2.0/TCP host1.example.com;branch=z9hG4bK-.!%66*_+`'~ 3 | To: "BEL:\ NUL:\ DEL:\" 4 | From: token1~` token2'+_ token3*%!.- ;fromParam''~+*_!.-%="работающий";tag=_token~1'+`*%!-. 5 | Call-ID: intmeth.word%ZK-!.*_+'@word`~)(><:\/"][?}{ 6 | CSeq: 139122385 !interesting-Method0123456789_*+`.%indeed'~ 7 | Max-Forwards: 255 8 | extensionHeader-!.%*+_`'~:大停電 9 | Content-Length: 0 10 | 11 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/inv2543.dat: -------------------------------------------------------------------------------- 1 | INVITE sip:UserB@example.com SIP/2.0 2 | Via: SIP/2.0/UDP iftgw.example.com 3 | From: 4 | Record-Route: 5 | To: sip:+16505552222@ss1.example.net;user=phone 6 | Call-ID: inv2543.1717@ift.client.example.com 7 | CSeq: 56 INVITE 8 | Content-Type: application/sdp 9 | 10 | v=0 11 | o=mhandley 29739 7272939 IN IP4 192.0.2.5 12 | s=- 13 | c=IN IP4 192.0.2.5 14 | t=0 0 15 | m=audio 49217 RTP/AVP 0 16 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/invut.dat: -------------------------------------------------------------------------------- 1 | INVITE sip:user@example.com SIP/2.0 2 | Contact: 3 | To: sip:j.user@example.com 4 | From: sip:caller@example.net;tag=8392034 5 | Max-Forwards: 70 6 | Call-ID: invut.0ha0isndaksdjadsfij34n23d 7 | CSeq: 235448 INVITE 8 | Via: SIP/2.0/UDP somehost.example.com;branch=z9hG4bKkdjuw 9 | Content-Type: application/unknownformat 10 | Content-Length: 40 11 | 12 | 15 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/longreq.dat: -------------------------------------------------------------------------------- 1 | INVITE sip:user@example.com SIP/2.0 2 | To: "I have a user name of extremeextremeextremeextremeextremeextremeextremeextremeextremeextreme proportion" 3 | F: sip:amazinglylongcallernameamazinglylongcallernameamazinglylongcallernameamazinglylongcallernameamazinglylongcallername@example.net;tag=12982982982982982982982982982982982982982982982982982982982982982982982982982982982982982982982982982982982982982982982982982982982982982982982982982982424;unknownheaderparamnamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamename=unknowheaderparamvaluevaluevaluevaluevaluevaluevaluevaluevaluevaluevaluevaluevaluevaluevalue;unknownValuelessparamnameparamnameparamnameparamnameparamnameparamnameparamnameparamnameparamnameparamname 4 | Call-ID: longreq.onereallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallylongcallid 5 | CSeq: 3882340 INVITE 6 | Unknown-LongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLong-Name: unknown-longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong-value; unknown-longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong-parameter-name = unknown-longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong-parameter-value 7 | Via: SIP/2.0/TCP sip33.example.com 8 | v: SIP/2.0/TCP sip32.example.com 9 | V: SIP/2.0/TCP sip31.example.com 10 | Via: SIP/2.0/TCP sip30.example.com 11 | ViA: SIP/2.0/TCP sip29.example.com 12 | VIa: SIP/2.0/TCP sip28.example.com 13 | VIA: SIP/2.0/TCP sip27.example.com 14 | via: SIP/2.0/TCP sip26.example.com 15 | viA: SIP/2.0/TCP sip25.example.com 16 | vIa: SIP/2.0/TCP sip24.example.com 17 | vIA: SIP/2.0/TCP sip23.example.com 18 | V : SIP/2.0/TCP sip22.example.com 19 | v : SIP/2.0/TCP sip21.example.com 20 | V : SIP/2.0/TCP sip20.example.com 21 | v : SIP/2.0/TCP sip19.example.com 22 | Via : SIP/2.0/TCP sip18.example.com 23 | Via : SIP/2.0/TCP sip17.example.com 24 | Via: SIP/2.0/TCP sip16.example.com 25 | Via: SIP/2.0/TCP sip15.example.com 26 | Via: SIP/2.0/TCP sip14.example.com 27 | Via: SIP/2.0/TCP sip13.example.com 28 | Via: SIP/2.0/TCP sip12.example.com 29 | Via: SIP/2.0/TCP sip11.example.com 30 | Via: SIP/2.0/TCP sip10.example.com 31 | Via: SIP/2.0/TCP sip9.example.com 32 | Via: SIP/2.0/TCP sip8.example.com 33 | Via: SIP/2.0/TCP sip7.example.com 34 | Via: SIP/2.0/TCP sip6.example.com 35 | Via: SIP/2.0/TCP sip5.example.com 36 | Via: SIP/2.0/TCP sip4.example.com 37 | Via: SIP/2.0/TCP sip3.example.com 38 | Via: SIP/2.0/TCP sip2.example.com 39 | Via: SIP/2.0/TCP sip1.example.com 40 | Via: SIP/2.0/TCP host.example.com;received=192.0.2.5;branch=verylonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglongbranchvalue 41 | Max-Forwards: 70 42 | Contact: 43 | Content-Type: application/sdp 44 | l: 150 45 | 46 | v=0 47 | o=mhandley 29739 7272939 IN IP4 192.0.2.1 48 | s=- 49 | c=IN IP4 192.0.2.1 50 | t=0 0 51 | m=audio 49217 RTP/AVP 0 12 52 | m=video 3227 RTP/AVP 31 53 | a=rtpmap:31 LPC 54 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/ltgtruri.dat: -------------------------------------------------------------------------------- 1 | INVITE SIP/2.0 2 | To: sip:user@example.com 3 | From: sip:caller@example.net;tag=39291 4 | Max-Forwards: 23 5 | Call-ID: ltgtruri.1@192.0.2.5 6 | CSeq: 1 INVITE 7 | Via: SIP/2.0/UDP 192.0.2.5 8 | Contact: 9 | Content-Type: application/sdp 10 | Content-Length: 159 11 | 12 | v=0 13 | o=mhandley 29739 7272939 IN IP4 192.0.2.5 14 | s=- 15 | c=IN IP4 192.0.2.5 16 | t=3149328700 0 17 | m=audio 49217 RTP/AVP 0 12 18 | m=video 3227 RTP/AVP 31 19 | a=rtpmap:31 LPC 20 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/lwsdisp.dat: -------------------------------------------------------------------------------- 1 | OPTIONS sip:user@example.com SIP/2.0 2 | To: sip:user@example.com 3 | From: caller;tag=323 4 | Max-Forwards: 70 5 | Call-ID: lwsdisp.1234abcd@funky.example.com 6 | CSeq: 60 OPTIONS 7 | Via: SIP/2.0/UDP funky.example.com;branch=z9hG4bKkdjuw 8 | l: 0 9 | 10 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/lwsruri.dat: -------------------------------------------------------------------------------- 1 | INVITE sip:user@example.com; lr SIP/2.0 2 | To: sip:user@example.com;tag=3xfe-9921883-z9f 3 | From: sip:caller@example.net;tag=231413434 4 | Max-Forwards: 5 5 | Call-ID: lwsruri.asdfasdoeoi2323-asdfwrn23-asd834rk423 6 | CSeq: 2130706432 INVITE 7 | Via: SIP/2.0/UDP 192.0.2.1:5060;branch=z9hG4bKkdjuw2395 8 | Contact: 9 | Content-Type: application/sdp 10 | Content-Length: 159 11 | 12 | v=0 13 | o=mhandley 29739 7272939 IN IP4 192.0.2.1 14 | s=- 15 | c=IN IP4 192.0.2.1 16 | t=3149328700 0 17 | m=audio 49217 RTP/AVP 0 12 18 | m=video 3227 RTP/AVP 31 19 | a=rtpmap:31 LPC 20 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/lwsstart.dat: -------------------------------------------------------------------------------- 1 | INVITE sip:user@example.com SIP/2.0 2 | Max-Forwards: 8 3 | To: sip:user@example.com 4 | From: sip:caller@example.net;tag=8814 5 | Call-ID: lwsstart.dfknq234oi243099adsdfnawe3@example.com 6 | CSeq: 1893884 INVITE 7 | Via: SIP/2.0/UDP host1.example.com;branch=z9hG4bKkdjuw3923 8 | Contact: 9 | Content-Type: application/sdp 10 | Content-Length: 150 11 | 12 | v=0 13 | o=mhandley 29739 7272939 IN IP4 192.0.2.1 14 | s=- 15 | c=IN IP4 192.0.2.1 16 | t=0 0 17 | m=audio 49217 RTP/AVP 0 12 18 | m=video 3227 RTP/AVP 31 19 | a=rtpmap:31 LPC 20 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/mcl01.dat: -------------------------------------------------------------------------------- 1 | OPTIONS sip:user@example.com SIP/2.0 2 | Via: SIP/2.0/UDP host5.example.net;branch=z9hG4bK293423 3 | To: sip:user@example.com 4 | From: sip:other@example.net;tag=3923942 5 | Call-ID: mcl01.fhn2323orihawfdoa3o4r52o3irsdf 6 | CSeq: 15932 OPTIONS 7 | Content-Length: 13 8 | Max-Forwards: 60 9 | Content-Length: 5 10 | Content-Type: text/plain 11 | 12 | There's no way to know how many octets are supposed to be here. 13 | 14 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/mismatch01.dat: -------------------------------------------------------------------------------- 1 | OPTIONS sip:user@example.com SIP/2.0 2 | To: sip:j.user@example.com 3 | From: sip:caller@example.net;tag=34525 4 | Max-Forwards: 6 5 | Call-ID: mismatch01.dj0234sxdfl3 6 | CSeq: 8 INVITE 7 | Via: SIP/2.0/UDP host.example.com;branch=z9hG4bKkdjuw 8 | l: 0 9 | 10 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/mismatch02.dat: -------------------------------------------------------------------------------- 1 | NEWMETHOD sip:user@example.com SIP/2.0 2 | To: sip:j.user@example.com 3 | From: sip:caller@example.net;tag=34525 4 | Max-Forwards: 6 5 | Call-ID: mismatch02.dj0234sxdfl3 6 | CSeq: 8 INVITE 7 | Contact: 8 | Via: SIP/2.0/UDP host.example.net;branch=z9hG4bKkdjuw 9 | Content-Type: application/sdp 10 | l: 138 11 | 12 | v=0 13 | o=mhandley 29739 7272939 IN IP4 192.0.2.1 14 | c=IN IP4 192.0.2.1 15 | m=audio 49217 RTP/AVP 0 12 16 | m=video 3227 RTP/AVP 31 17 | a=rtpmap:31 LPC 18 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/mpart01.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rtckit/php-sip/7e931877d45c5c64771c09393408ca04c0f5caa6/tests/fixtures/rfc4475/mpart01.dat -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/multi01.dat: -------------------------------------------------------------------------------- 1 | INVITE sip:user@company.com SIP/2.0 2 | Contact: 3 | Via: SIP/2.0/UDP 192.0.2.25;branch=z9hG4bKkdjuw 4 | Max-Forwards: 70 5 | CSeq: 5 INVITE 6 | Call-ID: multi01.98asdh@192.0.2.1 7 | CSeq: 59 INVITE 8 | Call-ID: multi01.98asdh@192.0.2.2 9 | From: sip:caller@example.com;tag=3413415 10 | To: sip:user@example.com 11 | To: sip:other@example.net 12 | From: sip:caller@example.net;tag=2923420123 13 | Content-Type: application/sdp 14 | l: 154 15 | Contact: 16 | Max-Forwards: 5 17 | 18 | v=0 19 | o=mhandley 29739 7272939 IN IP4 192.0.2.25 20 | s=- 21 | c=IN IP4 192.0.2.25 22 | t=0 0 23 | m=audio 49217 RTP/AVP 0 12 24 | m=video 3227 RTP/AVP 31 25 | a=rtpmap:31 LPC 26 | 27 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/ncl.dat: -------------------------------------------------------------------------------- 1 | INVITE sip:user@example.com SIP/2.0 2 | Max-Forwards: 254 3 | To: sip:j.user@example.com 4 | From: sip:caller@example.net;tag=32394234 5 | Call-ID: ncl.0ha0isndaksdj2193423r542w35 6 | CSeq: 0 INVITE 7 | Via: SIP/2.0/UDP 192.0.2.53;branch=z9hG4bKkdjuw 8 | Contact: 9 | Content-Type: application/sdp 10 | Content-Length: -999 11 | 12 | v=0 13 | o=mhandley 29739 7272939 IN IP4 192.0.2.53 14 | s=- 15 | c=IN IP4 192.0.2.53 16 | t=0 0 17 | m=audio 49217 RTP/AVP 0 12 18 | m=video 3227 RTP/AVP 31 19 | a=rtpmap:31 LPC 20 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/noreason.dat: -------------------------------------------------------------------------------- 1 | SIP/2.0 100 2 | Via: SIP/2.0/UDP 192.0.2.105;branch=z9hG4bK2398ndaoe 3 | Call-ID: noreason.asndj203insdf99223ndf 4 | CSeq: 35 INVITE 5 | From: ;tag=39ansfi3 6 | To: ;tag=902jndnke3 7 | Content-Length: 0 8 | Contact: 9 | 10 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/novelsc.dat: -------------------------------------------------------------------------------- 1 | OPTIONS soap.beep://192.0.2.103:3002 SIP/2.0 2 | To: sip:user@example.com 3 | From: sip:caller@example.net;tag=384 4 | Max-Forwards: 3 5 | Call-ID: novelsc.asdfasser0q239nwsdfasdkl34 6 | CSeq: 3923423 OPTIONS 7 | Via: SIP/2.0/TCP host9.example.com;branch=z9hG4bKkdjuw39234 8 | Content-Length: 0 9 | 10 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/quotbal.dat: -------------------------------------------------------------------------------- 1 | INVITE sip:user@example.com SIP/2.0 2 | To: "Mr. J. User 3 | From: sip:caller@example.net;tag=93334 4 | Max-Forwards: 10 5 | Call-ID: quotbal.aksdj 6 | Contact: 7 | CSeq: 8 INVITE 8 | Via: SIP/2.0/UDP 192.0.2.59:5050;branch=z9hG4bKkdjuw39234 9 | Content-Type: application/sdp 10 | Content-Length: 152 11 | 12 | v=0 13 | o=mhandley 29739 7272939 IN IP4 192.0.2.15 14 | s=- 15 | c=IN IP4 192.0.2.15 16 | t=0 0 17 | m=audio 49217 RTP/AVP 0 12 18 | m=video 3227 RTP/AVP 31 19 | a=rtpmap:31 LPC 20 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/regaut01.dat: -------------------------------------------------------------------------------- 1 | REGISTER sip:example.com SIP/2.0 2 | To: sip:j.user@example.com 3 | From: sip:j.user@example.com;tag=87321hj23128 4 | Max-Forwards: 8 5 | Call-ID: regaut01.0ha0isndaksdj 6 | CSeq: 9338 REGISTER 7 | Via: SIP/2.0/TCP 192.0.2.253;branch=z9hG4bKkdjuw 8 | Authorization: NoOneKnowsThisScheme opaque-data=here 9 | Content-Length:0 10 | 11 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/regbadct.dat: -------------------------------------------------------------------------------- 1 | REGISTER sip:example.com SIP/2.0 2 | To: sip:user@example.com 3 | From: sip:user@example.com;tag=998332 4 | Max-Forwards: 70 5 | Call-ID: regbadct.k345asrl3fdbv@10.0.0.1 6 | CSeq: 1 REGISTER 7 | Via: SIP/2.0/UDP 135.180.130.133:5060;branch=z9hG4bKkdjuw 8 | Contact: sip:user@example.com?Route=%3Csip:sip.example.com%3E 9 | l: 0 10 | 11 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/regescrt.dat: -------------------------------------------------------------------------------- 1 | REGISTER sip:example.com SIP/2.0 2 | To: sip:user@example.com 3 | From: sip:user@example.com;tag=8 4 | Max-Forwards: 70 5 | Call-ID: regescrt.k345asrl3fdbv@192.0.2.1 6 | CSeq: 14398234 REGISTER 7 | Via: SIP/2.0/UDP host5.example.com;branch=z9hG4bKkdjuw 8 | M: 9 | L:0 10 | 11 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/scalar02.dat: -------------------------------------------------------------------------------- 1 | REGISTER sip:example.com SIP/2.0 2 | Via: SIP/2.0/TCP host129.example.com;branch=z9hG4bK342sdfoi3 3 | To: 4 | From: ;tag=239232jh3 5 | CSeq: 36893488147419103232 REGISTER 6 | Call-ID: scalar02.23o0pd9vanlq3wnrlnewofjas9ui32 7 | Max-Forwards: 300 8 | Expires: 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 9 | Contact: 10 | ;expires=280297596632815 11 | Content-Length: 0 12 | 13 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/scalarlg.dat: -------------------------------------------------------------------------------- 1 | SIP/2.0 503 Service Unavailable 2 | Via: SIP/2.0/TCP host129.example.com;branch=z9hG4bKzzxdiwo34sw;received=192.0.2.129 3 | To: 4 | From: ;tag=2easdjfejw 5 | CSeq: 9292394834772304023312 OPTIONS 6 | Call-ID: scalarlg.noase0of0234hn2qofoaf0232aewf2394r 7 | Retry-After: 949302838503028349304023988 8 | Warning: 1812 overture "In Progress" 9 | Content-Length: 0 10 | 11 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/sdp01.dat: -------------------------------------------------------------------------------- 1 | INVITE sip:user@example.com SIP/2.0 2 | To: sip:j_user@example.com 3 | Contact: 4 | From: sip:caller@example.net;tag=234 5 | Max-Forwards: 5 6 | Call-ID: sdp01.ndaksdj9342dasdd 7 | Accept: text/nobodyKnowsThis 8 | CSeq: 8 INVITE 9 | Via: SIP/2.0/UDP 192.0.2.15;branch=z9hG4bKkdjuw 10 | Content-Length: 150 11 | Content-Type: application/sdp 12 | 13 | v=0 14 | o=mhandley 29739 7272939 IN IP4 192.0.2.5 15 | s=- 16 | c=IN IP4 192.0.2.5 17 | t=0 0 18 | m=audio 49217 RTP/AVP 0 12 19 | m=video 3227 RTP/AVP 31 20 | a=rtpmap:31 LPC 21 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/semiuri.dat: -------------------------------------------------------------------------------- 1 | OPTIONS sip:user;par=u%40example.net@example.com SIP/2.0 2 | To: sip:j_user@example.com 3 | From: sip:caller@example.org;tag=33242 4 | Max-Forwards: 3 5 | Call-ID: semiuri.0ha0isndaksdj 6 | CSeq: 8 OPTIONS 7 | Accept: application/sdp, application/pkcs7-mime, 8 | multipart/mixed, multipart/signed, 9 | message/sip, message/sipfrag 10 | Via: SIP/2.0/UDP 192.0.2.1;branch=z9hG4bKkdjuw 11 | l: 0 12 | 13 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/test.dat: -------------------------------------------------------------------------------- 1 | INVITE sip:alan@jasomi.com 2 | TO : alan@jasomi.com 3 | From: ralph@example.com 4 | MaX-fOrWaRdS: 0068 5 | Call-ID: test.0ha0isndaksdj@192.0.2.1 6 | Xyzzy-2: this is the number ten : 10 7 | Xyzzy-3: INVITE 8 | Xyzzy: 10000000000 9 | Meaning: foo bar spam 10 | Foobar roobar 11 | Content-Length: 18 12 | Content-Type: application/sdp 13 | 14 | v=0 15 | testing=123 16 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/transports.dat: -------------------------------------------------------------------------------- 1 | OPTIONS sip:user@example.com SIP/2.0 2 | To: sip:user@example.com 3 | From: ;tag=323 4 | Max-Forwards: 70 5 | Call-ID: transports.kijh4akdnaqjkwendsasfdj 6 | Accept: application/sdp 7 | CSeq: 60 OPTIONS 8 | Via: SIP/2.0/UDP t1.example.com;branch=z9hG4bKkdjuw 9 | Via: SIP/2.0/SCTP t2.example.com;branch=z9hG4bKklasjdhf 10 | Via: SIP/2.0/TLS t3.example.com;branch=z9hG4bK2980unddj 11 | Via: SIP/2.0/UNKNOWN t4.example.com;branch=z9hG4bKasd0f3en 12 | Via: SIP/2.0/TCP t5.example.com;branch=z9hG4bK0a9idfnee 13 | l: 0 14 | 15 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/trws.dat: -------------------------------------------------------------------------------- 1 | OPTIONS sip:remote-target@example.com SIP/2.0 2 | Via: SIP/2.0/TCP host1.examle.com;branch=z9hG4bK299342093 3 | To: 4 | From: ;tag=329429089 5 | Call-ID: trws.oicu34958239neffasdhr2345r 6 | Accept: application/sdp 7 | CSeq: 238923 OPTIONS 8 | Max-Forwards: 70 9 | Content-Length: 0 10 | 11 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/unkscm.dat: -------------------------------------------------------------------------------- 1 | OPTIONS nobodyKnowsThisScheme:totallyopaquecontent SIP/2.0 2 | To: sip:user@example.com 3 | From: sip:caller@example.net;tag=384 4 | Max-Forwards: 3 5 | Call-ID: unkscm.nasdfasser0q239nwsdfasdkl34 6 | CSeq: 3923423 OPTIONS 7 | Via: SIP/2.0/TCP host9.example.com;branch=z9hG4bKkdjuw39234 8 | Content-Length: 0 9 | 10 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/unksm2.dat: -------------------------------------------------------------------------------- 1 | REGISTER sip:example.com SIP/2.0 2 | To: isbn:2983792873 3 | From: ;tag=3234233 4 | Call-ID: unksm2.daksdj@hyphenated-host.example.com 5 | CSeq: 234902 REGISTER 6 | Max-Forwards: 70 7 | Via: SIP/2.0/UDP 192.0.2.21:5060;branch=z9hG4bKkdjuw 8 | Contact: 9 | l: 0 10 | 11 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/unreason.dat: -------------------------------------------------------------------------------- 1 | SIP/2.0 200 = 2**3 * 5**2 но сто девяносто девять - простое 2 | Via: SIP/2.0/UDP 192.0.2.198;branch=z9hG4bK1324923 3 | Call-ID: unreason.1234ksdfak3j2erwedfsASdf 4 | CSeq: 35 INVITE 5 | From: sip:user@example.com;tag=11141343 6 | To: sip:user@example.edu;tag=2229 7 | Content-Length: 154 8 | Content-Type: application/sdp 9 | Contact: 10 | 11 | v=0 12 | o=mhandley 29739 7272939 IN IP4 192.0.2.198 13 | s=- 14 | c=IN IP4 192.0.2.198 15 | t=0 0 16 | m=audio 49217 RTP/AVP 0 12 17 | m=video 3227 RTP/AVP 31 18 | a=rtpmap:31 LPC 19 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/wsinv.dat: -------------------------------------------------------------------------------- 1 | INVITE sip:vivekg@chair-dnrc.example.com;unknownparam SIP/2.0 2 | TO : 3 | sip:vivekg@chair-dnrc.example.com ; tag = 1918181833n 4 | from : "J Rosenberg \\\"" 5 | ; 6 | tag = 98asjd8 7 | MaX-fOrWaRdS: 0068 8 | Call-ID: wsinv.ndaksdj@192.0.2.1 9 | Content-Length : 150 10 | cseq: 0009 11 | INVITE 12 | Via : SIP / 2.0 13 | /UDP 14 | 192.0.2.2;branch=390skdjuw 15 | s : 16 | NewFangledHeader: newfangled value 17 | continued newfangled value 18 | UnknownHeaderWithUnusualValue: ;;,,;;,; 19 | Content-Type: application/sdp 20 | Route: 21 | 22 | v: SIP / 2.0 / TCP spindle.example.com ; 23 | branch = z9hG4bK9ikj8 , 24 | SIP / 2.0 / UDP 192.168.255.111 ; branch= 25 | z9hG4bK30239 26 | m:"Quoted string \"\"" ; newparam = 27 | newvalue ; 28 | secondparam ; q = 0.33 29 | 30 | v=0 31 | o=mhandley 29739 7272939 IN IP4 192.0.2.3 32 | s=- 33 | c=IN IP4 192.0.2.4 34 | t=0 0 35 | m=audio 49217 RTP/AVP 0 12 36 | m=video 3227 RTP/AVP 31 37 | a=rtpmap:31 LPC 38 | -------------------------------------------------------------------------------- /tests/fixtures/rfc4475/zeromf.dat: -------------------------------------------------------------------------------- 1 | OPTIONS sip:user@example.com SIP/2.0 2 | To: sip:user@example.com 3 | From: sip:caller@example.net;tag=3ghsd41 4 | Call-ID: zeromf.jfasdlfnm2o2l43r5u0asdfas 5 | CSeq: 39234321 OPTIONS 6 | Via: SIP/2.0/UDP host1.example.com;branch=z9hG4bKkdjuw2349i 7 | Max-Forwards: 0 8 | Content-Length: 0 9 | 10 | --------------------------------------------------------------------------------