1 |
|
2 |
|
3 | var util = require('util')
|
4 | , dgram = require('dgram')
|
5 | , logger = require('../lib/logger')
|
6 | , Pool = require('generic-pool').Pool
|
7 | , net = require('net');
|
8 |
|
9 |
|
10 | var l;
|
11 | var debug;
|
12 | var instance;
|
13 |
|
14 | function logerror(err) {
|
15 | if(err && debug) {
|
16 | l.log(err);
|
17 | }
|
18 | }
|
19 |
|
20 |
|
21 |
|
22 | function UDPRepeaterBackend(startupTime, config, emitter) {
|
23 | var self = this;
|
24 | this.config = config.repeater || [];
|
25 | this.sock = (config.repeaterProtocol == 'udp6') ?
|
26 | dgram.createSocket('udp6') :
|
27 | dgram.createSocket('udp4');
|
28 |
|
29 |
|
30 | this.sock.on('error', function (err) {
|
31 | if (debug) {
|
32 | l.log('Repeater error: ' + err);
|
33 | }
|
34 | });
|
35 |
|
36 |
|
37 | emitter.on('packet', function(packet, rinfo) { self.process(packet, rinfo); });
|
38 | }
|
39 |
|
40 |
|
41 | UDPRepeaterBackend.prototype.process = function(packet, rinfo) {
|
42 | var self = this;
|
43 | var hosts = self.config;
|
44 | for(var i=0; i<hosts.length; i++) {
|
45 | self.sock.send(packet,0,packet.length,hosts[i].port,hosts[i].host,logerror);
|
46 | }
|
47 | };
|
48 |
|
49 | UDPRepeaterBackend.prototype.stop = function(cb) {
|
50 | this.sock.close();
|
51 | cb();
|
52 | };
|
53 |
|
54 |
|
55 |
|
56 | var TCPRepeaterBackend = function(startupTime, config, emitter) {
|
57 | this.config = config;
|
58 | this.pools = [];
|
59 |
|
60 | var targets = this.config.repeater || [];
|
61 | for(var i = 0; i < targets.length; i++) {
|
62 | this.pools.push(this.createPool(targets[i]));
|
63 | }
|
64 |
|
65 | var self = this;
|
66 | emitter.on('packet', function(packet, rinfo) { self.process(packet, rinfo); });
|
67 | };
|
68 |
|
69 |
|
70 | TCPRepeaterBackend.prototype.createPool = function(server) {
|
71 | return Pool({
|
72 | name: server.host + ':' + server.port,
|
73 |
|
74 | create: function(cb) {
|
75 | var client = net.connect(server.port, server.host);
|
76 |
|
77 | function connectError(err) { cb(err, null); }
|
78 |
|
79 | client.on('connect', function() {
|
80 | client.removeListener('error', connectError);
|
81 | cb(null, client);
|
82 | });
|
83 |
|
84 | client.on('error', connectError);
|
85 | },
|
86 |
|
87 | destroy: function(client) {
|
88 | client.end();
|
89 | },
|
90 |
|
91 | max: 5
|
92 | });
|
93 | };
|
94 |
|
95 | TCPRepeaterBackend.prototype.process = function(packet, rinfo) {
|
96 | function send(buf, pool) {
|
97 | pool.acquire(function(err, client) {
|
98 | if(err) {
|
99 | logerror(err);
|
100 | } else {
|
101 | client.write(buf, function() {
|
102 | pool.release(client);
|
103 | });
|
104 | }
|
105 | });
|
106 | }
|
107 |
|
108 | for(var i = 0; i < this.pools.length; i++) {
|
109 | send(new Buffer(packet.toString() + "\n"), this.pools[i]);
|
110 | }
|
111 | };
|
112 |
|
113 |
|
114 | TCPRepeaterBackend.prototype.stop = function(cb) {
|
115 | var self = this;
|
116 | function drain_pool(i) {
|
117 | if(i == self.pools.length) {
|
118 | cb();
|
119 | return;
|
120 | }
|
121 |
|
122 | self.pools[i].drain(function() {
|
123 | self.pools[i].destroyAllNow(function() {
|
124 | drain_pool(i + 1);
|
125 | });
|
126 | });
|
127 | }
|
128 |
|
129 | drain_pool(0);
|
130 | };
|
131 |
|
132 |
|
133 | exports.init = function(startupTime, config, emitter, logger) {
|
134 | debug = config.debug;
|
135 | l = logger;
|
136 |
|
137 | var proto = config.repeaterProtocol;
|
138 | if(proto == 'tcp') {
|
139 | instance = new TCPRepeaterBackend(startupTime, config, emitter);
|
140 | } else {
|
141 | instance = new UDPRepeaterBackend(startupTime, config, emitter);
|
142 | }
|
143 |
|
144 | return true;
|
145 | };
|
146 |
|
147 |
|
148 | exports.stop = function(cb) {
|
149 | if(instance) {
|
150 | instance.stop(cb);
|
151 | instance = null;
|
152 | }
|
153 | };
|