lsof anon_inode

사내에서 개발한 리눅스 플랫폼 프로그램을 테스팅하면서 File descriptor 를 감시해야 하는 경우가 생겼다.

Socket 을 열고 정상적으로 종료를 하는지 확인하는 내용이었는데.. 이를 위해서 lsof 유틸리티를 사용했다.

$ lsof -p [PID] | wc -l

의 명령어로 갯수를 확인하면서 open file descriptor 수를 감시했다.

그러던 중, lsof 의 결과 출력을 분석했는데 이상한 것이 있었다.

cbapid  5560 root    3u  0000                0,7        0       521 anon_inode
cbapid  5560 root    4u  0000                0,7        0       521 anon_inode
cbapid  5560 root    5r  0000               0,11        0 271110595 eventpoll
cbapid  5560 root    6u  0000                0,7        0       521 anon_inode
cbapid  5560 root    7r  0000               0,11        0 271110596 eventpoll
cbapid  5560 root    8u  0000                0,7        0       521 anon_inode
cbapid  5560 root    9u  0000                0,7        0       521 anon_inode
cbapid  5560 root   10r   CHR                1,9      0t0  97762892 /dev/urandom
cbapid  5560 root   11r  0000               0,11        0 271110599 eventpoll

anon_inode 와 같이 나타난 file descriptor 들이 많이 있는 것을 확인한 것이다.

anon_inode 가 무엇이고 왜 나타나는 것일까?

해답은 다음과 같다.

anon_inode 는 anonymouse_inode 의 약자이며, epoll 을 사용할 경우, 감시대상 file descriptor 들을 관리하기 위해서 생성하고 사용하는 file descriptor 인 것이다.
즉, 내부적으로 epoll 을 사용하는 library 가 있다면 나타나는 정상적인 현상인 것이다.

참조 :  http://stackoverflow.com/questions/8170902/why-is-the-jdk-nio-using-so-many-anon-inode-file-descriptors

 

 

mtp mount in gentoo

Gentoo 머신에 안드로이드 폰을 연결해서 사용할 일이 있었다. 그냥 될 줄 알고 케이블을 연결했는데 인식이 안되는 것이었다. 역시… 뭔가를 해주어야 했다.

Gentoo wiki 에서는 mtp mount 하는 방법을 세가지 소개하고 있다. 바로 mtpfs, go-mtpfs, kde 이다. 이중 나는 mtpfs 와 go-mtpfs 를 사용했다.

결론적으로 mtpfs 는 원활한 동작이 되지 않았다. Mount 까지는 성공한 듯 싶었으나, 실제 마운트된 디렉토리에서 파일들에 접근할 수가 없었다. go-mtpfs 의 경우 완벽하게 동작했다.

먼저 go 를 설지하자.

$ sudo emerge dev-lang/go

그리고 mtpfs 를 위한 추가 작업을 진행해주자.

pchero@localhost ~ $ mkdir go
pchero@localhost ~ $ export GOPATH=/home/pchero/go
pchero@localhost ~ $ go get github.com/hanwen/go-mtpfs

그리고 그룹을 추가해주고…

$ sudo gpasswd -a pchero plugdev

마운트할 디렉토리를 생성하고 휴대폰에 케이블을 연결한 뒤, 마운트를 해주자.

$ mkdir ~/Android$ ~/go/bin/go-mtfs ~/Android

언마운트를 할 때는 아래와 같이..

$ fusermount -u ~/Android/

출처: https://wiki.gentoo.org/wiki/MTP

Asterisk – sip.conf

/etc/asterisk/sip.conf 파일은 Asterisk 에서 sip 채널을 설정하는 파일이다. 즉, Asterisk 에서 관리하는 SIP 단말기 정보를 입력하는 설정파일이다.

/etc/asterisk/sip.conf 파일 예제

[general]
context = unauthenticated               ; default context for incoming calls
allowguest = no                 ; disable unauthenticated calls
srvlookup = no                  ; disable DNS SRV record lookup on outbound calls
                                ;   (unless you have a reliable DNS connection,
                                ;   in which case yes)
udpbindaddr = 0.0.0.0           ; listen for UDP requests on all interfaces
port = 5060
tcpenable = no                  ; disable TCP support
register => 123123123:123123123@192.168.0.1  ; External trunk register information
;tlsenable = yes
;tlsbindaddr = ::

[teset_phone_ibk87ns4gj]
type = friend
host = dynamic
secret = tb9hibvp9c
context = demo

[messagewaiting](!)             ; a template to handle the settings common
                                ; to all mailboxes
type=peer
subscribecontext = voicemailbox ; the dialplan context on the voicemail server
context = voicemailbox          ; the dialplan context on the voicemail server
host = 192.168.200.10           ; ip address of presence server

[office-phone](!)       ; create a template for our devices
type = friend           ;   the channel driver will match on username first,
                        ;   IP second
context = LocalSets     ; this is where calls from the device will enter
                        ; the dialplan
host = dynamic          ; the device will register with asterisk
nat = force_rport,comedia       ; assume device is behind NAT
                        ;   *** NAT stands for Network Address Translation,
                        ;   which allows multiple internal devices to share an
                        ;   external IP address.
dtmfmode = auto ; accept touch-tone from the devices, negotiated
                ; automatically
disallow = all  ; reset which voice codec this device will accept or offer
allow = g722    ; audio codecs to accept from, and request to, the device
allow = ulaw    ; in the order we prefer

; define a device name and use the office-phone template
[0000FFFF0001](office-phone)
secret = helloworld      ; a unique password for this device --
                        ; DON'T USE THE PASSWORD WE'VE USED IN THIS EXAMPLE!

; define another device name using the same template
[0000FFFF0002](office-phone)
secret = helloworld ; a unique password for this device --
                        ; DON'T USE THE PASSWORD WE'VE USED IN THIS EXAMPLE!

[0000FFFF0003](office-phone)
secret = helloworld   ; DON'T USE THE PASSWORD WE'VE USED IN THIS EXAMPLE!
allow = gsm

[0000FFF0004](messagewaiting)   ; this will need to match the subsriber
                                ; name on the proxy
mailbox = 0000FFFF0004@DIR1     ; must be in the form mailbox@mailboxcontext
defaultuser = 0000FFFF0004      ; this will need to match the subscriber
                                ; name on the proxy

[general] Section

가장 기본적인 섹션이며, Default 값들을 설정하는 곳이다.
모든 채널 모듈 설정시, 기본적으로 설정의 제일 앞부분에 [general] 섹션을 포함한다고 생각하면 되며,  [general] 섹션의 이름은 바뀌어서는 안된다.
[general] 섹션에서는 기본적인 프로토콜 연결 방식과 Default Parameter 들을 설정할 수 있다.

context=unauthenticated         ; default context for incoming calls

위의 예제에서는 default context 로 unauthenticated 를 설정했다. 이것은, 별도로 context를 설정하지 않은 sip 채널들에 대해서는 unauthenticated 방식으로 처리하겠다는 뜻이다.
참고로 unauthenticated 에 관한 설정 내용은 /etc/asterisk/extension.conf 에 설정할 되어있어야 한다.

allowguest=no                   ; disable unauthenticated calls

Guest call 허용 여부. 명시적으로 계정을 가진 사람들만 통화가 가능하도록 할지 말지에 관한 옵션이다. No 로 설정시, sip.conf 에 등록된 계정만 통화가 가능하게 된다.

srvlookup=no                    ; disable DNS SRV record lookup on outbound calls
;   (unless you have a reliable DNS connection,
;   in which case yes)

DNS lookup 설정 여부

udpbindaddr=0.0.0.0             ; listen for UDP requests on all interfaces

NIC 가 여러개 있을 경우, 어느 IP 주소로 Listen 소켓을 열어둘지를 설정하는 옵션. 0.0.0.0 으로 설정할 경우, 사용가능한 모든 IP 주소로 Listen Port 를 열어놓는다.
Asterisk 의 NIC 사용방식은 all-or-one 방식이다. 즉, 하나를 사용하거나 모두를 사용하거나 이다.
예를 들어, 만약 NIC가 3개가 있을 경우 이중 2개만 사용할 수는 없다는 것이다.

tcpenable=no                    ; disable TCP support

TCP 사용 여부를 설정한다.

[office-phone](!) 섹션

 [office-phone](!)       ; create a template for our devices

템플릿 섹션 설정. [office-phone] 뒤에 붙은 (!) 표시는 이 섹션은 템플릿로 사용된다는 것을 가리킨다. 템플릿으로 만들어진 섹션은 추후 device 추가시 적용하여 사용가능 하다.

type=friend             ;   the channel driver will match on username first,
;   IP second

peer, user, friend 로 설정가능하다. 각각의 의미는 다음과 같다.
peer : Source IP 와 Port number 로 요청을 확인한다.
user : SIP Request 에서 From header 안의 username 으로 요청을 확인한다. sip.conf 에서 설정된 내용중에서 일치하는 device 정보를 찾는다.
friend : peer/user 두가지 방식 모두 사용해서 요청을 확인한다.

host=dynamic            ; the device will register with asterisk

연결되는 SIP 장비의 IP 주소를 설정한다. dynamic 또는 직접 IP 주소 입력 방식이 있는데, 만약 SIP 단말기가 고정 IP 가 아니라면 dynamic 으로 설정해야 한다.

 nat=force_rport,comedia ; assume device is behind NAT
;   *** NAT stands for Network Address Translation,
;   which allows multiple internal devices to share an
;   external IP address.

단말장치가 NAT 안쪽에 있는 경우 설정한다.

dtmfmode=auto   ; accept touch-tone from the devices, negotiated
; automatically

Asterisk 가 DTMF(touch-tone)을 보낼 때, 어떤 형식의 Dial tone을 보낼지 설정한다. info, inband, rfc2833, auto 중 한가지를 설정할 수 있다. info 설정은 SIP INFO method 를 사용하고, inband는 inband audio tone 을 전달한다. 그리고 rfc2833은 RFC-2833 에서 제정된 out-of-band method 를 전달한다.

disallow=all    ; reset which voice codec this device will accept or offer
allow=g722      ; audio codecs to accept from, and request to, the device
allow=ulaw      ; in the order we prefer
allow=alaw

사용/불가능 audio codec 을 지정한다. 제일 첫라인 disallow=all  은 general 에서 이미 설정된 코덱 내용들을 모두 버린다른 뜻이며, 바로 아랫 줄 부터 어떤 코덱들을 사용할 것인지 하나씩 설정한다.
ulaw의 경우, Canada 와 US를 제외한 거의 대부분의 국가에서 사용하며, alaw 는 주로 Canada 와 US 에서 사용한다.

[0000FFFF0003](office-phone) 섹션

[0000FFFF0003](office-phone)

장비 이름(username) 0000FFFF0003 과 office-phone 템플릿을 사용한다고 선언한 부분이다.

secret=helloworld     ; DON’T USE THE PASSWORD WE’VE USED IN THIS EXAMPLE!

password 를 설정한다.

ISO 8601

ISO 8601 은 날짜와 시간의 표기에 관한 국제 표준이다.

날짜와 시간을 나타낼 때, 누가 보아도 정확한 시간을 알 수 있도록 만들어 놓은 표준이다.

예를 들어, 여러개의 Time Zone 을 가진 나라가 있다면 (ex. USA) 하나의 로그파일을 분석 할 때, 각각의 Time zone에 맞춰서 로그를 분석하려고 하기때문에 여러가지 문제가 발생할 것이다.이런 경우 ISO 8601 표기에 맞춰 로그 시간을 표시한다면 해결책이 될 수 있다.

날짜의 경우, 우리가 평소에 쓰던 방식과 크게 다르지 않는데, 시간의 경우 조금 다르게 표시한다.
어떻게 시간을 표시할까? 생각보다 ISO 8601의 표기법은 간단하다.

다음은 Wikipedia 에서 가져온 ISO 8601 의 내용중 시간 표시에 관한 부분이다.

시간

시간의 표기에는 쌍점을 쓴 hh:mm:ss(확장 형식) 또는 hhmmss(기본 형식)를 사용한다. hh는 시(時)로서 00부터 24까지의 값을 갖는다.
mm은 분(分)으로서 00부터 59까지의 값을 갖는다. ss는 초(秒)로서 00부터 59까지의 값을 갖는다. 
반점이나 온점을 써서 앞 단위를 나눈 시간을 나타낼 수도 있는데, 이때 십진수를 사용하며 자릿수는 정보 교환 주체 사이에 미리 합의해야 한다. 
다음은 분절 시간 표현 자릿수로 한 자리를 정한 예이다.

    10:20:30,4 또는 102030,4 : 10시 20분 30.4초
    10:30,5 또는 1030,5 : 10:30:30과 같다.
    10.5 : 10:30와 같다.

날짜와 함께 표기할 때

날짜와 시간 사이에 T를 넣어 표기한다.

    1981-02-22T09:00:00 : 1981년 2월 22일 09:00

시간대 표기

UTC 시간대에서는 시각 뒤에 Z를 붙인다.

    1981-02-22T09:00Z 또는 19810222T1200Z : UTC 시간대에서의 1981년 2월 22일 오전 9시

UTC외의 시간대에서는 시각 뒤에 ±hh:mm, ±hhmm, ±hh를 덧붙여 쓴다.

    1981-02-22T09:00:00+09:00 : UTC+9 시간대에서의 1981년 2월 22일 오전 9시

우리 나라에서만 서비스하는 시스템이라면 굳이 ISO 8601 표기를 따르지 않아도 상관없다.
하지만 만약 다른 나라에서도 사용하는 시스템을 개발하고 그 시스템을 유지보수해야 하는 과정에서 Time zone 과 관련된 문제가 나타난다면 ISO 8601은 그 해답이 될 수 있겠다.

참조 : http://ko.wikipedia.org/wiki/ISO_8601

[Asterisk] Asterisk Manager Interface(AMI)

AMI

Asterisk Manager Interface(AMI)는 Asterisk 에서 제공하는 System monitoring/Management interface 이다. 즉, 이벤트 모니터링과 명령 전달을 위한 Interface 란 뜻이다.

AMI 간단 설정

기본적으로 AMI는 disable 로 되어 있다.
AMI를 활성화 하기 위해서는 /etc/asterisk/manager.conf 파일 수정이 필요하다.
/etc/asterisk/manager.conf 파일을 통해서 AMI 접속에 관한 설정을 해주고, /etc/asterisk/manager.d 디렉토리 밑에 각각의 접속에 대한 계정을 설정해준다.

예제로 hello 라는 계정에 world 라는 패스워드를 가진 계정을 추가해보자.

;
; Turn on the AMI and ask it to only accept connections from localhost
;
; By default asterisk will listen on localhost only.
[general]
enabled = yes
webenabled = yes
port = 5038
bindaddr = 192.168.200.10

; No access is allowed by default.
; To set a password, create a file in /etc/asterisk/manager.d
; use creative permission games to allow other serivces to create their own
; files
#include "manager.d/*.conf"

그리고 /etc/asterisk/manager.d 디렉토리 밑에 hello.conf 라는 파일을 하나 추가하자.

pchero@MyDebian:/etc/asterisk/manager.d$ cat hello.conf

; ami configure file for [hello]
[hello]
secret = world
read = all
write = all

이로써, AMI 로 접근이 가능한 hello 라는 계정이 생성되었다. 주의할 점은 아직 TLS/SSL 설정이 안되어있기 때문에 보안에 매우 취약하다는 점이다.

 

AMI 접속 테스트

이제 AMI에 접속해보자. Asterisk는 여러가지 AMI 접속 방법을 제공하는데… 먼저 telnet 부터 접속해보자.

pchero@MyGalaxy:~$ telnet 192.168.200.10 5038
Trying 192.168.200.10...
Connected to 192.168.200.10.
Escape character is '^]'.
Asterisk Call Manager/1.1
Action: Login
Username: hello
Secret: world

Response: Success
Message: Authentication accepted

Event: FullyBooted
Privilege: system,all
Status: Fully Booted

Action: Ping

Response: Success
Ping: Pong
Timestamp: 1395059659.619558

Action: Logoff

Response: Goodbye
Message: Thanks for all the fish.

Connection closed by foreign host.
pchero@MyGalaxy:~$

이번에는 HTTP 를 통한 접속을 해보자.

pchero@MyGalaxy:~$ wget "http://192.168.200.10:8088/rawman?action=login&username=hello&secret=world" --save-cookies cookies.txt -O -
--2014-03-17 13:36:55--  http://192.168.200.10:8088/rawman?action=login&username=hello&secret=world
Connecting to 192.168.200.10:8088... connected.
HTTP request sent, awaiting response... 200 OK
Length: 55 [text/plain]
Saving to: ‘STDOUT’

0% [                                                                                                                                              ] 0           --.-K/s              Response: Success
Message: Authentication accepted

100%[=============================================================================================================================================>] 55          --.-K/s   in 0s

2014-03-17 13:36:55 (6.75 MB/s) - written to stdout [55/55]

pchero@MyGalaxy:~$ wget "http://192.168.200.10:8088/rawman?action=ping" --load-cookies cookies.txt -O -
--2014-03-17 13:37:35--  http://192.168.200.10:8088/rawman?action=ping
Connecting to 192.168.200.10:8088... connected.
HTTP request sent, awaiting response... 200 OK
Length: 63 [text/plain]
Saving to: ‘STDOUT’

0% [                                                                                                                                              ] 0           --.-K/s              Response: Success
Ping: Pong
Timestamp: 1395059855.098176

100%[=============================================================================================================================================>] 63          --.-K/s   in 0s

2014-03-17 13:37:35 (6.22 MB/s) - written to stdout [63/63]

pchero@MyGalaxy:~$ wget "http://192.168.200.10:8088/rawman?action=logoff" --lo
--load-cookies=    --local-encoding=
pchero@MyGalaxy:~$ wget "http://192.168.200.10:8088/rawman?action=logoff" --load-cookies cookies.txt -O -
--2014-03-17 13:38:07--  http://192.168.200.10:8088/rawman?action=logoff
Connecting to 192.168.200.10:8088... connected.
HTTP request sent, awaiting response... 200 OK
Length: 56 [text/plain]
Saving to: ‘STDOUT’

0% [                                                                                                                                              ] 0           --.-K/s              Response: Goodbye
Message: Thanks for all the fish.

100%[=============================================================================================================================================>] 56          --.-K/s   in 0s

2014-03-17 13:38:07 (6.51 MB/s) - written to stdout [56/56]

 

AMI Protocol

AMI 에는 두가지 종류의 메시지가 있다. Manager event 와 manager Action 이다.

Manager Event는 단방향 메시지 전송이며, 메시지는 Asterisk 에서 AMI client로 전송된다. 주로 Asterisk에서 일어난 내용을 접속중인 AMI client로 Notice 하기 위해 사용한다.

Manager Action은 양방향 메시지 전송이며, AMI client 에서 Asterisk로 요청 메시지를 보내고, Asterisk는 처리 결과와 응답메시지를 보내는 방식으로 통신한다.

 

Message Encoding

모든 AMI message들(manager event, manager action, manager action response)은 같은 방식으로 인코딩된다. 모든 메시지들은 text-based 이고, Carriage return 과 Line-feed 기호로 끝맺음된다. 메시지 마지막은 공백 라인으로 끝이난다.

Header1: This is the first header<CR><LF>
Header2: This is the second header<CR><LF>
Header3: This is the last header of this message<CR><LF>
<CR><LF>

Events

모든 Manager event 는 항상 Event header 와 Privilege header 를 포함한다. Event header 에는 해당 event의 이름이, Privilege header 에는 해당 event 의 권한 레벨정보가 표시된다. 다른 헤더들은 해당 event 의 내용에맞는  내용들이 표시된다.

Event: Hangup
Privilege: call,all
Channel: SIP/0004F2060EB4-00000000
Uniqueid: 1283174108.0
CallerIDNum: 2565551212
CallerIDName: Russell Bryant
Cause: 16
Cause-txt: Normal Clearing

Action

모든 manager action 메시지들은 반드시 Action header 를 포함해야 한다. Action header 는 이 메시지가 어떤 명령에 대한 메시지인지를 나타낸다. 그 외 다른 header 들은 Action header 실행을 위한 인자값들로 구성된다. 상세 header 내용들을 확인하고자 한다면 Asterisk CLI 창에서 manager show command <Action> 을 입력하면 확인이 가능하다. 전체 Action list 확인은 manager show commands 명령으로 확인이 가능하다.

MyFBSD*CLI> manager show command ping
[Syntax]
Action: Ping
[ActionID:] <value>

[Synopsis]
Keepalive command.

[Description]
A 'Ping' action will ellicit a 'Pong' response. Used to keep the manager
connection open.

[Arguments]
ActionID
ActionID for this transaction. Will be returned.

[See Also]
Not available

Manager action 메시지에 대한 응답 중 제일 마지막에 오는 메시지는 Response header 를 가지고 있다. 이 Response header 를 통해서 manager action 명령의 성공 여부와 실패했을 경우 실패한 사유등을 확인할 수 있다.

Action: Login
Username: russell
Secret: russell

Response: Success
Message: Authentication accepted

Call originating

AMI 를 통해서 콜을 생성해보자.

Action: Originate
Channel: Sip/0000FFFF0001
Application: Playback
Data: demo-congrats

Response: Success
Message: Originate successfully queued