3
Redirecting Sametime Faux-Server
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.
12
Christopher O'Brien <siege@preoccupied.net>
19
#include <sys/socket.h>
21
#include <netinet/in.h>
25
#include <glib/glist.h>
27
#include <mw_common.h>
28
#include <mw_message.h>
31
/** the server socket or the connected socket */
35
static GIOChannel *chan;
37
/** the listening event on the io channel */
43
static gsize sbuf_size;
44
static gsize sbuf_recv;
47
static void send_msg(struct mwMessage *msg) {
48
struct mwPutBuffer *b;
49
struct mwOpaque o = { 0, 0 };
51
b = mwPutBuffer_new();
52
mwMessage_put(b, msg);
53
mwPutBuffer_finalize(&o, b);
55
b = mwPutBuffer_new();
58
mwPutBuffer_finalize(&o, b);
60
if(sock) write(sock, o.data, o.len);
66
static void handshake_ack() {
67
struct mwMsgHandshakeAck *msg;
69
msg = (struct mwMsgHandshakeAck *)
70
mwMessage_new(mwMessage_HANDSHAKE_ACK);
72
send_msg(MW_MESSAGE(msg));
73
mwMessage_free(MW_MESSAGE(msg));
77
static void login_redir() {
78
struct mwMsgLoginRedirect *msg;
80
msg = (struct mwMsgLoginRedirect *)
81
mwMessage_new(mwMessage_LOGIN_REDIRECT);
82
msg->host = g_strdup(host);
83
msg->server_id = NULL;
85
send_msg(MW_MESSAGE(msg));
86
mwMessage_free(MW_MESSAGE(msg));
96
static void side_process(const guchar *buf, gsize len) {
97
struct mwOpaque o = { .len = len, .data = (guchar *) buf };
98
struct mwGetBuffer *b;
103
b = mwGetBuffer_wrap(&o);
104
type = guint16_peek(b);
107
case mwMessage_HANDSHAKE:
111
case mwMessage_LOGIN:
115
case mwMessage_CHANNEL_DESTROY:
127
static void sbuf_free() {
135
#define ADVANCE(b, n, count) { b += count; n -= count; }
138
/* handle input to complete an existing buffer */
139
static gsize side_recv_cont(const guchar *b, gsize n) {
141
gsize x = sbuf_size - sbuf_recv;
144
memcpy(sbuf + sbuf_recv, b, n);
149
memcpy(sbuf + sbuf_recv, b, x);
153
struct mwOpaque o = { .len = 4, .data = sbuf };
154
struct mwGetBuffer *gb = mwGetBuffer_wrap(&o);
155
x = guint32_peek(gb);
156
mwGetBuffer_free(gb);
161
t = (guchar *) g_malloc(x);
179
side_process(sbuf+4, sbuf_size-4);
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;
195
sbuf = (guchar *) g_malloc0(4);
202
gb = mwGetBuffer_wrap(&o);
203
x = guint32_peek(gb);
204
mwGetBuffer_free(gb);
205
if(! x) return n - 4;
210
sbuf = (guchar *) g_malloc(x);
226
static gsize side_recv(const guchar *b, gsize n) {
228
if(n && (sbuf_size == 0) && (*b & 0x80)) {
235
} else if(sbuf_size > 0) {
236
return side_recv_cont(b, n);
239
return side_recv_empty(b, n);
244
static void feed_buf(const guchar *buf, gsize n) {
245
guchar *b = (guchar *) buf;
249
remain = side_recv(b, n);
256
static int read_recv() {
260
len = read(sock, buf, 2048);
261
if(len > 0) feed_buf(buf, (gsize) len);
267
static gboolean read_cb(GIOChannel *chan,
274
if(ret > 0) return TRUE;
278
g_source_remove(chan_io);
291
static gboolean listen_cb(GIOChannel *chan,
295
struct sockaddr_in rem;
296
guint len = sizeof(rem);
298
sock = accept(sock, (struct sockaddr *) &rem, &len);
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,
310
static void init_socket(int port) {
311
/* start listening on the local port specifier */
313
struct sockaddr_in sin;
315
sock = socket(PF_INET, SOCK_STREAM, 0);
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);
323
if(bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0)
324
g_assert_not_reached();
326
if(listen(sock, 1) < 0)
327
g_assert_not_reached();
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,
335
int main(int argc, char *argv[]) {
344
host = strchr(z, ':');
345
if(host) *host++ = '\0';
349
if(!host || !*host || !port) {
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" ),
358
/* @todo create signal handlers to cleanup socket */
362
g_main_loop_run(g_main_loop_new(NULL, FALSE));