Annotation of ChivanetAimPidgin/oscarprpl/src/c/peer_proxy.c, revision 1.1.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>