Annotation of ChivanetAimPidgin/oscarprpl/src/c/peer_proxy.c, revision 1.1

1.1     ! snw         1: /*
        !             2:  * Purple's oscar protocol plugin
        !             3:  * This file is the legal property of its developers.
        !             4:  * Please see the AUTHORS file distributed alongside this file.
        !             5:  *
        !             6:  * This library is free software; you can redistribute it and/or
        !             7:  * modify it under the terms of the GNU Lesser General Public
        !             8:  * License as published by the Free Software Foundation; either
        !             9:  * version 2 of the License, or (at your option) any later version.
        !            10:  *
        !            11:  * This library is distributed in the hope that it will be useful,
        !            12:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            13:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
        !            14:  * Lesser General Public License for more details.
        !            15:  *
        !            16:  * You should have received a copy of the GNU Lesser General Public
        !            17:  * License along with this library; if not, write to the Free Software
        !            18:  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
        !            19: */
        !            20: 
        !            21: #ifdef HAVE_CONFIG_H
        !            22: #include  <config.h>
        !            23: #endif
        !            24: 
        !            25: #include "oscar.h"
        !            26: #include "peer.h"
        !            27: 
        !            28: static void
        !            29: peer_proxy_send(PeerConnection *conn, ProxyFrame *frame)
        !            30: {
        !            31:        size_t length;
        !            32:        ByteStream bs;
        !            33: 
        !            34:        purple_debug_info("oscar", "Outgoing peer proxy frame with "
        !            35:                        "type=0x%04hx, unknown=0x%08x, flags=0x%04hx, and "
        !            36:                        "payload length=%" G_GSIZE_FORMAT "\n",
        !            37:                        frame->type, frame->unknown,
        !            38:                        frame->flags, frame->payload.len);
        !            39: 
        !            40:        length = 12 + frame->payload.len;
        !            41:        byte_stream_new(&bs, length);
        !            42:        byte_stream_put16(&bs, length - 2);
        !            43:        byte_stream_put16(&bs, PEER_PROXY_PACKET_VERSION);
        !            44:        byte_stream_put16(&bs, frame->type);
        !            45:        byte_stream_put32(&bs, frame->unknown);
        !            46:        byte_stream_put16(&bs, frame->flags);
        !            47:        byte_stream_putraw(&bs, frame->payload.data, frame->payload.len);
        !            48: 
        !            49:        peer_connection_send(conn, &bs);
        !            50: 
        !            51:        byte_stream_destroy(&bs);
        !            52: }
        !            53: 
        !            54: /**
        !            55:  * Create a rendezvous "init send" packet and send it on its merry way.
        !            56:  * This is the first packet sent to the proxy server by the first client
        !            57:  * to indicate that this will be a proxied connection
        !            58:  *
        !            59:  * @param conn The peer connection.
        !            60:  */
        !            61: static void
        !            62: peer_proxy_send_create_new_conn(PeerConnection *conn)
        !            63: {
        !            64:        ProxyFrame frame;
        !            65:        PurpleAccount *account;
        !            66:        const gchar *bn;
        !            67:        guint8 bn_length;
        !            68: 
        !            69:        memset(&frame, 0, sizeof(ProxyFrame));
        !            70:        frame.type = PEER_PROXY_TYPE_CREATE;
        !            71:        frame.flags = 0x0000;
        !            72: 
        !            73:        account = purple_connection_get_account(conn->od->gc);
        !            74:        bn = purple_account_get_username(account);
        !            75:        bn_length = strlen(bn);
        !            76:        byte_stream_new(&frame.payload, 1 + bn_length + 8 + 20);
        !            77:        byte_stream_put8(&frame.payload, bn_length);
        !            78:        byte_stream_putraw(&frame.payload, (const guint8 *)bn, bn_length);
        !            79:        byte_stream_putraw(&frame.payload, conn->cookie, 8);
        !            80: 
        !            81:        byte_stream_put16(&frame.payload, 0x0001); /* Type */
        !            82:        byte_stream_put16(&frame.payload, 16); /* Length */
        !            83:        byte_stream_putcaps(&frame.payload, conn->type); /* Value */
        !            84: 
        !            85:        peer_proxy_send(conn, &frame);
        !            86: 
        !            87:        byte_stream_destroy(&frame.payload);
        !            88: }
        !            89: 
        !            90: /**
        !            91:  * Create a rendezvous "init recv" packet and send it on its merry way.
        !            92:  * This is the first packet sent to the proxy server by the second client
        !            93:  * involved in this rendezvous proxy session.
        !            94:  *
        !            95:  * @param conn The peer connection.
        !            96:  * @param pin The 2 byte PIN sent to us by the other user.  This acts
        !            97:  *        as our passcode when establishing the proxy session.
        !            98:  */
        !            99: static void
        !           100: peer_proxy_send_join_existing_conn(PeerConnection *conn, guint16 pin)
        !           101: {
        !           102:        ProxyFrame frame;
        !           103:        PurpleAccount *account;
        !           104:        const gchar *bn;
        !           105:        guint8 bn_length;
        !           106: 
        !           107:        memset(&frame, 0, sizeof(ProxyFrame));
        !           108:        frame.type = PEER_PROXY_TYPE_JOIN;
        !           109:        frame.flags = 0x0000;
        !           110: 
        !           111:        account = purple_connection_get_account(conn->od->gc);
        !           112:        bn = purple_account_get_username(account);
        !           113:        bn_length = strlen(bn);
        !           114:        byte_stream_new(&frame.payload, 1 + bn_length + 2 + 8 + 20);
        !           115:        byte_stream_put8(&frame.payload, bn_length);
        !           116:        byte_stream_putraw(&frame.payload, (const guint8 *)bn, bn_length);
        !           117:        byte_stream_put16(&frame.payload, pin);
        !           118:        byte_stream_putraw(&frame.payload, conn->cookie, 8);
        !           119: 
        !           120:        byte_stream_put16(&frame.payload, 0x0001); /* Type */
        !           121:        byte_stream_put16(&frame.payload, 16); /* Length */
        !           122:        byte_stream_putcaps(&frame.payload, conn->type); /* Value */
        !           123: 
        !           124:        peer_proxy_send(conn, &frame);
        !           125: 
        !           126:        byte_stream_destroy(&frame.payload);
        !           127: }
        !           128: 
        !           129: /**
        !           130:  * Handle an incoming peer proxy negotiation frame.
        !           131:  */
        !           132: static void
        !           133: peer_proxy_recv_frame(PeerConnection *conn, ProxyFrame *frame)
        !           134: {
        !           135:        purple_debug_info("oscar", "Incoming peer proxy frame with "
        !           136:                        "type=0x%04hx, unknown=0x%08x, flags=0x%04hx, and "
        !           137:                        "payload length=%" G_GSIZE_FORMAT "\n", frame->type,
        !           138:                        frame->unknown, frame->flags, frame->payload.len);
        !           139: 
        !           140:        if (frame->type == PEER_PROXY_TYPE_CREATED)
        !           141:        {
        !           142:                /*
        !           143:                 * Read in 2 byte port then 4 byte IP and tell the
        !           144:                 * remote user to connect to it by sending an ICBM.
        !           145:                 */
        !           146:                guint16 pin;
        !           147:                int i;
        !           148:                guint8 ip[4];
        !           149: 
        !           150:                pin = byte_stream_get16(&frame->payload);
        !           151:                for (i = 0; i < 4; i++)
        !           152:                        ip[i] = byte_stream_get8(&frame->payload);
        !           153:                if (conn->type == OSCAR_CAPABILITY_DIRECTIM)
        !           154:                        aim_im_sendch2_odc_requestproxy(conn->od,
        !           155:                                        conn->cookie,
        !           156:                                        conn->bn, ip, pin, ++conn->lastrequestnumber);
        !           157:                else if (conn->type == OSCAR_CAPABILITY_SENDFILE)
        !           158:                {
        !           159:                        aim_im_sendch2_sendfile_requestproxy(conn->od,
        !           160:                                        conn->cookie, conn->bn,
        !           161:                                        ip, pin, ++conn->lastrequestnumber,
        !           162:                                        (const gchar *)conn->xferdata.name,
        !           163:                                        conn->xferdata.size, conn->xferdata.totfiles);
        !           164:                }
        !           165:        }
        !           166:        else if (frame->type == PEER_PROXY_TYPE_READY)
        !           167:        {
        !           168:                purple_input_remove(conn->watcher_incoming);
        !           169:                conn->watcher_incoming = 0;
        !           170: 
        !           171:                peer_connection_finalize_connection(conn);
        !           172:        }
        !           173:        else if (frame->type == PEER_PROXY_TYPE_ERROR)
        !           174:        {
        !           175:                if (byte_stream_bytes_left(&frame->payload) >= 2)
        !           176:                {
        !           177:                        guint16 error;
        !           178:                        const char *msg;
        !           179:                        error = byte_stream_get16(&frame->payload);
        !           180:                        if (error == 0x000d)
        !           181:                                msg = "bad request";
        !           182:                        else if (error == 0x0010)
        !           183:                                msg = "initial request timed out";
        !           184:                        else if (error == 0x001a)
        !           185:                                msg ="accept period timed out";
        !           186:                        else
        !           187:                                msg = "unknown reason";
        !           188:                        purple_debug_info("oscar", "Proxy negotiation failed with "
        !           189:                                        "error 0x%04hx: %s\n", error, msg);
        !           190:                }
        !           191:                else
        !           192:                {
        !           193:                        purple_debug_warning("oscar", "Proxy negotiation failed with "
        !           194:                                        "an unknown error\n");
        !           195:                }
        !           196:                peer_connection_trynext(conn);
        !           197:        }
        !           198:        else
        !           199:        {
        !           200:                purple_debug_warning("oscar", "Unknown peer proxy frame type 0x%04hx.\n",
        !           201:                                frame->type);
        !           202:        }
        !           203: }
        !           204: 
        !           205: static void
        !           206: peer_proxy_connection_recv_cb(gpointer data, gint source, PurpleInputCondition cond)
        !           207: {
        !           208:        PeerConnection *conn;
        !           209:        gssize read;
        !           210:        ProxyFrame *frame;
        !           211: 
        !           212:        conn = data;
        !           213:        frame = conn->frame;
        !           214: 
        !           215:        /* Start reading a new proxy frame */
        !           216:        if (frame == NULL)
        !           217:        {
        !           218:                /* Read the first 12 bytes (frame length and header) */
        !           219:                read = recv(conn->fd, conn->proxy_header + conn->proxy_header_received,
        !           220:                                12 - conn->proxy_header_received, 0);
        !           221: 
        !           222:                /* Check if the proxy server closed the connection */
        !           223:                if (read == 0)
        !           224:                {
        !           225:                        purple_debug_info("oscar", "Peer proxy server closed connection\n");
        !           226:                        peer_connection_trynext(conn);
        !           227:                        return;
        !           228:                }
        !           229: 
        !           230:                /* If there was an error then close the connection */
        !           231:                if (read < 0)
        !           232:                {
        !           233:                        if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
        !           234:                                /* No worries */
        !           235:                                return;
        !           236: 
        !           237:                        purple_debug_info("oscar", "Lost connection with peer proxy server\n");
        !           238:                        peer_connection_trynext(conn);
        !           239:                        return;
        !           240:                }
        !           241: 
        !           242:                conn->lastactivity = time(NULL);
        !           243: 
        !           244:                /* If we don't even have the first 12 bytes then do nothing */
        !           245:                conn->proxy_header_received += read;
        !           246:                if (conn->proxy_header_received < 12)
        !           247:                        return;
        !           248: 
        !           249:                /* We only support a specific version of the proxy protocol */
        !           250:                if (aimutil_get16(&conn->proxy_header[2]) != PEER_PROXY_PACKET_VERSION)
        !           251:                {
        !           252:                        purple_debug_warning("oscar", "Expected peer proxy protocol "
        !           253:                                "version %u but received version %u.  Closing "
        !           254:                                "connection.\n", PEER_PROXY_PACKET_VERSION,
        !           255:                                aimutil_get16(&conn->proxy_header[2]));
        !           256:                        peer_connection_trynext(conn);
        !           257:                        return;
        !           258:                }
        !           259: 
        !           260:                /* Initialize a new temporary ProxyFrame for incoming data */
        !           261:                frame = g_new0(ProxyFrame, 1);
        !           262:                frame->payload.len = aimutil_get16(&conn->proxy_header[0]) - 10;
        !           263:                frame->version = aimutil_get16(&conn->proxy_header[2]);
        !           264:                frame->type = aimutil_get16(&conn->proxy_header[4]);
        !           265:                frame->unknown = aimutil_get16(&conn->proxy_header[6]);
        !           266:                frame->flags = aimutil_get16(&conn->proxy_header[10]);
        !           267:                if (frame->payload.len > 0)
        !           268:                        frame->payload.data = g_new(guint8, frame->payload.len);
        !           269:                conn->frame = frame;
        !           270:        }
        !           271: 
        !           272:        /* If this frame has a payload then attempt to read it */
        !           273:        if (frame->payload.len - frame->payload.offset > 0)
        !           274:        {
        !           275:                /* Read data into the temporary buffer until it is complete */
        !           276:                read = recv(conn->fd,
        !           277:                                        &frame->payload.data[frame->payload.offset],
        !           278:                                        frame->payload.len - frame->payload.offset,
        !           279:                                        0);
        !           280: 
        !           281:                /* Check if the proxy server closed the connection */
        !           282:                if (read == 0)
        !           283:                {
        !           284:                        purple_debug_info("oscar", "Peer proxy server closed connection\n");
        !           285:                        g_free(frame->payload.data);
        !           286:                        g_free(frame);
        !           287:                        conn->frame = NULL;
        !           288:                        peer_connection_trynext(conn);
        !           289:                        return;
        !           290:                }
        !           291: 
        !           292:                /* If there was an error then close the connection */
        !           293:                if (read < 0)
        !           294:                {
        !           295:                        if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
        !           296:                                /* No worries */
        !           297:                                return;
        !           298: 
        !           299:                        purple_debug_info("oscar", "Lost connection with peer proxy server\n");
        !           300:                        g_free(frame->payload.data);
        !           301:                        g_free(frame);
        !           302:                        conn->frame = NULL;
        !           303:                        peer_connection_trynext(conn);
        !           304:                        return;
        !           305:                }
        !           306: 
        !           307:                frame->payload.offset += read;
        !           308:        }
        !           309: 
        !           310:        conn->lastactivity = time(NULL);
        !           311:        if (frame->payload.offset < frame->payload.len)
        !           312:                /* Waiting for more data to arrive */
        !           313:                return;
        !           314: 
        !           315:        /* We have a complete proxy frame!  Handle it and continue reading */
        !           316:        conn->frame = NULL;
        !           317:        byte_stream_rewind(&frame->payload);
        !           318:        peer_proxy_recv_frame(conn, frame);
        !           319: 
        !           320:        g_free(frame->payload.data);
        !           321:        g_free(frame);
        !           322: 
        !           323:        conn->proxy_header_received = 0;
        !           324: }
        !           325: 
        !           326: /**
        !           327:  * We tried to make an outgoing connection to a proxy server.  It
        !           328:  * either connected or failed to connect.
        !           329:  */
        !           330: void
        !           331: peer_proxy_connection_established_cb(gpointer data, gint source, const gchar *error_message)
        !           332: {
        !           333:        PeerConnection *conn;
        !           334: 
        !           335:        conn = data;
        !           336: 
        !           337:        conn->verified_connect_data = NULL;
        !           338: 
        !           339:        if (source < 0)
        !           340:        {
        !           341:                peer_connection_trynext(conn);
        !           342:                return;
        !           343:        }
        !           344: 
        !           345:        conn->fd = source;
        !           346:        conn->watcher_incoming = purple_input_add(conn->fd,
        !           347:                        PURPLE_INPUT_READ, peer_proxy_connection_recv_cb, conn);
        !           348: 
        !           349:        if (conn->proxyip != NULL)
        !           350:                /* Connect to the session created by the remote user */
        !           351:                peer_proxy_send_join_existing_conn(conn, conn->port);
        !           352:        else
        !           353:                /* Create a new session */
        !           354:                peer_proxy_send_create_new_conn(conn);
        !           355: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>