non vorrei lavorare

ブログ名の通りです。javascript three.js mruby rust OCaml golang julialang blender

iPad Wifi版でiPhone4Sの3G回線が使えた件

この件の最新情報はこちら「iPhone4Sの疑似テザリングツールをGitHubに上げた」の記事へ

 

できました!

こんばんは、息子の保育園が始まり、息子は保育園を楽しんでいるようで、癒し系キャラと先生方に評価されているようです。まずは一安心といったところでしょうか、kjunichiです。

ここしばらく、思わせぶりな記事の投稿が続きましたが、出来ました!

まずはソースです

iPhoneで動かすJavaScript

LAN側?のnode.jsを動かせる何かに以下のHTML(JavaScript)を入れておき、iPhoneでこのページをアクセスします。まぁ、そんな訳で、iPhoneの自動ロック設定は解除しておかないと実用的では無いです。



iPad用HTTPプロキシー

iPadのHttpProxyの指定をこのプログラムを動かすnode.jsサーバのIPアドレスにします

// HttpProxyとして要求を受けて、WebSocketにして要求を転送する。
// WebSocketから応答を受けて、HttpProxyに転送する。

// 例外が発生してもサービスを停止しないようにする
process.on('uncaughtException', function(err){ console.log(err.stack); });

var app = require('http').createServer(handler)
  , io = require('socket.io').listen(app)
  , fs = require('fs')

app.listen(80);

function handler (req, res) {
  fs.readFile(__dirname + '/index.html',
  function (err, data) {
    if (err) {
      res.writeHead(500);
      return res.end('Error loading index.html');
    }

    res.writeHead(200);
    res.end(data);
  });
}

var myWsClient = {};
var count = 0;
var webClients = {};

io.sockets.on('connection', function (wsclient) {
        myWsClient = wsclient;
        console.log("HTTP Proxy start");
        var server = doProxy(wsclient);
        wsclient.on('end',function() {
                console.log("HTTP Proxy end");
                server.close();
        });
});

function doProxy(wsclient) {
        // HttpProxyを開始する。
        var port = 8081;
        var sys = require('util');
        var net = require('net');

        var server = net.createServer(function(webBrowser) {
                count++;
                // 接続してきたブラウザのソケットを保持する。
                webClients[count] = webBrowser;
                webBrowser.wid=count;
                
                console.log('web client connected [' + count + "]");
                
                // クライアントからデータを受けた場合
                webBrowser.on('data', function(data) {
                        webBrowser.pause();
                        var parseheader = data.toString().split(/\n/);
                        if(parseheader[0].match(/^GET/) ||
                                parseheader[0].match(/^CONNECT/) ||
                                parseheader[0].match(/^POST/)) {
                                console.log("client send : " + parseheader[0].toString());
                        } else {
                                console.log("client send ");
                        }
                                
                        // Base64化してWS->HttpProxyへ送る
                        //console.log("to ws : " + data.toString('base64'));
                        wsclient.emit('httptows' ,{httpdata: data.toString('base64'),wid:webBrowser.wid});
                        webBrowser.resume();
                });

                webBrowser.on('end', function() {
                        // ブラウザの接続が切断された場合の処理
                        console.log('client disconnected['+ webBrowser.wid + ']');
                        wsclient.emit('httpend',{wid: webBrowser.wid});
                        webClients[webBrowser.wid] = "";
                });

                webBrowser.on('close', function() {
                        // ブラウザの接続が切断された場合の処理
                        console.log('client connection is closed.['+ webBrowser.wid + ']');
                        webClients[webBrowser.wid] = "";
                        
                        wsclient.emit('httpend', {wid: webBrowser.wid });
                });
                
                webBrowser.on('error', function(err) {
                        // ブラウザの接続が切断された場合の処理
                        console.log('client err['+ webBrowser.wid + '].' + err);
                        webClients[webBrowser.wid] = "";
                        
                        wsclient.emit('httpend', {wid: webBrowser.wid });
                });
                
                
        }); // server

        server.listen(port, function() { //'listening' listener
                console.log('server bound');
        });

        wsclient.on('wstohttp', function(data) {
                // WebSocketからの応答をブラウザに返す。
                if(webClients[data['wid']]=="") {
                        console.log('web client connection has been closed.');
                        wsclient.emit('httpend', { wid: data['wid']});
                        return;
                }
                // WebSocket経由で結果受取、Base64デコードしてブラウザに返す。
                console.log('server send data : [' +data['wid'] + "]");
                var a = new Buffer(data['httpdata'].toString(), 'base64');
                var clientSocket = webClients[data['wid']];
                clientSocket.pause();
                clientSocket.write(a);
                //dumpResponse(a);
                clientSocket.resume();
        });
                
        wsclient.on('httpend', function(data) {
                console.log("server is closed.["+data['wid']+"]");
                // HttpProxy先でコネクションが切れたら、こちらもクライアントを切断
                var clientSocket = webClients[data['wid']];
                if(clientSocket=="") {
                        return;
                }
                clientSocket.end();
                webClients[data['wid']] = "";
        });
                
        wsclient.on('end', function() {
                console.log('server disconnected');
                //webBrowser.end();
                //var clientSocket = webClients[data['wid']];
                //clientSocket.end();
        });
        
        sys.puts('Server listening on port ' + port);
}

function dumpResponse(buf) {
        var tmp = "";
        // 表示できる文字は表示する
        for (var i = 0; i < buf.length ; i++) {
                var c = buf.readUInt8(i);
                if( (c > 31 && c < 127) || c==13 || c==10) {
                        tmp = tmp + String.fromCharCode(c);
                } else {
                        tmp = tmp + c + ":";
                }
        }
        console.log(tmp);
}

WebSocketを受信してHTTPプロキシーに転送するサーバ

// WebSocketで受けた要求をHttpProxyに転送する。
// HttpProxyで受けた応答をWebSocketに転送する。

// 例外が発生してもサービスを停止しないようにする
process.on('uncaughtException', function(err){ console.log(err.stack); });

var app = require('http').createServer(handler)
  , io = require('socket.io').listen(app)
  , fs = require('fs');

var net = require('net');

app.listen(8123);

function handler (req, res) {
  fs.readFile(__dirname + '/index.html',
  function (err, data) {
    if (err) {
      res.writeHead(500);
      return res.end('Error loading index.html');
    }

    res.writeHead(200);
    res.end(data);
  });
}

io.sockets.on('connection', function (socket) {
        var isProxyClose = true;
        // HTTP Proxyサーバへ接続する。
        doProxyProc(socket, isProxyClose);
});

var proxys = {};

function doProxyProc(socket,isProxyClose) {
        var isProxyClose = true;
        console.log('server connected');
        var wid = -1;
        
        socket.on('wstohttp', function(data) {
                console.log("proxys at "+ data['wid'] + " is " + proxys[data['wid']]);
                if(proxys[data['wid']]==undefined){
                        var proxy = net.createConnection(8080,'127.0.0.1',function() {
                                proxys[data['wid']] = proxy;
                                proxy.wid = data['wid'];
                                // WebSocketでデータを受けたらHttpProxyに接続する
                                proxy.pause();
                
                                console.log("from client : " + data);

                                // base64デコードしてproxyサーバに送る
                                var a = new Buffer(data['httpdata'].toString(), 'base64');
                                wid = data['wid'];
                                
                                proxy.write(a);
                                dumpResponse(a);
                                proxy.resume();
                        });
                        
                        proxy.on('data',function(pdata) {
                                // HttpProxyからの応答をWebSocketに転送する。
                                
                                proxy.pause();
                                
                                // WebSocketでHttpProxyからの応答をBase64エンコードして返す。
                                socket.emit('httptows', {httpdata: pdata.toString('base64'), wid: proxy.wid});
                                
                                proxy.resume();
                        });
                        
                        proxy.on('end', function() {
                                        console.log('server disconnected');
                                        socket.emit('httpend', {wid: proxy.wid});
                                        proxys[proxy.wid] = "";
                        });
        
                        proxy.on('close',function(){
                                // HttpProxyから切断された場合の処理
                                console.log('server close!');
                                proxys[proxy.wid] = "";
                        });
                                
                        proxy.on('error', function(err) {
                                console.log("proxy["+proxy.wid+"] error! " + err);
                                socket.emit('httpend',{wid: proxy.wid});
                        });
                } else {
                        // 既に接続済みのHttpProxyへのSocketを利用する。
                        var workProxy = proxys[data['wid']];
                        if(workProxy=="") {
                                console.log("proxy has been closed.");
                                socket.emit('httpend', {wid: data['wid'] });
                                return;
                        }
                        workProxy.pause();
                        console.log("from client : " + data);
                        var a = new Buffer(data['httpdata'].toString(), 'base64');
                        workProxy.write(a);
                        dumpResponse(a);
                        workProxy.resume();
                }
                
                
        }); // end socket.on('wstohttp'

        socket.on('httpend', function(data) {
                console.log('client disconnected['+data['wid']+"]");
                var p = proxys[data['wid']];
                console.log("P = " + p);
                if(p!="" && p != undefined) {
                        p.end();
                        proxys[data['wid']]="";
                }
        });
}

function dumpString(str) {
        var tmp = "";
        // 表示できる文字は表示する
        for (var i = 0; i < str.length ; i++) {
                var c = str.charAt(i);
                if( (c > 31 && c < 127) || c==13 || c==10) {
                        tmp = tmp + String.fromCharCode(c);
                } else {
                        tmp = tmp + c + ":";
                }
        }
        console.log(tmp);
}

function dumpResponse(buf) {
        var tmp = "";
        // 表示できる文字は表示する
        for (var i = 0; i < buf.length ; i++) {
                var c = buf.readUInt8(i);
                if( (c > 31 && c < 127) || c==13 || c==10) {
                        tmp = tmp + String.fromCharCode(c);
                } else {
                        tmp = tmp + c + ":";
                }
        }
        console.log(tmp);
}

わかりにくいけど構成図

Img_0110jpg_2

iPhoneの設定

iPhoneアドホック通信で、iPhone側にプロキシアプリを開発環境を経由して インストールするとテザリングできる記事はこれまでありました。 アドホック接続だと、iPhoneとPC間(ローカルIP向けの通信)はWifiで通信して、iPhoneからは 3G経由でインターネット(グローバルIP)へアクセスできるのです。 つまり、iPhoneWifiと3G回線を同時にアクセスできる!

実はアドホック接続でなくてもWifiと3Gが同時に使える

Wifiの設定で、ルータのアドレスを指定しなければ、ローカルIPへの 通信はWifiを使い、グローバルIPへの通信は3G回線を使う動きを します。

node.jsが動き、無線LANアクセスポイントとして動かす何か

iPhoneiPadに加えてnode.jsが動き、無線LANアクセスポイントとして動かす何か があれば、iPadからiPhoneの3G回線を利用できるのです。

関連リンク