blob: 8ebf93a4aadf71ad44c0ff9d45496316cece8b54 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package main
import (
"fmt"
"log"
"net"
"net/http"
"time"
"mojo/public/go/application"
"mojo/public/go/bindings"
"mojo/public/go/system"
"mojo/services/network/interfaces/net_address"
"mojo/services/network/interfaces/network_service"
"mojo/services/network/interfaces/tcp_bound_socket"
"mojo/services/network/interfaces/tcp_connected_socket"
"mojo/services/network/interfaces/tcp_server_socket"
)
//#include "mojo/public/c/system/handle.h"
//#include "mojo/public/c/system/result.h"
import "C"
type MojoConnection struct {
sendStream system.ProducerHandle
receiveStream system.ConsumerHandle
socket system.MessagePipeHandle
localAddr net.Addr
remoteAddr net.Addr
}
// Implements net.Conn.
func (c *MojoConnection) Read(b []byte) (int, error) {
r, read := c.receiveStream.BeginReadData(system.MOJO_READ_DATA_FLAG_NONE)
if r != system.MOJO_RESULT_OK {
return 0, fmt.Errorf("can't read: %v", r)
}
l := len(b)
if (l > len(read)) {
l = len(read)
}
copy(b, read[:l])
if r := c.receiveStream.EndReadData(l); r != system.MOJO_RESULT_OK {
return 0, fmt.Errorf("can't read %v bytes: %v", l, r)
}
return l, nil
}
// Implements net.Conn.
func (c *MojoConnection) Write(b []byte) (int, error) {
r, buf := c.sendStream.BeginWriteData(system.MOJO_WRITE_DATA_FLAG_NONE)
if r != system.MOJO_RESULT_OK {
return 0, fmt.Errorf("can't write: %v", r)
}
l := len(b)
if l > len(buf) {
l = len(buf)
}
copy(buf, b[:l])
if r := c.sendStream.EndWriteData(l); r != system.MOJO_RESULT_OK {
return 0, fmt.Errorf("can't write %v bytes: %v", l, r)
}
return l, nil
}
// Implements net.Conn.
func (c *MojoConnection) Close() error {
c.sendStream.Close()
c.receiveStream.Close()
c.socket.Close()
return nil
}
// Implements net.Conn.
func (c *MojoConnection) LocalAddr() net.Addr {
return c.localAddr
}
// Implements net.Conn.
func (c *MojoConnection) RemoteAddr() net.Addr {
return c.remoteAddr
}
// Implements net.Conn.
func (c *MojoConnection) SetDeadline(t time.Time) error {
if err := c.SetReadDeadline(t); err != nil {
return err
}
return c.SetWriteDeadline(t)
}
// Implements net.Conn.
func (c *MojoConnection) SetReadDeadline(t time.Time) error {
// Do nothing.
return nil
}
// Implements net.Conn.
func (c *MojoConnection) SetWriteDeadline(t time.Time) error {
// Do nothing.
return nil
}
type MojoListener struct {
serverSocket *tcp_server_socket.TcpServerSocket_Proxy
}
// Implements net.Listener.
func (l *MojoListener) Accept() (net.Conn, error) {
r, sendProducer, sendConsumer := system.GetCore().CreateDataPipe(nil)
if r != system.MOJO_RESULT_OK {
panic(fmt.Sprintf("can't create data pipe: %v", r))
}
r, receiveProducer, receiveConsumer := system.GetCore().CreateDataPipe(nil)
if r != system.MOJO_RESULT_OK {
panic(fmt.Sprintf("can't create data pipe: %v", r))
}
request, pointer := tcp_connected_socket.CreateMessagePipeForTcpConnectedSocket()
networkError, remoteAddress, err := l.serverSocket.Accept(sendConsumer, receiveProducer, request)
if err != nil {
return nil, err
}
if networkError.Code != 0 {
return nil, fmt.Errorf("%s", *networkError.Description)
}
var addr net.Addr
if remoteAddress.Ipv4 != nil {
addr = &net.TCPAddr{
IP: remoteAddress.Ipv4.Addr[:4],
Port: int(remoteAddress.Ipv4.Port),
}
} else {
addr = &net.TCPAddr{
IP: remoteAddress.Ipv6.Addr[:16],
Port: int(remoteAddress.Ipv6.Port),
}
}
return &MojoConnection{
sendProducer,
receiveConsumer,
pointer.PassMessagePipe(),
l.Addr(),
addr,
}, nil
}
// Implements net.Listener.
func (l *MojoListener) Close() error {
l.serverSocket.Close_Proxy()
return nil
}
// Implements net.Listener.
func (l *MojoListener) Addr() net.Addr {
return &net.TCPAddr{
IP: []byte{127, 0, 0, 1},
Port: 8080,
}
}
type HttpServerDelegate struct {
networkService *network_service.NetworkService_Proxy
tcpBoundSocket *tcp_bound_socket.TcpBoundSocket_Proxy
serverSocket *tcp_server_socket.TcpServerSocket_Proxy
}
func (d *HttpServerDelegate) InitTCPBoundSocket() error {
addr := &net_address.NetAddress{
net_address.NetAddressFamily_Ipv4,
&net_address.NetAddressIPv4{
8080,
[4]uint8{127, 0, 0, 1},
},
nil,
}
request, pointer := tcp_bound_socket.CreateMessagePipeForTcpBoundSocket()
networkError, _, err := d.networkService.CreateTcpBoundSocket(addr, request)
if err != nil {
return err
}
if networkError.Code != 0 {
return fmt.Errorf("%s", *networkError.Description)
}
d.tcpBoundSocket = tcp_bound_socket.NewTcpBoundSocketProxy(pointer, bindings.GetAsyncWaiter())
return nil
}
func (d *HttpServerDelegate) InitServerSocket() error {
request, pointer := tcp_server_socket.CreateMessagePipeForTcpServerSocket()
networkError, err := d.tcpBoundSocket.StartListening(request)
if err != nil {
return err
}
if networkError.Code != 0 {
return fmt.Errorf("%s", *networkError.Description)
}
d.serverSocket = tcp_server_socket.NewTcpServerSocketProxy(pointer, bindings.GetAsyncWaiter())
return nil
}
func (d *HttpServerDelegate) Initialize(ctx application.Context) {
request, pointer := network_service.CreateMessagePipeForNetworkService()
ctx.ConnectToApplication("mojo:network_service").ConnectToService(&request)
d.networkService = network_service.NewNetworkServiceProxy(pointer, bindings.GetAsyncWaiter())
if err := d.InitTCPBoundSocket(); err != nil {
log.Printf("can't create TCP socket: %v\n", err)
return
}
if err := d.InitServerSocket(); err != nil {
log.Printf("can't create server socket: %v\n", err)
return
}
http.HandleFunc("/go", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, Go http server!")
})
l := &MojoListener{d.serverSocket}
if err := http.Serve(l, nil); err != nil {
log.Printf("can't serve request: %v\n", err)
return
}
}
func (d *HttpServerDelegate) AcceptConnection(c *application.Connection) {
c.Close()
}
func (d *HttpServerDelegate) Quit() {
d.networkService.Close_Proxy()
d.tcpBoundSocket.Close_Proxy()
d.serverSocket.Close_Proxy()
}
//export MojoMain
func MojoMain(handle C.MojoHandle) C.MojoResult {
application.Run(&HttpServerDelegate{}, system.MojoHandle(handle))
return C.MOJO_RESULT_OK
}
func main() {
}