unofficial mirror of guix-devel@gnu.org 
 help / color / mirror / code / Atom feed
* [PATCH] Add msgpack
@ 2016-05-30 20:50 Lukas Gradl
  2016-05-31 21:45 ` Leo Famulari
                   ` (2 more replies)
  0 siblings, 3 replies; 25+ messages in thread
From: Lukas Gradl @ 2016-05-30 20:50 UTC (permalink / raw)
  To: guix-devel

[-- Attachment #1: Type: text/plain, Size: 116 bytes --]


Hello Guix,

Attached is a patch for the c/c++ version of msgpack.  This is a
dependency of the Ring.

Thank you!


[-- Attachment #2: 0001-gnu-serialization-Add-msgpack.patch --]
[-- Type: text/x-patch, Size: 2176 bytes --]

From 25eef52146bc84e83d90e429a0a2a5ca607280bc Mon Sep 17 00:00:00 2001
From: Lukas Gradl <lgradl@openmailbox.org>
Date: Mon, 30 May 2016 15:46:29 -0500
Subject: [PATCH] gnu: serialization: Add msgpack.

* gnu/packages/serialization.scm (msgpack): New variable.
---
 gnu/packages/serialization.scm | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/gnu/packages/serialization.scm b/gnu/packages/serialization.scm
index 8dfd21d..524754b 100644
--- a/gnu/packages/serialization.scm
+++ b/gnu/packages/serialization.scm
@@ -1,5 +1,6 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2015 Ricardo Wurmus <rekado@elephly.net>
+;;; Copyright © 2016 Lukas Gradl <lgradl@openmailbox.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -21,7 +22,11 @@
   #:use-module (guix packages)
   #:use-module (guix download)
   #:use-module (guix build-system cmake)
+  #:use-module (guix build-system gnu)
   #:use-module (gnu packages)
+  #:use-module (gnu packages autotools)
+  #:use-module (gnu packages check)
+  #:use-module (gnu packages compression)
   #:use-module (gnu packages documentation))
 
 (define-public cereal
@@ -72,3 +77,29 @@
 arbitrary data types and reversibly turns them into different representations,
 such as compact binary encodings, XML, or JSON.")
     (license license:bsd-3)))
+
+
+(define-public msgpack
+  (package
+    (name "msgpack")
+    (version "1.4.1")
+    (source
+     (origin
+       (method url-fetch)
+       (uri
+        (string-append
+         "https://github.com/msgpack/msgpack-c/releases/download/"
+         "cpp-1.4.1/msgpack-" version ".tar.gz"))
+       (sha256
+        (base32
+         "0bpjfh9vz0n2k93mph3x15clmigkgs223xfn8h12ymrh5gsi5ica"))))
+    (build-system gnu-build-system)
+    (native-inputs
+     `(("googletest" ,googletest)))
+    (inputs
+     `(("zlib" ,zlib)))
+    (home-page "http://www.msgpack.org")
+    (synopsis "Binary serialization library")
+    (description "Msgpack is a library for C/C++ that implements binary
+serialization.")
+    (license license:boost1.0)))
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [PATCH] Add msgpack
  2016-05-30 20:50 [PATCH] Add msgpack Lukas Gradl
@ 2016-05-31 21:45 ` Leo Famulari
  2016-06-01  4:49 ` Efraim Flashner
  2016-06-06 14:07 ` Leo Famulari
  2 siblings, 0 replies; 25+ messages in thread
From: Leo Famulari @ 2016-05-31 21:45 UTC (permalink / raw)
  To: Lukas Gradl; +Cc: guix-devel

On Mon, May 30, 2016 at 03:50:41PM -0500, Lukas Gradl wrote:
> * gnu/packages/serialization.scm (msgpack): New variable.

LGTM. Waiting on a response to some questions about the 'googletest'
dependency.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Add msgpack
  2016-05-30 20:50 [PATCH] Add msgpack Lukas Gradl
  2016-05-31 21:45 ` Leo Famulari
@ 2016-06-01  4:49 ` Efraim Flashner
  2016-06-03  0:50   ` Lukas Gradl
  2016-06-06 14:07 ` Leo Famulari
  2 siblings, 1 reply; 25+ messages in thread
From: Efraim Flashner @ 2016-06-01  4:49 UTC (permalink / raw)
  To: Lukas Gradl; +Cc: guix-devel

[-- Attachment #1: Type: text/plain, Size: 2790 bytes --]

On Mon, May 30, 2016 at 03:50:41PM -0500, Lukas Gradl wrote:
> 
> Hello Guix,
> 
> Attached is a patch for the c/c++ version of msgpack.  This is a
> dependency of the Ring.
> 
> Thank you!
> 

> From 25eef52146bc84e83d90e429a0a2a5ca607280bc Mon Sep 17 00:00:00 2001
> From: Lukas Gradl <lgradl@openmailbox.org>
> Date: Mon, 30 May 2016 15:46:29 -0500
> Subject: [PATCH] gnu: serialization: Add msgpack.
> 
> * gnu/packages/serialization.scm (msgpack): New variable.
> ---
>  gnu/packages/serialization.scm | 31 +++++++++++++++++++++++++++++++
>  1 file changed, 31 insertions(+)
> 
> diff --git a/gnu/packages/serialization.scm b/gnu/packages/serialization.scm
> index 8dfd21d..524754b 100644
> --- a/gnu/packages/serialization.scm
> +++ b/gnu/packages/serialization.scm
> @@ -1,5 +1,6 @@
>  ;;; GNU Guix --- Functional package management for GNU
>  ;;; Copyright © 2015 Ricardo Wurmus <rekado@elephly.net>
> +;;; Copyright © 2016 Lukas Gradl <lgradl@openmailbox.org>
>  ;;;
>  ;;; This file is part of GNU Guix.
>  ;;;
> @@ -21,7 +22,11 @@
>    #:use-module (guix packages)
>    #:use-module (guix download)
>    #:use-module (guix build-system cmake)
> +  #:use-module (guix build-system gnu)
>    #:use-module (gnu packages)
> +  #:use-module (gnu packages autotools)
> +  #:use-module (gnu packages check)
> +  #:use-module (gnu packages compression)
>    #:use-module (gnu packages documentation))
>  
>  (define-public cereal
> @@ -72,3 +77,29 @@
>  arbitrary data types and reversibly turns them into different representations,
>  such as compact binary encodings, XML, or JSON.")
>      (license license:bsd-3)))
> +
> +
> +(define-public msgpack
> +  (package
> +    (name "msgpack")
> +    (version "1.4.1")
> +    (source
> +     (origin
> +       (method url-fetch)
> +       (uri
> +        (string-append
> +         "https://github.com/msgpack/msgpack-c/releases/download/"
> +         "cpp-1.4.1/msgpack-" version ".tar.gz"))
                ^^^
            "cpp-" version "/msgpack-"

> +       (sha256
> +        (base32
> +         "0bpjfh9vz0n2k93mph3x15clmigkgs223xfn8h12ymrh5gsi5ica"))))
> +    (build-system gnu-build-system)
> +    (native-inputs
> +     `(("googletest" ,googletest)))
> +    (inputs
> +     `(("zlib" ,zlib)))
> +    (home-page "http://www.msgpack.org")
> +    (synopsis "Binary serialization library")
> +    (description "Msgpack is a library for C/C++ that implements binary
> +serialization.")
> +    (license license:boost1.0)))
> -- 
> 2.7.4
> 


-- 
Efraim Flashner   <efraim@flashner.co.il>   אפרים פלשנר
GPG key = A28B F40C 3E55 1372 662D  14F7 41AA E7DC CA3D 8351
Confidentiality cannot be guaranteed on emails sent or received unencrypted

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Add msgpack
  2016-06-01  4:49 ` Efraim Flashner
@ 2016-06-03  0:50   ` Lukas Gradl
  0 siblings, 0 replies; 25+ messages in thread
From: Lukas Gradl @ 2016-06-03  0:50 UTC (permalink / raw)
  To: Efraim Flashner; +Cc: guix-devel

[-- Attachment #1: Type: text/plain, Size: 2823 bytes --]


Hi,

Thank you for your review!

Efraim Flashner <efraim@flashner.co.il> writes:

> On Mon, May 30, 2016 at 03:50:41PM -0500, Lukas Gradl wrote:
>> 
>> Hello Guix,
>> 
>> Attached is a patch for the c/c++ version of msgpack.  This is a
>> dependency of the Ring.
>> 
>> Thank you!
>> 
>
>> From 25eef52146bc84e83d90e429a0a2a5ca607280bc Mon Sep 17 00:00:00 2001
>> From: Lukas Gradl <lgradl@openmailbox.org>
>> Date: Mon, 30 May 2016 15:46:29 -0500
>> Subject: [PATCH] gnu: serialization: Add msgpack.
>> 
>> * gnu/packages/serialization.scm (msgpack): New variable.
>> ---
>>  gnu/packages/serialization.scm | 31 +++++++++++++++++++++++++++++++
>>  1 file changed, 31 insertions(+)
>> 
>> diff --git a/gnu/packages/serialization.scm b/gnu/packages/serialization.scm
>> index 8dfd21d..524754b 100644
>> --- a/gnu/packages/serialization.scm
>> +++ b/gnu/packages/serialization.scm
>> @@ -1,5 +1,6 @@
>>  ;;; GNU Guix --- Functional package management for GNU
>>  ;;; Copyright © 2015 Ricardo Wurmus <rekado@elephly.net>
>> +;;; Copyright © 2016 Lukas Gradl <lgradl@openmailbox.org>
>>  ;;;
>>  ;;; This file is part of GNU Guix.
>>  ;;;
>> @@ -21,7 +22,11 @@
>>    #:use-module (guix packages)
>>    #:use-module (guix download)
>>    #:use-module (guix build-system cmake)
>> +  #:use-module (guix build-system gnu)
>>    #:use-module (gnu packages)
>> +  #:use-module (gnu packages autotools)
>> +  #:use-module (gnu packages check)
>> +  #:use-module (gnu packages compression)
>>    #:use-module (gnu packages documentation))
>>  
>>  (define-public cereal
>> @@ -72,3 +77,29 @@
>>  arbitrary data types and reversibly turns them into different representations,
>>  such as compact binary encodings, XML, or JSON.")
>>      (license license:bsd-3)))
>> +
>> +
>> +(define-public msgpack
>> +  (package
>> +    (name "msgpack")
>> +    (version "1.4.1")
>> +    (source
>> +     (origin
>> +       (method url-fetch)
>> +       (uri
>> +        (string-append
>> +         "https://github.com/msgpack/msgpack-c/releases/download/"
>> +         "cpp-1.4.1/msgpack-" version ".tar.gz"))
>                 ^^^
>             "cpp-" version "/msgpack-"

Oops! The attached patch fixes that.

>
>> +       (sha256
>> +        (base32
>> +         "0bpjfh9vz0n2k93mph3x15clmigkgs223xfn8h12ymrh5gsi5ica"))))
>> +    (build-system gnu-build-system)
>> +    (native-inputs
>> +     `(("googletest" ,googletest)))
>> +    (inputs
>> +     `(("zlib" ,zlib)))
>> +    (home-page "http://www.msgpack.org")
>> +    (synopsis "Binary serialization library")
>> +    (description "Msgpack is a library for C/C++ that implements binary
>> +serialization.")
>> +    (license license:boost1.0)))
>> -- 
>> 2.7.4
>> 

Thank you!

Best,
Lukas



[-- Attachment #2: 0001-gnu-Add-msgpack.patch --]
[-- Type: text/x-patch, Size: 2166 bytes --]

From e079729d0d2318f218115dfeb046c09a970ba355 Mon Sep 17 00:00:00 2001
From: Lukas Gradl <lgradl@openmailbox.org>
Date: Thu, 2 Jun 2016 19:46:34 -0500
Subject: [PATCH] gnu: Add msgpack.

* gnu/packages/serialization.scm (msgpack): New variable.
---
 gnu/packages/serialization.scm | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/gnu/packages/serialization.scm b/gnu/packages/serialization.scm
index 8dfd21d..0f65a00 100644
--- a/gnu/packages/serialization.scm
+++ b/gnu/packages/serialization.scm
@@ -1,5 +1,6 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2015 Ricardo Wurmus <rekado@elephly.net>
+;;; Copyright © 2016 Lukas Gradl <lgradl@openmailbox.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -21,7 +22,11 @@
   #:use-module (guix packages)
   #:use-module (guix download)
   #:use-module (guix build-system cmake)
+  #:use-module (guix build-system gnu)
   #:use-module (gnu packages)
+  #:use-module (gnu packages autotools)
+  #:use-module (gnu packages check)
+  #:use-module (gnu packages compression)
   #:use-module (gnu packages documentation))
 
 (define-public cereal
@@ -72,3 +77,29 @@
 arbitrary data types and reversibly turns them into different representations,
 such as compact binary encodings, XML, or JSON.")
     (license license:bsd-3)))
+
+
+(define-public msgpack
+  (package
+    (name "msgpack")
+    (version "1.4.1")
+    (source
+     (origin
+       (method url-fetch)
+       (uri
+        (string-append
+         "https://github.com/msgpack/msgpack-c/releases/download/"
+         "cpp-" version "/msgpack-" version ".tar.gz"))
+       (sha256
+        (base32
+         "0bpjfh9vz0n2k93mph3x15clmigkgs223xfn8h12ymrh5gsi5ica"))))
+    (build-system gnu-build-system)
+    (native-inputs
+     `(("googletest" ,googletest)))
+    (inputs
+     `(("zlib" ,zlib)))
+    (home-page "http://www.msgpack.org")
+    (synopsis "Binary serialization library")
+    (description "Msgpack is a library for C/C++ that implements binary
+serialization.")
+    (license license:boost1.0)))
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [PATCH] Add msgpack
  2016-05-30 20:50 [PATCH] Add msgpack Lukas Gradl
  2016-05-31 21:45 ` Leo Famulari
  2016-06-01  4:49 ` Efraim Flashner
@ 2016-06-06 14:07 ` Leo Famulari
  2016-06-11  3:06   ` Leo Famulari
  2 siblings, 1 reply; 25+ messages in thread
From: Leo Famulari @ 2016-06-06 14:07 UTC (permalink / raw)
  To: Lukas Gradl; +Cc: guix-devel

On Mon, May 30, 2016 at 03:50:41PM -0500, Lukas Gradl wrote:
> * gnu/packages/serialization.scm (msgpack): New variable.

> +    (inputs
> +     `(("zlib" ,zlib)))

I noticed that the output does not refer to zlib:

$ guix gc --references $(./pre-inst-env guix build msgpack)
/gnu/store/8m00x5x8ykmar27s9248cmhnkdb2n54a-glibc-2.22
/gnu/store/jh52sklgbvq5f0z637wr99a64y25cx8r-msgpack-1.4.1
/gnu/store/v39bh3ln3ncnzhyw0kd12d46kww9747v-gcc-4.9.3-lib

However, the compilation fails without it.

We need to make sure that msgpack can find zlib at run time. Lukas, can
you check if there is a build-time configuration option to provide the
path to zlib?

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Add msgpack
  2016-06-06 14:07 ` Leo Famulari
@ 2016-06-11  3:06   ` Leo Famulari
  2016-06-11 23:56     ` Lukas Gradl
  0 siblings, 1 reply; 25+ messages in thread
From: Leo Famulari @ 2016-06-11  3:06 UTC (permalink / raw)
  To: Lukas Gradl; +Cc: guix-devel

On Mon, Jun 06, 2016 at 10:07:37AM -0400, Leo Famulari wrote:
> On Mon, May 30, 2016 at 03:50:41PM -0500, Lukas Gradl wrote:
> > * gnu/packages/serialization.scm (msgpack): New variable.
> 
> > +    (inputs
> > +     `(("zlib" ,zlib)))
> 
> I noticed that the output does not refer to zlib:
> 
> $ guix gc --references $(./pre-inst-env guix build msgpack)
> /gnu/store/8m00x5x8ykmar27s9248cmhnkdb2n54a-glibc-2.22
> /gnu/store/jh52sklgbvq5f0z637wr99a64y25cx8r-msgpack-1.4.1
> /gnu/store/v39bh3ln3ncnzhyw0kd12d46kww9747v-gcc-4.9.3-lib
> 
> However, the compilation fails without it.
> 
> We need to make sure that msgpack can find zlib at run time. Lukas, can
> you check if there is a build-time configuration option to provide the
> path to zlib?

This is from the top of the msgpack source tree:
$ grep -rI zlib
include/msgpack/zbuffer.h:#include <zlib.h>
include/msgpack/zbuffer.hpp:#include <zlib.h>

Should we do string substitution to provide the abolute path to the zlib
headers?

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Add msgpack
  2016-06-11  3:06   ` Leo Famulari
@ 2016-06-11 23:56     ` Lukas Gradl
  2016-06-12  0:17       ` Leo Famulari
  0 siblings, 1 reply; 25+ messages in thread
From: Lukas Gradl @ 2016-06-11 23:56 UTC (permalink / raw)
  To: Leo Famulari; +Cc: guix-devel

[-- Attachment #1: Type: text/plain, Size: 2622 bytes --]


Hi,

I am sorry for the long silence, this week was busy and I did not find a
lot of time to look into this.  My apologies for that!

Leo Famulari <leo@famulari.name> writes:

> On Mon, Jun 06, 2016 at 10:07:37AM -0400, Leo Famulari wrote:
>> On Mon, May 30, 2016 at 03:50:41PM -0500, Lukas Gradl wrote:
>> > * gnu/packages/serialization.scm (msgpack): New variable.
>> 
>> > +    (inputs
>> > +     `(("zlib" ,zlib)))
>> 
>> I noticed that the output does not refer to zlib:
>> 
>> $ guix gc --references $(./pre-inst-env guix build msgpack)
>> /gnu/store/8m00x5x8ykmar27s9248cmhnkdb2n54a-glibc-2.22
>> /gnu/store/jh52sklgbvq5f0z637wr99a64y25cx8r-msgpack-1.4.1
>> /gnu/store/v39bh3ln3ncnzhyw0kd12d46kww9747v-gcc-4.9.3-lib
>>

Indeed.  I was not aware of this '--references' before.

>> However, the compilation fails without it.
>>

Specifically, the phase that fails is 'check'.  The phase 'build' passes.

>> We need to make sure that msgpack can find zlib at run time. Lukas, can
>> you check if there is a build-time configuration option to provide the
>> path to zlib?
>
> This is from the top of the msgpack source tree:
> $ grep -rI zlib
> include/msgpack/zbuffer.h:#include <zlib.h>
> include/msgpack/zbuffer.hpp:#include <zlib.h>
>
> Should we do string substitution to provide the abolute path to the zlib
> headers?

This is probably not necessary, since it can find zlib (at compile time)
if zlib is provided as an input, i.e. all phases pass in this case.  I
think the reason for the missing reference is another:

I did:

$ grep -ri "Zlib" .
./include/msgpack/zbuffer.hpp:#include <zlib.h>
./include/msgpack/zbuffer.h:#include <zlib.h>
./CMakeLists.txt:FIND_PACKAGE (ZLIB)
./CMakeLists.txt:IF (GTEST_FOUND AND ZLIB_FOUND AND THREADS_FOUND)
./test/CMakeLists.txt:FIND_PACKAGE (ZLIB REQUIRED)
./test/CMakeLists.txt:    ${ZLIB_INCLUDE_DIRS}
./test/CMakeLists.txt:        ${ZLIB_LIBRARIES}


Cmake is also supported as build system.  I looked into ./CMakeLists.txt
in the top of the source tree and this is the passage that refers to
zlib:


FIND_PACKAGE (GTest)
FIND_PACKAGE (ZLIB)
FIND_PACKAGE (Threads)
IF (GTEST_FOUND AND ZLIB_FOUND AND THREADS_FOUND)
    OPTION (MSGPACK_BUILD_TESTS "Build msgpack tests." ON)
ENDIF ()


It seems that zlib is only required for tests.  In README and README.md
zlib is never  mentioned among the dependencies, which also supports
that it is only needed for tests.  I was not aware of that before (Shame
on me).

I moved zlib from inputs to native-inputs.  An updated patch is
attached.

Sorry for the confusion and thank you very much for your work on this!

Best,
Lukas



[-- Attachment #2: 0001-gnu-Add-msgpack.patch --]
[-- Type: text/x-patch, Size: 2150 bytes --]

From ed3dae4a8f34599c0dc5cf47c26df01adda5a209 Mon Sep 17 00:00:00 2001
From: Lukas Gradl <lgradl@openmailbox.org>
Date: Sat, 11 Jun 2016 18:46:13 -0500
Subject: [PATCH] gnu: Add msgpack.

* gnu/packages/serialization.scm (msgpack): New variable.
---
 gnu/packages/serialization.scm | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/gnu/packages/serialization.scm b/gnu/packages/serialization.scm
index 8dfd21d..9bd5d60 100644
--- a/gnu/packages/serialization.scm
+++ b/gnu/packages/serialization.scm
@@ -1,5 +1,6 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2015 Ricardo Wurmus <rekado@elephly.net>
+;;; Copyright © 2016 Lukas Gradl <lgradl@openmailbox.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -21,7 +22,11 @@
   #:use-module (guix packages)
   #:use-module (guix download)
   #:use-module (guix build-system cmake)
+  #:use-module (guix build-system gnu)
   #:use-module (gnu packages)
+  #:use-module (gnu packages autotools)
+  #:use-module (gnu packages check)
+  #:use-module (gnu packages compression)
   #:use-module (gnu packages documentation))
 
 (define-public cereal
@@ -72,3 +77,28 @@
 arbitrary data types and reversibly turns them into different representations,
 such as compact binary encodings, XML, or JSON.")
     (license license:bsd-3)))
+
+
+(define-public msgpack
+  (package
+    (name "msgpack")
+    (version "1.4.1")
+    (source
+     (origin
+       (method url-fetch)
+       (uri
+        (string-append
+         "https://github.com/msgpack/msgpack-c/releases/download/"
+         "cpp-" version "/msgpack-" version ".tar.gz"))
+       (sha256
+        (base32
+         "0bpjfh9vz0n2k93mph3x15clmigkgs223xfn8h12ymrh5gsi5ica"))))
+    (build-system gnu-build-system)
+    (native-inputs
+     `(("googletest" ,googletest)
+       ("zlib" ,zlib)))
+    (home-page "http://www.msgpack.org")
+    (synopsis "Binary serialization library")
+    (description "Msgpack is a library for C/C++ that implements binary
+serialization.")
+    (license license:boost1.0)))
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [PATCH] Add msgpack
  2016-06-11 23:56     ` Lukas Gradl
@ 2016-06-12  0:17       ` Leo Famulari
  2016-06-12  4:24         ` Lukas Gradl
  0 siblings, 1 reply; 25+ messages in thread
From: Leo Famulari @ 2016-06-12  0:17 UTC (permalink / raw)
  To: Lukas Gradl; +Cc: guix-devel

On Sat, Jun 11, 2016 at 06:56:38PM -0500, Lukas Gradl wrote:
> It seems that zlib is only required for tests.  In README and README.md
> zlib is never  mentioned among the dependencies, which also supports
> that it is only needed for tests.  I was not aware of that before (Shame
> on me).

Is zlib really only required for tests? I see this:

$ grep -rIi zlib /gnu/store/xn8z7k6j7zm4qz14bm29fgk0kwwvz3c4-msgpack-1.4.1
/gnu/store/xn8z7k6j7zm4qz14bm29fgk0kwwvz3c4-msgpack-1.4.1/include/msgpack/zbuffer.h:#include <zlib.h>
/gnu/store/xn8z7k6j7zm4qz14bm29fgk0kwwvz3c4-msgpack-1.4.1/include/msgpack/zbuffer.hpp:#include <zlib.h>

So, there are headers in the msgpack output that require zlib.

If you are at the stage where you are using Ring based on these
packages, I wonder if it is not using the part of msgpack that uses
zlib? Or, if it's finding zlib in the environment (if you are on a
foreign distro)?

Or have I misunderstood?

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Add msgpack
  2016-06-12  0:17       ` Leo Famulari
@ 2016-06-12  4:24         ` Lukas Gradl
  2016-06-13 16:58           ` Leo Famulari
  0 siblings, 1 reply; 25+ messages in thread
From: Lukas Gradl @ 2016-06-12  4:24 UTC (permalink / raw)
  To: Leo Famulari; +Cc: guix-devel

Leo Famulari <leo@famulari.name> writes:

> On Sat, Jun 11, 2016 at 06:56:38PM -0500, Lukas Gradl wrote:
>> It seems that zlib is only required for tests.  In README and README.md
>> zlib is never  mentioned among the dependencies, which also supports
>> that it is only needed for tests.  I was not aware of that before (Shame
>> on me).
>
> Is zlib really only required for tests? I see this:
>
> $ grep -rIi zlib /gnu/store/xn8z7k6j7zm4qz14bm29fgk0kwwvz3c4-msgpack-1.4.1
> /gnu/store/xn8z7k6j7zm4qz14bm29fgk0kwwvz3c4-msgpack-1.4.1/include/msgpack/zbuffer.h:#include <zlib.h>
> /gnu/store/xn8z7k6j7zm4qz14bm29fgk0kwwvz3c4-msgpack-1.4.1/include/msgpack/zbuffer.hpp:#include <zlib.h>
>
> So, there are headers in the msgpack output that require zlib.

Oh, that is true.  I searched around, but I could not find anything
about zbuffer.h[pp].  I am not sure what it is used for.  FWIW, it is
only referenced in src/Makefile, src/Makefile.in, src/Makefile.am
CMakeLists.txt and in the tests:


$ grep -ri zbuffer
src/Makefile:	../include/msgpack/zbuffer.hpp \
src/Makefile:	../include/msgpack/vrefbuffer.h ../include/msgpack/zbuffer.h \
src/Makefile:	../include/msgpack/zbuffer.hpp ../include/msgpack/zone.hpp \
src/Makefile:	../include/msgpack/vrefbuffer.h ../include/msgpack/zbuffer.h \
src/Makefile.in:@ENABLE_CXX_TRUE@	../include/msgpack/zbuffer.hpp \
src/Makefile.in:	../include/msgpack/vrefbuffer.h ../include/msgpack/zbuffer.h \
src/Makefile.in:	../include/msgpack/zbuffer.hpp ../include/msgpack/zone.hpp \
src/Makefile.in:	../include/msgpack/vrefbuffer.h ../include/msgpack/zbuffer.h \
src/Makefile.am:		../include/msgpack/zbuffer.h \
src/Makefile.am:		../include/msgpack/zbuffer.hpp \
ChangeLog:  * Fix zbuffer with empty string problem (#303)
include/msgpack/zbuffer.hpp:#ifndef MSGPACK_ZBUFFER_HPP
include/msgpack/zbuffer.hpp:#define MSGPACK_ZBUFFER_HPP
include/msgpack/zbuffer.hpp:#ifndef MSGPACK_ZBUFFER_RESERVE_SIZE
include/msgpack/zbuffer.hpp:#define MSGPACK_ZBUFFER_RESERVE_SIZE 512
include/msgpack/zbuffer.hpp:#ifndef MSGPACK_ZBUFFER_INIT_SIZE
include/msgpack/zbuffer.hpp:#define MSGPACK_ZBUFFER_INIT_SIZE 8192
include/msgpack/zbuffer.hpp:class zbuffer {
include/msgpack/zbuffer.hpp:    zbuffer(int level = Z_DEFAULT_COMPRESSION,
include/msgpack/zbuffer.hpp:            size_t init_size = MSGPACK_ZBUFFER_INIT_SIZE)
include/msgpack/zbuffer.hpp:    ~zbuffer()
include/msgpack/zbuffer.hpp:            if(m_stream.avail_out < MSGPACK_ZBUFFER_RESERVE_SIZE) {
include/msgpack/zbuffer.hpp:    zbuffer(const zbuffer&);
include/msgpack/zbuffer.hpp:    zbuffer& operator=(const zbuffer&);
include/msgpack/zbuffer.hpp:    zbuffer(const zbuffer&) = delete;
include/msgpack/zbuffer.hpp:    zbuffer& operator=(const zbuffer&) = delete;
include/msgpack/zbuffer.hpp:#endif /* msgpack/zbuffer.hpp */
include/msgpack/zbuffer.h:#ifndef MSGPACK_ZBUFFER_H
include/msgpack/zbuffer.h:#define MSGPACK_ZBUFFER_H
include/msgpack/zbuffer.h: * @defgroup msgpack_zbuffer Compressed buffer
include/msgpack/zbuffer.h:typedef struct msgpack_zbuffer {
include/msgpack/zbuffer.h:} msgpack_zbuffer;
include/msgpack/zbuffer.h:#ifndef MSGPACK_ZBUFFER_INIT_SIZE
include/msgpack/zbuffer.h:#define MSGPACK_ZBUFFER_INIT_SIZE 8192
include/msgpack/zbuffer.h:static inline bool msgpack_zbuffer_init(
include/msgpack/zbuffer.h:    msgpack_zbuffer* zbuf, int level, size_t init_size);
include/msgpack/zbuffer.h:static inline void msgpack_zbuffer_destroy(msgpack_zbuffer* zbuf);
include/msgpack/zbuffer.h:static inline msgpack_zbuffer* msgpack_zbuffer_new(int level, size_t init_size);
include/msgpack/zbuffer.h:static inline void msgpack_zbuffer_free(msgpack_zbuffer* zbuf);
include/msgpack/zbuffer.h:static inline char* msgpack_zbuffer_flush(msgpack_zbuffer* zbuf);
include/msgpack/zbuffer.h:static inline const char* msgpack_zbuffer_data(const msgpack_zbuffer* zbuf);
include/msgpack/zbuffer.h:static inline size_t msgpack_zbuffer_size(const msgpack_zbuffer* zbuf);
include/msgpack/zbuffer.h:static inline bool msgpack_zbuffer_reset(msgpack_zbuffer* zbuf);
include/msgpack/zbuffer.h:static inline void msgpack_zbuffer_reset_buffer(msgpack_zbuffer* zbuf);
include/msgpack/zbuffer.h:static inline char* msgpack_zbuffer_release_buffer(msgpack_zbuffer* zbuf);
include/msgpack/zbuffer.h:#ifndef MSGPACK_ZBUFFER_RESERVE_SIZE
include/msgpack/zbuffer.h:#define MSGPACK_ZBUFFER_RESERVE_SIZE 512
include/msgpack/zbuffer.h:static inline int msgpack_zbuffer_write(void* data, const char* buf, size_t len);
include/msgpack/zbuffer.h:static inline bool msgpack_zbuffer_expand(msgpack_zbuffer* zbuf);
include/msgpack/zbuffer.h:static inline bool msgpack_zbuffer_init(msgpack_zbuffer* zbuf,
include/msgpack/zbuffer.h:    memset(zbuf, 0, sizeof(msgpack_zbuffer));
include/msgpack/zbuffer.h:static inline void msgpack_zbuffer_destroy(msgpack_zbuffer* zbuf)
include/msgpack/zbuffer.h:static inline msgpack_zbuffer* msgpack_zbuffer_new(int level, size_t init_size)
include/msgpack/zbuffer.h:    msgpack_zbuffer* zbuf = (msgpack_zbuffer*)malloc(sizeof(msgpack_zbuffer));
include/msgpack/zbuffer.h:    if(!msgpack_zbuffer_init(zbuf, level, init_size)) {
include/msgpack/zbuffer.h:static inline void msgpack_zbuffer_free(msgpack_zbuffer* zbuf)
include/msgpack/zbuffer.h:    msgpack_zbuffer_destroy(zbuf);
include/msgpack/zbuffer.h:static inline bool msgpack_zbuffer_expand(msgpack_zbuffer* zbuf)
include/msgpack/zbuffer.h:static inline int msgpack_zbuffer_write(void* data, const char* buf, size_t len)
include/msgpack/zbuffer.h:    msgpack_zbuffer* zbuf = (msgpack_zbuffer*)data;
include/msgpack/zbuffer.h:        if(zbuf->stream.avail_out < MSGPACK_ZBUFFER_RESERVE_SIZE) {
include/msgpack/zbuffer.h:            if(!msgpack_zbuffer_expand(zbuf)) {
include/msgpack/zbuffer.h:static inline char* msgpack_zbuffer_flush(msgpack_zbuffer* zbuf)
include/msgpack/zbuffer.h:            if(!msgpack_zbuffer_expand(zbuf)) {
include/msgpack/zbuffer.h:static inline const char* msgpack_zbuffer_data(const msgpack_zbuffer* zbuf)
include/msgpack/zbuffer.h:static inline size_t msgpack_zbuffer_size(const msgpack_zbuffer* zbuf)
include/msgpack/zbuffer.h:static inline void msgpack_zbuffer_reset_buffer(msgpack_zbuffer* zbuf)
include/msgpack/zbuffer.h:static inline bool msgpack_zbuffer_reset(msgpack_zbuffer* zbuf)
include/msgpack/zbuffer.h:    msgpack_zbuffer_reset_buffer(zbuf);
include/msgpack/zbuffer.h:static inline char* msgpack_zbuffer_release_buffer(msgpack_zbuffer* zbuf)
include/msgpack/zbuffer.h:#endif /* msgpack/zbuffer.h */
CMakeLists.txt:    include/msgpack/zbuffer.h
CMakeLists.txt:        include/msgpack/zbuffer.hpp
test/buffer.cpp:#include <msgpack/zbuffer.hpp>
test/buffer.cpp:#include <msgpack/zbuffer.h>
test/buffer.cpp:TEST(buffer, zbuffer)
test/buffer.cpp:    msgpack::zbuffer zbuf;
test/buffer.cpp:TEST(buffer, zbuffer_c)
test/buffer.cpp:    msgpack_zbuffer zbuf;
test/buffer.cpp:    EXPECT_TRUE(msgpack_zbuffer_init(&zbuf, 1, MSGPACK_ZBUFFER_INIT_SIZE));
test/buffer.cpp:    EXPECT_EQ(0, msgpack_zbuffer_write(&zbuf, "a", 1));
test/buffer.cpp:    EXPECT_EQ(0, msgpack_zbuffer_write(&zbuf, "a", 1));
test/buffer.cpp:    EXPECT_EQ(0, msgpack_zbuffer_write(&zbuf, "a", 1));
test/buffer.cpp:    EXPECT_EQ(0, msgpack_zbuffer_write(&zbuf, "", 0));
test/buffer.cpp:    EXPECT_TRUE(msgpack_zbuffer_flush(&zbuf) != NULL);
test/buffer.cpp:    msgpack_zbuffer_destroy(&zbuf);


Judging from this, I am inclined to think that msgpack does not use
these two headers for anything but tests.  But I am not sure about
this.

> If you are at the stage where you are using Ring based on these
> packages, I wonder if it is not using the part of msgpack that uses
> zlib? Or, if it's finding zlib in the environment (if you are on a
> foreign distro)?

I am on GuixSD, but I do not have any packages besides opendht that
would depend on msgpack, yet.  I do not have a working definition for
Ring.  At this point, I do not see any way I could really test if
msgpack works properly with/without zlib.

FWIW, I looked at what other distributions do:

The Arch PKGBUILD does not refer to Zlib at all:
https://git.archlinux.org/svntogit/community.git/tree/trunk/PKGBUILD?h=packages/msgpack-c

Gentoo has Zlib for tests:
https://gitweb.gentoo.org/repo/gentoo.git/tree/dev-libs/msgpack/msgpack-1.1.0.ebuild

Debian seems to not refer to Zlib:
https://packages.debian.org/jessie/libmsgpackc2
https://packages.debian.org/jessie/libmsgpack3
https://packages.debian.org/jessie/libmsgpack-dev

This Nix expression does not mention zlib:
https://github.com/NixOS/nixpkgs/blob/f199be0fafcff0713dd4340b4373e575294aad58/pkgs/development/libraries/libmsgpack/generic.nix#L41


However, all of these seem to be different versions of msgpack.


On one hand, since these distributions seem to not include zlib as a
dependency, maybe zbuffer.h and zbuffer.hpp are not meant to be used or are
seldom used by other projects.  On the other hand msgpack installs these
headers, so they should be useful.

>
> Or have I misunderstood?

No, I missed that.  My mistake.  But I am not sure what to do about
this.

I am working on packaging pjproject now.  After that I think I will have
most of the dependencies of libring.  At that point I could probably
test if msgpack works the way it is now.  I am perfectly fine if we wait
with the inclusion of msgpack until then. What do you think?

Best,
Lukas

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Add msgpack
  2016-06-12  4:24         ` Lukas Gradl
@ 2016-06-13 16:58           ` Leo Famulari
  2016-06-13 17:59             ` Leo Famulari
  0 siblings, 1 reply; 25+ messages in thread
From: Leo Famulari @ 2016-06-13 16:58 UTC (permalink / raw)
  To: Lukas Gradl; +Cc: guix-devel

On Sat, Jun 11, 2016 at 11:24:23PM -0500, Lukas Gradl wrote:
> Oh, that is true.  I searched around, but I could not find anything
> about zbuffer.h[pp].  I am not sure what it is used for.  FWIW, it is
> only referenced in src/Makefile, src/Makefile.in, src/Makefile.am
> CMakeLists.txt and in the tests:

[...]

> Judging from this, I am inclined to think that msgpack does not use
> these two headers for anything but tests.  But I am not sure about
> this.

I think that another application would call the zbuffer functions,
although the string 'zbuffer' does not exist in the opendht source code.
But, we should make sure msgpack will work for other calling
applications that might be added later.

On #guix, bavier suggested we patch 'msgpack.pc.in'. Specifically, we
should append the include flag to 'Cflags:' and create a 'Libs.private:'
field for the -L and -l flags. There are some examples in
'gnu/packages'.

More details on the IRC log:
https://gnunet.org/bot/log/guix/2016-06-13#T1056507

I've cc-ed Eric since I don't know much about pkg-config.

> FWIW, I looked at what other distributions do:
> 
> The Arch PKGBUILD does not refer to Zlib at all:
> https://git.archlinux.org/svntogit/community.git/tree/trunk/PKGBUILD?h=packages/msgpack-c
> 
> Gentoo has Zlib for tests:
> https://gitweb.gentoo.org/repo/gentoo.git/tree/dev-libs/msgpack/msgpack-1.1.0.ebuild
> 
> Debian seems to not refer to Zlib:
> https://packages.debian.org/jessie/libmsgpackc2
> https://packages.debian.org/jessie/libmsgpack3
> https://packages.debian.org/jessie/libmsgpack-dev

I think that zlib is so ubiquitous that it's a safe assumption it will
can be found in the environment on the '/usr' distros.

> This Nix expression does not mention zlib:
> https://github.com/NixOS/nixpkgs/blob/f199be0fafcff0713dd4340b4373e575294aad58/pkgs/development/libraries/libmsgpack/generic.nix#L41

An oversight? I don't know the Nix equivalent of `guix refresh -l` to
check which of their packages use msgpack.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Add msgpack
  2016-06-13 16:58           ` Leo Famulari
@ 2016-06-13 17:59             ` Leo Famulari
  2016-06-17 15:13               ` Lukas Gradl
  0 siblings, 1 reply; 25+ messages in thread
From: Leo Famulari @ 2016-06-13 17:59 UTC (permalink / raw)
  To: Lukas Gradl; +Cc: guix-devel

On Mon, Jun 13, 2016 at 12:58:52PM -0400, Leo Famulari wrote:
> On Sat, Jun 11, 2016 at 11:24:23PM -0500, Lukas Gradl wrote:
> > Oh, that is true.  I searched around, but I could not find anything
> > about zbuffer.h[pp].  I am not sure what it is used for.  FWIW, it is
> > only referenced in src/Makefile, src/Makefile.in, src/Makefile.am
> > CMakeLists.txt and in the tests:
> 
> [...]
> 
> > Judging from this, I am inclined to think that msgpack does not use
> > these two headers for anything but tests.  But I am not sure about
> > this.
> 
> I think that another application would call the zbuffer functions,
> although the string 'zbuffer' does not exist in the opendht source code.
> But, we should make sure msgpack will work for other calling
> applications that might be added later.
> 
> On #guix, bavier suggested we patch 'msgpack.pc.in'. Specifically, we
> should append the include flag to 'Cflags:' and create a 'Libs.private:'
> field for the -L and -l flags. There are some examples in
> 'gnu/packages'.
> 
> More details on the IRC log:
> https://gnunet.org/bot/log/guix/2016-06-13#T1056507
> 
> I've cc-ed Eric since I don't know much about pkg-config.

Of course, I forgot to do this :p

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Add msgpack
  2016-06-13 17:59             ` Leo Famulari
@ 2016-06-17 15:13               ` Lukas Gradl
  2016-06-19  3:44                 ` Lukas Gradl
  2016-06-25 15:31                 ` Leo Famulari
  0 siblings, 2 replies; 25+ messages in thread
From: Lukas Gradl @ 2016-06-17 15:13 UTC (permalink / raw)
  To: Leo Famulari; +Cc: guix-devel

[-- Attachment #1: Type: text/plain, Size: 6084 bytes --]


Hi,

Leo Famulari <leo@famulari.name> writes:

> On Mon, Jun 13, 2016 at 12:58:52PM -0400, Leo Famulari wrote:
>> On Sat, Jun 11, 2016 at 11:24:23PM -0500, Lukas Gradl wrote:
>> > Oh, that is true.  I searched around, but I could not find anything
>> > about zbuffer.h[pp].  I am not sure what it is used for.  FWIW, it is
>> > only referenced in src/Makefile, src/Makefile.in, src/Makefile.am
>> > CMakeLists.txt and in the tests:
>> 
>> [...]
>> 
>> > Judging from this, I am inclined to think that msgpack does not use
>> > these two headers for anything but tests.  But I am not sure about
>> > this.
>> 
>> I think that another application would call the zbuffer functions,
>> although the string 'zbuffer' does not exist in the opendht source code.
>> But, we should make sure msgpack will work for other calling
>> applications that might be added later.

OK, I agree.

>> 
>> On #guix, bavier suggested we patch 'msgpack.pc.in'. Specifically, we
>> should append the include flag to 'Cflags:' and create a 'Libs.private:'
>> field for the -L and -l flags. There are some examples in
>> 'gnu/packages'.
>> 
>> More details on the IRC log:
>> https://gnunet.org/bot/log/guix/2016-06-13#T1056507
>> 
>> I've cc-ed Eric since I don't know much about pkg-config.

Neither do I. 

I have experimented with this a bit.  IIUC, since our zlib provides a
pkg-config file we can generate the the -I flag by adding

---8<--- cut here -------------------- start --->8---
Requires.private: zlib
---8<--- cut here -------------------- end ----->8---

to the msgpack.pc.in file.  This also gives me the -L flag. The -l flag
is only emitted when --static is passed to pkg-config.  I tried to fix
this by adding -lz to Libs.private resulting in:

---8<--- cut here -------------------- start --->8---
lukas@serenity$ guix environment msgpack
lukas@serenity [env]$ cat /gnu/store/gibnvxf2029gxmmxv8bgqilvlagzzskb-msgpack-1.4.1/lib/pkgconfig/msgpack.pc 
prefix=/gnu/store/gibnvxf2029gxmmxv8bgqilvlagzzskb-msgpack-1.4.1
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include

Name: MessagePack
Description: Binary-based efficient object serialization library
Version: 1.4.1
Libs: -L${libdir} -lmsgpackc
Cflags: -I${includedir}
Requires.private: zlib
Libs.private: -lz
lukas@serenity [env]$ pkg-config --libs --cflags /gnu/store/gibnvxf2029gxmmxv8bgqilvlagzzskb-msgpack-1.4.1/lib/pkgconfig/msgpack.pc 
-I/gnu/store/gibnvxf2029gxmmxv8bgqilvlagzzskb-msgpack-1.4.1/include -I/gnu/store/hsxhfmjgh8m4c0pavq3gd3gcrn8zrgxj-zlib-1.2.8/include -L/gnu/store/gibnvxf2029gxmmxv8bgqilvlagzzskb-msgpack-1.4.1/lib -lmsgpackc
lukas@serenity [env]$ pkg-config --libs --cflags --static /gnu/store/gibnvxf2029gxmmxv8bgqilvlagzzskb-msgpack-1.4.1/lib/pkgconfig/msgpack.pc 
-I/gnu/store/gibnvxf2029gxmmxv8bgqilvlagzzskb-msgpack-1.4.1/include -I/gnu/store/hsxhfmjgh8m4c0pavq3gd3gcrn8zrgxj-zlib-1.2.8/include -L/gnu/store/gibnvxf2029gxmmxv8bgqilvlagzzskb-msgpack-1.4.1/lib -L/gnu/store/hsxhfmjgh8m4c0pavq3gd3gcrn8zrgxj-zlib-1.2.8/lib -lmsgpackc -lz
lukas@serenity [env]$ guix gc --references /gnu/store/gibnvxf2029gxmmxv8bgqilvlagzzskb-msgpack-1.4.1
/gnu/store/8m00x5x8ykmar27s9248cmhnkdb2n54a-glibc-2.22
/gnu/store/gibnvxf2029gxmmxv8bgqilvlagzzskb-msgpack-1.4.1
/gnu/store/v39bh3ln3ncnzhyw0kd12d46kww9747v-gcc-4.9.3-lib
lukas@serenity [env]$ 
---8<--- cut here -------------------- end ----->8---

So I still only get the -lz flag for static linking.  I am not sure if
this is what we want, what do you think?

Also, still no store refernece. BTW, where is "guix gc --references"
implemented?  I looked for it but failed to find the actual logic, since
I am not that fluent with Scheme...

From this I think that adding the -lz to Libs.private is redundant if
zlib is in "Requires.private".  But if we want -lz also for dynamic
linking then I think we need to move zlib to "Requires".  I went ahead
and tried that leading to this result:

---8<--- cut here -------------------- start --->8---
lukas@serenity$ guix environment msgpack
lukas@serenity [env]$ cat /gnu/store/9ipfx15i5hbkgq26by13d07i47nmbldp-msgpack-1.4.1/lib/pkgconfig/msgpack.pc 
prefix=/gnu/store/9ipfx15i5hbkgq26by13d07i47nmbldp-msgpack-1.4.1
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include

Name: MessagePack
Description: Binary-based efficient object serialization library
Version: 1.4.1
Libs: -L${libdir} -lmsgpackc
Cflags: -I${includedir}
Requires: zlib
lukas@serenity [env]$ pkg-config --libs --cflags /gnu/store/9ipfx15i5hbkgq26by13d07i47nmbldp-msgpack-1.4.1/lib/pkgconfig/msgpack.pc 
-I/gnu/store/9ipfx15i5hbkgq26by13d07i47nmbldp-msgpack-1.4.1/include -I/gnu/store/hsxhfmjgh8m4c0pavq3gd3gcrn8zrgxj-zlib-1.2.8/include -L/gnu/store/9ipfx15i5hbkgq26by13d07i47nmbldp-msgpack-1.4.1/lib -L/gnu/store/hsxhfmjgh8m4c0pavq3gd3gcrn8zrgxj-zlib-1.2.8/lib -lmsgpackc -lz
lukas@serenity [env]$ pkg-config --libs --cflags --static /gnu/store/9ipfx15i5hbkgq26by13d07i47nmbldp-msgpack-1.4.1/lib/pkgconfig/msgpack.pc 
-I/gnu/store/9ipfx15i5hbkgq26by13d07i47nmbldp-msgpack-1.4.1/include -I/gnu/store/hsxhfmjgh8m4c0pavq3gd3gcrn8zrgxj-zlib-1.2.8/include -L/gnu/store/9ipfx15i5hbkgq26by13d07i47nmbldp-msgpack-1.4.1/lib -L/gnu/store/hsxhfmjgh8m4c0pavq3gd3gcrn8zrgxj-zlib-1.2.8/lib -lmsgpackc -lz
lukas@serenity [env]$ guix gc --references /gnu/store/9ipfx15i5hbkgq26by13d07i47nmbldp-msgpack-1.4.1
/gnu/store/8m00x5x8ykmar27s9248cmhnkdb2n54a-glibc-2.22
/gnu/store/9ipfx15i5hbkgq26by13d07i47nmbldp-msgpack-1.4.1
/gnu/store/v39bh3ln3ncnzhyw0kd12d46kww9747v-gcc-4.9.3-lib
lukas@serenity [env]$ 
---8<--- cut here -------------------- end ----->8---

So the flags -I, -L, -l for zlib are all there for both dynamic and
static linking.  But still no store reference.

A patch for this last case is attached.

IIUC, zlib has to be a propagated input in this case.  Do you agree with
that?

More general, do you think what I did makes sense?  I am not really sure
if -lz is needed for dynamic linking or not.

Also, is it OK to do things like that in a snippet as in the attached
patch?

Thank you for your help!

Best,
Lukas



[-- Attachment #2: 0001-gnu-Add-msgpack.patch --]
[-- Type: text/x-patch, Size: 2846 bytes --]

From cfb8a68cb4e18e3a811e7ae96b7df64fceb8c6c5 Mon Sep 17 00:00:00 2001
From: Lukas Gradl <lgradl@openmailbox.org>
Date: Fri, 17 Jun 2016 10:08:48 -0500
Subject: [PATCH] gnu: Add msgpack.

* gnu/packages/serialization.scm (msgpack): New variable.
---
 gnu/packages/serialization.scm | 50 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 49 insertions(+), 1 deletion(-)

diff --git a/gnu/packages/serialization.scm b/gnu/packages/serialization.scm
index 8dfd21d..085534d 100644
--- a/gnu/packages/serialization.scm
+++ b/gnu/packages/serialization.scm
@@ -1,5 +1,6 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2015 Ricardo Wurmus <rekado@elephly.net>
+;;; Copyright © 2016 Lukas Gradl <lgradl@openmailbox.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -21,8 +22,13 @@
   #:use-module (guix packages)
   #:use-module (guix download)
   #:use-module (guix build-system cmake)
+  #:use-module (guix build-system gnu)
   #:use-module (gnu packages)
-  #:use-module (gnu packages documentation))
+  #:use-module (gnu packages autotools)
+  #:use-module (gnu packages check)
+  #:use-module (gnu packages compression)
+  #:use-module (gnu packages documentation)
+  #:use-module (gnu packages pkg-config))
 
 (define-public cereal
   (package
@@ -72,3 +78,45 @@
 arbitrary data types and reversibly turns them into different representations,
 such as compact binary encodings, XML, or JSON.")
     (license license:bsd-3)))
+
+
+(define-public msgpack
+  (package
+    (name "msgpack")
+    (version "1.4.1")
+    (source
+     (origin
+       (method url-fetch)
+       (uri
+        (string-append
+         "https://github.com/msgpack/msgpack-c/releases/download/"
+         "cpp-" version "/msgpack-" version ".tar.gz"))
+       (snippet
+        '(let ((p (open-file "msgpack.pc.in" "a")))
+           (begin
+             (display
+              (string-append "Requires: " "zlib" "\n") p)
+             (close-output-port p))))
+       (sha256
+        (base32
+         "0bpjfh9vz0n2k93mph3x15clmigkgs223xfn8h12ymrh5gsi5ica"))))
+    (build-system gnu-build-system)
+    (native-inputs
+     `(("googletest" ,googletest)
+       ("autoconf" ,autoconf)
+       ("automake" ,automake)
+       ("libtool" ,libtool)
+       ("pkg-config" ,pkg-config)))
+    (propagated-inputs
+     `(("zlib" ,zlib)))
+    (arguments
+     `(#:phases
+       (modify-phases %standard-phases
+         (add-before 'configure 'autoconf
+           (lambda _
+             (system* "autoreconf" "-vfi"))))))
+    (home-page "http://www.msgpack.org")
+    (synopsis "Binary serialization library")
+    (description "Msgpack is a library for C/C++ that implements binary
+serialization.")
+    (license license:boost1.0)))
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [PATCH] Add msgpack
  2016-06-17 15:13               ` Lukas Gradl
@ 2016-06-19  3:44                 ` Lukas Gradl
  2016-06-20 17:09                   ` Leo Famulari
  2016-06-21  8:38                   ` Ludovic Courtès
  2016-06-25 15:31                 ` Leo Famulari
  1 sibling, 2 replies; 25+ messages in thread
From: Lukas Gradl @ 2016-06-19  3:44 UTC (permalink / raw)
  To: Leo Famulari; +Cc: guix-devel

Lukas Gradl <lgradl@openmailbox.org> writes:

> So the flags -I, -L, -l for zlib are all there for both dynamic and
> static linking.  But still no store reference.

I think the reason why there is no reference is that msgpack uses
zbuffer only for tests.  Before compilation, the file only references
the name "zlib" and does not mention the hash in the path of zlib in the
store.  During compilation (during "check"), this mere name "zlib" gets
somehow resolved to the path of zlib in the store.  The binary file
resulting from compiling zbuffer should therefore contain a reference to
zlib, which should be detectable by guix gc --references.  I think
however, that this binary file does not get installed as it is only used
for tests.  All the files that do get installed in the output path of
msgpack in the store do not contain the hash part of the store-path of
zlib.  They only refer to zlib by name.  IIUC this can not be detected
by guix gc --references since it only searches for the hash part of
the store-path of zlib.

This is what I grasp from looking at libstore/references.cc and
libstore/store-api.cc.  I am not sure about this though.

Best,
Lukas

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Add msgpack
  2016-06-19  3:44                 ` Lukas Gradl
@ 2016-06-20 17:09                   ` Leo Famulari
  2016-06-21 13:55                     ` Lukas Gradl
  2016-06-21 15:59                     ` Lukas Gradl
  2016-06-21  8:38                   ` Ludovic Courtès
  1 sibling, 2 replies; 25+ messages in thread
From: Leo Famulari @ 2016-06-20 17:09 UTC (permalink / raw)
  To: Lukas Gradl; +Cc: guix-devel

On Sat, Jun 18, 2016 at 10:44:16PM -0500, Lukas Gradl wrote:
> Lukas Gradl <lgradl@openmailbox.org> writes:
> 
> > So the flags -I, -L, -l for zlib are all there for both dynamic and
> > static linking.  But still no store reference.
> 
> I think the reason why there is no reference is that msgpack uses
> zbuffer only for tests.  Before compilation, the file only references
> the name "zlib" and does not mention the hash in the path of zlib in the
> store.  During compilation (during "check"), this mere name "zlib" gets
> somehow resolved to the path of zlib in the store.  The binary file
> resulting from compiling zbuffer should therefore contain a reference to
> zlib, which should be detectable by guix gc --references.  I think
> however, that this binary file does not get installed as it is only used
> for tests.  All the files that do get installed in the output path of
> msgpack in the store do not contain the hash part of the store-path of
> zlib.  They only refer to zlib by name.  IIUC this can not be detected
> by guix gc --references since it only searches for the hash part of
> the store-path of zlib.
> 
> This is what I grasp from looking at libstore/references.cc and
> libstore/store-api.cc.  I am not sure about this though.

That's my understanding as well.

Thanks for trying all the things you described in your previous email.

Since we are still stuck on this, I think we should continue with Ring
and see if this becomes a problem later on. If so, let's contact the
msgpack maintainers and ask for advice.

We should add a caveat in a comment in msgpack's package definition, for
future readers.

I'm curious — how close are you to a Ring package definition?

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Add msgpack
  2016-06-19  3:44                 ` Lukas Gradl
  2016-06-20 17:09                   ` Leo Famulari
@ 2016-06-21  8:38                   ` Ludovic Courtès
  2016-06-21 13:31                     ` Lukas Gradl
  1 sibling, 1 reply; 25+ messages in thread
From: Ludovic Courtès @ 2016-06-21  8:38 UTC (permalink / raw)
  To: Lukas Gradl; +Cc: guix-devel

Hello!

Sorry for the late reply, but…

Lukas Gradl <lgradl@openmailbox.org> skribis:

> All the files that do get installed in the output path of
> msgpack in the store do not contain the hash part of the store-path of
> zlib.  They only refer to zlib by name.

What kind of files are these, and how do they refer to zlib exactly?

(I’m curious, but this shouldn’t block the process, as Leo wrote.)

Thanks,
Ludo’.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Add msgpack
  2016-06-21  8:38                   ` Ludovic Courtès
@ 2016-06-21 13:31                     ` Lukas Gradl
  2016-06-21 14:11                       ` Ludovic Courtès
  0 siblings, 1 reply; 25+ messages in thread
From: Lukas Gradl @ 2016-06-21 13:31 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: guix-devel


Hi,

ludo@gnu.org (Ludovic Courtès) writes:

> Hello!
>
> Sorry for the late reply, but…
>
> Lukas Gradl <lgradl@openmailbox.org> skribis:
>
>> All the files that do get installed in the output path of
>> msgpack in the store do not contain the hash part of the store-path of
>> zlib.  They only refer to zlib by name.
>
> What kind of files are these, and how do they refer to zlib exactly?
>
> (I’m curious, but this shouldn’t block the process, as Leo wrote.)

It is a C Header file and a corresponding C++ Header file
(include/msgpack/zbuffer.h[pp]).  They refer to zlib by just doing:

#include <zlib.h>

These two files do get installed in the store, but their compiled
counterparts do not.



Thinking out loud, we could possibly force the creation of a reference to
zlib by putting the path of the zlib used when building the package into
a comment or a seperate file.
On the other hand, I am not so sure if we really want a reference, since,
as you said, they are for run-time dependencies.  Since msgpack itself
does not use zbuffer at run-time (only at build time for tests) and does
not provide a library including zbuffer for other packages to link
against, the files zbuffer.h[pp] are really not used at run-time.  The
only time that I can think of when these files could be used is during
the build of a dependent package that wants to include these files.
Propagating zlib would assure that zlib is available whenever
zbuffer.h[pp] gets included by some other package.  Maybe this is the
right way to represent the situation?

Best,
Lukas

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Add msgpack
  2016-06-20 17:09                   ` Leo Famulari
@ 2016-06-21 13:55                     ` Lukas Gradl
  2016-06-21 16:06                       ` Leo Famulari
  2016-06-21 15:59                     ` Lukas Gradl
  1 sibling, 1 reply; 25+ messages in thread
From: Lukas Gradl @ 2016-06-21 13:55 UTC (permalink / raw)
  To: Leo Famulari; +Cc: guix-devel

[-- Attachment #1: Type: text/plain, Size: 2143 bytes --]

Leo Famulari <leo@famulari.name> writes:

> On Sat, Jun 18, 2016 at 10:44:16PM -0500, Lukas Gradl wrote:
>> Lukas Gradl <lgradl@openmailbox.org> writes:
>> 
>> > So the flags -I, -L, -l for zlib are all there for both dynamic and
>> > static linking.  But still no store reference.
>> 
>> I think the reason why there is no reference is that msgpack uses
>> zbuffer only for tests.  Before compilation, the file only references
>> the name "zlib" and does not mention the hash in the path of zlib in the
>> store.  During compilation (during "check"), this mere name "zlib" gets
>> somehow resolved to the path of zlib in the store.  The binary file
>> resulting from compiling zbuffer should therefore contain a reference to
>> zlib, which should be detectable by guix gc --references.  I think
>> however, that this binary file does not get installed as it is only used
>> for tests.  All the files that do get installed in the output path of
>> msgpack in the store do not contain the hash part of the store-path of
>> zlib.  They only refer to zlib by name.  IIUC this can not be detected
>> by guix gc --references since it only searches for the hash part of
>> the store-path of zlib.
>> 
>> This is what I grasp from looking at libstore/references.cc and
>> libstore/store-api.cc.  I am not sure about this though.
>
> That's my understanding as well.
>
> Thanks for trying all the things you described in your previous email.
>
> Since we are still stuck on this, I think we should continue with Ring
> and see if this becomes a problem later on. If so, let's contact the
> msgpack maintainers and ask for advice.

OK, sounds good.

>
> We should add a caveat in a comment in msgpack's package definition, for
> future readers.

I added a comment in the attached patch.

>
> I'm curious — how close are you to a Ring package definition?

Yes, packaging Ring is taking longer than I expected (on my side that
is).  I will send a detailed update within the next two hours.

Thank you for all your work on this.  I would have never even noticed
that issue!  Thank you!

Best,
Lukas


[-- Attachment #2: 0001-gnu-Add-msgpack.patch --]
[-- Type: text/x-patch, Size: 3069 bytes --]

From ae4a2a66b39059463eb16b8094e2d598249bf9c6 Mon Sep 17 00:00:00 2001
From: Lukas Gradl <lgradl@openmailbox.org>
Date: Tue, 21 Jun 2016 08:46:15 -0500
Subject: [PATCH] gnu: Add msgpack.

* gnu/packages/serialization.scm (msgpack): New variable.
---
 gnu/packages/serialization.scm | 53 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 52 insertions(+), 1 deletion(-)

diff --git a/gnu/packages/serialization.scm b/gnu/packages/serialization.scm
index 8dfd21d..6ab0d59 100644
--- a/gnu/packages/serialization.scm
+++ b/gnu/packages/serialization.scm
@@ -1,5 +1,6 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2015 Ricardo Wurmus <rekado@elephly.net>
+;;; Copyright © 2016 Lukas Gradl <lgradl@openmailbox.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -21,8 +22,13 @@
   #:use-module (guix packages)
   #:use-module (guix download)
   #:use-module (guix build-system cmake)
+  #:use-module (guix build-system gnu)
   #:use-module (gnu packages)
-  #:use-module (gnu packages documentation))
+  #:use-module (gnu packages autotools)
+  #:use-module (gnu packages check)
+  #:use-module (gnu packages compression)
+  #:use-module (gnu packages documentation)
+  #:use-module (gnu packages pkg-config))
 
 (define-public cereal
   (package
@@ -72,3 +78,48 @@
 arbitrary data types and reversibly turns them into different representations,
 such as compact binary encodings, XML, or JSON.")
     (license license:bsd-3)))
+
+
+(define-public msgpack
+  (package
+    (name "msgpack")
+    (version "1.4.1")
+    (source
+     (origin
+       (method url-fetch)
+       (uri
+        (string-append
+         "https://github.com/msgpack/msgpack-c/releases/download/"
+         "cpp-" version "/msgpack-" version ".tar.gz"))
+       (snippet
+        '(let ((p (open-file "msgpack.pc.in" "a")))
+           (begin
+             (display
+              (string-append "Requires: " "zlib" "\n") p)
+             (close-output-port p))))
+       (sha256
+        (base32
+         "0bpjfh9vz0n2k93mph3x15clmigkgs223xfn8h12ymrh5gsi5ica"))))
+    (build-system gnu-build-system)
+    (native-inputs
+     `(("googletest" ,googletest)
+       ("autoconf" ,autoconf)
+       ("automake" ,automake)
+       ("libtool" ,libtool)
+       ("pkg-config" ,pkg-config)))
+    (propagated-inputs
+     `(("zlib" ,zlib))) ;; Msgpack installs two headers (zbuffer.h,
+    ;; zbuffer.hpp) which #include <zlib.h>.  However, 'guix gc --references'
+    ;; does not detect a store reference to zlib since these headers are not
+    ;; compiled. 
+    (arguments
+     `(#:phases
+       (modify-phases %standard-phases
+         (add-before 'configure 'autoconf
+           (lambda _
+             (system* "autoreconf" "-vfi"))))))
+    (home-page "http://www.msgpack.org")
+    (synopsis "Binary serialization library")
+    (description "Msgpack is a library for C/C++ that implements binary
+serialization.")
+    (license license:boost1.0)))
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [PATCH] Add msgpack
  2016-06-21 13:31                     ` Lukas Gradl
@ 2016-06-21 14:11                       ` Ludovic Courtès
  0 siblings, 0 replies; 25+ messages in thread
From: Ludovic Courtès @ 2016-06-21 14:11 UTC (permalink / raw)
  To: Lukas Gradl; +Cc: guix-devel

Hello!

Lukas Gradl <lgradl@openmailbox.org> skribis:

> ludo@gnu.org (Ludovic Courtès) writes:
>
>> Hello!
>>
>> Sorry for the late reply, but…
>>
>> Lukas Gradl <lgradl@openmailbox.org> skribis:
>>
>>> All the files that do get installed in the output path of
>>> msgpack in the store do not contain the hash part of the store-path of
>>> zlib.  They only refer to zlib by name.
>>
>> What kind of files are these, and how do they refer to zlib exactly?
>>
>> (I’m curious, but this shouldn’t block the process, as Leo wrote.)
>
> It is a C Header file and a corresponding C++ Header file
> (include/msgpack/zbuffer.h[pp]).  They refer to zlib by just doing:
>
> #include <zlib.h>
>
> These two files do get installed in the store, but their compiled
> counterparts do not.

OK, this is a justification for putting zlib in ‘propagated-inputs’
rather than ‘inputs’ (the manual mentions this as one of the valid
justifications for ‘propagated-inputs’ (info "(guix) package Reference")).
It is worth adding a margin comment with this explanation.

> Thinking out loud, we could possibly force the creation of a reference to
> zlib by putting the path of the zlib used when building the package into
> a comment or a seperate file.
> On the other hand, I am not so sure if we really want a reference, since,
> as you said, they are for run-time dependencies.  Since msgpack itself
> does not use zbuffer at run-time (only at build time for tests) and does
> not provide a library including zbuffer for other packages to link
> against, the files zbuffer.h[pp] are really not used at run-time.  The
> only time that I can think of when these files could be used is during
> the build of a dependent package that wants to include these files.
> Propagating zlib would assure that zlib is available whenever
> zbuffer.h[pp] gets included by some other package.  Maybe this is the
> right way to represent the situation?

It is.  :-)

Thanks for explaining!

Ludo’.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Add msgpack
  2016-06-20 17:09                   ` Leo Famulari
  2016-06-21 13:55                     ` Lukas Gradl
@ 2016-06-21 15:59                     ` Lukas Gradl
  2016-06-21 16:49                       ` Efraim Flashner
  2016-06-22  5:56                       ` Lukas Gradl
  1 sibling, 2 replies; 25+ messages in thread
From: Lukas Gradl @ 2016-06-21 15:59 UTC (permalink / raw)
  To: Leo Famulari; +Cc: guix-devel

Leo Famulari <leo@famulari.name> writes:

> I'm curious — how close are you to a Ring package definition?


According to
https://tuleap.ring.cx/plugins/mediawiki/wiki/ring/index.php/Build_Instructions,
Ring is divided into three Layers:
 * Libring (or ring-daemon)
 * LibringClient
 * Clints

I have a work-in-progress definition for libring, I have not started
working on the other layers yet.  I will clean up the wip-patches that I
have and send them them later today.

At the moment I am still tracking down (i.e. unbundling) dependencies
for libring.  At the moment I am working on pjptoject which is one of
the "main" dependencies according to this:
https://ring.cx/en/about/technical#Libraries

There are some more dependencies that might be needed, that I noticed
when looking at librings contrib directory.  This inputs field reflects
all the dependencies from libring's contrib:

      (inputs
       `(("ffmpeg" ,ffmpeg)
         ("flac" ,flac)
         ("libgcrypt" ,libgcrypt)
         ("gmp" ,gmp)
        ; ("gnutls" ,gnutls) ; Maybe not needed as already used by inputs
         ("libgpg-error" ,libgpg-error)
        ; ("gsm" ,gsm)  ; not found
         ("libiax2" ,libiax2)
         ("libiconv" ,libiconv)
         ("jack" ,jack-1)
        ; ("json-c" ,json-c) ; not found
        ; ("msgpack" ,msgpack) ; maybe not needed as used by inputs (opendht)
        ; ("nettle" ,nettle) ; maybe not needed (only certain proprietary OSes?)
         ("libogg" ,libogg)
         ("opendht" ,opendht)
         ("opus" ,opus)
         ("pcre" ,pcre)
        ; ("pjproject" ,pjproject-for-libring) ; not found, WIP
        ; ("pkg-static" ,pkg-static) ; not found
         ("portaudio" ,portaudio)
         ("libsamplerate" ,libsamplerate)
         ("libsndfile" ,libsndfile)
         ("speex" ,speex)
        ; ("speexdsp" ,speexdsp)
         ("libupnp" ,libupnp)
        ; ("uuid" ,uuid) ; not found, maybe not needed (only certain proprietary OSes?)
         ("libvorbis" ,libvorbis)
         ("libvpx" ,libvpx)
         ("libx264" ,libx264)
        ; ("yaml-cpp" ,yaml-cpp) ;not found
         ("zlib" ,zlib))) ; maybe not needed as used by inputs


Sorry for the format, I will send a real patch later today.  The ones
that are commented above have some issue that needs to be resolved.

I don't really have a lot of time to work on this so progress has been
slow.  Sorry for that.

As I said I will post two patches later (pjproject & libring).  Any help
on those or some of the missing inputs is of course greatly appreciated!


Sorry for the delay!
Best,
Lukas

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Add msgpack
  2016-06-21 13:55                     ` Lukas Gradl
@ 2016-06-21 16:06                       ` Leo Famulari
  0 siblings, 0 replies; 25+ messages in thread
From: Leo Famulari @ 2016-06-21 16:06 UTC (permalink / raw)
  To: Lukas Gradl; +Cc: guix-devel

On Tue, Jun 21, 2016 at 08:55:45AM -0500, Lukas Gradl wrote:
> Leo Famulari <leo@famulari.name> writes:
> > I'm curious — how close are you to a Ring package definition?
> 
> Yes, packaging Ring is taking longer than I expected (on my side that
> is).  I will send a detailed update within the next two hours.

I didn't mean to make you feel rushed. I was just curious :)

> Thank you for all your work on this.  I would have never even noticed
> that issue!  Thank you!

Thank *you* for working on it, too!

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Add msgpack
  2016-06-21 15:59                     ` Lukas Gradl
@ 2016-06-21 16:49                       ` Efraim Flashner
  2016-06-22  6:05                         ` Lukas Gradl
  2016-06-22  5:56                       ` Lukas Gradl
  1 sibling, 1 reply; 25+ messages in thread
From: Efraim Flashner @ 2016-06-21 16:49 UTC (permalink / raw)
  To: Lukas Gradl; +Cc: guix-devel

[-- Attachment #1: Type: text/plain, Size: 3259 bytes --]

On Tue, Jun 21, 2016 at 10:59:06AM -0500, Lukas Gradl wrote:
> Leo Famulari <leo@famulari.name> writes:
> 
> > I'm curious — how close are you to a Ring package definition?
> 
> 
> According to
> https://tuleap.ring.cx/plugins/mediawiki/wiki/ring/index.php/Build_Instructions,
> Ring is divided into three Layers:
>  * Libring (or ring-daemon)
>  * LibringClient
>  * Clints
> 
> I have a work-in-progress definition for libring, I have not started
> working on the other layers yet.  I will clean up the wip-patches that I
> have and send them them later today.
> 
> At the moment I am still tracking down (i.e. unbundling) dependencies
> for libring.  At the moment I am working on pjptoject which is one of
> the "main" dependencies according to this:
> https://ring.cx/en/about/technical#Libraries
> 
> There are some more dependencies that might be needed, that I noticed
> when looking at librings contrib directory.  This inputs field reflects
> all the dependencies from libring's contrib:
> 
>       (inputs
>        `(("ffmpeg" ,ffmpeg)
>          ("flac" ,flac)
>          ("libgcrypt" ,libgcrypt)
>          ("gmp" ,gmp)
>         ; ("gnutls" ,gnutls) ; Maybe not needed as already used by inputs
>          ("libgpg-error" ,libgpg-error)
>         ; ("gsm" ,gsm)  ; not found
>          ("libiax2" ,libiax2)
>          ("libiconv" ,libiconv)
>          ("jack" ,jack-1)
>         ; ("json-c" ,json-c) ; not found

there's a json-c in web.scm

>         ; ("msgpack" ,msgpack) ; maybe not needed as used by inputs (opendht)
>         ; ("nettle" ,nettle) ; maybe not needed (only certain proprietary OSes?)
>          ("libogg" ,libogg)
>          ("opendht" ,opendht)
>          ("opus" ,opus)
>          ("pcre" ,pcre)
>         ; ("pjproject" ,pjproject-for-libring) ; not found, WIP
>         ; ("pkg-static" ,pkg-static) ; not found
>          ("portaudio" ,portaudio)
>          ("libsamplerate" ,libsamplerate)
>          ("libsndfile" ,libsndfile)
>          ("speex" ,speex)
>         ; ("speexdsp" ,speexdsp)
>          ("libupnp" ,libupnp)
>         ; ("uuid" ,uuid) ; not found, maybe not needed (only certain proprietary OSes?)

try util-linux for this one

>          ("libvorbis" ,libvorbis)
>          ("libvpx" ,libvpx)
>          ("libx264" ,libx264)
>         ; ("yaml-cpp" ,yaml-cpp) ;not found

there's a libyaml in web.scm. not exactly yaml-cpp in name, but it might
be close enough

>          ("zlib" ,zlib))) ; maybe not needed as used by inputs
> 
> 
> Sorry for the format, I will send a real patch later today.  The ones
> that are commented above have some issue that needs to be resolved.
> 
> I don't really have a lot of time to work on this so progress has been
> slow.  Sorry for that.
> 
> As I said I will post two patches later (pjproject & libring).  Any help
> on those or some of the missing inputs is of course greatly appreciated!
> 
> 
> Sorry for the delay!
> Best,
> Lukas
> 

keep up the great work!

-- 
Efraim Flashner   <efraim@flashner.co.il>   אפרים פלשנר
GPG key = A28B F40C 3E55 1372 662D  14F7 41AA E7DC CA3D 8351
Confidentiality cannot be guaranteed on emails sent or received unencrypted

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Add msgpack
  2016-06-21 15:59                     ` Lukas Gradl
  2016-06-21 16:49                       ` Efraim Flashner
@ 2016-06-22  5:56                       ` Lukas Gradl
  1 sibling, 0 replies; 25+ messages in thread
From: Lukas Gradl @ 2016-06-22  5:56 UTC (permalink / raw)
  To: Leo Famulari; +Cc: guix-devel

[-- Attachment #1: Type: text/plain, Size: 1248 bytes --]

Lukas Gradl <lgradl@openmailbox.org> writes:

> As I said I will post two patches later (pjproject & libring).  Any help
> on those or some of the missing inputs is of course greatly appreciated!

Here they are!


pjproject still fails to build one of its components (pjmedia) because
of a missing include (resamplesubs.h).  I almost have a package
providing that header.

I am not super happy with the fact that this is a special package
dedicated to libring.  There are a lot of patches that ship with
libring's bundeled version of pjproject.  These patches are nice
(e.g. gnutls instead of openssl), but they fail on the most recent
release 2.5.1 of pjproject and I have no idea in what way they affect
other software that might want to use pjproject (I think Asterisk would
be an example of this).  I will try to remove some of the constraints on
pjproject that are imposed by libring without breaking anything, but
first I want to get it to build and we might end up needing another
seperate definition for a "normal" pjproject.


The patch for libring is mostly just to keep track of dependencies right
now; it fails during 'configure (when it is looking for pjproject :-))


Any comments are very much appreciated!

Thank you!
Best,
Lukas



[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-gnu-Add-libring.patch --]
[-- Type: text/x-patch, Size: 4619 bytes --]

From ecc5faebb7586e4d8e080c9cd08ea0367157c63c Mon Sep 17 00:00:00 2001
From: Lukas Gradl <lgradl@openmailbox.org>
Date: Wed, 22 Jun 2016 00:31:43 -0500
Subject: [PATCH] gnu: Add libring.

* gnu/packages/telephony.scm (libring): New variable.
---
 gnu/packages/telephony.scm | 84 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 84 insertions(+)

diff --git a/gnu/packages/telephony.scm b/gnu/packages/telephony.scm
index e4668cf..35a18c7 100644
--- a/gnu/packages/telephony.scm
+++ b/gnu/packages/telephony.scm
@@ -24,16 +24,28 @@
   #:use-module (gnu packages)
   #:use-module (gnu packages audio)
   #:use-module (gnu packages autotools)
+  #:use-module (gnu packages base)
+  #:use-module (gnu packages compression)
+  #:use-module (gnu packages crypto)
   #:use-module (gnu packages gnupg)
+  #:use-module (gnu packages libupnp)
   #:use-module (gnu packages linux)
+  #:use-module (gnu packages multiprecision)
+  #:use-module (gnu packages nettle)
+  #:use-module (gnu packages pcre)
   #:use-module (gnu packages pkg-config)
   #:use-module (gnu packages pulseaudio)
   #:use-module (gnu packages python)
+  #:use-module (gnu packages readline)
+  #:use-module (gnu packages serialization)
   #:use-module (gnu packages tls)
+  #:use-module (gnu packages video)
+  #:use-module (gnu packages web)
   #:use-module (gnu packages xiph)
   #:use-module (guix licenses)
   #:use-module (guix packages)
   #:use-module (guix download)
+  #:use-module (guix git-download)
   #:use-module (guix build-system gnu))
 
 (define-public commoncpp
@@ -358,3 +370,75 @@ Initiation Protocol (SIP) and a multimedia framework.
 This package is intended for use with libring.  There are several custom
 patches, most notably the use of gnutls instead of openssl for encryption.")
     (license gpl2+)))
+
+
+
+(define-public libring
+  (let ((commit "3dbedf53e9cceebb1eed155b5143026f6d253cb8")) ; tagged 2.2.0
+    (package
+      (name "libring")
+      (version (string-append "2.2.0-1." (string-take commit 7)))
+      (source
+       (origin
+         (method git-fetch)
+         (uri (git-reference
+               (url "https://gerrit-ring.savoirfairelinux.com/ring-daemon.git")
+               (commit commit)))
+         (file-name (string-append name "-" version "-checkout"))
+         (modules '((guix build utils)))
+         (snippet
+          '(begin
+             (delete-file-recursively "contrib")))
+         (sha256
+          (base32
+           "1xnvkv0h24zr1dcmp7djjhqgzvrwic242jy4hb3m5qv71azvcsqg"))))
+      (build-system gnu-build-system)
+      (inputs
+       `(("ffmpeg" ,ffmpeg)
+         ("flac" ,flac)
+         ("libgcrypt" ,libgcrypt)
+         ("gmp" ,gmp)
+        ; ("gnutls" ,gnutls) ; Maybe not needed as already used by inputs
+         ("libgpg-error" ,libgpg-error)
+        ; ("gsm" ,gsm)  ; not found
+         ("libiax2" ,libiax2)
+         ("libiconv" ,libiconv)
+         ("jack" ,jack-1)
+        ; ("msgpack" ,msgpack) ; maybe not needed as used by inputs (opendht)
+        ; ("nettle" ,nettle) ; maybe not needed (only certain proprietary OSes?)
+         ("libogg" ,libogg)
+         ("opendht" ,opendht)
+         ("opus" ,opus)
+         ("pcre" ,pcre)
+        ; ("pjproject" ,pjproject-for-libring) ; not found, WIP
+        ; ("pkg-static" ,pkg-static) ; not found
+         ("portaudio" ,portaudio)
+         ("libsamplerate" ,libsamplerate)
+         ("libsndfile" ,libsndfile)
+         ("speex" ,speex)
+        ; ("speexdsp" ,speexdsp)
+         ("libupnp" ,libupnp)
+        ; ("uuid" ,uuid) ; not found, maybe not needed (only certain proprietary OSes?)
+         ("libvorbis" ,libvorbis)
+         ("libvpx" ,libvpx)
+         ("libx264" ,libx264)
+        ; ("yaml-cpp" ,yaml-cpp) ;not found
+         ("zlib" ,zlib))) ; maybe not needed as used by inputs
+      (native-inputs
+       `(("autoconf" ,autoconf)
+         ("pkg-config" ,pkg-config)
+         ("automake" ,automake)
+         ("libtool" ,libtool)))
+      (arguments
+       `(#:phases
+         (modify-phases %standard-phases
+           (add-before 'configure 'autoconf
+             (lambda _
+               (zero? (system* "autoreconf" "-vfi")))))))
+      (synopsis "Distributed multimedia communications platform")
+      (description "Ring is a secure and distributed voice, video and chat
+communication platform that requires no centralized server and leaves the
+power of privacy in the hands of the user.  It supports the SIP and IAX
+protocols, as well as decentralized calling using P2P-DHT.")
+      (home-page "https://ring.cx/")
+      (license gpl3+))))
-- 
2.7.4


[-- Attachment #3: 0001-gnu-Add-pjproject.patch --]
[-- Type: text/x-patch, Size: 141264 bytes --]

From 909dbecc19da3a65a91e3d45750be63d400760fb Mon Sep 17 00:00:00 2001
From: Lukas Gradl <lgradl@openmailbox.org>
Date: Wed, 22 Jun 2016 00:21:21 -0500
Subject: [PATCH] gnu: Add pjproject.

* gnu/packages/patches/pjproject-endianness.patch: New file.
* gnu/packages/patches/pjproject-errno.patch: New file.
* gnu/packages/patches/pjproject-ice-config.patch: New file.
* gnu/packages/patches/pjproject-ice-sess.patch: New file.
* gnu/packages/patches/pjproject-ipv6.patch: New file.
* gnu/packages/patches/pjproject-multiple-listeners.patch: New file.
* gnu/packages/patches/pjproject-no-test-apps.patch: New file.
* gnu/packages/patches/pjproject-use-gnutls.patch: New file.
* gnu/local.mk (dist_patch_DATA): Add them.
* gnu/packages/telephony.scm (pjproject): New variable.
---
 gnu/local.mk                                       |    8 +
 gnu/packages/patches/pjproject-endianness.patch    |   19 +
 gnu/packages/patches/pjproject-errno.patch         |   13 +
 gnu/packages/patches/pjproject-ice-config.patch    |   23 +
 gnu/packages/patches/pjproject-ice-sess.patch      |   22 +
 gnu/packages/patches/pjproject-ipv6.patch          |   11 +
 .../patches/pjproject-multiple-listeners.patch     |   66 +
 gnu/packages/patches/pjproject-no-test-apps.patch  |   97 +
 gnu/packages/patches/pjproject-use-gnutls.patch    | 3380 ++++++++++++++++++++
 gnu/packages/telephony.scm                         |  106 +
 10 files changed, 3745 insertions(+)
 create mode 100644 gnu/packages/patches/pjproject-endianness.patch
 create mode 100644 gnu/packages/patches/pjproject-errno.patch
 create mode 100644 gnu/packages/patches/pjproject-ice-config.patch
 create mode 100644 gnu/packages/patches/pjproject-ice-sess.patch
 create mode 100644 gnu/packages/patches/pjproject-ipv6.patch
 create mode 100644 gnu/packages/patches/pjproject-multiple-listeners.patch
 create mode 100644 gnu/packages/patches/pjproject-no-test-apps.patch
 create mode 100644 gnu/packages/patches/pjproject-use-gnutls.patch

diff --git a/gnu/local.mk b/gnu/local.mk
index 86b56d4..784afc7 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -682,6 +682,14 @@ dist_patch_DATA =						\
   %D%/packages/patches/pinball-src-deps.patch			\
   %D%/packages/patches/pinball-system-ltdl.patch		\
   %D%/packages/patches/pingus-sdl-libs-config.patch		\
+  %D%/packages/patches/pjproject-endianness.patch		\
+  %D%/packages/patches/pjproject-errno.patch			\
+  %D%/packages/patches/pjproject-ice-config.patch		\
+  %D%/packages/patches/pjproject-ice-sess.patch			\
+  %D%/packages/patches/pjproject-ipv6.patch			\
+  %D%/packages/patches/pjproject-multiple-listeners.patch	\
+  %D%/packages/patches/pjproject-no-test-apps.patch		\
+  %D%/packages/patches/pjproject-use-gnutls.patch		\
   %D%/packages/patches/plink-1.07-unclobber-i.patch		\
   %D%/packages/patches/plotutils-libpng-jmpbuf.patch		\
   %D%/packages/patches/polkit-drop-test.patch			\
diff --git a/gnu/packages/patches/pjproject-endianness.patch b/gnu/packages/patches/pjproject-endianness.patch
new file mode 100644
index 0000000..84b9499
--- /dev/null
+++ b/gnu/packages/patches/pjproject-endianness.patch
@@ -0,0 +1,19 @@
+diff --git a/pjlib/include/pj/config.h b/pjlib/include/pj/config.h
+index 10f86fd..4ace1bc 100644
+--- a/pjlib/include/pj/config.h
++++ b/pjlib/include/pj/config.h
+@@ -245,7 +245,13 @@
+ #   define PJ_M_NAME		"armv4"
+ #   define PJ_HAS_PENTIUM	0
+ #   if !PJ_IS_LITTLE_ENDIAN && !PJ_IS_BIG_ENDIAN
+-#   	error Endianness must be declared for this processor
++#       if defined(__GNUC__)
++#           include <endian.h>
++#           define PJ_IS_LITTLE_ENDIAN  __BYTE_ORDER__ == __LITTLE_ENDIAN__
++#           define PJ_IS_BIG_ENDIAN     __BYTE_ORDER__ == __BIG_ENDIAN__
++#       else
++#           error Endianness must be declared for this processor
++#       endif
+ #   endif
+ 
+ #elif defined (PJ_M_POWERPC) || defined(__powerpc) || defined(__powerpc__) || \
diff --git a/gnu/packages/patches/pjproject-errno.patch b/gnu/packages/patches/pjproject-errno.patch
new file mode 100644
index 0000000..357fb19
--- /dev/null
+++ b/gnu/packages/patches/pjproject-errno.patch
@@ -0,0 +1,13 @@
+--- pjproject/pjlib/include/pj/errno.h	2013-04-04 23:02:19.000000000 -0400
++++ pjproject/pjlib/include/pj/errno.h	2015-02-27 12:21:24.171567801 -0500
+@@ -432,6 +432,11 @@
+  * Socket is stopped
+  */
+ #define PJ_ESOCKETSTOP	    (PJ_ERRNO_START_STATUS + 24)/* 70024 */
++/**
++ * @hideinitializer
++ * There is no data available right now, try again later.
++ */
++#define PJ_EAGAIN	    	(PJ_ERRNO_START_STATUS + 25)/* 70025 */
+
+ /** @} */   /* pj_errnum */
diff --git a/gnu/packages/patches/pjproject-ice-config.patch b/gnu/packages/patches/pjproject-ice-config.patch
new file mode 100644
index 0000000..e958c0d
--- /dev/null
+++ b/gnu/packages/patches/pjproject-ice-config.patch
@@ -0,0 +1,23 @@
+--- a/pjnath/include/pjnath/config.h
++++ b/pjnath/include/pjnath/config.h
+@@ -231,5 +231,5 @@
+  * Default: 16
+  */
+ #ifndef PJ_ICE_MAX_CAND
+-#   define PJ_ICE_MAX_CAND			    16
++#   define PJ_ICE_MAX_CAND			    32
+ #endif
+@@ -250,5 +250,5 @@
+  * the maximum number of components (PJ_ICE_MAX_COMP) value.
+  */
+ #ifndef PJ_ICE_COMP_BITS
+-#   define PJ_ICE_COMP_BITS			    1
++#   define PJ_ICE_COMP_BITS			    2
+ #endif
+@@ -301,5 +301,5 @@
+  * Default: 32
+  */
+ #ifndef PJ_ICE_MAX_CHECKS
+-#   define PJ_ICE_MAX_CHECKS			    32
++#   define PJ_ICE_MAX_CHECKS			    150
+ #endif
diff --git a/gnu/packages/patches/pjproject-ice-sess.patch b/gnu/packages/patches/pjproject-ice-sess.patch
new file mode 100644
index 0000000..bd040ff
--- /dev/null
+++ b/gnu/packages/patches/pjproject-ice-sess.patch
@@ -0,0 +1,22 @@
+--- a/pjnath/include/pjnath/ice_strans.h
++++ b/pjnath/include/pjnath/ice_strans.h
+@@ -845,6 +845,8 @@ PJ_DECL(pj_status_t) pj_ice_strans_sendt
+					  int dst_addr_len);
+
+
++PJ_DECL(pj_ice_sess *) pj_ice_strans_get_ice_sess(pj_ice_strans *ice_st);
++
+ /**
+  * @}
+  */
+--- a/pjnath/src/pjnath/ice_strans.c
++++ b/pjnath/src/pjnath/ice_strans.c
+@@ -1243,6 +1243,11 @@ PJ_DEF(pj_status_t) pj_ice_strans_sendto
+	return PJ_EINVALIDOP;
+ }
+
++PJ_DECL(pj_ice_sess *) pj_ice_strans_get_ice_sess( pj_ice_strans *ice_st )
++{
++	return ice_st->ice;
++}
++
diff --git a/gnu/packages/patches/pjproject-ipv6.patch b/gnu/packages/patches/pjproject-ipv6.patch
new file mode 100644
index 0000000..8b42fbb
--- /dev/null
+++ b/gnu/packages/patches/pjproject-ipv6.patch
@@ -0,0 +1,11 @@
+--- a/pjlib/include/pj/config.h
++++ b/pjlib/include/pj/config.h
+@@ -549,7 +549,7 @@
+  * Default: 0 (disabled, for now)
+  */
+ #ifndef PJ_HAS_IPV6
+-#  define PJ_HAS_IPV6		    0
++#  define PJ_HAS_IPV6		    1
+ #endif
+ 
+  /**
diff --git a/gnu/packages/patches/pjproject-multiple-listeners.patch b/gnu/packages/patches/pjproject-multiple-listeners.patch
new file mode 100644
index 0000000..9bd58ee
--- /dev/null
+++ b/gnu/packages/patches/pjproject-multiple-listeners.patch
@@ -0,0 +1,66 @@
+diff --git a/pjproject/pjsip/src/pjsip/sip_transport.c b/pjproject_new/pjsip/src/pjsip/sip_transport.c
+index 4b2cc1a..22e3603 100644
+--- a/pjsip/src/pjsip/sip_transport.c
++++ b/pjsip/src/pjsip/sip_transport.c
+@@ -1179,22 +1179,22 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_register_tpfactory( pjsip_tpmgr *mgr,
+ 
+     pj_lock_acquire(mgr->lock);
+ 
+-    /* Check that no factory with the same type has been registered. */
++    /* Check that no factory with the same type and bound address has been registered. */
+     status = PJ_SUCCESS;
+     for (p=mgr->factory_list.next; p!=&mgr->factory_list; p=p->next) {
+-	if (p->type == tpf->type) {
+-	    status = PJSIP_ETYPEEXISTS;
+-	    break;
+-	}
+-	if (p == tpf) {
+-	    status = PJ_EEXISTS;
+-	    break;
+-	}
++        if (p->type == tpf->type && !pj_sockaddr_cmp(&tpf->local_addr, &p->local_addr)) {
++            status = PJSIP_ETYPEEXISTS;
++            break;
++        }
++        if (p == tpf) {
++            status = PJ_EEXISTS;
++            break;
++        }
+     }
+ 
+     if (status != PJ_SUCCESS) {
+-	pj_lock_release(mgr->lock);
+-	return status;
++        pj_lock_release(mgr->lock);
++        return status;
+     }
+ 
+     pj_list_insert_before(&mgr->factory_list, tpf);
+@@ -1909,13 +1909,11 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport2(pjsip_tpmgr *mgr,
+ 	pj_memcpy(&key.rem_addr, remote, addr_len);
+ 
+ 	transport = (pjsip_transport*)
+-		    pj_hash_get(mgr->table, &key, key_len, NULL);
+-
++    pj_hash_get(mgr->table, &key, key_len, NULL);
++    unsigned flag = pjsip_transport_get_flag_from_type(type);
+ 	if (transport == NULL) {
+-	    unsigned flag = pjsip_transport_get_flag_from_type(type);
+ 	    const pj_sockaddr *remote_addr = (const pj_sockaddr*)remote;
+ 
+-
+ 	    /* Ignore address for loop transports. */
+ 	    if (type == PJSIP_TRANSPORT_LOOP ||
+ 		     type == PJSIP_TRANSPORT_LOOP_DGRAM)
+@@ -1954,6 +1952,11 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport2(pjsip_tpmgr *mgr,
+ 	    return PJ_SUCCESS;
+ 	}
+ 
++    if (flag & PJSIP_TRANSPORT_SECURE) {
++        TRACE_((THIS_FILE, "Can't create new TLS transport with no provided suitable TLS listener."));
++        return PJSIP_ETPNOTSUITABLE;
++    }
++
+ 	/*
+ 	 * Transport not found!
+ 	 * Find factory that can create such transport.
diff --git a/gnu/packages/patches/pjproject-no-test-apps.patch b/gnu/packages/patches/pjproject-no-test-apps.patch
new file mode 100644
index 0000000..662f1db
--- /dev/null
+++ b/gnu/packages/patches/pjproject-no-test-apps.patch
@@ -0,0 +1,97 @@
+diff --git a/Makefile b/Makefile
+index 33a4e6b..a486eb7 100644
+--- a/Makefile
++++ b/Makefile
+@@ -4,7 +4,7 @@ include build/host-$(HOST_NAME).mak
+ include version.mak
+ 
+ LIB_DIRS = pjlib/build pjlib-util/build pjnath/build third_party/build pjmedia/build pjsip/build
+-DIRS = $(LIB_DIRS) pjsip-apps/build $(EXTRA_DIRS)
++DIRS = $(LIB_DIRS) $(EXTRA_DIRS)
+ 
+ ifdef MINSIZE
+ MAKE_FLAGS := MINSIZE=1
+diff --git a/pjlib-util/build/Makefile b/pjlib-util/build/Makefile
+index cb601cb..862a78a 100644
+--- a/pjlib-util/build/Makefile
++++ b/pjlib-util/build/Makefile
+@@ -54,7 +54,6 @@ export UTIL_TEST_OBJS += xml.o encryption.o stun.o resolver_test.o test.o \
+ export UTIL_TEST_CFLAGS += $(_CFLAGS)
+ export UTIL_TEST_CXXFLAGS += $(_CXXFLAGS)
+ export UTIL_TEST_LDFLAGS += $(PJLIB_UTIL_LDLIB) $(PJLIB_LDLIB) $(_LDFLAGS)
+-export UTIL_TEST_EXE:=pjlib-util-test-$(TARGET_NAME)$(HOST_EXE)
+ 
+ 	
+ export CC_OUT CC AR RANLIB HOST_MV HOST_RM HOST_RMDIR HOST_MKDIR OBJEXT LD LDOUT 
+diff --git a/pjlib/build/Makefile b/pjlib/build/Makefile
+index 1e64950..a75fa65 100644
+--- a/pjlib/build/Makefile
++++ b/pjlib/build/Makefile
+@@ -56,7 +56,6 @@ export TEST_OBJS += activesock.o atomic.o echo_clt.o errno.o exception.o \
+ export TEST_CFLAGS += $(_CFLAGS)
+ export TEST_CXXFLAGS += $(_CXXFLAGS)
+ export TEST_LDFLAGS += $(PJLIB_LDLIB) $(_LDFLAGS)
+-export TEST_EXE := pjlib-test-$(TARGET_NAME)$(HOST_EXE)
+ 
+ 
+ export CC_OUT CC AR RANLIB HOST_MV HOST_RM HOST_RMDIR HOST_MKDIR OBJEXT LD LDOUT 
+diff --git a/pjmedia/build/Makefile b/pjmedia/build/Makefile
+index 8012cb7..2ca283a 100644
+--- a/pjmedia/build/Makefile
++++ b/pjmedia/build/Makefile
+@@ -165,7 +165,6 @@ export PJMEDIA_TEST_LDFLAGS += $(PJMEDIA_CODEC_LDLIB) \
+ 			       $(PJLIB_UTIL_LDLIB) \
+ 			       $(PJNATH_LDLIB) \
+ 			       $(_LDFLAGS)
+-export PJMEDIA_TEST_EXE:=pjmedia-test-$(TARGET_NAME)$(HOST_EXE)
+ 
+ 	
+ export CC_OUT CC AR RANLIB HOST_MV HOST_RM HOST_RMDIR HOST_MKDIR OBJEXT LD LDOUT 
+diff --git a/pjnath/build/Makefile b/pjnath/build/Makefile
+index 1bc08b5..109f79b 100644
+--- a/pjnath/build/Makefile
++++ b/pjnath/build/Makefile
+@@ -54,7 +54,6 @@ export PJNATH_TEST_OBJS += ice_test.o stun.o sess_auth.o server.o concur_test.o
+ export PJNATH_TEST_CFLAGS += $(_CFLAGS)
+ export PJNATH_TEST_CXXFLAGS += $(_CXXFLAGS)
+ export PJNATH_TEST_LDFLAGS += $(PJNATH_LDLIB) $(PJLIB_UTIL_LDLIB) $(PJLIB_LDLIB) $(_LDFLAGS)
+-export PJNATH_TEST_EXE:=pjnath-test-$(TARGET_NAME)$(HOST_EXE)
+ 
+ 	
+ ###############################################################################
+@@ -65,7 +64,6 @@ export PJTURN_CLIENT_OBJS += client_main.o
+ export PJTURN_CLIENT_CFLAGS += $(_CFLAGS)
+ export PJTURN_CLIENT_CXXFLAGS += $(_CXXFLAGS)
+ export PJTURN_CLIENT_LDFLAGS += $(PJNATH_LDLIB) $(PJLIB_UTIL_LDLIB) $(PJLIB_LDLIB) $(_LDFLAGS)
+-export PJTURN_CLIENT_EXE:=pjturn-client-$(TARGET_NAME)$(HOST_EXE)
+ 
+ ###############################################################################
+ # Defines for building TURN server application
+@@ -76,7 +74,6 @@ export PJTURN_SRV_OBJS += allocation.o auth.o listener_udp.o \
+ export PJTURN_SRV_CFLAGS += $(_CFLAGS)
+ export PJTURN_SRV_CXXFLAGS += $(_CXXFLAGS)
+ export PJTURN_SRV_LDFLAGS += $(PJNATH_LDLIB) $(PJLIB_UTIL_LDLIB) $(PJLIB_LDLIB) $(_LDFLAGS)
+-export PJTURN_SRV_EXE:=pjturn-srv-$(TARGET_NAME)$(HOST_EXE)
+ 
+ 	
+ 	
+diff --git a/pjsip/build/Makefile b/pjsip/build/Makefile
+index d2a5c2a..7e2ec60 100644
+--- a/pjsip/build/Makefile
++++ b/pjsip/build/Makefile
+@@ -165,7 +165,6 @@ export PJSUA2_TEST_OBJS += $(OS_OBJS) $(M_OBJS) $(CC_OBJS) $(HOST_OBJS) \
+ export PJSUA2_TEST_CFLAGS += $(_CFLAGS) $(PJ_VIDEO_CFLAGS)
+ export PJSUA2_TEST_CXXFLAGS = $(PJSUA2_LIB_CFLAGS) 
+ export PJSUA2_TEST_LDFLAGS += $(PJ_LDXXFLAGS) $(PJ_LDXXLIBS) $(LDFLAGS)
+-export PJSUA2_TEST_EXE := pjsua2-test-$(TARGET_NAME)$(HOST_EXE)
+ 
+ export CC_OUT CC AR RANLIB HOST_MV HOST_RM HOST_RMDIR HOST_MKDIR OBJEXT LD LDOUT 
+ 
+@@ -195,7 +194,6 @@ export TEST_LDFLAGS += $(PJSIP_LDLIB) \
+ 		       $(PJLIB_UTIL_LDLIB) \
+ 		       $(PJNATH_LDLIB) \
+ 		       $(_LDFLAGS)
+-export TEST_EXE := pjsip-test-$(TARGET_NAME)$(HOST_EXE)
+ 
+ 	
+ export CC_OUT CC AR RANLIB HOST_MV HOST_RM HOST_RMDIR HOST_MKDIR OBJEXT LD LDOUT 
diff --git a/gnu/packages/patches/pjproject-use-gnutls.patch b/gnu/packages/patches/pjproject-use-gnutls.patch
new file mode 100644
index 0000000..00bdd95
--- /dev/null
+++ b/gnu/packages/patches/pjproject-use-gnutls.patch
@@ -0,0 +1,3380 @@
+From 5cb3786d107bdea372ab45e6c35f882fd867d5e0 Mon Sep 17 00:00:00 2001
+From: Vittorio Giovara <vittorio.giovara@savoirfairelinux.com>
+Date: Mon, 9 Jun 2014 14:20:55 -0400
+Subject: [PATCH 1/1] ssl_sock: add gnutls backend
+
+This backend is mutually exclusive with the OpenSSL one, but completely
+compatible, and conformant to the PJSIP API. Also avoids any license issues
+when linking statically.
+
+The configure script is updated to select either OpenSSL or GnuTLS
+with --enable-ssl[='...'] and a new symbol (PJ_HAS_TLS_SOCK) is introduced
+to identify which backend is in use.
+
+Written by
+Vittorio Giovara <vittorio.giovara@savoirfairelinux.com>
+Philippe Proulx <philippe.proulx@savoirfairelinux.com> and
+Adrien Béraud <adrien.beraud@savoirfairelinux.com>
+on behalf of Savoir-Faire Linux.
+---
+ {a => b}/aconfigure                           |  194 +-
+ {a => b}/aconfigure.ac                        |  109 +-
+ {a => b}/pjlib/build/Makefile                 |    2 +-
+ {a => b}/pjlib/include/pj/compat/os_auto.h.in |    3 +
+ {a => b}/pjlib/include/pj/config.h            |    4 +-
+ {a => b}/pjlib/include/pj/ssl_sock.h          |    5 +
+ {a => b}/pjlib/src/pj/ssl_sock_common.c       |    5 +
+ /dev/null => b/pjlib/src/pj/ssl_sock_gtls.c   | 2867 +++++++++++++++++++++++++
+ {a => b}/pjlib/src/pj/ssl_sock_ossl.c         |    6 +-
+ 9 files changed, 3124 insertions(+), 71 deletions(-)
+
+diff --git a/aconfigure b/aconfigure
+index 084ab0a..d4f4639 100755
+--- a/aconfigure
++++ b/aconfigure
+@@ -637,6 +637,8 @@ ac_no_opencore_amrnb
+ libcrypto_present
+ libssl_present
+ openssl_h_present
++libgnutls_present
++gnutls_h_present
+ ac_no_ssl
+ ac_libyuv_ldflags
+ ac_libyuv_cflags
+@@ -1469,8 +1471,8 @@ Optional Features:
+                           package and samples location using IPPROOT and
+                           IPPSAMPLES env var or with --with-ipp and
+                           --with-ipp-samples options
+-  --disable-ssl           Exclude SSL support the build (default: autodetect)
+-
++  --enable-ssl=backend    Select 'gnutls' or 'openssl' (default) to provide
++                          SSL support (autodetect)
+   --disable-opencore-amr  Exclude OpenCORE AMR support from the build
+                           (default: autodetect)
+ 
+@@ -7644,33 +7646,160 @@ fi
+ 
+ # Check whether --enable-ssl was given.
+ if test "${enable_ssl+set}" = set; then :
+-  enableval=$enable_ssl;
+-		if test "$enable_ssl" = "no"; then
+-		 ac_no_ssl=1
+-		 { $as_echo "$as_me:${as_lineno-$LINENO}: result: Checking if SSL support is disabled... yes" >&5
++  enableval=$enable_ssl;  if test "x$enableval" = "xgnutls"; then
++                    ssl_backend="gnutls"
++                else
++                    ssl_backend="openssl"
++
++                fi
++
++fi
++
++
++if test "x$enable_ssl" = "xno"; then
++    ac_no_ssl=1
++    { $as_echo "$as_me:${as_lineno-$LINENO}: result: Checking if SSL support is disabled... yes" >&5
+ $as_echo "Checking if SSL support is disabled... yes" >&6; }
+-	        fi
++else
++    if test "x$with_ssl" != "xno" -a "x$with_ssl" != "x"; then
++        CFLAGS="$CFLAGS -I$with_ssl/include"
++        LDFLAGS="$LDFLAGS -L$with_ssl/lib"
++        { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using SSL prefix... $with_ssl" >&5
++$as_echo "Using SSL prefix... $with_ssl" >&6; }
++    fi
++    if test "x$ssl_backend" = "xgnutls"; then
++        for ac_prog in $host-pkg-config pkg-config "python pkgconfig.py"
++do
++  # Extract the first word of "$ac_prog", so it can be a program name with args.
++set dummy $ac_prog; ac_word=$2
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_PKG_CONFIG+:} false; then :
++  $as_echo_n "(cached) " >&6
++else
++  if test -n "$PKG_CONFIG"; then
++  ac_cv_prog_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test.
++else
++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++  IFS=$as_save_IFS
++  test -z "$as_dir" && as_dir=.
++    for ac_exec_ext in '' $ac_executable_extensions; do
++  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
++    ac_cv_prog_PKG_CONFIG="$ac_prog"
++    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
++    break 2
++  fi
++done
++  done
++IFS=$as_save_IFS
+ 
++fi
++fi
++PKG_CONFIG=$ac_cv_prog_PKG_CONFIG
++if test -n "$PKG_CONFIG"; then
++  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
++$as_echo "$PKG_CONFIG" >&6; }
+ else
++  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
+ 
+-		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: checking for OpenSSL installations.." >&5
++  test -n "$PKG_CONFIG" && break
++done
++test -n "$PKG_CONFIG" || PKG_CONFIG="none"
++
++        { $as_echo "$as_me:${as_lineno-$LINENO}: result: checking for GnuTLS installations.." >&5
++$as_echo "checking for GnuTLS installations.." >&6; }
++
++
++        ac_fn_c_check_header_mongrel "$LINENO" "gnutls/gnutls.h" "ac_cv_header_gnutls_gnutls_h" "$ac_includes_default"
++if test "x$ac_cv_header_gnutls_gnutls_h" = xyes; then :
++  gnutls_h_present=1
++fi
++
++
++
++        if test "$PKG_CONFIG" != "none"; then
++            if $PKG_CONFIG --exists gnutls; then
++                LIBS="$LIBS `$PKG_CONFIG --libs gnutls`"
++                libgnutls_present=1
++            else
++                { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gnutls_certificate_set_x509_system_trust in -lgnutls" >&5
++$as_echo_n "checking for gnutls_certificate_set_x509_system_trust in -lgnutls... " >&6; }
++if ${ac_cv_lib_gnutls_gnutls_certificate_set_x509_system_trust+:} false; then :
++  $as_echo_n "(cached) " >&6
++else
++  ac_check_lib_save_LIBS=$LIBS
++LIBS="-lgnutls  $LIBS"
++cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h.  */
++
++/* Override any GCC internal prototype to avoid an error.
++   Use char because int might match the return type of a GCC
++   builtin and then its argument prototype would still apply.  */
++#ifdef __cplusplus
++extern "C"
++#endif
++char gnutls_certificate_set_x509_system_trust ();
++int
++main ()
++{
++return gnutls_certificate_set_x509_system_trust ();
++  ;
++  return 0;
++}
++_ACEOF
++if ac_fn_c_try_link "$LINENO"; then :
++  ac_cv_lib_gnutls_gnutls_certificate_set_x509_system_trust=yes
++else
++  ac_cv_lib_gnutls_gnutls_certificate_set_x509_system_trust=no
++fi
++rm -f core conftest.err conftest.$ac_objext \
++    conftest$ac_exeext conftest.$ac_ext
++LIBS=$ac_check_lib_save_LIBS
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gnutls_gnutls_certificate_set_x509_system_trust" >&5
++$as_echo "$ac_cv_lib_gnutls_gnutls_certificate_set_x509_system_trust" >&6; }
++if test "x$ac_cv_lib_gnutls_gnutls_certificate_set_x509_system_trust" = xyes; then :
++  libgnutls_present=1 &&
++                              LIBS="$LIBS -lgnutls"
++fi
++
++            fi
++        else
++            { $as_echo "$as_me:${as_lineno-$LINENO}: result: *** Warning: neither pkg-config nor python is available, disabling gnutls. ***" >&5
++$as_echo "*** Warning: neither pkg-config nor python is available, disabling gnutls. ***" >&6; }
++        fi
++
++        if test "x$gnutls_h_present" = "x1" -a "x$libgnutls_present" = "x1"; then
++            { $as_echo "$as_me:${as_lineno-$LINENO}: result: GnuTLS library found, SSL support enabled" >&5
++$as_echo "GnuTLS library found, SSL support enabled" >&6; }
++            # PJSIP_HAS_TLS_TRANSPORT setting follows PJ_HAS_SSL_SOCK
++            #AC_DEFINE(PJSIP_HAS_TLS_TRANSPORT, 1)
++            $as_echo "#define PJ_HAS_SSL_SOCK 1" >>confdefs.h
++
++            $as_echo "#define PJ_HAS_TLS_SOCK 1" >>confdefs.h
++
++        else
++            { $as_echo "$as_me:${as_lineno-$LINENO}: result: ** No GnuTLS libraries found, disabling SSL support **" >&5
++$as_echo "** No GnuTLS libraries found, disabling SSL support **" >&6; }
++        fi
++    else
++        { $as_echo "$as_me:${as_lineno-$LINENO}: result: checking for OpenSSL installations.." >&5
+ $as_echo "checking for OpenSSL installations.." >&6; }
+-                if test "x$with_ssl" != "xno" -a "x$with_ssl" != "x"; then
+-                    CFLAGS="$CFLAGS -I$with_ssl/include"
+-                    LDFLAGS="$LDFLAGS -L$with_ssl/lib"
+-                    { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using SSL prefix... $with_ssl" >&5
+-$as_echo "Using SSL prefix... $with_ssl" >&6; }
+-                fi
+ 
+ 
+ 
+-		ac_fn_c_check_header_mongrel "$LINENO" "openssl/ssl.h" "ac_cv_header_openssl_ssl_h" "$ac_includes_default"
++        ac_fn_c_check_header_mongrel "$LINENO" "openssl/ssl.h" "ac_cv_header_openssl_ssl_h" "$ac_includes_default"
+ if test "x$ac_cv_header_openssl_ssl_h" = xyes; then :
+   openssl_h_present=1
+ fi
+ 
+ 
+-		{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ERR_load_BIO_strings in -lcrypto" >&5
++        { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ERR_load_BIO_strings in -lcrypto" >&5
+ $as_echo_n "checking for ERR_load_BIO_strings in -lcrypto... " >&6; }
+ if ${ac_cv_lib_crypto_ERR_load_BIO_strings+:} false; then :
+   $as_echo_n "(cached) " >&6
+@@ -7710,7 +7839,7 @@ if test "x$ac_cv_lib_crypto_ERR_load_BIO_strings" = xyes; then :
+   libcrypto_present=1 && LIBS="-lcrypto -ldl -lz $LIBS"
+ fi
+ 
+-		{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_library_init in -lssl" >&5
++        { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_library_init in -lssl" >&5
+ $as_echo_n "checking for SSL_library_init in -lssl... " >&6; }
+ if ${ac_cv_lib_ssl_SSL_library_init+:} false; then :
+   $as_echo_n "(cached) " >&6
+@@ -7750,14 +7879,16 @@ if test "x$ac_cv_lib_ssl_SSL_library_init" = xyes; then :
+   libssl_present=1 && LIBS="-lssl $LIBS"
+ fi
+ 
+-		if test "x$openssl_h_present" = "x1" -a "x$libssl_present" = "x1" -a "x$libcrypto_present" = "x1"; then
+-	        	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: OpenSSL library found, SSL support enabled" >&5
++        if test "x$openssl_h_present" = "x1" -a "x$libssl_present" = "x1" -a "x$libcrypto_present" = "x1"; then
++            { $as_echo "$as_me:${as_lineno-$LINENO}: result: OpenSSL library found, SSL support enabled" >&5
+ $as_echo "OpenSSL library found, SSL support enabled" >&6; }
+-			# PJSIP_HAS_TLS_TRANSPORT setting follows PJ_HAS_SSL_SOCK
+-			#AC_DEFINE(PJSIP_HAS_TLS_TRANSPORT, 1)
+-			$as_echo "#define PJ_HAS_SSL_SOCK 1" >>confdefs.h
++            # PJSIP_HAS_TLS_TRANSPORT setting follows PJ_HAS_SSL_SOCK
++            #AC_DEFINE(PJSIP_HAS_TLS_TRANSPORT, 1)
++            $as_echo "#define PJ_HAS_SSL_SOCK 1" >>confdefs.h
++
++            $as_echo "#define PJ_HAS_TLS_SOCK 0" >>confdefs.h
+ 
+-			{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSLv2_method in -lssl" >&5
++            { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSLv2_method in -lssl" >&5
+ $as_echo_n "checking for SSLv2_method in -lssl... " >&6; }
+ if ${ac_cv_lib_ssl_SSLv2_method+:} false; then :
+   $as_echo_n "(cached) " >&6
+@@ -7797,18 +7928,17 @@ if test "x$ac_cv_lib_ssl_SSLv2_method" = xyes; then :
+   libssl_no_ssl2=1
+ fi
+ 
+-			if test "x$libssl_no_ssl2" != "x1"; then
+-				CFLAGS="$CFLAGS -DOPENSSL_NO_SSL2=1"
+-			fi
+-		else
+-			{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ** OpenSSL libraries not found, disabling SSL support **" >&5
+-$as_echo "** OpenSSL libraries not found, disabling SSL support **" >&6; }
+-		fi
+-
++            if test "x$libssl_no_ssl2" != "x1"; then
++                    CFLAGS="$CFLAGS -DOPENSSL_NO_SSL2=1"
++            fi
++        else
++            { $as_echo "$as_me:${as_lineno-$LINENO}: result: ** No OpenSSL libraries found, disabling SSL support **" >&5
++$as_echo "** No OpenSSL libraries found, disabling SSL support **" >&6; }
++        fi
++    fi
+ fi
+ 
+ 
+-
+ # Check whether --with-opencore-amrnb was given.
+ if test "${with_opencore_amrnb+set}" = set; then :
+   withval=$with_opencore_amrnb; as_fn_error $? "This option is obsolete and replaced by --with-opencore-amr=DIR" "$LINENO" 5
+diff --git a/aconfigure.ac b/aconfigure.ac
+index 67cf24f..c6cbf82 100644
+--- a/aconfigure.ac
++++ b/aconfigure.ac
+@@ -1512,42 +1512,81 @@ fi
+ 
+ dnl # Include SSL support
+ AC_SUBST(ac_no_ssl)
+-AC_ARG_ENABLE(ssl,
+-	      AC_HELP_STRING([--disable-ssl],
+-			     [Exclude SSL support the build (default: autodetect)])
+-	      ,
+-	      [
+-		if test "$enable_ssl" = "no"; then
+-		 [ac_no_ssl=1]
+-		 AC_MSG_RESULT([Checking if SSL support is disabled... yes])
+-	        fi
+-	      ],
+-	      [
+-		AC_MSG_RESULT([checking for OpenSSL installations..])
+-                if test "x$with_ssl" != "xno" -a "x$with_ssl" != "x"; then
+-                    CFLAGS="$CFLAGS -I$with_ssl/include"
+-                    LDFLAGS="$LDFLAGS -L$with_ssl/lib"
+-                    AC_MSG_RESULT([Using SSL prefix... $with_ssl])
++AC_ARG_ENABLE([ssl],
++              AC_HELP_STRING([--enable-ssl[=backend]],
++                             [Select 'gnutls' or 'openssl' (default) to provide SSL support (autodetect)]),
++              [ if test "x$enableval" = "xgnutls"; then
++                    [ssl_backend="gnutls"]
++                else
++                    [ssl_backend="openssl"]
++
+                 fi
+-		AC_SUBST(openssl_h_present)
+-		AC_SUBST(libssl_present)
+-		AC_SUBST(libcrypto_present)
+-		AC_CHECK_HEADER(openssl/ssl.h,[openssl_h_present=1])
+-		AC_CHECK_LIB(crypto,ERR_load_BIO_strings,[libcrypto_present=1 && LIBS="-lcrypto -ldl -lz $LIBS"],,-ldl -lz)
+-		AC_CHECK_LIB(ssl,SSL_library_init,[libssl_present=1 && LIBS="-lssl $LIBS"])
+-		if test "x$openssl_h_present" = "x1" -a "x$libssl_present" = "x1" -a "x$libcrypto_present" = "x1"; then
+-	        	AC_MSG_RESULT([OpenSSL library found, SSL support enabled])
+-			# PJSIP_HAS_TLS_TRANSPORT setting follows PJ_HAS_SSL_SOCK
+-			#AC_DEFINE(PJSIP_HAS_TLS_TRANSPORT, 1)
+-			AC_DEFINE(PJ_HAS_SSL_SOCK, 1)
+-			AC_CHECK_LIB(ssl,SSLv2_method,[libssl_no_ssl2=1])
+-			if test "x$libssl_no_ssl2" != "x1"; then
+-				CFLAGS="$CFLAGS -DOPENSSL_NO_SSL2=1"
+-			fi
+-		else
+-			AC_MSG_RESULT([** OpenSSL libraries not found, disabling SSL support **])
+-		fi
+-	      ])
++              ])
++
++if test "x$enable_ssl" = "xno"; then
++    [ac_no_ssl=1]
++    AC_MSG_RESULT([Checking if SSL support is disabled... yes])
++else
++    if test "x$with_ssl" != "xno" -a "x$with_ssl" != "x"; then
++        CFLAGS="$CFLAGS -I$with_ssl/include"
++        LDFLAGS="$LDFLAGS -L$with_ssl/lib"
++        AC_MSG_RESULT([Using SSL prefix... $with_ssl])
++    fi
++    if test "x$ssl_backend" = "xgnutls"; then
++        AC_CHECK_PROGS(PKG_CONFIG,
++                       $host-pkg-config pkg-config "python pkgconfig.py",
++                       none)
++        AC_MSG_RESULT([checking for GnuTLS installations..])
++        AC_SUBST(gnutls_h_present)
++        AC_SUBST(libgnutls_present)
++        AC_CHECK_HEADER(gnutls/gnutls.h, [gnutls_h_present=1])
++
++        if test "$PKG_CONFIG" != "none"; then
++            if $PKG_CONFIG --exists gnutls; then
++                LIBS="$LIBS `$PKG_CONFIG --libs gnutls`"
++                libgnutls_present=1
++            else
++                AC_CHECK_LIB(gnutls,
++                             gnutls_certificate_set_x509_system_trust,
++                             [libgnutls_present=1 &&
++                              LIBS="$LIBS -lgnutls"])
++            fi
++        else
++            AC_MSG_RESULT([*** Warning: neither pkg-config nor python is available, disabling gnutls. ***])
++        fi
++
++        if test "x$gnutls_h_present" = "x1" -a "x$libgnutls_present" = "x1"; then
++            AC_MSG_RESULT([GnuTLS library found, SSL support enabled])
++            # PJSIP_HAS_TLS_TRANSPORT setting follows PJ_HAS_SSL_SOCK
++            #AC_DEFINE(PJSIP_HAS_TLS_TRANSPORT, 1)
++            AC_DEFINE(PJ_HAS_SSL_SOCK, 1)
++            AC_DEFINE(PJ_HAS_TLS_SOCK, 1)
++        else
++            AC_MSG_RESULT([** No GnuTLS libraries found, disabling SSL support **])
++        fi
++    else
++        AC_MSG_RESULT([checking for OpenSSL installations..])
++        AC_SUBST(openssl_h_present)
++        AC_SUBST(libssl_present)
++        AC_SUBST(libcrypto_present)
++        AC_CHECK_HEADER(openssl/ssl.h, [openssl_h_present=1])
++        AC_CHECK_LIB(crypto,ERR_load_BIO_strings,[libcrypto_present=1 && LIBS="-lcrypto -ldl -lz $LIBS"],,-ldl -lz)
++        AC_CHECK_LIB(ssl,SSL_library_init,[libssl_present=1 && LIBS="-lssl $LIBS"])
++        if test "x$openssl_h_present" = "x1" -a "x$libssl_present" = "x1" -a "x$libcrypto_present" = "x1"; then
++            AC_MSG_RESULT([OpenSSL library found, SSL support enabled])
++            # PJSIP_HAS_TLS_TRANSPORT setting follows PJ_HAS_SSL_SOCK
++            #AC_DEFINE(PJSIP_HAS_TLS_TRANSPORT, 1)
++            AC_DEFINE(PJ_HAS_SSL_SOCK, 1)
++            AC_DEFINE(PJ_HAS_TLS_SOCK, 0)
++            AC_CHECK_LIB(ssl,SSLv2_method,[libssl_no_ssl2=1])
++            if test "x$libssl_no_ssl2" != "x1"; then
++                    CFLAGS="$CFLAGS -DOPENSSL_NO_SSL2=1"
++            fi
++        else
++            AC_MSG_RESULT([** No OpenSSL libraries found, disabling SSL support **])
++        fi
++    fi
++fi
+ 
+ dnl # Obsolete option --with-opencore-amrnb
+ AC_ARG_WITH(opencore-amrnb,
+diff --git a/pjlib/build/Makefile b/pjlib/build/Makefile
+index 1e64950..e650a31 100644
+--- a/pjlib/build/Makefile
++++ b/pjlib/build/Makefile
+@@ -35,7 +35,7 @@ export PJLIB_OBJS += $(OS_OBJS) $(M_OBJS) $(CC_OBJS) $(HOST_OBJS) \
+ 	guid.o hash.o ip_helper_generic.o list.o lock.o log.o os_time_common.o \
+ 	os_info.o pool.o pool_buf.o pool_caching.o pool_dbg.o rand.o \
+ 	rbtree.o sock_common.o sock_qos_common.o sock_qos_bsd.o \
+-	ssl_sock_common.o ssl_sock_ossl.o ssl_sock_dump.o \
++	ssl_sock_common.o ssl_sock_ossl.o ssl_sock_gtls.o ssl_sock_dump.o \
+ 	string.o timer.o types.o
+ export PJLIB_CFLAGS += $(_CFLAGS)
+ export PJLIB_CXXFLAGS += $(_CXXFLAGS)
+diff --git a/pjlib/include/pj/compat/os_auto.h.in b/pjlib/include/pj/compat/os_auto.h.in
+index 18df2bf..9295740 100644
+--- a/pjlib/include/pj/compat/os_auto.h.in
++++ b/pjlib/include/pj/compat/os_auto.h.in
+@@ -206,6 +206,9 @@
+ #ifndef PJ_HAS_SSL_SOCK
+ #undef PJ_HAS_SSL_SOCK
+ #endif
++#ifndef PJ_HAS_TLS_SOCK
++#undef PJ_HAS_TLS_SOCK
++#endif
+ 
+ 
+ #endif	/* __PJ_COMPAT_OS_AUTO_H__ */
+diff --git a/pjlib/include/pj/config.h b/pjlib/include/pj/config.h
+index 08116cd..6d042fd 100644
+--- a/pjlib/include/pj/config.h
++++ b/pjlib/include/pj/config.h
+@@ -854,13 +854,15 @@
+ 
+ /**
+  * Enable secure socket. For most platforms, this is implemented using
+- * OpenSSL, so this will require OpenSSL to be installed. For Symbian
++ * OpenSSL, so this will require OpenSSL or GnuTLS to be installed. For Symbian
+  * platform, this is implemented natively using CSecureSocket.
+  *
+  * Default: 0 (for now)
+  */
+ #ifndef PJ_HAS_SSL_SOCK
+ #  define PJ_HAS_SSL_SOCK	    0
++   // When set to 1 secure sockets will use the GnuTLS backend
++#  define PJ_HAS_TLS_SOCK	    0
+ #endif
+ 
+ 
+diff --git a/pjlib/include/pj/ssl_sock.h b/pjlib/include/pj/ssl_sock.h
+index 161bcf3..0b8d1fc 100644
+--- a/pjlib/include/pj/ssl_sock.h
++++ b/pjlib/include/pj/ssl_sock.h
+@@ -181,6 +181,11 @@ typedef struct pj_ssl_cert_info {
+     } subj_alt_name;		    /**< Subject alternative
+ 					 name extension		*/
+ 
++    struct {
++        unsigned    cnt;        /**< # of entry     */
++        pj_str_t* cert_raw;
++    } raw_chain;
++
+ } pj_ssl_cert_info;
+ 
+ 
+diff --git a/pjlib/src/pj/ssl_sock_common.c b/pjlib/src/pj/ssl_sock_common.c
+index 913efee..ac7f683 100644
+--- a/pjlib/src/pj/ssl_sock_common.c
++++ b/pjlib/src/pj/ssl_sock_common.c
+@@ -34,7 +34,12 @@ PJ_DEF(void) pj_ssl_sock_param_default(pj_ssl_sock_param *param)
+     param->async_cnt = 1;
+     param->concurrency = -1;
+     param->whole_data = PJ_TRUE;
++#if defined(PJ_HAS_TLS_SOCK) && PJ_HAS_TLS_SOCK == 1
++    // GnuTLS is allowed to send bigger chunks
++    param->send_buffer_size = 65536;
++#else
+     param->send_buffer_size = 8192;
++#endif
+ #if !defined(PJ_SYMBIAN) || PJ_SYMBIAN==0
+     param->read_buffer_size = 1500;
+ #endif
+diff --git b/pjlib/src/pj/ssl_sock_gtls.c b/pjlib/src/pj/ssl_sock_gtls.c
+new file mode 100644
+index 0000000..5a383d7
+--- /dev/null
++++ b/pjlib/src/pj/ssl_sock_gtls.c
+@@ -0,0 +1,2867 @@
++/* $Id$ */
++/*
++ * Copyright (C) 2014-2015 Savoir-Faire Linux. (http://www.savoirfairelinux.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#include <pj/ssl_sock.h>
++#include <pj/activesock.h>
++#include <pj/compat/socket.h>
++#include <pj/assert.h>
++#include <pj/errno.h>
++#include <pj/list.h>
++#include <pj/lock.h>
++#include <pj/log.h>
++#include <pj/math.h>
++#include <pj/os.h>
++#include <pj/pool.h>
++#include <pj/string.h>
++#include <pj/timer.h>
++#include <pj/file_io.h>
++
++#if GNUTLS_VERSION_NUMBER < 0x030306
++#include <dirent.h>
++#endif
++
++/* Only build when PJ_HAS_SSL_SOCK and PJ_HAS_TLS_SOCK are enabled */
++#if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK != 0 && \
++    defined(PJ_HAS_TLS_SOCK) && PJ_HAS_TLS_SOCK != 0
++
++#define THIS_FILE               "ssl_sock_gtls.c"
++
++/* Workaround for ticket #985 */
++#define DELAYED_CLOSE_TIMEOUT   200
++
++/* Maximum ciphers */
++#define MAX_CIPHERS             100
++
++/* Standard trust locations */
++#define TRUST_STORE_FILE1 "/etc/ssl/certs/ca-certificates.crt"
++#define TRUST_STORE_FILE2 "/etc/ssl/certs/ca-bundle.crt"
++
++/* Debugging output level for GnuTLS only */
++#define GNUTLS_LOG_LEVEL 0
++
++/* GnuTLS includes */
++#include <gnutls/gnutls.h>
++#include <gnutls/x509.h>
++#include <gnutls/abstract.h>
++
++#ifdef _MSC_VER
++#  pragma comment( lib, "gnutls")
++#endif
++
++
++/* TLS state enumeration. */
++enum tls_connection_state {
++    TLS_STATE_NULL,
++    TLS_STATE_HANDSHAKING,
++    TLS_STATE_ESTABLISHED
++};
++
++/* Internal timer types. */
++enum timer_id {
++    TIMER_NONE,
++    TIMER_HANDSHAKE_TIMEOUT,
++    TIMER_CLOSE
++};
++
++/* Structure of SSL socket read buffer. */
++typedef struct read_data_t {
++    void *data;
++    pj_size_t len;
++} read_data_t;
++
++/*
++ * Get the offset of pointer to read-buffer of SSL socket from read-buffer
++ * of active socket. Note that both SSL socket and active socket employ
++ * different but correlated read-buffers (as much as async_cnt for each),
++ * and to make it easier/faster to find corresponding SSL socket's read-buffer
++ * from known active socket's read-buffer, the pointer of corresponding
++ * SSL socket's read-buffer is stored right after the end of active socket's
++ * read-buffer.
++ */
++#define OFFSET_OF_READ_DATA_PTR(ssock, asock_rbuf) \
++                                        (read_data_t**) \
++                                        ((pj_int8_t *)(asock_rbuf) + \
++                                        ssock->param.read_buffer_size)
++
++/* Structure of SSL socket write data. */
++typedef struct write_data_t {
++    PJ_DECL_LIST_MEMBER(struct write_data_t);
++    pj_ioqueue_op_key_t  key;
++    pj_size_t            record_len;
++    pj_ioqueue_op_key_t *app_key;
++    pj_size_t            plain_data_len;
++    pj_size_t            data_len;
++    unsigned             flags;
++    union {
++        char             content[1];
++        const char      *ptr;
++    } data;
++} write_data_t;
++
++
++/* Structure of SSL socket write buffer (circular buffer). */
++typedef struct send_buf_t {
++    char                *buf;
++    pj_size_t            max_len;
++    char                *start;
++    pj_size_t            len;
++} send_buf_t;
++
++
++/* Circular buffer object */
++typedef struct circ_buf_t {
++    pj_size_t      cap;    /* maximum number of elements (must be power of 2) */
++    pj_size_t      readp;  /* index of oldest element */
++    pj_size_t      writep; /* index at which to write new element  */
++    pj_size_t      size;   /* number of elements */
++    pj_uint8_t    *buf;    /* data buffer */
++    pj_pool_t     *pool;   /* where new allocations will take place */
++} circ_buf_t;
++
++
++/* Secure socket structure definition. */
++struct pj_ssl_sock_t {
++    pj_pool_t            *pool;
++    pj_ssl_sock_t        *parent;
++    pj_ssl_sock_param     param;
++    pj_ssl_cert_t        *cert;
++
++    pj_ssl_cert_info      local_cert_info;
++    pj_ssl_cert_info      remote_cert_info;
++
++    pj_bool_t             is_server;
++    enum tls_connection_state connection_state;
++    pj_ioqueue_op_key_t   handshake_op_key;
++    pj_timer_entry        timer;
++    pj_status_t           verify_status;
++
++    int                   last_err;
++
++    pj_sock_t             sock;
++    pj_activesock_t      *asock;
++
++    pj_sockaddr           local_addr;
++    pj_sockaddr           rem_addr;
++    int                   addr_len;
++
++    pj_bool_t             read_started;
++    pj_size_t             read_size;
++    pj_uint32_t           read_flags;
++    void                **asock_rbuf;
++    read_data_t          *ssock_rbuf;
++
++    write_data_t          write_pending;       /* list of pending writes */
++    write_data_t          write_pending_empty; /* cache for write_pending */
++    pj_bool_t             flushing_write_pend; /* flag of flushing is ongoing */
++    send_buf_t            send_buf;
++    write_data_t          send_pending; /* list of pending write to network */
++
++    gnutls_session_t      session;
++    gnutls_certificate_credentials_t xcred;
++
++    circ_buf_t            circ_buf_input;
++    pj_lock_t            *circ_buf_input_mutex;
++
++    circ_buf_t            circ_buf_output;
++    pj_lock_t            *circ_buf_output_mutex;
++
++    int                   tls_init_count; /* library initialization counter */
++};
++
++
++/* Certificate/credential structure definition. */
++struct pj_ssl_cert_t {
++    pj_str_t CA_file;
++    pj_str_t CA_path;
++    pj_str_t cert_file;
++    pj_str_t privkey_file;
++    pj_str_t privkey_pass;
++};
++
++/* GnuTLS available ciphers */
++static unsigned tls_available_ciphers;
++
++/* Array of id/names for available ciphers */
++static struct tls_ciphers_t {
++    pj_ssl_cipher id;
++    const char *name;
++} tls_ciphers[MAX_CIPHERS];
++
++/* Last error reported somehow */
++static int tls_last_error;
++
++
++/*
++ *******************************************************************
++ * Circular buffer functions.
++ *******************************************************************
++ */
++
++static pj_status_t circ_init(pj_pool_factory *factory,
++                             circ_buf_t *cb, pj_size_t cap)
++{
++    cb->cap    = cap;
++    cb->readp  = 0;
++    cb->writep = 0;
++    cb->size   = 0;
++
++    /* Initial pool holding the buffer elements */
++    cb->pool = pj_pool_create(factory, "tls-circ%p", cap, cap, NULL);
++    if (!cb->pool)
++        return PJ_ENOMEM;
++
++    /* Allocate circular buffer */
++    cb->buf = pj_pool_alloc(cb->pool, cap);
++    if (!cb->buf) {
++        pj_pool_release(cb->pool);
++        return PJ_ENOMEM;
++    }
++
++    return PJ_SUCCESS;
++}
++
++static void circ_deinit(circ_buf_t *cb)
++{
++    if (cb->pool) {
++        pj_pool_release(cb->pool);
++        cb->pool = NULL;
++    }
++}
++
++static pj_bool_t circ_empty(const circ_buf_t *cb)
++{
++    return cb->size == 0;
++}
++
++static pj_size_t circ_size(const circ_buf_t *cb)
++{
++    return cb->size;
++}
++
++static pj_size_t circ_avail(const circ_buf_t *cb)
++{
++    return cb->cap - cb->size;
++}
++
++static void circ_read(circ_buf_t *cb, pj_uint8_t *dst, pj_size_t len)
++{
++    pj_size_t size_after = cb->cap - cb->readp;
++    pj_size_t tbc = PJ_MIN(size_after, len);
++    pj_size_t rem = len - tbc;
++
++    pj_memcpy(dst, cb->buf + cb->readp, tbc);
++    pj_memcpy(dst + tbc, cb->buf, rem);
++
++    cb->readp += len;
++    cb->readp &= (cb->cap - 1);
++
++    cb->size -= len;
++}
++
++static pj_status_t circ_write(circ_buf_t *cb,
++                              const pj_uint8_t *src, pj_size_t len)
++{
++    /* Overflow condition: resize */
++    if (len > circ_avail(cb)) {
++        /* Minimum required capacity */
++        pj_size_t min_cap = len + cb->size;
++
++        /* Next 32-bit power of two */
++        min_cap--;
++        min_cap |= min_cap >> 1;
++        min_cap |= min_cap >> 2;
++        min_cap |= min_cap >> 4;
++        min_cap |= min_cap >> 8;
++        min_cap |= min_cap >> 16;
++        min_cap++;
++
++        /* Create a new pool to hold a bigger buffer, using the same factory */
++        pj_pool_t *pool = pj_pool_create(cb->pool->factory, "tls-circ%p",
++                                         min_cap, min_cap, NULL);
++        if (!pool)
++            return PJ_ENOMEM;
++
++        /* Allocate our new buffer */
++        pj_uint8_t *buf = pj_pool_alloc(pool, min_cap);
++        if (!buf) {
++            pj_pool_release(pool);
++            return PJ_ENOMEM;
++        }
++
++        /* Save old size, which we shall restore after the next read */
++        pj_size_t old_size = cb->size;
++
++        /* Copy old data into beginning of new buffer */
++        circ_read(cb, buf, cb->size);
++
++        /* Restore old size now */
++        cb->size = old_size;
++
++        /* Release the previous pool */
++        pj_pool_release(cb->pool);
++
++        /* Update circular buffer members */
++        cb->pool = pool;
++        cb->buf = buf;
++        cb->readp = 0;
++        cb->writep = cb->size;
++        cb->cap = min_cap;
++    }
++
++    pj_size_t size_after = cb->cap - cb->writep;
++    pj_size_t tbc = PJ_MIN(size_after, len);
++    pj_size_t rem = len - tbc;
++
++    pj_memcpy(cb->buf + cb->writep, src, tbc);
++    pj_memcpy(cb->buf, src + tbc, rem);
++
++    cb->writep += len;
++    cb->writep &= (cb->cap - 1);
++
++    cb->size += len;
++
++    return PJ_SUCCESS;
++}
++
++
++/*
++ *******************************************************************
++ * Static/internal functions.
++ *******************************************************************
++ */
++
++/* Convert from GnuTLS error to pj_status_t. */
++static pj_status_t tls_status_from_err(pj_ssl_sock_t *ssock, int err)
++{
++    pj_status_t status;
++
++    switch (err) {
++    case GNUTLS_E_SUCCESS:
++        status = PJ_SUCCESS;
++        break;
++    case GNUTLS_E_MEMORY_ERROR:
++        status = PJ_ENOMEM;
++        break;
++    case GNUTLS_E_LARGE_PACKET:
++        status = PJ_ETOOBIG;
++        break;
++    case GNUTLS_E_NO_CERTIFICATE_FOUND:
++        status = PJ_ENOTFOUND;
++        break;
++    case GNUTLS_E_SESSION_EOF:
++        status = PJ_EEOF;
++        break;
++    case GNUTLS_E_HANDSHAKE_TOO_LARGE:
++        status = PJ_ETOOBIG;
++        break;
++    case GNUTLS_E_EXPIRED:
++        status = PJ_EGONE;
++        break;
++    case GNUTLS_E_TIMEDOUT:
++        status = PJ_ETIMEDOUT;
++        break;
++    case GNUTLS_E_PREMATURE_TERMINATION:
++        status = PJ_ECANCELLED;
++        break;
++    case GNUTLS_E_INTERNAL_ERROR:
++    case GNUTLS_E_UNIMPLEMENTED_FEATURE:
++        status = PJ_EBUG;
++        break;
++    case GNUTLS_E_AGAIN:
++    case GNUTLS_E_INTERRUPTED:
++    case GNUTLS_E_REHANDSHAKE:
++        status = PJ_EPENDING;
++        break;
++    case GNUTLS_E_TOO_MANY_EMPTY_PACKETS:
++    case GNUTLS_E_TOO_MANY_HANDSHAKE_PACKETS:
++    case GNUTLS_E_RECORD_LIMIT_REACHED:
++        status = PJ_ETOOMANY;
++        break;
++    case GNUTLS_E_UNSUPPORTED_VERSION_PACKET:
++    case GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM:
++    case GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE:
++    case GNUTLS_E_X509_UNSUPPORTED_ATTRIBUTE:
++    case GNUTLS_E_X509_UNSUPPORTED_EXTENSION:
++    case GNUTLS_E_X509_UNSUPPORTED_CRITICAL_EXTENSION:
++        status = PJ_ENOTSUP;
++        break;
++    case GNUTLS_E_INVALID_SESSION:
++    case GNUTLS_E_INVALID_REQUEST:
++    case GNUTLS_E_INVALID_PASSWORD:
++    case GNUTLS_E_ILLEGAL_PARAMETER:
++    case GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION:
++    case GNUTLS_E_UNEXPECTED_PACKET:
++    case GNUTLS_E_UNEXPECTED_PACKET_LENGTH:
++    case GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET:
++    case GNUTLS_E_UNWANTED_ALGORITHM:
++    case GNUTLS_E_USER_ERROR:
++        status = PJ_EINVAL;
++        break;
++    default:
++        status = PJ_EUNKNOWN;
++        break;
++    }
++
++    /* Not thread safe */
++    tls_last_error = err;
++    if (ssock)
++        ssock->last_err = err;
++    return status;
++}
++
++
++/* Get error string from GnuTLS using tls_last_error */
++static pj_str_t tls_strerror(pj_status_t status,
++                             char *buf, pj_size_t bufsize)
++{
++    pj_str_t errstr;
++    const char *tmp = gnutls_strerror(tls_last_error);
++
++#if defined(PJ_HAS_ERROR_STRING) && (PJ_HAS_ERROR_STRING != 0)
++    if (tmp) {
++        pj_ansi_strncpy(buf, tmp, bufsize);
++        errstr = pj_str(buf);
++        return errstr;
++    }
++#endif /* PJ_HAS_ERROR_STRING */
++
++    errstr.ptr = buf;
++    errstr.slen = pj_ansi_snprintf(buf, bufsize, "GnuTLS error %d: %s",
++                                   tls_last_error, tmp);
++    if (errstr.slen < 1 || errstr.slen >= (int) bufsize)
++        errstr.slen = bufsize - 1;
++
++    return errstr;
++}
++
++
++/* GnuTLS way of reporting internal operations. */
++static void tls_print_logs(int level, const char* msg)
++{
++    PJ_LOG(3, (THIS_FILE, "GnuTLS [%d]: %s", level, msg));
++}
++
++
++/* Initialize GnuTLS. */
++static pj_status_t tls_init(void)
++{
++    /* Register error subsystem */
++    pj_status_t status = pj_register_strerror(PJ_ERRNO_START_USER +
++                                              PJ_ERRNO_SPACE_SIZE * 6,
++                                              PJ_ERRNO_SPACE_SIZE,
++                                              &tls_strerror);
++    pj_assert(status == PJ_SUCCESS);
++
++    /* Init GnuTLS library */
++    int ret = gnutls_global_init();
++    if (ret < 0)
++        return tls_status_from_err(NULL, ret);
++
++    gnutls_global_set_log_level(GNUTLS_LOG_LEVEL);
++    gnutls_global_set_log_function(tls_print_logs);
++
++    /* Init available ciphers */
++    if (!tls_available_ciphers) {
++        unsigned int i;
++
++        for (i = 0; ; i++) {
++            unsigned char id[2];
++            const char *suite = gnutls_cipher_suite_info(i, (unsigned char *)id,
++                                                         NULL, NULL, NULL, NULL);
++            tls_ciphers[i].id = 0;
++            /* usually the array size is bigger than the number of available
++             * ciphers anyway, so by checking here we can exit the loop as soon
++             * as either all ciphers have been added or the array is full */
++            if (suite && i < PJ_ARRAY_SIZE(tls_ciphers)) {
++                tls_ciphers[i].id = (pj_ssl_cipher)
++                    (pj_uint32_t) ((id[0] << 8) | id[1]);
++                tls_ciphers[i].name = suite;
++            } else
++                break;
++        }
++
++        tls_available_ciphers = i;
++    }
++
++    return PJ_SUCCESS;
++}
++
++
++/* Shutdown GnuTLS */
++static void tls_deinit(void)
++{
++    gnutls_global_deinit();
++}
++
++
++/* Callback invoked every time a certificate has to be validated. */
++static int tls_cert_verify_cb(gnutls_session_t session)
++{
++    pj_ssl_sock_t *ssock;
++    unsigned int status;
++    int ret;
++
++    /* Get SSL socket instance */
++    ssock = (pj_ssl_sock_t *)gnutls_session_get_ptr(session);
++    pj_assert(ssock);
++
++    /* Support only x509 format */
++    ret = gnutls_certificate_type_get(session) != GNUTLS_CRT_X509;
++    if (ret < 0) {
++        ssock->verify_status |= PJ_SSL_CERT_EINVALID_FORMAT;
++        return GNUTLS_E_CERTIFICATE_ERROR;
++    }
++
++    /* Store verification status */
++    ret = gnutls_certificate_verify_peers2(session, &status);
++    if (ret < 0) {
++        ssock->verify_status |= PJ_SSL_CERT_EUNKNOWN;
++        return GNUTLS_E_CERTIFICATE_ERROR;
++    }
++    if (ssock->param.verify_peer) {
++    if (status & GNUTLS_CERT_INVALID) {
++        if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
++            ssock->verify_status |= PJ_SSL_CERT_EISSUER_NOT_FOUND;
++        else if (status & GNUTLS_CERT_EXPIRED ||
++                 status & GNUTLS_CERT_NOT_ACTIVATED)
++            ssock->verify_status |= PJ_SSL_CERT_EVALIDITY_PERIOD;
++        else if (status & GNUTLS_CERT_SIGNER_NOT_CA ||
++                 status & GNUTLS_CERT_INSECURE_ALGORITHM)
++            ssock->verify_status |= PJ_SSL_CERT_EUNTRUSTED;
++        else if (status & GNUTLS_CERT_UNEXPECTED_OWNER ||
++                 status & GNUTLS_CERT_MISMATCH)
++            ssock->verify_status |= PJ_SSL_CERT_EISSUER_MISMATCH;
++        else if (status & GNUTLS_CERT_REVOKED)
++            ssock->verify_status |= PJ_SSL_CERT_EREVOKED;
++        else
++            ssock->verify_status |= PJ_SSL_CERT_EUNKNOWN;
++
++        return GNUTLS_E_CERTIFICATE_ERROR;
++    }
++
++    /* When verification is not requested just return ok here, however
++     * applications can still get the verification status. */
++        gnutls_x509_crt_t cert;
++        unsigned int cert_list_size;
++        const gnutls_datum_t *cert_list;
++        int ret;
++
++        ret = gnutls_x509_crt_init(&cert);
++        if (ret < 0)
++            goto out;
++
++        cert_list = gnutls_certificate_get_peers(session, &cert_list_size);
++        if (cert_list == NULL) {
++            ret = GNUTLS_E_NO_CERTIFICATE_FOUND;
++            goto out;
++        }
++
++        /* TODO: verify whole chain perhaps? */
++        ret = gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
++        if (ret < 0)
++            ret = gnutls_x509_crt_import(cert, &cert_list[0],
++                                         GNUTLS_X509_FMT_PEM);
++        if (ret < 0) {
++            ssock->verify_status |= PJ_SSL_CERT_EINVALID_FORMAT;
++            goto out;
++        }
++        ret = gnutls_x509_crt_check_hostname(cert, ssock->param.server_name.ptr);
++        if (ret < 0)
++            goto out;
++
++        gnutls_x509_crt_deinit(cert);
++
++        /* notify GnuTLS to continue handshake normally */
++        return GNUTLS_E_SUCCESS;
++
++out:
++        tls_last_error = ret;
++        ssock->verify_status |= PJ_SSL_CERT_EUNKNOWN;
++        return GNUTLS_E_CERTIFICATE_ERROR;
++    }
++
++    return GNUTLS_E_SUCCESS;
++}
++
++
++/* gnutls_handshake() and gnutls_record_send() will call this function to
++ * send/write (encrypted) data */
++static ssize_t tls_data_push(gnutls_transport_ptr_t ptr,
++                             const void *data, size_t len)
++{
++    pj_ssl_sock_t *ssock = (pj_ssl_sock_t *)ptr;
++
++    pj_lock_acquire(ssock->circ_buf_output_mutex);
++    if (circ_write(&ssock->circ_buf_output, data, len) != PJ_SUCCESS) {
++        pj_lock_release(ssock->circ_buf_output_mutex);
++
++        gnutls_transport_set_errno(ssock->session, PJ_ENOMEM);
++        return -1;
++    }
++
++    pj_lock_release(ssock->circ_buf_output_mutex);
++
++    return len;
++}
++
++
++/* gnutls_handshake() and gnutls_record_recv() will call this function to
++ * receive/read (encrypted) data */
++static ssize_t tls_data_pull(gnutls_transport_ptr_t ptr,
++                             void *data, pj_size_t len)
++{
++    pj_ssl_sock_t *ssock = (pj_ssl_sock_t *)ptr;
++
++    pj_lock_acquire(ssock->circ_buf_input_mutex);
++
++    if (circ_empty(&ssock->circ_buf_input)) {
++        pj_lock_release(ssock->circ_buf_input_mutex);
++
++        /* Data buffers not yet filled */
++        gnutls_transport_set_errno(ssock->session, PJ_EAGAIN);
++        return -1;
++    }
++
++    pj_size_t circ_buf_size = circ_size(&ssock->circ_buf_input);
++    pj_size_t read_size = PJ_MIN(circ_buf_size, len);
++
++    circ_read(&ssock->circ_buf_input, data, read_size);
++
++    pj_lock_release(ssock->circ_buf_input_mutex);
++
++    return read_size;
++}
++
++
++/* Append a string to the priority string, only once. */
++static pj_status_t tls_str_append_once(pj_str_t *dst, pj_str_t *src)
++{
++    if (pj_strstr(dst, src) == NULL) {
++        /* Check buffer size */
++        if (dst->slen + src->slen + 3 > 1024)
++            return PJ_ETOOMANY;
++
++        pj_strcat2(dst, ":+");
++        pj_strcat(dst, src);
++    }
++    return PJ_SUCCESS;
++}
++
++
++/* Generate priority string with user preference order. */
++static pj_status_t tls_priorities_set(pj_ssl_sock_t *ssock)
++{
++    char buf[1024];
++    char priority_buf[256];
++    pj_str_t cipher_list;
++    pj_str_t compression = pj_str("COMP-NULL");
++    pj_str_t server = pj_str(":%SERVER_PRECEDENCE");
++    int i, j, ret;
++    pj_str_t priority;
++    const char *err;
++
++    pj_strset(&cipher_list, buf, 0);
++    pj_strset(&priority, priority_buf, 0);
++
++    /* For each level, enable only the requested protocol */
++    pj_strcat2(&priority, "NORMAL:");
++    if (ssock->param.proto & PJ_SSL_SOCK_PROTO_TLS1_2) {
++        pj_strcat2(&priority, "+VERS-TLS1.2:");
++    }
++    if (ssock->param.proto & PJ_SSL_SOCK_PROTO_TLS1_1) {
++        pj_strcat2(&priority, "+VERS-TLS1.1:");
++    }
++    if (ssock->param.proto & PJ_SSL_SOCK_PROTO_TLS1) {
++        pj_strcat2(&priority, "+VERS-TLS1.0:");
++    }
++    if (ssock->param.proto & PJ_SSL_SOCK_PROTO_SSL3) {
++        pj_strcat2(&priority, "+VERS-SSL3.0:");
++    } else {
++        pj_strcat2(&priority, "-VERS-SSL3.0:");
++    }
++    pj_strcat2(&priority, "%LATEST_RECORD_VERSION");
++
++    pj_strcat(&cipher_list, &priority);
++    for (i = 0; i < ssock->param.ciphers_num; i++) {
++        for (j = 0; ; j++) {
++            pj_ssl_cipher c;
++            const char *suite;
++            unsigned char id[2];
++            gnutls_protocol_t proto;
++            gnutls_kx_algorithm_t kx;
++            gnutls_mac_algorithm_t mac;
++            gnutls_cipher_algorithm_t algo;
++
++            suite = gnutls_cipher_suite_info(j, (unsigned char *)id,
++                                             &kx, &algo, &mac, &proto);
++            if (!suite)
++                break;
++
++            c = (pj_ssl_cipher) (pj_uint32_t) ((id[0] << 8) | id[1]);
++            if (ssock->param.ciphers[i] == c) {
++                char temp[256];
++                pj_str_t cipher_entry;
++
++                /* Protocol version */
++                pj_strset(&cipher_entry, temp, 0);
++                pj_strcat2(&cipher_entry, "VERS-");
++                pj_strcat2(&cipher_entry, gnutls_protocol_get_name(proto));
++                ret = tls_str_append_once(&cipher_list, &cipher_entry);
++                if (ret != PJ_SUCCESS)
++                    return ret;
++
++                /* Cipher */
++                pj_strset(&cipher_entry, temp, 0);
++                pj_strcat2(&cipher_entry, gnutls_cipher_get_name(algo));
++                ret = tls_str_append_once(&cipher_list, &cipher_entry);
++                if (ret != PJ_SUCCESS)
++                    return ret;
++
++                /* Mac */
++                pj_strset(&cipher_entry, temp, 0);
++                pj_strcat2(&cipher_entry, gnutls_mac_get_name(mac));
++                ret = tls_str_append_once(&cipher_list, &cipher_entry);
++                if (ret != PJ_SUCCESS)
++                    return ret;
++
++                /* Key exchange */
++                pj_strset(&cipher_entry, temp, 0);
++                pj_strcat2(&cipher_entry, gnutls_kx_get_name(kx));
++                ret = tls_str_append_once(&cipher_list, &cipher_entry);
++                if (ret != PJ_SUCCESS)
++                    return ret;
++
++                /* Compression is always disabled */
++                /* Signature is level-default */
++                break;
++            }
++        }
++    }
++
++    /* Disable compression, it's a TLS-only extension after all */
++    tls_str_append_once(&cipher_list, &compression);
++
++    /* Server will be the one deciding which crypto to use */
++    if (ssock->is_server) {
++        if (cipher_list.slen + server.slen + 1 > sizeof(buf))
++            return PJ_ETOOMANY;
++        else
++            pj_strcat(&cipher_list, &server);
++    }
++
++    /* End the string and print it */
++    cipher_list.ptr[cipher_list.slen] = '\0';
++    PJ_LOG(5, (ssock->pool->obj_name, "Priority string: %s", cipher_list.ptr));
++
++    /* Set our priority string */
++    ret = gnutls_priority_set_direct(ssock->session,
++                                        cipher_list.ptr, &err);
++    if (ret < 0) {
++        tls_last_error = GNUTLS_E_INVALID_REQUEST;
++        return PJ_EINVAL;
++    }
++
++    return PJ_SUCCESS;
++}
++
++
++/* Load root CA file or load the installed ones. */
++static pj_status_t tls_trust_set(pj_ssl_sock_t *ssock)
++{
++    int ntrusts = 0;
++    int err;
++
++    err = gnutls_certificate_set_x509_system_trust(ssock->xcred);
++    if (err > 0)
++        ntrusts += err;
++    err = gnutls_certificate_set_x509_trust_file(ssock->xcred,
++                                                 TRUST_STORE_FILE1,
++                                                 GNUTLS_X509_FMT_PEM);
++    if (err > 0)
++        ntrusts += err;
++
++    err = gnutls_certificate_set_x509_trust_file(ssock->xcred,
++                                                 TRUST_STORE_FILE2,
++                                                 GNUTLS_X509_FMT_PEM);
++    if (err > 0)
++        ntrusts += err;
++
++    if (ntrusts > 0)
++        return PJ_SUCCESS;
++    else if (!ntrusts)
++        return PJ_ENOTFOUND;
++    else
++        return PJ_EINVAL;
++}
++
++#if GNUTLS_VERSION_NUMBER < 0x030306
++
++#ifdef _POSIX_PATH_MAX
++# define GNUTLS_PATH_MAX _POSIX_PATH_MAX
++#else
++# define GNUTLS_PATH_MAX 256
++#endif
++
++static
++int gnutls_certificate_set_x509_trust_dir(gnutls_certificate_credentials_t cred, const char *dirname, unsigned type)
++{
++    DIR *dirp;
++    struct dirent *d;
++    int ret;
++    int r = 0;
++    char path[GNUTLS_PATH_MAX];
++#ifndef _WIN32
++    struct dirent e;
++#endif
++
++    dirp = opendir(dirname);
++    if (dirp != NULL) {
++        do {
++#ifdef _WIN32
++            d = readdir(dirp);
++            if (d != NULL) {
++#else
++            ret = readdir_r(dirp, &e, &d);
++            if (ret == 0 && d != NULL
++#ifdef _DIRENT_HAVE_D_TYPE
++                && (d->d_type == DT_REG || d->d_type == DT_LNK || d->d_type == DT_UNKNOWN)
++#endif
++            ) {
++#endif
++                snprintf(path, sizeof(path), "%s/%s",
++                     dirname, d->d_name);
++
++                ret = gnutls_certificate_set_x509_trust_file(cred, path, type);
++                if (ret >= 0)
++                    r += ret;
++            }
++        }
++        while (d != NULL);
++        closedir(dirp);
++    }
++
++    return r;
++}
++
++#endif
++
++/* Create and initialize new GnuTLS context and instance */
++static pj_status_t tls_open(pj_ssl_sock_t *ssock)
++{
++    pj_ssl_cert_t *cert;
++    pj_status_t status;
++    int ret;
++
++    pj_assert(ssock);
++
++    cert = ssock->cert;
++
++    /* Even if reopening is harmless, having one instance only simplifies
++     * deallocating it later on */
++    if (!ssock->tls_init_count) {
++        ssock->tls_init_count++;
++        ret = tls_init();
++        if (ret < 0)
++            return ret;
++    } else
++        return PJ_SUCCESS;
++
++    /* Start this socket session */
++    ret = gnutls_init(&ssock->session, ssock->is_server ? GNUTLS_SERVER
++                                                        : GNUTLS_CLIENT);
++    if (ret < 0)
++        goto out;
++
++    /* Set the ssock object to be retrieved by transport (send/recv) and by
++     * user data from this session */
++    gnutls_transport_set_ptr(ssock->session,
++                             (gnutls_transport_ptr_t) (uintptr_t) ssock);
++    gnutls_session_set_ptr(ssock->session,
++                           (gnutls_transport_ptr_t) (uintptr_t) ssock);
++
++    /* Initialize input circular buffer */
++    status = circ_init(ssock->pool->factory, &ssock->circ_buf_input, 512);
++    if (status != PJ_SUCCESS)
++        return status;
++
++    /* Initialize output circular buffer */
++    status = circ_init(ssock->pool->factory, &ssock->circ_buf_output, 512);
++    if (status != PJ_SUCCESS)
++        return status;
++
++    /* Set the callback that allows GnuTLS to PUSH and PULL data
++     * TO and FROM the transport layer */
++    gnutls_transport_set_push_function(ssock->session, tls_data_push);
++    gnutls_transport_set_pull_function(ssock->session, tls_data_pull);
++
++    /* Determine which cipher suite to support */
++    status = tls_priorities_set(ssock);
++    if (status != PJ_SUCCESS)
++        return status;
++
++    /* Allocate credentials for handshaking and transmission */
++    ret = gnutls_certificate_allocate_credentials(&ssock->xcred);
++    if (ret < 0)
++        goto out;
++    gnutls_certificate_set_verify_function(ssock->xcred, tls_cert_verify_cb);
++
++    /* Load system trust file(s) */
++    status = tls_trust_set(ssock);
++    if (status != PJ_SUCCESS)
++        return status;
++
++    /* Load user-provided CA, certificate and key if available */
++    if (cert) {
++        /* Load CA if one is specified. */
++        if (cert->CA_file.slen) {
++            ret = gnutls_certificate_set_x509_trust_file(ssock->xcred,
++                                                         cert->CA_file.ptr,
++                                                         GNUTLS_X509_FMT_PEM);
++            if (ret < 0)
++                ret = gnutls_certificate_set_x509_trust_file(ssock->xcred,
++                                                             cert->CA_file.ptr,
++                                                             GNUTLS_X509_FMT_DER);
++            if (ret < 0)
++                goto out;
++        }
++        if (cert->CA_path.slen) {
++            ret = gnutls_certificate_set_x509_trust_dir(ssock->xcred,
++                                                         cert->CA_path.ptr,
++                                                         GNUTLS_X509_FMT_PEM);
++            if (ret < 0)
++                ret = gnutls_certificate_set_x509_trust_dir(ssock->xcred,
++                                                             cert->CA_path.ptr,
++                                                             GNUTLS_X509_FMT_DER);
++            if (ret < 0)
++                goto out;
++        }
++
++        /* Load certificate, key and pass if one is specified */
++        if (cert->cert_file.slen && cert->privkey_file.slen) {
++            const char *prikey_file = cert->privkey_file.ptr;
++            const char *prikey_pass = cert->privkey_pass.slen
++                                    ? cert->privkey_pass.ptr
++                                    : NULL;
++            ret = gnutls_certificate_set_x509_key_file2(ssock->xcred,
++                                                        cert->cert_file.ptr,
++                                                        prikey_file,
++                                                        GNUTLS_X509_FMT_PEM,
++                                                        prikey_pass,
++                                                        0);
++            if (ret != GNUTLS_E_SUCCESS)
++                ret = gnutls_certificate_set_x509_key_file2(ssock->xcred,
++                                                            cert->cert_file.ptr,
++                                                            prikey_file,
++                                                            GNUTLS_X509_FMT_DER,
++                                                            prikey_pass,
++                                                            0);
++            if (ret < 0)
++                goto out;
++        }
++    }
++
++    /* Require client certificate if asked */
++    if (ssock->is_server && ssock->param.require_client_cert)
++        gnutls_certificate_server_set_request(ssock->session,
++                                              GNUTLS_CERT_REQUIRE);
++
++    /* Finally set credentials for this session */
++    ret = gnutls_credentials_set(ssock->session,
++                                 GNUTLS_CRD_CERTIFICATE, ssock->xcred);
++    if (ret < 0)
++        goto out;
++
++    ret = GNUTLS_E_SUCCESS;
++out:
++    return tls_status_from_err(ssock, ret);
++}
++
++
++/* Destroy GnuTLS credentials and session. */
++static void tls_close(pj_ssl_sock_t *ssock)
++{
++    if (ssock->session) {
++        gnutls_bye(ssock->session, GNUTLS_SHUT_RDWR);
++        gnutls_deinit(ssock->session);
++        ssock->session = NULL;
++    }
++
++    if (ssock->xcred) {
++        gnutls_certificate_free_credentials(ssock->xcred);
++        ssock->xcred = NULL;
++    }
++
++    /* Free GnuTLS library */
++    if (ssock->tls_init_count) {
++        ssock->tls_init_count--;
++        tls_deinit();
++    }
++
++    /* Destroy circular buffers */
++    circ_deinit(&ssock->circ_buf_input);
++    circ_deinit(&ssock->circ_buf_output);
++}
++
++
++/* Reset socket state. */
++static void tls_sock_reset(pj_ssl_sock_t *ssock)
++{
++    ssock->connection_state = TLS_STATE_NULL;
++
++    tls_close(ssock);
++
++    if (ssock->asock) {
++        pj_activesock_close(ssock->asock);
++        ssock->asock = NULL;
++        ssock->sock = PJ_INVALID_SOCKET;
++    }
++    if (ssock->sock != PJ_INVALID_SOCKET) {
++        pj_sock_close(ssock->sock);
++        ssock->sock = PJ_INVALID_SOCKET;
++    }
++
++    ssock->last_err = tls_last_error = GNUTLS_E_SUCCESS;
++}
++
++
++/* Get Common Name field string from a general name string */
++static void tls_cert_get_cn(const pj_str_t *gen_name, pj_str_t *cn)
++{
++    pj_str_t CN_sign = {"CN=", 3};
++    char *p, *q;
++
++    pj_bzero(cn, sizeof(cn));
++
++    p = pj_strstr(gen_name, &CN_sign);
++    if (!p)
++        return;
++
++    p += 3; /* shift pointer to value part */
++    pj_strset(cn, p, gen_name->slen - (p - gen_name->ptr));
++    q = pj_strchr(cn, ',');
++    if (q)
++        cn->slen = q - p;
++}
++
++
++/* Get certificate info; in case the certificate info is already populated,
++ * this function will check if the contents need updating by inspecting the
++ * issuer and the serial number. */
++static void tls_cert_get_info(pj_pool_t *pool, pj_ssl_cert_info *ci, gnutls_x509_crt_t cert)
++{
++    pj_bool_t update_needed;
++    char buf[512] = { 0 };
++    size_t bufsize = sizeof(buf);
++    pj_uint8_t serial_no[64] = { 0 }; /* should be >= sizeof(ci->serial_no) */
++    size_t serialsize = sizeof(serial_no);
++    size_t len = sizeof(buf);
++    int i, ret, seq = 0;
++    pj_ssl_cert_name_type type;
++
++    pj_assert(pool && ci && cert);
++
++    /* Get issuer */
++    gnutls_x509_crt_get_issuer_dn(cert, buf, &bufsize);
++
++    /* Get serial no */
++    gnutls_x509_crt_get_serial(cert, serial_no, &serialsize);
++
++    /* Check if the contents need to be updated */
++    update_needed = pj_strcmp2(&ci->issuer.info, buf) ||
++                    pj_memcmp(ci->serial_no, serial_no, serialsize);
++    if (!update_needed)
++        return;
++
++    /* Update cert info */
++
++    pj_bzero(ci, sizeof(pj_ssl_cert_info));
++
++    /* Version */
++    ci->version = gnutls_x509_crt_get_version(cert);
++
++    /* Issuer */
++    pj_strdup2(pool, &ci->issuer.info, buf);
++    tls_cert_get_cn(&ci->issuer.info, &ci->issuer.cn);
++
++    /* Serial number */
++    pj_memcpy(ci->serial_no, serial_no, sizeof(ci->serial_no));
++
++    /* Subject */
++    bufsize = sizeof(buf);
++    gnutls_x509_crt_get_dn(cert, buf, &bufsize);
++    pj_strdup2(pool, &ci->subject.info, buf);
++    tls_cert_get_cn(&ci->subject.info, &ci->subject.cn);
++
++    /* Validity */
++    ci->validity.end.sec = gnutls_x509_crt_get_expiration_time(cert);
++    ci->validity.start.sec = gnutls_x509_crt_get_activation_time(cert);
++    ci->validity.gmt = 0;
++
++    /* Subject Alternative Name extension */
++    if (ci->version >= 3) {
++        char out[256] = { 0 };
++        /* Get the number of all alternate names so that we can allocate
++         * the correct number of bytes in subj_alt_name */
++        while (gnutls_x509_crt_get_subject_alt_name(cert, seq, out, &len,
++                                                    NULL) != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
++            seq++;
++
++        ci->subj_alt_name.entry = pj_pool_calloc(pool, seq,
++                                                 sizeof(*ci->subj_alt_name.entry));
++        if (!ci->subj_alt_name.entry) {
++            tls_last_error = GNUTLS_E_MEMORY_ERROR;
++            return;
++        }
++
++        /* Now populate the alternative names */
++        for (i = 0; i < seq; i++) {
++            len = sizeof(out) - 1;
++            ret = gnutls_x509_crt_get_subject_alt_name(cert, i, out, &len, NULL);
++            switch (ret) {
++            case GNUTLS_SAN_IPADDRESS:
++                type = PJ_SSL_CERT_NAME_IP;
++                pj_inet_ntop2(len == sizeof(pj_in6_addr) ? pj_AF_INET6()
++                                                         : pj_AF_INET(),
++                              out, buf, sizeof(buf));
++                break;
++            case GNUTLS_SAN_URI:
++                type = PJ_SSL_CERT_NAME_URI;
++                break;
++            case GNUTLS_SAN_RFC822NAME:
++                type = PJ_SSL_CERT_NAME_RFC822;
++                break;
++            case GNUTLS_SAN_DNSNAME:
++                type = PJ_SSL_CERT_NAME_DNS;
++                break;
++            default:
++                type = PJ_SSL_CERT_NAME_UNKNOWN;
++                break;
++            }
++
++            if (len && type != PJ_SSL_CERT_NAME_UNKNOWN) {
++                ci->subj_alt_name.entry[ci->subj_alt_name.cnt].type = type;
++                pj_strdup2(pool,
++                           &ci->subj_alt_name.entry[ci->subj_alt_name.cnt].name,
++                           type == PJ_SSL_CERT_NAME_IP ? buf : out);
++                ci->subj_alt_name.cnt++;
++            }
++        }
++        /* TODO: if no DNS alt. names were found, we could check against
++         * the commonName as per RFC3280. */
++    }
++}
++
++static void tls_cert_get_chain_raw(pj_pool_t *pool, pj_ssl_cert_info *ci, const gnutls_datum_t *certs, size_t certs_num)
++{
++    size_t i=0;
++    ci->raw_chain.cert_raw = pj_pool_calloc(pool, certs_num, sizeof(*ci->raw_chain.cert_raw));
++    ci->raw_chain.cnt = certs_num;
++    for (i=0; i < certs_num; ++i) {
++        const pj_str_t crt_raw = {(const char*)certs[i].data, (pj_ssize_t)certs[i].size};
++        pj_strdup(pool, ci->raw_chain.cert_raw+i, &crt_raw);
++    }
++}
++
++/* Update local & remote certificates info. This function should be
++ * called after handshake or renegotiation successfully completed. */
++static void tls_cert_update(pj_ssl_sock_t *ssock)
++{
++    gnutls_x509_crt_t cert = NULL;
++    const gnutls_datum_t *us;
++    const gnutls_datum_t *certs;
++    unsigned int certslen = 0;
++    int ret = GNUTLS_CERT_INVALID;
++
++    pj_assert(ssock->connection_state == TLS_STATE_ESTABLISHED);
++
++    /* Get active local certificate */
++    us = gnutls_certificate_get_ours(ssock->session);
++    if (!us)
++        goto us_out;
++
++    ret = gnutls_x509_crt_init(&cert);
++    if (ret < 0)
++        goto us_out;
++    ret = gnutls_x509_crt_import(cert, us, GNUTLS_X509_FMT_DER);
++    if (ret < 0)
++        ret = gnutls_x509_crt_import(cert, us, GNUTLS_X509_FMT_PEM);
++    if (ret < 0)
++        goto us_out;
++
++    tls_cert_get_info(ssock->pool, &ssock->local_cert_info, cert);
++    tls_cert_get_chain_raw(ssock->pool, &ssock->local_cert_info, us, 1);
++
++us_out:
++    tls_last_error = ret;
++    if (cert)
++        gnutls_x509_crt_deinit(cert);
++    else
++        pj_bzero(&ssock->local_cert_info, sizeof(pj_ssl_cert_info));
++
++    cert = NULL;
++
++    /* Get active remote certificate */
++    certs = gnutls_certificate_get_peers(ssock->session, &certslen);
++    if (certs == NULL || certslen == 0)
++        goto peer_out;
++
++    ret = gnutls_x509_crt_init(&cert);
++    if (ret < 0)
++        goto peer_out;
++
++    ret = gnutls_x509_crt_import(cert, certs, GNUTLS_X509_FMT_PEM);
++    if (ret < 0)
++        ret = gnutls_x509_crt_import(cert, certs, GNUTLS_X509_FMT_DER);
++    if (ret < 0)
++        goto peer_out;
++
++    tls_cert_get_info(ssock->pool, &ssock->remote_cert_info, cert);
++    tls_cert_get_chain_raw(ssock->pool, &ssock->remote_cert_info, certs, certslen);
++
++peer_out:
++    tls_last_error = ret;
++    if (cert)
++        gnutls_x509_crt_deinit(cert);
++    else
++        pj_bzero(&ssock->remote_cert_info, sizeof(pj_ssl_cert_info));
++}
++
++
++/* When handshake completed:
++ * - notify application
++ * - if handshake failed, reset SSL state
++ * - return PJ_FALSE when SSL socket instance is destroyed by application. */
++static pj_bool_t on_handshake_complete(pj_ssl_sock_t *ssock,
++                                       pj_status_t status)
++{
++    pj_bool_t ret = PJ_TRUE;
++
++    /* Cancel handshake timer */
++    if (ssock->timer.id == TIMER_HANDSHAKE_TIMEOUT) {
++        pj_timer_heap_cancel(ssock->param.timer_heap, &ssock->timer);
++        ssock->timer.id = TIMER_NONE;
++    }
++
++    /* Update certificates info on successful handshake */
++    if (status == PJ_SUCCESS)
++        tls_cert_update(ssock);
++
++    /* Accepting */
++    if (ssock->is_server) {
++        if (status != PJ_SUCCESS) {
++            /* Handshake failed in accepting, destroy our self silently. */
++
++            char errmsg[PJ_ERR_MSG_SIZE];
++            char buf[PJ_INET6_ADDRSTRLEN + 10];
++
++            pj_strerror(status, errmsg, sizeof(errmsg));
++            PJ_LOG(3, (ssock->pool->obj_name,
++                       "Handshake failed in accepting %s: %s",
++                       pj_sockaddr_print(&ssock->rem_addr, buf, sizeof(buf), 3),
++                       errmsg));
++
++            /* Workaround for ticket #985 */
++#if (defined(PJ_WIN32) && PJ_WIN32 != 0) || (defined(PJ_WIN64) && PJ_WIN64 != 0)
++            if (ssock->param.timer_heap) {
++                pj_time_val interval = {0, DELAYED_CLOSE_TIMEOUT};
++
++                tls_sock_reset(ssock);
++
++                ssock->timer.id = TIMER_CLOSE;
++                pj_time_val_normalize(&interval);
++                if (pj_timer_heap_schedule(ssock->param.timer_heap,
++                                           &ssock->timer, &interval) != 0)
++                {
++                    ssock->timer.id = TIMER_NONE;
++                    pj_ssl_sock_close(ssock);
++                }
++            } else
++#endif /* PJ_WIN32 */
++            {
++                pj_ssl_sock_close(ssock);
++            }
++
++            return PJ_FALSE;
++        }
++        /* Notify application the newly accepted SSL socket */
++        if (ssock->param.cb.on_accept_complete)
++            ret = (*ssock->param.cb.on_accept_complete)
++                      (ssock->parent, ssock, (pj_sockaddr_t*)&ssock->rem_addr,
++                       pj_sockaddr_get_len((pj_sockaddr_t*)&ssock->rem_addr));
++
++    } else { /* Connecting */
++        /* On failure, reset SSL socket state first, as app may try to
++         * reconnect in the callback. */
++        if (status != PJ_SUCCESS) {
++            /* Server disconnected us, possibly due to negotiation failure */
++            tls_sock_reset(ssock);
++        }
++        if (ssock->param.cb.on_connect_complete) {
++
++            ret = (*ssock->param.cb.on_connect_complete)(ssock, status);
++        }
++    }
++
++    return ret;
++}
++
++static write_data_t *alloc_send_data(pj_ssl_sock_t *ssock, pj_size_t len)
++{
++    send_buf_t *send_buf = &ssock->send_buf;
++    pj_size_t avail_len, skipped_len = 0;
++    char *reg1, *reg2;
++    pj_size_t reg1_len, reg2_len;
++    write_data_t *p;
++
++    /* Check buffer availability */
++    avail_len = send_buf->max_len - send_buf->len;
++    if (avail_len < len)
++        return NULL;
++
++    /* If buffer empty, reset start pointer and return it */
++    if (send_buf->len == 0) {
++        send_buf->start = send_buf->buf;
++        send_buf->len   = len;
++        p = (write_data_t*)send_buf->start;
++        goto init_send_data;
++    }
++
++    /* Free space may be wrapped/splitted into two regions, so let's
++     * analyze them if any region can hold the write data. */
++    reg1 = send_buf->start + send_buf->len;
++    if (reg1 >= send_buf->buf + send_buf->max_len)
++        reg1 -= send_buf->max_len;
++        reg1_len = send_buf->max_len - send_buf->len;
++    if (reg1 + reg1_len > send_buf->buf + send_buf->max_len) {
++        reg1_len = send_buf->buf + send_buf->max_len - reg1;
++        reg2 = send_buf->buf;
++        reg2_len = send_buf->start - send_buf->buf;
++    } else {
++        reg2 = NULL;
++        reg2_len = 0;
++    }
++
++    /* More buffer availability check, note that the write data must be in
++     * a contigue buffer. */
++    avail_len = PJ_MAX(reg1_len, reg2_len);
++    if (avail_len < len)
++    return NULL;
++
++    /* Get the data slot */
++    if (reg1_len >= len) {
++        p = (write_data_t*)reg1;
++    } else {
++        p = (write_data_t*)reg2;
++        skipped_len = reg1_len;
++    }
++
++    /* Update buffer length */
++    send_buf->len += len + skipped_len;
++
++init_send_data:
++    /* Init the new send data */
++    pj_bzero(p, sizeof(*p));
++    pj_list_init(p);
++    pj_list_push_back(&ssock->send_pending, p);
++
++    return p;
++}
++
++static void free_send_data(pj_ssl_sock_t *ssock, write_data_t *wdata)
++{
++    send_buf_t *buf = &ssock->send_buf;
++    write_data_t *spl = &ssock->send_pending;
++
++    pj_assert(!pj_list_empty(&ssock->send_pending));
++
++    /* Free slot from the buffer */
++    if (spl->next == wdata && spl->prev == wdata) {
++    /* This is the only data, reset the buffer */
++    buf->start = buf->buf;
++    buf->len = 0;
++    } else if (spl->next == wdata) {
++    /* This is the first data, shift start pointer of the buffer and
++     * adjust the buffer length.
++     */
++    buf->start = (char*)wdata->next;
++    if (wdata->next > wdata) {
++        buf->len -= ((char*)wdata->next - buf->start);
++    } else {
++        /* Overlapped */
++        pj_size_t right_len, left_len;
++        right_len = buf->buf + buf->max_len - (char*)wdata;
++        left_len  = (char*)wdata->next - buf->buf;
++        buf->len -= (right_len + left_len);
++    }
++    } else if (spl->prev == wdata) {
++    /* This is the last data, just adjust the buffer length */
++    if (wdata->prev < wdata) {
++        pj_size_t jump_len;
++        jump_len = (char*)wdata -
++               ((char*)wdata->prev + wdata->prev->record_len);
++        buf->len -= (wdata->record_len + jump_len);
++    } else {
++        /* Overlapped */
++        pj_size_t right_len, left_len;
++        right_len = buf->buf + buf->max_len -
++            ((char*)wdata->prev + wdata->prev->record_len);
++        left_len  = (char*)wdata + wdata->record_len - buf->buf;
++        buf->len -= (right_len + left_len);
++    }
++    }
++    /* For data in the middle buffer, just do nothing on the buffer. The slot
++     * will be freed later when freeing the first/last data. */
++
++    /* Remove the data from send pending list */
++    pj_list_erase(wdata);
++}
++
++#if 0
++/* Just for testing send buffer alloc/free */
++#include <pj/rand.h>
++pj_status_t pj_ssl_sock_ossl_test_send_buf(pj_pool_t *pool)
++{
++    enum { MAX_CHUNK_NUM = 20 };
++    unsigned chunk_size, chunk_cnt, i;
++    write_data_t *wdata[MAX_CHUNK_NUM] = {0};
++    pj_time_val now;
++    pj_ssl_sock_t *ssock = NULL;
++    pj_ssl_sock_param param;
++    pj_status_t status;
++
++    pj_gettimeofday(&now);
++    pj_srand((unsigned)now.sec);
++
++    pj_ssl_sock_param_default(&param);
++    status = pj_ssl_sock_create(pool, &param, &ssock);
++    if (status != PJ_SUCCESS) {
++        return status;
++    }
++
++    if (ssock->send_buf.max_len == 0) {
++        ssock->send_buf.buf = (char *)
++                              pj_pool_alloc(ssock->pool,
++                                            ssock->param.send_buffer_size);
++        ssock->send_buf.max_len = ssock->param.send_buffer_size;
++        ssock->send_buf.start = ssock->send_buf.buf;
++        ssock->send_buf.len = 0;
++    }
++
++    chunk_size = ssock->param.send_buffer_size / MAX_CHUNK_NUM / 2;
++    chunk_cnt = 0;
++    for (i = 0; i < MAX_CHUNK_NUM; i++) {
++        wdata[i] = alloc_send_data(ssock, pj_rand() % chunk_size + 321);
++        if (wdata[i])
++            chunk_cnt++;
++        else
++            break;
++    }
++
++    while (chunk_cnt) {
++        i = pj_rand() % MAX_CHUNK_NUM;
++        if (wdata[i]) {
++            free_send_data(ssock, wdata[i]);
++            wdata[i] = NULL;
++            chunk_cnt--;
++        }
++    }
++
++    if (ssock->send_buf.len != 0)
++        status = PJ_EBUG;
++
++    pj_ssl_sock_close(ssock);
++    return status;
++}
++#endif
++
++/* Flush write circular buffer to network socket. */
++static pj_status_t flush_circ_buf_output(pj_ssl_sock_t *ssock,
++                                         pj_ioqueue_op_key_t *send_key,
++                                         pj_size_t orig_len, unsigned flags)
++{
++    pj_ssize_t len;
++    write_data_t *wdata;
++    pj_size_t needed_len;
++    pj_status_t status;
++
++    pj_lock_acquire(ssock->circ_buf_output_mutex);
++
++    /* Check if there is data in the circular buffer, flush it if any */
++    if (circ_empty(&ssock->circ_buf_output)) {
++        pj_lock_release(ssock->circ_buf_output_mutex);
++
++        return PJ_SUCCESS;
++    }
++
++    len = circ_size(&ssock->circ_buf_output);
++
++    /* Calculate buffer size needed, and align it to 8 */
++    needed_len = len + sizeof(write_data_t);
++    needed_len = ((needed_len + 7) >> 3) << 3;
++
++    /* Allocate buffer for send data */
++    wdata = alloc_send_data(ssock, needed_len);
++    if (wdata == NULL) {
++        pj_lock_release(ssock->circ_buf_output_mutex);
++        return PJ_ENOMEM;
++    }
++
++    /* Copy the data and set its properties into the send data */
++    pj_ioqueue_op_key_init(&wdata->key, sizeof(pj_ioqueue_op_key_t));
++    wdata->key.user_data = wdata;
++    wdata->app_key = send_key;
++    wdata->record_len = needed_len;
++    wdata->data_len = len;
++    wdata->plain_data_len = orig_len;
++    wdata->flags = flags;
++    circ_read(&ssock->circ_buf_output, (pj_uint8_t *)&wdata->data, len);
++
++    /* Ticket #1573: Don't hold mutex while calling PJLIB socket send(). */
++    pj_lock_release(ssock->circ_buf_output_mutex);
++
++    /* Send it */
++    if (ssock->param.sock_type == pj_SOCK_STREAM()) {
++        status = pj_activesock_send(ssock->asock, &wdata->key,
++                                    wdata->data.content, &len,
++                                    flags);
++    } else {
++        status = pj_activesock_sendto(ssock->asock, &wdata->key,
++                                      wdata->data.content, &len,
++                                      flags,
++                                      (pj_sockaddr_t*)&ssock->rem_addr,
++                                      ssock->addr_len);
++    }
++
++    if (status != PJ_EPENDING) {
++        /* When the sending is not pending, remove the wdata from send
++         * pending list. */
++        pj_lock_acquire(ssock->circ_buf_output_mutex);
++        free_send_data(ssock, wdata);
++        pj_lock_release(ssock->circ_buf_output_mutex);
++    }
++
++    return status;
++}
++
++static void on_timer(pj_timer_heap_t *th, struct pj_timer_entry *te)
++{
++    pj_ssl_sock_t *ssock = (pj_ssl_sock_t*)te->user_data;
++    int timer_id = te->id;
++
++    te->id = TIMER_NONE;
++
++    PJ_UNUSED_ARG(th);
++
++    switch (timer_id) {
++    case TIMER_HANDSHAKE_TIMEOUT:
++        PJ_LOG(1, (ssock->pool->obj_name, "TLS timeout after %d.%ds",
++                   ssock->param.timeout.sec, ssock->param.timeout.msec));
++
++        on_handshake_complete(ssock, PJ_ETIMEDOUT);
++        break;
++    case TIMER_CLOSE:
++        pj_ssl_sock_close(ssock);
++        break;
++    default:
++        pj_assert(!"Unknown timer");
++        break;
++    }
++}
++
++
++/* Try to perform an asynchronous handshake */
++static pj_status_t tls_try_handshake(pj_ssl_sock_t *ssock)
++{
++    int ret;
++    pj_status_t status;
++
++    /* Perform SSL handshake */
++    ret = gnutls_handshake(ssock->session);
++
++    status = flush_circ_buf_output(ssock, &ssock->handshake_op_key, 0, 0);
++    if (status != PJ_SUCCESS)
++        return status;
++
++    if (ret == GNUTLS_E_SUCCESS) {
++        /* System are GO */
++        ssock->connection_state = TLS_STATE_ESTABLISHED;
++        status = PJ_SUCCESS;
++    } else if (!gnutls_error_is_fatal(ret)) {
++        /* Non fatal error, retry later (busy or again) */
++        status = PJ_EPENDING;
++    } else {
++        /* Fatal error invalidates session, no fallback */
++        status = PJ_EINVAL;
++    }
++
++    tls_last_error = ret;
++
++    return status;
++}
++
++
++/*
++ *******************************************************************
++ * Active socket callbacks.
++ *******************************************************************
++ */
++
++/* PJ_TRUE asks the socket to read more data, PJ_FALSE takes it off the queue */
++static pj_bool_t asock_on_data_read(pj_activesock_t *asock, void *data,
++                                    pj_size_t size, pj_status_t status,
++                                    pj_size_t *remainder)
++{
++    pj_ssl_sock_t *ssock = (pj_ssl_sock_t *)
++                           pj_activesock_get_user_data(asock);
++
++    pj_size_t app_remainder = 0;
++
++    if (data && size > 0) {
++        /* Push data into input circular buffer (for GnuTLS) */
++        pj_lock_acquire(ssock->circ_buf_input_mutex);
++        circ_write(&ssock->circ_buf_input, data, size);
++        pj_lock_release(ssock->circ_buf_input_mutex);
++    }
++
++    /* Check if SSL handshake hasn't finished yet */
++    if (ssock->connection_state == TLS_STATE_HANDSHAKING) {
++        pj_bool_t ret = PJ_TRUE;
++
++        if (status == PJ_SUCCESS)
++            status = tls_try_handshake(ssock);
++
++        /* Not pending is either success or failed */
++        if (status != PJ_EPENDING)
++            ret = on_handshake_complete(ssock, status);
++
++        return ret;
++    }
++
++    /* See if there is any decrypted data for the application */
++    if (ssock->read_started) {
++        do {
++            /* Get read data structure at the end of the data */
++            read_data_t *app_read_data = *(OFFSET_OF_READ_DATA_PTR(ssock, data));
++            int app_data_size = (int)(ssock->read_size - app_read_data->len);
++
++            /* Decrypt received data using GnuTLS (will read our input
++             * circular buffer) */
++            int decrypted_size = gnutls_record_recv(ssock->session,
++                                                    app_read_data->data +
++                                                    app_read_data->len,
++                                                    app_data_size);
++
++            if (decrypted_size > 0 || status != PJ_SUCCESS) {
++                if (ssock->param.cb.on_data_read) {
++                    pj_bool_t ret;
++                    app_remainder = 0;
++
++                    if (decrypted_size > 0)
++                        app_read_data->len += decrypted_size;
++
++                    ret = (*ssock->param.cb.on_data_read)(ssock,
++                                                          app_read_data->data,
++                                                          app_read_data->len,
++                                                          status,
++                                                          &app_remainder);
++
++                    if (!ret) {
++                        /* We've been destroyed */
++                        return PJ_FALSE;
++                    }
++
++                    /* Application may have left some data to be consumed
++                     * later as remainder */
++                    app_read_data->len = app_remainder;
++                }
++
++                /* Active socket signalled connection closed/error, this has
++                 * been signalled to the application along with any remaining
++                 * buffer. So, let's just reset SSL socket now.  */
++                if (status != PJ_SUCCESS) {
++                    tls_sock_reset(ssock);
++                    return PJ_FALSE;
++                }
++            } else if (decrypted_size == 0) {
++                /* Nothing more to read */
++
++                return PJ_TRUE;
++            } else if (decrypted_size == GNUTLS_E_AGAIN ||
++                       decrypted_size == GNUTLS_E_INTERRUPTED) {
++                return PJ_TRUE;
++            } else if (decrypted_size == GNUTLS_E_REHANDSHAKE) {
++                /* Seems like we are renegotiating */
++                pj_status_t try_handshake_status = tls_try_handshake(ssock);
++
++                /* Not pending is either success or failed */
++                if (try_handshake_status != PJ_EPENDING) {
++                    if (!on_handshake_complete(ssock, try_handshake_status)) {
++                        return PJ_FALSE;
++                    }
++                }
++
++                if (try_handshake_status != PJ_SUCCESS &&
++                    try_handshake_status != PJ_EPENDING) {
++                    return PJ_FALSE;
++                }
++            } else if (!gnutls_error_is_fatal(decrypted_size)) {
++                /* non-fatal error, let's just continue */
++            } else {
++                return PJ_FALSE;
++            }
++        } while (PJ_TRUE);
++    }
++
++    return PJ_TRUE;
++}
++
++
++/* Callback every time new data is available from the active socket */
++static pj_bool_t asock_on_data_sent(pj_activesock_t *asock,
++                                    pj_ioqueue_op_key_t *send_key,
++                                    pj_ssize_t sent)
++{
++    pj_ssl_sock_t *ssock = (pj_ssl_sock_t *)pj_activesock_get_user_data(asock);
++
++    PJ_UNUSED_ARG(send_key);
++    PJ_UNUSED_ARG(sent);
++
++    if (ssock->connection_state == TLS_STATE_HANDSHAKING) {
++        /* Initial handshaking */
++        pj_status_t status = tls_try_handshake(ssock);
++
++        /* Not pending is either success or failed */
++        if (status != PJ_EPENDING)
++            return on_handshake_complete(ssock, status);
++
++    } else if (send_key != &ssock->handshake_op_key) {
++        /* Some data has been sent, notify application */
++        write_data_t *wdata = (write_data_t*)send_key->user_data;
++        if (ssock->param.cb.on_data_sent) {
++            pj_bool_t ret;
++            pj_ssize_t sent_len;
++
++            sent_len = sent > 0 ? wdata->plain_data_len : sent;
++
++            ret = (*ssock->param.cb.on_data_sent)(ssock, wdata->app_key,
++                                                  sent_len);
++            if (!ret) {
++                /* We've been destroyed */
++                return PJ_FALSE;
++            }
++        }
++
++        /* Update write buffer state */
++        pj_lock_acquire(ssock->circ_buf_output_mutex);
++        free_send_data(ssock, wdata);
++        pj_lock_release(ssock->circ_buf_output_mutex);
++    } else {
++        /* SSL re-negotiation is on-progress, just do nothing */
++        /* FIXME: check if this is valid for GnuTLS too */
++    }
++
++    return PJ_TRUE;
++}
++
++
++/* Callback every time a new connection has been accepted (server) */
++static pj_bool_t asock_on_accept_complete(pj_activesock_t *asock,
++                                          pj_sock_t newsock,
++                                          const pj_sockaddr_t *src_addr,
++                                          int src_addr_len)
++{
++    pj_ssl_sock_t *ssock_parent = (pj_ssl_sock_t *)
++                                  pj_activesock_get_user_data(asock);
++
++    pj_ssl_sock_t *ssock;
++    pj_activesock_cb asock_cb;
++    pj_activesock_cfg asock_cfg;
++    unsigned int i;
++    pj_status_t status;
++
++    PJ_UNUSED_ARG(src_addr_len);
++
++    /* Create new SSL socket instance */
++    status = pj_ssl_sock_create(ssock_parent->pool, &ssock_parent->param,
++                                &ssock);
++    if (status != PJ_SUCCESS)
++        goto on_return;
++
++    /* Update new SSL socket attributes */
++    ssock->sock = newsock;
++    ssock->parent = ssock_parent;
++    ssock->is_server = PJ_TRUE;
++    if (ssock_parent->cert) {
++        status = pj_ssl_sock_set_certificate(ssock, ssock->pool,
++                                             ssock_parent->cert);
++        if (status != PJ_SUCCESS)
++            goto on_return;
++    }
++
++    /* Apply QoS, if specified */
++    status = pj_sock_apply_qos2(ssock->sock, ssock->param.qos_type,
++                                &ssock->param.qos_params, 1,
++                                ssock->pool->obj_name, NULL);
++    if (status != PJ_SUCCESS && !ssock->param.qos_ignore_error)
++        goto on_return;
++
++    /* Update local address */
++    ssock->addr_len = src_addr_len;
++    status = pj_sock_getsockname(ssock->sock, &ssock->local_addr,
++                                 &ssock->addr_len);
++    if (status != PJ_SUCCESS) {
++        /* This fails on few envs, e.g: win IOCP, just tolerate this and
++         * use parent local address instead.
++         */
++        pj_sockaddr_cp(&ssock->local_addr, &ssock_parent->local_addr);
++    }
++
++    /* Set remote address */
++    pj_sockaddr_cp(&ssock->rem_addr, src_addr);
++
++    /* Create SSL context */
++    status = tls_open(ssock);
++    if (status != PJ_SUCCESS)
++        goto on_return;
++
++    /* Prepare read buffer */
++    ssock->asock_rbuf = (void **)pj_pool_calloc(ssock->pool,
++                                                ssock->param.async_cnt,
++                                                sizeof(void*));
++    if (!ssock->asock_rbuf)
++        return PJ_ENOMEM;
++
++    for (i = 0; i < ssock->param.async_cnt; ++i) {
++        ssock->asock_rbuf[i] = (void *)pj_pool_alloc(
++                                            ssock->pool,
++                                            ssock->param.read_buffer_size +
++                                            sizeof(read_data_t*));
++        if (!ssock->asock_rbuf[i])
++            return PJ_ENOMEM;
++    }
++
++    /* Create active socket */
++    pj_activesock_cfg_default(&asock_cfg);
++    asock_cfg.async_cnt = ssock->param.async_cnt;
++    asock_cfg.concurrency = ssock->param.concurrency;
++    asock_cfg.whole_data = PJ_TRUE;
++
++    pj_bzero(&asock_cb, sizeof(asock_cb));
++    asock_cb.on_data_read = asock_on_data_read;
++    asock_cb.on_data_sent = asock_on_data_sent;
++
++    status = pj_activesock_create(ssock->pool,
++                                  ssock->sock,
++                                  ssock->param.sock_type,
++                                  &asock_cfg,
++                                  ssock->param.ioqueue,
++                                  &asock_cb,
++                                  ssock,
++                                  &ssock->asock);
++
++    if (status != PJ_SUCCESS)
++        goto on_return;
++
++    /* Start reading */
++    status = pj_activesock_start_read2(ssock->asock, ssock->pool,
++                                       (unsigned)ssock->param.read_buffer_size,
++                                       ssock->asock_rbuf,
++                                       PJ_IOQUEUE_ALWAYS_ASYNC);
++    if (status != PJ_SUCCESS)
++        goto on_return;
++
++    /* Prepare write/send state */
++    pj_assert(ssock->send_buf.max_len == 0);
++    ssock->send_buf.buf = (char *)pj_pool_alloc(ssock->pool,
++                                                ssock->param.send_buffer_size);
++    if (!ssock->send_buf.buf)
++        return PJ_ENOMEM;
++
++    ssock->send_buf.max_len = ssock->param.send_buffer_size;
++    ssock->send_buf.start = ssock->send_buf.buf;
++    ssock->send_buf.len = 0;
++
++    /* Start handshake timer */
++    if (ssock->param.timer_heap &&
++        (ssock->param.timeout.sec != 0 || ssock->param.timeout.msec != 0)) {
++        pj_assert(ssock->timer.id == TIMER_NONE);
++        ssock->timer.id = TIMER_HANDSHAKE_TIMEOUT;
++        status = pj_timer_heap_schedule(ssock->param.timer_heap,
++                                        &ssock->timer,
++                                        &ssock->param.timeout);
++        if (status != PJ_SUCCESS)
++            ssock->timer.id = TIMER_NONE;
++    }
++
++    /* Start SSL handshake */
++    ssock->connection_state = TLS_STATE_HANDSHAKING;
++
++    status = tls_try_handshake(ssock);
++
++on_return:
++    if (ssock && status != PJ_EPENDING)
++        on_handshake_complete(ssock, status);
++
++    /* Must return PJ_TRUE whatever happened, as active socket must
++     * continue listening.
++     */
++    return PJ_TRUE;
++}
++
++
++/* Callback every time a new connection has been completed (client) */
++static pj_bool_t asock_on_connect_complete (pj_activesock_t *asock,
++                                            pj_status_t status)
++{
++    pj_ssl_sock_t *ssock = (pj_ssl_sock_t*)
++                           pj_activesock_get_user_data(asock);
++
++    unsigned int i;
++    int ret;
++
++    if (status != PJ_SUCCESS)
++        goto on_return;
++
++    /* Update local address */
++    ssock->addr_len = sizeof(pj_sockaddr);
++    status = pj_sock_getsockname(ssock->sock, &ssock->local_addr,
++                                 &ssock->addr_len);
++    if (status != PJ_SUCCESS)
++        goto on_return;
++
++    /* Create SSL context */
++    status = tls_open(ssock);
++    if (status != PJ_SUCCESS)
++        goto on_return;
++
++    /* Prepare read buffer */
++    ssock->asock_rbuf = (void **)pj_pool_calloc(ssock->pool,
++                                                ssock->param.async_cnt,
++                                                sizeof(void *));
++    if (!ssock->asock_rbuf)
++        return PJ_ENOMEM;
++
++    for (i = 0; i < ssock->param.async_cnt; ++i) {
++        ssock->asock_rbuf[i] = (void *)pj_pool_alloc(
++                                            ssock->pool,
++                                            ssock->param.read_buffer_size +
++                                            sizeof(read_data_t *));
++        if (!ssock->asock_rbuf[i])
++            return PJ_ENOMEM;
++    }
++
++    /* Start read */
++    status = pj_activesock_start_read2(ssock->asock, ssock->pool,
++                                       (unsigned) ssock->param.read_buffer_size,
++                                       ssock->asock_rbuf,
++                                       PJ_IOQUEUE_ALWAYS_ASYNC);
++    if (status != PJ_SUCCESS)
++        goto on_return;
++
++    /* Prepare write/send state */
++    pj_assert(ssock->send_buf.max_len == 0);
++    ssock->send_buf.buf = (char *)pj_pool_alloc(ssock->pool,
++                                                ssock->param.send_buffer_size);
++    if (!ssock->send_buf.buf)
++        return PJ_ENOMEM;
++
++    ssock->send_buf.max_len = ssock->param.send_buffer_size;
++    ssock->send_buf.start = ssock->send_buf.buf;
++    ssock->send_buf.len = 0;
++
++    /* Set server name to connect */
++    if (ssock->param.server_name.slen) {
++        /* Server name is null terminated already */
++        ret = gnutls_server_name_set(ssock->session, GNUTLS_NAME_DNS,
++                                     ssock->param.server_name.ptr,
++                                     ssock->param.server_name.slen);
++        if (ret < 0) {
++            PJ_LOG(3, (ssock->pool->obj_name,
++                       "gnutls_server_name_set() failed: %s",
++                       gnutls_strerror(ret)));
++        }
++    }
++
++    /* Start handshake */
++    ssock->connection_state = TLS_STATE_HANDSHAKING;
++
++    status = tls_try_handshake(ssock);
++    if (status != PJ_EPENDING)
++        goto on_return;
++
++    return PJ_TRUE;
++
++on_return:
++    return on_handshake_complete(ssock, status);
++}
++
++static void tls_ciphers_fill(void)
++{
++     if (!tls_available_ciphers) {
++         tls_init();
++         tls_deinit();
++     }
++}
++
++/*
++ *******************************************************************
++ * API
++ *******************************************************************
++ */
++
++/* Load credentials from files. */
++PJ_DEF(pj_status_t) pj_ssl_cert_load_from_files(pj_pool_t *pool,
++                                                const pj_str_t *CA_file,
++                                                const pj_str_t *cert_file,
++                                                const pj_str_t *privkey_file,
++                                                const pj_str_t *privkey_pass,
++                                                pj_ssl_cert_t **p_cert)
++{
++    return pj_ssl_cert_load_from_files2(pool, CA_file, NULL, cert_file,
++                    privkey_file, privkey_pass, p_cert);
++}
++
++/* Load credentials from files. */
++PJ_DECL(pj_status_t) pj_ssl_cert_load_from_files2(
++                        pj_pool_t *pool,
++                        const pj_str_t *CA_file,
++                        const pj_str_t *CA_path,
++                        const pj_str_t *cert_file,
++                        const pj_str_t *privkey_file,
++                        const pj_str_t *privkey_pass,
++                        pj_ssl_cert_t **p_cert)
++{
++    pj_ssl_cert_t *cert;
++
++    PJ_ASSERT_RETURN(pool && (CA_file || CA_path) && cert_file &&
++             privkey_file,
++             PJ_EINVAL);
++
++    cert = PJ_POOL_ZALLOC_T(pool, pj_ssl_cert_t);
++    if (CA_file) {
++        pj_strdup_with_null(pool, &cert->CA_file, CA_file);
++    }
++    if (CA_path) {
++        pj_strdup_with_null(pool, &cert->CA_path, CA_path);
++    }
++    pj_strdup_with_null(pool, &cert->cert_file, cert_file);
++    pj_strdup_with_null(pool, &cert->privkey_file, privkey_file);
++    pj_strdup_with_null(pool, &cert->privkey_pass, privkey_pass);
++
++    *p_cert = cert;
++
++    return PJ_SUCCESS;
++}
++
++/* Store credentials. */
++PJ_DECL(pj_status_t) pj_ssl_sock_set_certificate(pj_ssl_sock_t *ssock,
++                                                 pj_pool_t *pool,
++                                                 const pj_ssl_cert_t *cert)
++{
++    pj_ssl_cert_t *cert_;
++
++    PJ_ASSERT_RETURN(ssock && pool && cert, PJ_EINVAL);
++
++    cert_ = PJ_POOL_ZALLOC_T(pool, pj_ssl_cert_t);
++    pj_memcpy(cert_, cert, sizeof(cert));
++    pj_strdup_with_null(pool, &cert_->CA_file, &cert->CA_file);
++    pj_strdup_with_null(pool, &cert_->CA_path, &cert->CA_path);
++    pj_strdup_with_null(pool, &cert_->cert_file, &cert->cert_file);
++    pj_strdup_with_null(pool, &cert_->privkey_file, &cert->privkey_file);
++    pj_strdup_with_null(pool, &cert_->privkey_pass, &cert->privkey_pass);
++
++    ssock->cert = cert_;
++
++    return PJ_SUCCESS;
++}
++
++
++/* Get available ciphers. */
++PJ_DEF(pj_status_t) pj_ssl_cipher_get_availables(pj_ssl_cipher ciphers[],
++                                                 unsigned *cipher_num)
++{
++    unsigned int i;
++
++    PJ_ASSERT_RETURN(ciphers && cipher_num, PJ_EINVAL);
++
++    tls_ciphers_fill();
++
++    if (!tls_available_ciphers) {
++        *cipher_num = 0;
++        return PJ_ENOTFOUND;
++    }
++
++    *cipher_num = PJ_MIN(*cipher_num, tls_available_ciphers);
++
++    for (i = 0; i < *cipher_num; ++i)
++        ciphers[i] = tls_ciphers[i].id;
++
++    return PJ_SUCCESS;
++}
++
++
++/* Get cipher name string. */
++PJ_DEF(const char *)pj_ssl_cipher_name(pj_ssl_cipher cipher)
++{
++    unsigned int i;
++
++    tls_ciphers_fill();
++
++    for (i = 0; i < tls_available_ciphers; ++i) {
++        if (cipher == tls_ciphers[i].id)
++            return tls_ciphers[i].name;
++    }
++
++    return NULL;
++}
++
++
++/* Get cipher identifier. */
++PJ_DEF(pj_ssl_cipher) pj_ssl_cipher_id(const char *cipher_name)
++{
++    unsigned int i;
++
++    tls_ciphers_fill();
++
++    for (i = 0; i < tls_available_ciphers; ++i) {
++        if (!pj_ansi_stricmp(tls_ciphers[i].name, cipher_name))
++            return tls_ciphers[i].id;
++    }
++
++    return PJ_TLS_UNKNOWN_CIPHER;
++}
++
++
++/* Check if the specified cipher is supported by the TLS backend. */
++PJ_DEF(pj_bool_t) pj_ssl_cipher_is_supported(pj_ssl_cipher cipher)
++{
++    unsigned int i;
++
++    tls_ciphers_fill();
++
++    for (i = 0; i < tls_available_ciphers; ++i) {
++        if (cipher == tls_ciphers[i].id)
++            return PJ_TRUE;
++    }
++
++    return PJ_FALSE;
++}
++
++/* Create SSL socket instance. */
++PJ_DEF(pj_status_t) pj_ssl_sock_create(pj_pool_t *pool,
++                                       const pj_ssl_sock_param *param,
++                                       pj_ssl_sock_t **p_ssock)
++{
++    pj_ssl_sock_t *ssock;
++    pj_status_t status;
++
++    PJ_ASSERT_RETURN(pool && param && p_ssock, PJ_EINVAL);
++    PJ_ASSERT_RETURN(param->sock_type == pj_SOCK_STREAM(), PJ_ENOTSUP);
++
++    pool = pj_pool_create(pool->factory, "tls%p", 512, 512, NULL);
++
++    /* Create secure socket */
++    ssock = PJ_POOL_ZALLOC_T(pool, pj_ssl_sock_t);
++    ssock->pool = pool;
++    ssock->sock = PJ_INVALID_SOCKET;
++    ssock->connection_state = TLS_STATE_NULL;
++    pj_list_init(&ssock->write_pending);
++    pj_list_init(&ssock->write_pending_empty);
++    pj_list_init(&ssock->send_pending);
++    pj_timer_entry_init(&ssock->timer, 0, ssock, &on_timer);
++    pj_ioqueue_op_key_init(&ssock->handshake_op_key,
++                           sizeof(pj_ioqueue_op_key_t));
++
++    /* Create secure socket mutex */
++    status = pj_lock_create_recursive_mutex(pool, pool->obj_name,
++                                            &ssock->circ_buf_output_mutex);
++    if (status != PJ_SUCCESS)
++        return status;
++
++    /* Create input circular buffer mutex */
++    status = pj_lock_create_simple_mutex(pool, pool->obj_name,
++                                         &ssock->circ_buf_input_mutex);
++    if (status != PJ_SUCCESS)
++        return status;
++
++    /* Create output circular buffer mutex */
++    status = pj_lock_create_simple_mutex(pool, pool->obj_name,
++                                         &ssock->circ_buf_output_mutex);
++    if (status != PJ_SUCCESS)
++        return status;
++
++    /* Init secure socket param */
++    ssock->param = *param;
++    ssock->param.read_buffer_size = ((ssock->param.read_buffer_size + 7) >> 3) << 3;
++
++    if (param->ciphers_num > 0) {
++        unsigned int i;
++        ssock->param.ciphers = (pj_ssl_cipher *)
++                               pj_pool_calloc(pool, param->ciphers_num,
++                                              sizeof(pj_ssl_cipher));
++        if (!ssock->param.ciphers)
++            return PJ_ENOMEM;
++
++        for (i = 0; i < param->ciphers_num; ++i)
++            ssock->param.ciphers[i] = param->ciphers[i];
++    }
++
++    /* Server name must be null-terminated */
++    pj_strdup_with_null(pool, &ssock->param.server_name, &param->server_name);
++
++    /* Finally */
++    *p_ssock = ssock;
++
++    return PJ_SUCCESS;
++}
++
++
++/*
++ * Close the secure socket. This will unregister the socket from the
++ * ioqueue and ultimately close the socket.
++ */
++PJ_DEF(pj_status_t) pj_ssl_sock_close(pj_ssl_sock_t *ssock)
++{
++    pj_pool_t *pool;
++
++    PJ_ASSERT_RETURN(ssock, PJ_EINVAL);
++
++    if (!ssock->pool)
++        return PJ_SUCCESS;
++
++    if (ssock->timer.id != TIMER_NONE) {
++        pj_timer_heap_cancel(ssock->param.timer_heap, &ssock->timer);
++        ssock->timer.id = TIMER_NONE;
++    }
++
++    tls_sock_reset(ssock);
++
++    pj_lock_destroy(ssock->circ_buf_output_mutex);
++    pj_lock_destroy(ssock->circ_buf_input_mutex);
++
++    pool = ssock->pool;
++    ssock->pool = NULL;
++    if (pool)
++        pj_pool_release(pool);
++
++    return PJ_SUCCESS;
++}
++
++
++/* Associate arbitrary data with the secure socket. */
++PJ_DEF(pj_status_t) pj_ssl_sock_set_user_data(pj_ssl_sock_t *ssock,
++                                              void *user_data)
++{
++    PJ_ASSERT_RETURN(ssock, PJ_EINVAL);
++
++    ssock->param.user_data = user_data;
++    return PJ_SUCCESS;
++}
++
++
++/* Retrieve the user data previously associated with this secure socket. */
++PJ_DEF(void *)pj_ssl_sock_get_user_data(pj_ssl_sock_t *ssock)
++{
++    PJ_ASSERT_RETURN(ssock, NULL);
++
++    return ssock->param.user_data;
++}
++
++
++/* Retrieve the local address and port used by specified SSL socket. */
++PJ_DEF(pj_status_t) pj_ssl_sock_get_info (pj_ssl_sock_t *ssock,
++                                          pj_ssl_sock_info *info)
++{
++    pj_bzero(info, sizeof(*info));
++
++    /* Established flag */
++    info->established = (ssock->connection_state == TLS_STATE_ESTABLISHED);
++
++    /* Protocol */
++    info->proto = ssock->param.proto;
++
++    /* Local address */
++    pj_sockaddr_cp(&info->local_addr, &ssock->local_addr);
++
++    if (info->established) {
++        int i;
++        gnutls_cipher_algorithm_t lookup;
++        gnutls_cipher_algorithm_t cipher;
++
++        /* Current cipher */
++        cipher = gnutls_cipher_get(ssock->session);
++        for (i = 0; ; i++) {
++            unsigned char id[2];
++            const char *suite = gnutls_cipher_suite_info(i, (unsigned char *)id,
++                                                         NULL, &lookup, NULL,
++                                                         NULL);
++            if (suite) {
++                if (lookup == cipher) {
++                    info->cipher = (pj_uint32_t) ((id[0] << 8) | id[1]);
++                    break;
++                }
++            } else
++                break;
++        }
++
++        /* Remote address */
++        pj_sockaddr_cp(&info->remote_addr, &ssock->rem_addr);
++
++        /* Certificates info */
++        info->local_cert_info = &ssock->local_cert_info;
++        info->remote_cert_info = &ssock->remote_cert_info;
++
++        /* Verification status */
++        info->verify_status = ssock->verify_status;
++    }
++
++    /* Last known GnuTLS error code */
++    info->last_native_err = ssock->last_err;
++
++    return PJ_SUCCESS;
++}
++
++
++/* Starts read operation on this secure socket. */
++PJ_DEF(pj_status_t) pj_ssl_sock_start_read(pj_ssl_sock_t *ssock,
++                                           pj_pool_t *pool,
++                                           unsigned buff_size,
++                                           pj_uint32_t flags)
++{
++    void **readbuf;
++    unsigned int i;
++
++    PJ_ASSERT_RETURN(ssock && pool && buff_size, PJ_EINVAL);
++    PJ_ASSERT_RETURN(ssock->connection_state == TLS_STATE_ESTABLISHED,
++                     PJ_EINVALIDOP);
++
++    readbuf = (void**) pj_pool_calloc(pool, ssock->param.async_cnt,
++                                      sizeof(void *));
++    if (!readbuf)
++        return PJ_ENOMEM;
++
++    for (i = 0; i < ssock->param.async_cnt; ++i) {
++        readbuf[i] = pj_pool_alloc(pool, buff_size);
++        if (!readbuf[i])
++            return PJ_ENOMEM;
++    }
++
++    return pj_ssl_sock_start_read2(ssock, pool, buff_size, readbuf, flags);
++}
++
++
++/*
++ * Same as #pj_ssl_sock_start_read(), except that the application
++ * supplies the buffers for the read operation so that the acive socket
++ * does not have to allocate the buffers.
++ */
++PJ_DEF(pj_status_t) pj_ssl_sock_start_read2 (pj_ssl_sock_t *ssock,
++                                             pj_pool_t *pool,
++                                             unsigned buff_size,
++                                             void *readbuf[],
++                                             pj_uint32_t flags)
++{
++    unsigned int i;
++
++    PJ_ASSERT_RETURN(ssock && pool && buff_size && readbuf, PJ_EINVAL);
++    PJ_ASSERT_RETURN(ssock->connection_state == TLS_STATE_ESTABLISHED,
++                     PJ_EINVALIDOP);
++
++    /* Create SSL socket read buffer */
++    ssock->ssock_rbuf = (read_data_t*)pj_pool_calloc(pool,
++                                                     ssock->param.async_cnt,
++                                                     sizeof(read_data_t));
++    if (!ssock->ssock_rbuf)
++        return PJ_ENOMEM;
++
++    /* Store SSL socket read buffer pointer in the activesock read buffer */
++    for (i = 0; i < ssock->param.async_cnt; ++i) {
++        read_data_t **p_ssock_rbuf =
++                        OFFSET_OF_READ_DATA_PTR(ssock, ssock->asock_rbuf[i]);
++
++        ssock->ssock_rbuf[i].data = readbuf[i];
++        ssock->ssock_rbuf[i].len = 0;
++
++        *p_ssock_rbuf = &ssock->ssock_rbuf[i];
++    }
++
++    ssock->read_size = buff_size;
++    ssock->read_started = PJ_TRUE;
++    ssock->read_flags = flags;
++
++    return PJ_SUCCESS;
++}
++
++
++/*
++ * Same as pj_ssl_sock_start_read(), except that this function is used
++ * only for datagram sockets, and it will trigger \a on_data_recvfrom()
++ * callback instead.
++ */
++PJ_DEF(pj_status_t) pj_ssl_sock_start_recvfrom (pj_ssl_sock_t *ssock,
++                                                pj_pool_t *pool,
++                                                unsigned buff_size,
++                                                pj_uint32_t flags)
++{
++    PJ_UNUSED_ARG(ssock);
++    PJ_UNUSED_ARG(pool);
++    PJ_UNUSED_ARG(buff_size);
++    PJ_UNUSED_ARG(flags);
++
++    return PJ_ENOTSUP;
++}
++
++
++/*
++ * Same as #pj_ssl_sock_start_recvfrom() except that the recvfrom()
++ * operation takes the buffer from the argument rather than creating
++ * new ones.
++ */
++PJ_DEF(pj_status_t) pj_ssl_sock_start_recvfrom2 (pj_ssl_sock_t *ssock,
++                                                 pj_pool_t *pool,
++                                                 unsigned buff_size,
++                                                 void *readbuf[],
++                                                 pj_uint32_t flags)
++{
++    PJ_UNUSED_ARG(ssock);
++    PJ_UNUSED_ARG(pool);
++    PJ_UNUSED_ARG(buff_size);
++    PJ_UNUSED_ARG(readbuf);
++    PJ_UNUSED_ARG(flags);
++
++    return PJ_ENOTSUP;
++}
++
++
++/*
++ * Write the plain data to GnuTLS, it will be encrypted by gnutls_record_send()
++ * and sent via tls_data_push. Note that re-negotitation may be on progress, so
++ * sending data should be delayed until re-negotiation is completed.
++ */
++static pj_status_t tls_write(pj_ssl_sock_t *ssock,
++                             pj_ioqueue_op_key_t *send_key,
++                             const void *data, pj_ssize_t size, unsigned flags)
++{
++    pj_status_t status;
++    int nwritten;
++    pj_ssize_t total_written = 0;
++
++    /* Ask GnuTLS to encrypt our plaintext now. GnuTLS will use the push
++     * callback to actually write the encrypted bytes into our output circular
++     * buffer. GnuTLS may refuse to "send" everything at once, but since we are
++     * not really sending now, we will just call it again now until it succeeds
++     * (or fails in a fatal way). */
++    while (total_written < size) {
++        /* Try encrypting using GnuTLS */
++        nwritten = gnutls_record_send(ssock->session, data + total_written,
++                                      size);
++
++        if (nwritten > 0) {
++            /* Good, some data was encrypted and written */
++            total_written += nwritten;
++        } else {
++            /* Normally we would have to retry record_send but our internal
++             * state has not changed, so we have to ask for more data first.
++             * We will just try again later, although this should never happen.
++             */
++            return tls_status_from_err(ssock, nwritten);
++        }
++    }
++
++    /* All encrypted data is written to the output circular buffer;
++     * now send it on the socket (or notify problem). */
++    if (total_written == size)
++        status = flush_circ_buf_output(ssock, send_key, size, flags);
++    else
++        status = PJ_ENOMEM;
++
++    return status;
++}
++
++
++/* Flush delayed data sending in the write pending list. */
++static pj_status_t flush_delayed_send(pj_ssl_sock_t *ssock)
++{
++    /* Check for another ongoing flush */
++    if (ssock->flushing_write_pend) {
++        return PJ_EBUSY;
++    }
++
++    pj_lock_acquire(ssock->circ_buf_output_mutex);
++
++    /* Again, check for another ongoing flush */
++    if (ssock->flushing_write_pend) {
++        pj_lock_release(ssock->circ_buf_output_mutex);
++        return PJ_EBUSY;
++    }
++
++    /* Set ongoing flush flag */
++    ssock->flushing_write_pend = PJ_TRUE;
++
++    while (!pj_list_empty(&ssock->write_pending)) {
++        write_data_t *wp;
++        pj_status_t status;
++
++        wp = ssock->write_pending.next;
++
++        /* Ticket #1573: Don't hold mutex while calling socket send. */
++        pj_lock_release(ssock->circ_buf_output_mutex);
++
++        status = tls_write(ssock, &wp->key, wp->data.ptr,
++                           wp->plain_data_len, wp->flags);
++        if (status != PJ_SUCCESS) {
++            /* Reset ongoing flush flag first. */
++            ssock->flushing_write_pend = PJ_FALSE;
++            return status;
++        }
++
++        pj_lock_acquire(ssock->circ_buf_output_mutex);
++        pj_list_erase(wp);
++        pj_list_push_back(&ssock->write_pending_empty, wp);
++    }
++
++    /* Reset ongoing flush flag */
++    ssock->flushing_write_pend = PJ_FALSE;
++
++    pj_lock_release(ssock->circ_buf_output_mutex);
++
++    return PJ_SUCCESS;
++}
++
++
++/* Sending is delayed, push back the sending data into pending list. */
++static pj_status_t delay_send(pj_ssl_sock_t *ssock,
++                              pj_ioqueue_op_key_t *send_key,
++                              const void *data, pj_ssize_t size,
++                              unsigned flags)
++{
++    write_data_t *wp;
++
++    pj_lock_acquire(ssock->circ_buf_output_mutex);
++
++    /* Init write pending instance */
++    if (!pj_list_empty(&ssock->write_pending_empty)) {
++        wp = ssock->write_pending_empty.next;
++        pj_list_erase(wp);
++    } else {
++        wp = PJ_POOL_ZALLOC_T(ssock->pool, write_data_t);
++    }
++
++    wp->app_key = send_key;
++    wp->plain_data_len = size;
++    wp->data.ptr = data;
++    wp->flags = flags;
++
++    pj_list_push_back(&ssock->write_pending, wp);
++
++    pj_lock_release(ssock->circ_buf_output_mutex);
++
++    /* Must return PJ_EPENDING */
++    return PJ_EPENDING;
++}
++
++
++/**
++ * Send data using the socket.
++ */
++PJ_DEF(pj_status_t) pj_ssl_sock_send(pj_ssl_sock_t *ssock,
++                                     pj_ioqueue_op_key_t *send_key,
++                                     const void *data, pj_ssize_t *size,
++                                     unsigned flags)
++{
++    pj_status_t status;
++
++    PJ_ASSERT_RETURN(ssock && data && size && (*size > 0), PJ_EINVAL);
++    PJ_ASSERT_RETURN(ssock->connection_state==TLS_STATE_ESTABLISHED,
++                     PJ_EINVALIDOP);
++
++    /* Flush delayed send first. Sending data might be delayed when
++     * re-negotiation is on-progress. */
++    status = flush_delayed_send(ssock);
++    if (status == PJ_EBUSY) {
++        /* Re-negotiation or flushing is on progress, delay sending */
++        status = delay_send(ssock, send_key, data, *size, flags);
++        goto on_return;
++    } else if (status != PJ_SUCCESS) {
++        goto on_return;
++    }
++
++    /* Write data to SSL */
++    status = tls_write(ssock, send_key, data, *size, flags);
++    if (status == PJ_EBUSY) {
++        /* Re-negotiation is on progress, delay sending */
++        status = delay_send(ssock, send_key, data, *size, flags);
++    }
++
++on_return:
++    return status;
++}
++
++
++/**
++ * Send datagram using the socket.
++ */
++PJ_DEF(pj_status_t) pj_ssl_sock_sendto (pj_ssl_sock_t *ssock,
++                                        pj_ioqueue_op_key_t *send_key,
++                                        const void *data, pj_ssize_t *size,
++                                        unsigned flags,
++                                        const pj_sockaddr_t *addr, int addr_len)
++{
++    PJ_UNUSED_ARG(ssock);
++    PJ_UNUSED_ARG(send_key);
++    PJ_UNUSED_ARG(data);
++    PJ_UNUSED_ARG(size);
++    PJ_UNUSED_ARG(flags);
++    PJ_UNUSED_ARG(addr);
++    PJ_UNUSED_ARG(addr_len);
++
++    return PJ_ENOTSUP;
++}
++
++
++/**
++ * Starts asynchronous socket accept() operations on this secure socket.
++ */
++PJ_DEF(pj_status_t) pj_ssl_sock_start_accept (pj_ssl_sock_t *ssock,
++                                              pj_pool_t *pool,
++                                              const pj_sockaddr_t *localaddr,
++                                              int addr_len)
++{
++    pj_activesock_cb asock_cb;
++    pj_activesock_cfg asock_cfg;
++    pj_status_t status;
++
++    PJ_ASSERT_RETURN(ssock && pool && localaddr && addr_len, PJ_EINVAL);
++
++    /* Create socket */
++    status = pj_sock_socket(ssock->param.sock_af, ssock->param.sock_type, 0,
++                            &ssock->sock);
++    if (status != PJ_SUCCESS)
++        goto on_error;
++
++    /* Apply SO_REUSEADDR */
++    if (ssock->param.reuse_addr) {
++        int enabled = 1;
++        status = pj_sock_setsockopt(ssock->sock, pj_SOL_SOCKET(),
++                                    pj_SO_REUSEADDR(),
++                                    &enabled, sizeof(enabled));
++        if (status != PJ_SUCCESS) {
++            PJ_PERROR(4,(ssock->pool->obj_name, status,
++                         "Warning: error applying SO_REUSEADDR"));
++        }
++    }
++
++    /* Apply QoS, if specified */
++    status = pj_sock_apply_qos2(ssock->sock, ssock->param.qos_type,
++                                &ssock->param.qos_params, 2,
++                                ssock->pool->obj_name, NULL);
++    if (status != PJ_SUCCESS && !ssock->param.qos_ignore_error)
++        goto on_error;
++
++    /* Bind socket */
++    status = pj_sock_bind(ssock->sock, localaddr, addr_len);
++    if (status != PJ_SUCCESS)
++        goto on_error;
++
++    /* Start listening to the address */
++    status = pj_sock_listen(ssock->sock, PJ_SOMAXCONN);
++    if (status != PJ_SUCCESS)
++        goto on_error;
++
++    /* Create active socket */
++    pj_activesock_cfg_default(&asock_cfg);
++    asock_cfg.async_cnt = ssock->param.async_cnt;
++    asock_cfg.concurrency = ssock->param.concurrency;
++    asock_cfg.whole_data = PJ_TRUE;
++
++    pj_bzero(&asock_cb, sizeof(asock_cb));
++    asock_cb.on_accept_complete = asock_on_accept_complete;
++
++    status = pj_activesock_create(pool,
++                                  ssock->sock,
++                                  ssock->param.sock_type,
++                                  &asock_cfg,
++                                  ssock->param.ioqueue,
++                                  &asock_cb,
++                                  ssock,
++                                  &ssock->asock);
++
++    if (status != PJ_SUCCESS)
++        goto on_error;
++
++    /* Start accepting */
++    status = pj_activesock_start_accept(ssock->asock, pool);
++    if (status != PJ_SUCCESS)
++        goto on_error;
++
++    /* Update local address */
++    ssock->addr_len = addr_len;
++    status = pj_sock_getsockname(ssock->sock, &ssock->local_addr,
++                                 &ssock->addr_len);
++    if (status != PJ_SUCCESS)
++        pj_sockaddr_cp(&ssock->local_addr, localaddr);
++
++    ssock->is_server = PJ_TRUE;
++
++    return PJ_SUCCESS;
++
++on_error:
++    tls_sock_reset(ssock);
++    return status;
++}
++
++
++/**
++ * Starts asynchronous socket connect() operation.
++ */
++PJ_DECL(pj_status_t) pj_ssl_sock_start_connect(pj_ssl_sock_t *ssock,
++                                               pj_pool_t *pool,
++                                               const pj_sockaddr_t *localaddr,
++                                               const pj_sockaddr_t *remaddr,
++                                               int addr_len)
++{
++    pj_activesock_cb asock_cb;
++    pj_activesock_cfg asock_cfg;
++    pj_status_t status;
++
++    PJ_ASSERT_RETURN(ssock && pool && localaddr && remaddr && addr_len,
++                     PJ_EINVAL);
++
++    /* Create socket */
++    status = pj_sock_socket(ssock->param.sock_af, ssock->param.sock_type, 0,
++                            &ssock->sock);
++    if (status != PJ_SUCCESS)
++        goto on_error;
++
++    /* Apply QoS, if specified */
++    status = pj_sock_apply_qos2(ssock->sock, ssock->param.qos_type,
++                                &ssock->param.qos_params, 2,
++                                ssock->pool->obj_name, NULL);
++    if (status != PJ_SUCCESS && !ssock->param.qos_ignore_error)
++        goto on_error;
++
++    /* Bind socket */
++    status = pj_sock_bind(ssock->sock, localaddr, addr_len);
++    if (status != PJ_SUCCESS)
++        goto on_error;
++
++    /* Create active socket */
++    pj_activesock_cfg_default(&asock_cfg);
++    asock_cfg.async_cnt = ssock->param.async_cnt;
++    asock_cfg.concurrency = ssock->param.concurrency;
++    asock_cfg.whole_data = PJ_TRUE;
++
++    pj_bzero(&asock_cb, sizeof(asock_cb));
++    asock_cb.on_connect_complete = asock_on_connect_complete;
++    asock_cb.on_data_read = asock_on_data_read;
++    asock_cb.on_data_sent = asock_on_data_sent;
++
++    status = pj_activesock_create(pool,
++                                  ssock->sock,
++                                  ssock->param.sock_type,
++                                  &asock_cfg,
++                                  ssock->param.ioqueue,
++                                  &asock_cb,
++                                  ssock,
++                                  &ssock->asock);
++
++    if (status != PJ_SUCCESS)
++        goto on_error;
++
++    /* Save remote address */
++    pj_sockaddr_cp(&ssock->rem_addr, remaddr);
++
++    /* Start timer */
++    if (ssock->param.timer_heap &&
++        (ssock->param.timeout.sec != 0 || ssock->param.timeout.msec != 0))
++    {
++        pj_assert(ssock->timer.id == TIMER_NONE);
++        ssock->timer.id = TIMER_HANDSHAKE_TIMEOUT;
++        status = pj_timer_heap_schedule(ssock->param.timer_heap,
++                                        &ssock->timer,
++                                        &ssock->param.timeout);
++        if (status != PJ_SUCCESS)
++            ssock->timer.id = TIMER_NONE;
++    }
++
++    status = pj_activesock_start_connect(ssock->asock, pool, remaddr,
++                                         addr_len);
++
++    if (status == PJ_SUCCESS)
++        asock_on_connect_complete(ssock->asock, PJ_SUCCESS);
++    else if (status != PJ_EPENDING)
++        goto on_error;
++
++    /* Update local address */
++    ssock->addr_len = addr_len;
++    status = pj_sock_getsockname(ssock->sock, &ssock->local_addr,
++                                 &ssock->addr_len);
++    /* Note that we may not get an IP address here. This can
++     * happen for example on Windows, where getsockname()
++     * would return 0.0.0.0 if socket has just started the
++     * async connect. In this case, just leave the local
++     * address with 0.0.0.0 for now; it will be updated
++     * once the socket is established.
++     */
++
++    /* Update socket state */
++    ssock->is_server = PJ_FALSE;
++
++    return PJ_EPENDING;
++
++on_error:
++    tls_sock_reset(ssock);
++    return status;
++}
++
++
++PJ_DEF(pj_status_t) pj_ssl_sock_renegotiate(pj_ssl_sock_t *ssock)
++{
++    int status;
++
++    /* Nothing established yet */
++    PJ_ASSERT_RETURN(ssock->connection_state == TLS_STATE_ESTABLISHED,
++                     PJ_EINVALIDOP);
++
++    /* Cannot renegotiate; we're a client */
++    /* FIXME: in fact maybe that's not true */
++    PJ_ASSERT_RETURN(!ssock->is_server, PJ_EINVALIDOP);
++
++    /* First call gnutls_rehandshake() to see if this is even possible */
++    status = gnutls_rehandshake(ssock->session);
++
++    if (status == GNUTLS_E_SUCCESS) {
++        /* Rehandshake is possible, so try a GnuTLS handshake now. The eventual
++         * gnutls_record_recv() calls could return a few specific values during
++         * this state:
++         *
++         *   - GNUTLS_E_REHANDSHAKE: rehandshake message processing
++         *   - GNUTLS_E_WARNING_ALERT_RECEIVED: client does not wish to
++         *                                      renegotiate
++         */
++        ssock->connection_state = TLS_STATE_HANDSHAKING;
++        status = tls_try_handshake(ssock);
++
++        return status;
++    } else {
++        return tls_status_from_err(ssock, status);
++    }
++}
++
++#endif /* PJ_HAS_SSL_SOCK */
+diff --git a/pjlib/src/pj/ssl_sock_ossl.c b/pjlib/src/pj/ssl_sock_ossl.c
+index 513d754..d1db3f0 100644
+--- a/pjlib/src/pj/ssl_sock_ossl.c
++++ b/pjlib/src/pj/ssl_sock_ossl.c
+@@ -31,8 +31,10 @@
+ #include <pj/timer.h>
+ 
+ 
+-/* Only build when PJ_HAS_SSL_SOCK is enabled */
+-#if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK!=0
++/* Only build when PJ_HAS_SSL_SOCK is enabled and when PJ_HAS_TLS_SOCK is
++ * disabled (meaning GnuTLS is off) */
++#if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK != 0 && \
++    defined(PJ_HAS_TLS_SOCK) && PJ_HAS_TLS_SOCK == 0
+ 
+ #define THIS_FILE		"ssl_sock_ossl.c"
+ 
diff --git a/gnu/packages/telephony.scm b/gnu/packages/telephony.scm
index b27dd1f..e4668cf 100644
--- a/gnu/packages/telephony.scm
+++ b/gnu/packages/telephony.scm
@@ -22,11 +22,15 @@
 
 (define-module (gnu packages telephony)
   #:use-module (gnu packages)
+  #:use-module (gnu packages audio)
   #:use-module (gnu packages autotools)
   #:use-module (gnu packages gnupg)
   #:use-module (gnu packages linux)
   #:use-module (gnu packages pkg-config)
+  #:use-module (gnu packages pulseaudio)
+  #:use-module (gnu packages python)
   #:use-module (gnu packages tls)
+  #:use-module (gnu packages xiph)
   #:use-module (guix licenses)
   #:use-module (guix packages)
   #:use-module (guix download)
@@ -252,3 +256,105 @@ Voice-over-IP (VoIP) communications.")
       ;; covered under the 'GPL'.
       ;; The package as a whole is distributed under the LGPL 2.0.
       (license (list lgpl2.0 public-domain gpl2+)))))
+
+
+(define-public pjproject-for-libring
+  (package
+    (name "pjproject")
+    (version "2.4")
+    (source
+     (origin
+       (method url-fetch)
+       (uri (string-append
+             "http://www.pjsip.org/release/"
+             version "/" name "-" version ".tar.bz2"))
+       (modules '((guix build utils)))
+       (patches (search-patches "pjproject-errno.patch"
+                                "pjproject-endianness.patch"
+                                "pjproject-use-gnutls.patch"
+                               ; "pjproject-no-test-apps.patch" breaks tests
+                                "pjproject-ipv6.patch"
+                                "pjproject-ice-config.patch"
+                                "pjproject-multiple-listeners.patch"
+                                "pjproject-ice-sess.patch"))
+       ;; All these patches are distributed with the libring source code by
+       ;; the Ring project.
+       (snippet
+        '(begin
+           (delete-file-recursively "third_party")
+           (substitute* "aconfigure.ac"
+             (("third_party/build/os-auto.mak") "")
+             (("third_party/build/portaudio/os-auto.mak") ""))
+           (substitute* "pjmedia/src/pjmedia/resample_libsamplerate.c"
+             (("../../third_party/libsamplerate/src/samplerate.h")
+              "samplerate.h"))
+           (substitute* "pjmedia/src/pjmedia/resample_resample.c"
+             (("third_party/resample/include/resamplesubs.h")
+              "resamplesubs.h"))
+           (substitute* "Makefile"
+             (("third_party/build") ""))))
+       (sha256
+        (base32
+         "0n90n1p41svf23d4fag8jqbjnv82fz14z6zchb8j1kldvap1b00h"))))
+         ;"1jvxhny268nannz242rj1yfh2j1iyhn62sfdvm9zych8gbnkp9n5")))) version 2.5.1
+    (build-system gnu-build-system)
+    (inputs
+     `(("libsrtp" ,libsrtp)
+       ("portaudio" ,portaudio)
+       ("opus" ,opus)
+       ("speex" ,speex)
+       ("libsamplerate" ,libsamplerate)
+       ("gnutls" ,gnutls)
+       ("alsa-lib" ,alsa-lib)))
+    (native-inputs
+     `(("autoconf" ,autoconf)
+       ("automake" ,automake)
+       ("python" ,python)
+       ("pkg-config" ,pkg-config)
+       ("libtool" ,libtool)))
+    (arguments
+     `(#:test-target
+       "selftest"
+       #:make-flags
+       (list (string-append "CFLAGS+="
+                            "-DPJ_ICE_MAX_CAND=32" " "
+                            "-DPJ_ICE_MAX_CHECKS=150" " "
+                            "-DPJMEDIA_AUDIO_DEV_HAS_WMME=0" " "
+                            "-DPJ_ICE_COMP_BITS=2"))
+       #:configure-flags
+       (list "--disable-oss"
+             "--disable-sound"
+             "--disable-video"
+             "--enable-ext-sound"
+             "--disable-speex-aec"
+             "--disable-g711-codec"
+             "--disable-l16-codec"
+             "--disable-gsm-codec"
+             "--disable-g722-codec"
+             "--disable-g7221-codec"
+             "--disable-ilbc-codec"
+             "--disable-opencore-amr"
+             "--disable-sdl"
+             "--disable-ffmpeg"
+             "--disable-v4l2"
+             "--enable-ssl=gnutls"
+             "--enable-libsamplerate"
+            ; "--with-external-speex"
+             "--disable-speex-codec"
+             "--with-external-pa"
+             "--with-external-srtp")
+       #:phases
+       (modify-phases %standard-phases
+         (add-before 'patch-source-shebangs 'autoconf
+           (lambda _
+             (zero?
+              (system* "autoconf" "-v" "-f" "-i" "-o"
+                       "aconfigure" "aconfigure.ac")))))))
+    (home-page "www.pjsip.org")
+    (synopsis "Session Initiation Protocol (SIP) stack")
+    (description "PJProject provides an implementation of the Session
+Initiation Protocol (SIP) and a multimedia framework.
+
+This package is intended for use with libring.  There are several custom
+patches, most notably the use of gnutls instead of openssl for encryption.")
+    (license gpl2+)))
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [PATCH] Add msgpack
  2016-06-21 16:49                       ` Efraim Flashner
@ 2016-06-22  6:05                         ` Lukas Gradl
  0 siblings, 0 replies; 25+ messages in thread
From: Lukas Gradl @ 2016-06-22  6:05 UTC (permalink / raw)
  To: Efraim Flashner; +Cc: guix-devel



Thank you for looking at this!

Efraim Flashner <efraim@flashner.co.il> writes:

> On Tue, Jun 21, 2016 at 10:59:06AM -0500, Lukas Gradl wrote:
>> Leo Famulari <leo@famulari.name> writes:
>> 
>> > I'm curious — how close are you to a Ring package definition?

>> 
>> There are some more dependencies that might be needed, that I noticed
>> when looking at librings contrib directory.  This inputs field reflects
>> all the dependencies from libring's contrib:
>> 
>>       (inputs
>>        `(("ffmpeg" ,ffmpeg)
>>          ("flac" ,flac)
>>          ("libgcrypt" ,libgcrypt)
>>          ("gmp" ,gmp)
>>         ; ("gnutls" ,gnutls) ; Maybe not needed as already used by inputs
>>          ("libgpg-error" ,libgpg-error)
>>         ; ("gsm" ,gsm)  ; not found
>>          ("libiax2" ,libiax2)
>>          ("libiconv" ,libiconv)
>>          ("jack" ,jack-1)
>>         ; ("json-c" ,json-c) ; not found
>
> there's a json-c in web.scm

This one is actually a typo and a mistake on my part.  This is supposed
to be jsoncpp.  But I recently changed to the commit tagged with the
latest version number and it seems this is not needed anymore/yet.

>
>>         ; ("msgpack" ,msgpack) ; maybe not needed as used by inputs (opendht)
>>         ; ("nettle" ,nettle) ; maybe not needed (only certain proprietary OSes?)
>>          ("libogg" ,libogg)
>>          ("opendht" ,opendht)
>>          ("opus" ,opus)
>>          ("pcre" ,pcre)
>>         ; ("pjproject" ,pjproject-for-libring) ; not found, WIP
>>         ; ("pkg-static" ,pkg-static) ; not found
>>          ("portaudio" ,portaudio)
>>          ("libsamplerate" ,libsamplerate)
>>          ("libsndfile" ,libsndfile)
>>          ("speex" ,speex)
>>         ; ("speexdsp" ,speexdsp)
>>          ("libupnp" ,libupnp)
>>         ; ("uuid" ,uuid) ; not found, maybe not needed (only certain proprietary OSes?)
>
> try util-linux for this one
>

This looks good on first glance.  I will need to look into this more.
Thank you!

>>          ("libvorbis" ,libvorbis)
>>          ("libvpx" ,libvpx)
>>          ("libx264" ,libx264)
>>         ; ("yaml-cpp" ,yaml-cpp) ;not found
>
> there's a libyaml in web.scm. not exactly yaml-cpp in name, but it might
> be close enough
>

I have not investigated this much yet, but I think these are different.
FWIW, they are mentioned seperately in
https://en.wikipedia.org/wiki/YAML#Implementations
I will have a look at this.


>>          ("zlib" ,zlib))) ; maybe not needed as used by inputs

>> 
>> 
>> 
>
> keep up the great work!

Thank you! And thank you for your help!

Best,
Lukas

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Add msgpack
  2016-06-17 15:13               ` Lukas Gradl
  2016-06-19  3:44                 ` Lukas Gradl
@ 2016-06-25 15:31                 ` Leo Famulari
  2016-06-25 16:40                   ` Lukas Gradl
  1 sibling, 1 reply; 25+ messages in thread
From: Leo Famulari @ 2016-06-25 15:31 UTC (permalink / raw)
  To: Lukas Gradl; +Cc: guix-devel

On Fri, Jun 17, 2016 at 10:13:28AM -0500, Lukas Gradl wrote:
> Also, is it OK to do things like that in a snippet as in the attached
> patch?

> * gnu/packages/serialization.scm (msgpack): New variable.

I think it's fine and I pushed as d1ef573de. If we need to change it for
libring, we'll do that. Thanks!

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Add msgpack
  2016-06-25 15:31                 ` Leo Famulari
@ 2016-06-25 16:40                   ` Lukas Gradl
  0 siblings, 0 replies; 25+ messages in thread
From: Lukas Gradl @ 2016-06-25 16:40 UTC (permalink / raw)
  To: Leo Famulari; +Cc: guix-devel

Leo Famulari <leo@famulari.name> writes:

> On Fri, Jun 17, 2016 at 10:13:28AM -0500, Lukas Gradl wrote:
>> Also, is it OK to do things like that in a snippet as in the attached
>> patch?
>
>> * gnu/packages/serialization.scm (msgpack): New variable.
>
> I think it's fine and I pushed as d1ef573de. If we need to change it for
> libring, we'll do that. Thanks!

OK, Thank you!

^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2016-06-25 16:41 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-05-30 20:50 [PATCH] Add msgpack Lukas Gradl
2016-05-31 21:45 ` Leo Famulari
2016-06-01  4:49 ` Efraim Flashner
2016-06-03  0:50   ` Lukas Gradl
2016-06-06 14:07 ` Leo Famulari
2016-06-11  3:06   ` Leo Famulari
2016-06-11 23:56     ` Lukas Gradl
2016-06-12  0:17       ` Leo Famulari
2016-06-12  4:24         ` Lukas Gradl
2016-06-13 16:58           ` Leo Famulari
2016-06-13 17:59             ` Leo Famulari
2016-06-17 15:13               ` Lukas Gradl
2016-06-19  3:44                 ` Lukas Gradl
2016-06-20 17:09                   ` Leo Famulari
2016-06-21 13:55                     ` Lukas Gradl
2016-06-21 16:06                       ` Leo Famulari
2016-06-21 15:59                     ` Lukas Gradl
2016-06-21 16:49                       ` Efraim Flashner
2016-06-22  6:05                         ` Lukas Gradl
2016-06-22  5:56                       ` Lukas Gradl
2016-06-21  8:38                   ` Ludovic Courtès
2016-06-21 13:31                     ` Lukas Gradl
2016-06-21 14:11                       ` Ludovic Courtès
2016-06-25 15:31                 ` Leo Famulari
2016-06-25 16:40                   ` Lukas Gradl

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/guix.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).