Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mobileproxy clib #226

Draft
wants to merge 17 commits into
base: main
Choose a base branch
from
Draft
73 changes: 73 additions & 0 deletions x/examples/mobileproxy-clib/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package main

// #include <stdlib.h>
import (
"C"
"runtime/cgo"
"unsafe"

"github.com/Jigsaw-Code/outline-sdk/x/mobileproxy"
)

type StreamDialerPtr = unsafe.Pointer
daniellacosse marked this conversation as resolved.
Show resolved Hide resolved
type ProxyPtr = unsafe.Pointer

//export NewStreamDialerFromConfig
func NewStreamDialerFromConfig(config *C.char) StreamDialerPtr {
streamDialerObject, err := mobileproxy.NewStreamDialerFromConfig(C.GoString(config))

if err != nil {
// TODO: print something?
return unsafe.Pointer(nil)
}

streamDialerHandle := cgo.NewHandle(streamDialerObject)

return unsafe.Pointer(&streamDialerHandle)
}

//export RunProxy
func RunProxy(address *C.char, dialer StreamDialerPtr) ProxyPtr {
dialerObject := (*cgo.Handle)(dialer).Value().(mobileproxy.StreamDialer)

proxyObject, err := mobileproxy.RunProxy(C.GoString(address), &dialerObject)

if err != nil {
// TODO: print something?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We must have a way to return errors. Go Mobile returns a struct instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jyyi1 you can return a tuple right?

Copy link
Contributor

@jyyi1 jyyi1 May 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you can return a tuple and paste the header here.

@fortuna, do you mean a more C-friendly way of returning errors, like below?

Proxy *proxy;
int err = CreateProxy(&proxy);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need a way to return an error meesage.

Also, which design should we use?

  • Return error (proxy reference)
  • Return proxy (error reference)
  • Return tuple
  • return nothing (error and proxy reference)

I think Go Mobile on ios returns the value and writes the error to an input reference.

Copy link
Contributor Author

@daniellacosse daniellacosse May 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I lean towards tuple with two pointers in it. Since we're throwing around unsafe pointers, with the tuple approach the caller doesn't have to do any guesswork around what kind of pointer they've received. But maybe there's a C way to do it? @jyyi1 thoughts?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

errno is very Unix specific. But sure, we can introduce our own errno. That's actually my code above, we'll return an int, and put the proxy into a "output parameter".

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need a way to return an error message too. Errno is not enough.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going with tuple w/ error message as second optional argument

return unsafe.Pointer(nil)
}

handle := cgo.NewHandle(proxyObject)

return unsafe.Pointer(&handle)
}

//export AddURLProxy
func AddURLProxy(proxy ProxyPtr, url *C.char, dialer StreamDialerPtr) {
proxyObject := (*cgo.Handle)(proxy).Value().(mobileproxy.Proxy)
dialerObject := (*cgo.Handle)(dialer).Value().(mobileproxy.StreamDialer)

proxyObject.AddURLProxy(C.GoString(url), &dialerObject)
}

//export StopProxy
func StopProxy(proxy ProxyPtr, timeoutSeconds C.uint) {
proxyObject := (*cgo.Handle)(proxy).Value().(mobileproxy.Proxy)

proxyObject.Stop(int(timeoutSeconds))
}

//export DeleteStreamDialer
func DeleteStreamDialer(dialer StreamDialerPtr) {
(*cgo.Handle)(dialer).Delete()
}

//export DeleteProxy
func DeleteProxy(proxy ProxyPtr) {
(*cgo.Handle)(proxy).Delete()
}

func main() {
// We need the main function to make possible
// CGO compiler to compile the package as C shared library
}
Loading