~ubuntu-branches/ubuntu/intrepid/meanwhile/intrepid

« back to all changes in this revision

Viewing changes to samples/redirect_server.c

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2006-01-13 12:38:18 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20060113123818-zod7j3hd9z0iz5fy
Tags: 1.0.2-0ubuntu1
* New upstream release
* Rename libmeanwhile0 to libmeanwhile1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
/*
 
3
  Redirecting Sametime Faux-Server
 
4
  The Meanwhile Project
 
5
 
 
6
  This is a tool which helps to test handling of login-redirects when
 
7
  you don't have a server which will issue them. It will listen for a
 
8
  single incoming connection, will accept a handshake message and send
 
9
  a handshake ack, and will respond to a login message with a redirect
 
10
  message to a server specified on the command line.
 
11
 
 
12
  Christopher O'Brien <siege@preoccupied.net>
 
13
*/
 
14
 
 
15
 
 
16
#include <stdio.h>
 
17
#include <stdlib.h>
 
18
#include <string.h>
 
19
#include <sys/socket.h>
 
20
#include <netdb.h>
 
21
#include <netinet/in.h>
 
22
#include <unistd.h>
 
23
 
 
24
#include <glib.h>
 
25
#include <glib/glist.h>
 
26
 
 
27
#include <mw_common.h>
 
28
#include <mw_message.h>
 
29
 
 
30
 
 
31
/** the server socket or the connected socket */
 
32
static int sock;
 
33
 
 
34
/** the io channel */
 
35
static GIOChannel *chan;
 
36
 
 
37
/** the listening event on the io channel */
 
38
static int chan_io;
 
39
 
 
40
static char *host;
 
41
 
 
42
static guchar *sbuf;
 
43
static gsize sbuf_size;
 
44
static gsize sbuf_recv;
 
45
 
 
46
 
 
47
static void send_msg(struct mwMessage *msg) {
 
48
  struct mwPutBuffer *b;
 
49
  struct mwOpaque o = { 0, 0 };
 
50
 
 
51
  b = mwPutBuffer_new();
 
52
  mwMessage_put(b, msg);
 
53
  mwPutBuffer_finalize(&o, b);
 
54
 
 
55
  b = mwPutBuffer_new();
 
56
  mwOpaque_put(b, &o);
 
57
  mwOpaque_clear(&o);
 
58
  mwPutBuffer_finalize(&o, b);
 
59
 
 
60
  if(sock) write(sock, o.data, o.len);
 
61
 
 
62
  mwOpaque_clear(&o);
 
63
}
 
64
 
 
65
 
 
66
static void handshake_ack() {
 
67
  struct mwMsgHandshakeAck *msg;
 
68
 
 
69
  msg = (struct mwMsgHandshakeAck *)
 
70
    mwMessage_new(mwMessage_HANDSHAKE_ACK);
 
71
 
 
72
  send_msg(MW_MESSAGE(msg));
 
73
  mwMessage_free(MW_MESSAGE(msg));
 
74
}
 
75
 
 
76
 
 
77
static void login_redir() {
 
78
  struct mwMsgLoginRedirect *msg;
 
79
 
 
80
  msg = (struct mwMsgLoginRedirect *)
 
81
    mwMessage_new(mwMessage_LOGIN_REDIRECT);
 
82
  msg->host = g_strdup(host);
 
83
  msg->server_id = NULL;
 
84
 
 
85
  send_msg(MW_MESSAGE(msg));
 
86
  mwMessage_free(MW_MESSAGE(msg));
 
87
}
 
88
 
 
89
 
 
90
static void done() {
 
91
  close(sock);
 
92
  exit(0);
 
93
}
 
94
 
 
95
 
 
96
static void side_process(const guchar *buf, gsize len) {
 
97
  struct mwOpaque o = { .len = len, .data = (guchar *) buf };
 
98
  struct mwGetBuffer *b;
 
99
  guint16 type;
 
100
 
 
101
  if(! len) return;
 
102
 
 
103
  b = mwGetBuffer_wrap(&o);
 
104
  type = guint16_peek(b);
 
105
 
 
106
  switch(type) {
 
107
  case mwMessage_HANDSHAKE:
 
108
    handshake_ack();
 
109
    break;
 
110
 
 
111
  case mwMessage_LOGIN:
 
112
    login_redir();
 
113
    break;
 
114
 
 
115
  case mwMessage_CHANNEL_DESTROY:
 
116
    done();
 
117
    break;
 
118
 
 
119
  default:
 
120
    ;
 
121
  }
 
122
 
 
123
  mwGetBuffer_free(b);
 
124
}
 
125
 
 
126
 
 
127
static void sbuf_free() {
 
128
  g_free(sbuf);
 
129
  sbuf = NULL;
 
130
  sbuf_size = 0;
 
131
  sbuf_recv = 0;
 
132
}
 
133
 
 
134
 
 
135
#define ADVANCE(b, n, count) { b += count; n -= count; }
 
136
 
 
137
 
 
138
/* handle input to complete an existing buffer */
 
139
static gsize side_recv_cont(const guchar *b, gsize n) {
 
140
 
 
141
  gsize x = sbuf_size - sbuf_recv;
 
142
 
 
143
  if(n < x) {
 
144
    memcpy(sbuf + sbuf_recv, b, n);
 
145
    sbuf_recv += n;
 
146
    return 0;
 
147
    
 
148
  } else {
 
149
    memcpy(sbuf + sbuf_recv, b, x);
 
150
    ADVANCE(b, n, x);
 
151
    
 
152
    if(sbuf_size == 4) {
 
153
      struct mwOpaque o = { .len = 4, .data = sbuf };
 
154
      struct mwGetBuffer *gb = mwGetBuffer_wrap(&o);
 
155
      x = guint32_peek(gb);
 
156
      mwGetBuffer_free(gb);
 
157
 
 
158
      if(n < x) {
 
159
        guchar *t;
 
160
        x += 4;
 
161
        t = (guchar *) g_malloc(x);
 
162
        memcpy(t, sbuf, 4);
 
163
        memcpy(t+4, b, n);
 
164
        
 
165
        sbuf_free();
 
166
        
 
167
        sbuf = t;
 
168
        sbuf_size = x;
 
169
        sbuf_recv = n + 4;
 
170
        return 0;
 
171
        
 
172
      } else {
 
173
        sbuf_free();
 
174
        side_process(b, x);
 
175
        ADVANCE(b, n, x);
 
176
      }
 
177
      
 
178
    } else {
 
179
      side_process(sbuf+4, sbuf_size-4);
 
180
      sbuf_free();
 
181
    }
 
182
  }
 
183
 
 
184
  return n;
 
185
}
 
186
 
 
187
 
 
188
/* handle input when there's nothing previously buffered */
 
189
static gsize side_recv_empty(const guchar *b, gsize n) {
 
190
  struct mwOpaque o = { .len = n, .data = (guchar *) b };
 
191
  struct mwGetBuffer *gb;
 
192
  gsize x;
 
193
 
 
194
  if(n < 4) {
 
195
    sbuf = (guchar *) g_malloc0(4);
 
196
    memcpy(sbuf, b, n);
 
197
    sbuf_size = 4;
 
198
    sbuf_recv = n;
 
199
    return 0;
 
200
  }
 
201
  
 
202
  gb = mwGetBuffer_wrap(&o);
 
203
  x = guint32_peek(gb);
 
204
  mwGetBuffer_free(gb);
 
205
  if(! x) return n - 4;
 
206
 
 
207
  if(n < (x + 4)) {
 
208
 
 
209
    x += 4;
 
210
    sbuf = (guchar *) g_malloc(x);
 
211
    memcpy(sbuf, b, n);
 
212
    sbuf_size = x;
 
213
    sbuf_recv = n;
 
214
    return 0;
 
215
    
 
216
  } else {
 
217
    ADVANCE(b, n, 4);
 
218
    side_process(b, x);
 
219
    ADVANCE(b, n, x);
 
220
 
 
221
    return n;
 
222
  }
 
223
}
 
224
 
 
225
 
 
226
static gsize side_recv(const guchar *b, gsize n) {
 
227
 
 
228
  if(n && (sbuf_size == 0) && (*b & 0x80)) {
 
229
    ADVANCE(b, n, 1);
 
230
  }
 
231
 
 
232
  if(n == 0) {
 
233
    return 0;
 
234
 
 
235
  } else if(sbuf_size > 0) {
 
236
    return side_recv_cont(b, n);
 
237
 
 
238
  } else {
 
239
    return side_recv_empty(b, n);
 
240
  }
 
241
}
 
242
 
 
243
 
 
244
static void feed_buf(const guchar *buf, gsize n) {
 
245
  guchar *b = (guchar *) buf;
 
246
  gsize remain = 0;
 
247
 
 
248
  while(n > 0) {
 
249
    remain = side_recv(b, n);
 
250
    b += (n - remain);
 
251
    n = remain;
 
252
  }
 
253
}
 
254
 
 
255
 
 
256
static int read_recv() {
 
257
  guchar buf[2048];
 
258
  int len;
 
259
 
 
260
  len = read(sock, buf, 2048);
 
261
  if(len > 0) feed_buf(buf, (gsize) len);
 
262
 
 
263
  return len;
 
264
}
 
265
 
 
266
 
 
267
static gboolean read_cb(GIOChannel *chan,
 
268
                        GIOCondition cond,
 
269
                        gpointer data) {
 
270
  int ret = 0;
 
271
 
 
272
  if(cond & G_IO_IN) {
 
273
    ret = read_recv();
 
274
    if(ret > 0) return TRUE;
 
275
  }
 
276
 
 
277
  if(sock) {
 
278
    g_source_remove(chan_io);
 
279
    close(sock);
 
280
    sock = 0;
 
281
    chan = NULL;
 
282
    chan_io = 0;
 
283
  }
 
284
 
 
285
  done();
 
286
  
 
287
  return FALSE;
 
288
}
 
289
 
 
290
 
 
291
static gboolean listen_cb(GIOChannel *chan,
 
292
                          GIOCondition cond,
 
293
                          gpointer data) {
 
294
 
 
295
  struct sockaddr_in rem;
 
296
  guint len = sizeof(rem);
 
297
  
 
298
  sock = accept(sock, (struct sockaddr *) &rem, &len);
 
299
  g_assert(sock > 0);
 
300
 
 
301
  g_source_remove(chan_io);
 
302
  chan = g_io_channel_unix_new(sock);
 
303
  chan_io = g_io_add_watch(chan, G_IO_IN | G_IO_ERR | G_IO_HUP,
 
304
                           read_cb, NULL);
 
305
  
 
306
  return FALSE;
 
307
}
 
308
 
 
309
 
 
310
static void init_socket(int port) {
 
311
  /* start listening on the local port specifier */
 
312
 
 
313
  struct sockaddr_in sin;
 
314
 
 
315
  sock = socket(PF_INET, SOCK_STREAM, 0);
 
316
  g_assert(sock >= 0);
 
317
 
 
318
  memset(&sin, 0, sizeof(struct sockaddr_in));
 
319
  sin.sin_family = PF_INET;
 
320
  sin.sin_port = htons(port);
 
321
  sin.sin_addr.s_addr = htonl(INADDR_ANY);
 
322
 
 
323
  if(bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0)
 
324
    g_assert_not_reached();
 
325
 
 
326
  if(listen(sock, 1) < 0)
 
327
    g_assert_not_reached();
 
328
 
 
329
  chan = g_io_channel_unix_new(sock);
 
330
  chan_io = g_io_add_watch(chan, G_IO_IN | G_IO_ERR | G_IO_HUP,
 
331
                           listen_cb, NULL);
 
332
}
 
333
 
 
334
 
 
335
int main(int argc, char *argv[]) {
 
336
  int port = 0;
 
337
 
 
338
  if(argc > 1) {
 
339
    char *z;
 
340
 
 
341
    host = argv[1];
 
342
    z = host;
 
343
 
 
344
    host = strchr(z, ':');
 
345
    if(host) *host++ = '\0';
 
346
    port = atoi(z);
 
347
  }
 
348
 
 
349
  if(!host || !*host || !port) {
 
350
    fprintf(stderr,
 
351
            ( " Usage: %s local_port:redirect_host\n"
 
352
              " Creates a locally-running sametime proxy which redirects"
 
353
              " logins to the\n specified host\n" ),
 
354
            argv[0]);
 
355
    exit(1);
 
356
  }
 
357
 
 
358
  /* @todo create signal handlers to cleanup socket */
 
359
 
 
360
  init_socket(port);
 
361
 
 
362
  g_main_loop_run(g_main_loop_new(NULL, FALSE)); 
 
363
  return 0;
 
364
}
 
365