📄 peer.c
字号:
if (read < 0) { if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) /* No worries */ return; peer_connection_destroy(conn, OSCAR_DISCONNECT_LOST_CONNECTION, strerror(errno)); return; } conn->lastactivity = time(NULL); conn->buffer_incoming.offset += read; if (conn->buffer_incoming.offset < conn->buffer_incoming.len) /* Waiting for more data to arrive */ return; /* We have a complete ODC/OFT frame! Handle it and continue reading */ byte_stream_rewind(&conn->buffer_incoming); if (conn->type == OSCAR_CAPABILITY_DIRECTIM) { peer_odc_recv_frame(conn, &conn->buffer_incoming); } else if (conn->type == OSCAR_CAPABILITY_SENDFILE) { peer_oft_recv_frame(conn, &conn->buffer_incoming); } g_free(conn->buffer_incoming.data); conn->buffer_incoming.data = NULL; conn->header_received = 0;}/*******************************************************************//* End code for receiving data on a peer connection *//*******************************************************************//*******************************************************************//* Begin code for sending data on a peer connection *//*******************************************************************/static voidsend_cb(gpointer data, gint source, PurpleInputCondition cond){ PeerConnection *conn; gsize writelen; ssize_t wrotelen; conn = data; writelen = purple_circ_buffer_get_max_read(conn->buffer_outgoing); if (writelen == 0) { purple_input_remove(conn->watcher_outgoing); conn->watcher_outgoing = 0; return; } wrotelen = send(conn->fd, conn->buffer_outgoing->outptr, writelen, 0); if (wrotelen <= 0) { if (wrotelen < 0 && ((errno == EAGAIN) || (errno == EWOULDBLOCK))) /* No worries */ return; if (conn->ready) { purple_input_remove(conn->watcher_outgoing); conn->watcher_outgoing = 0; close(conn->fd); conn->fd = -1; peer_connection_schedule_destroy(conn, OSCAR_DISCONNECT_LOST_CONNECTION, NULL); } else { /* * This could happen when unable to send a negotiation * frame to a peer proxy server. */ peer_connection_trynext(conn); } return; } purple_circ_buffer_mark_read(conn->buffer_outgoing, wrotelen); conn->lastactivity = time(NULL);}/** * This should be called by OFT/ODC code to send a standard OFT or ODC * frame across the peer connection along with some payload data. Or * maybe a file. Anything, really. */voidpeer_connection_send(PeerConnection *conn, ByteStream *bs){ /* Add everything to our outgoing buffer */ purple_circ_buffer_append(conn->buffer_outgoing, bs->data, bs->len); /* If we haven't already started writing stuff, then start the cycle */ if ((conn->watcher_outgoing == 0) && (conn->fd >= 0)) { conn->watcher_outgoing = purple_input_add(conn->fd, PURPLE_INPUT_WRITE, send_cb, conn); send_cb(conn, conn->fd, 0); }}/*******************************************************************//* End code for sending data on a peer connection *//*******************************************************************//*******************************************************************//* Begin code for establishing a peer connection *//*******************************************************************/voidpeer_connection_finalize_connection(PeerConnection *conn){ conn->watcher_incoming = purple_input_add(conn->fd, PURPLE_INPUT_READ, peer_connection_recv_cb, conn); if (conn->type == OSCAR_CAPABILITY_DIRECTIM) { /* * If we are connecting to them then send our cookie so they * can verify who we are. Note: This doesn't seem to be * necessary, but it also doesn't seem to hurt. */ if (!(conn->flags & PEER_CONNECTION_FLAG_IS_INCOMING)) peer_odc_send_cookie(conn); } else if (conn->type == OSCAR_CAPABILITY_SENDFILE) { if (purple_xfer_get_type(conn->xfer) == PURPLE_XFER_SEND) { peer_oft_send_prompt(conn); } } /* * Tell the remote user that we're connected (which may also imply * that we've accepted their request). */ if (!(conn->flags & PEER_CONNECTION_FLAG_IS_INCOMING)) aim_im_sendch2_connected(conn);}/** * We tried to make an outgoing connection to a remote user. It * either connected or failed to connect. */static voidpeer_connection_common_established_cb(gpointer data, gint source, const gchar *error_message, gboolean verified){ PeerConnection *conn; conn = data; if (verified) conn->verified_connect_data = NULL; else conn->client_connect_data = NULL; if (source < 0) { if ((conn->verified_connect_data == NULL) && (conn->client_connect_data == NULL)) { /* Our parallel connection attemps have both failed. */ peer_connection_trynext(conn); } return; } purple_timeout_remove(conn->connect_timeout_timer); conn->connect_timeout_timer = 0; if (conn->client_connect_data != NULL) { purple_proxy_connect_cancel(conn->client_connect_data); conn->client_connect_data = NULL; } if (conn->verified_connect_data != NULL) { purple_proxy_connect_cancel(conn->verified_connect_data); conn->verified_connect_data = NULL; } conn->fd = source; peer_connection_finalize_connection(conn);}static voidpeer_connection_verified_established_cb(gpointer data, gint source, const gchar *error_message){ peer_connection_common_established_cb(data, source, error_message, TRUE);}static voidpeer_connection_client_established_cb(gpointer data, gint source, const gchar *error_message){ peer_connection_common_established_cb(data, source, error_message, FALSE);}/** * This is the watcher callback for any listening socket that is * waiting for a peer to connect. When a peer connects we set the * input watcher to start reading data from the peer. * * To make sure that the connection is with the intended person and * not with a malicious middle man, we don't send anything until we've * received a peer frame from the remote user and have verified that * the cookie in the peer frame matches the cookie that was exchanged * in the channel 2 ICBM. */voidpeer_connection_listen_cb(gpointer data, gint source, PurpleInputCondition cond){ PeerConnection *conn; OscarData *od; PurpleConnection *gc; struct sockaddr addr; socklen_t addrlen = sizeof(addr); conn = data; od = conn->od; gc = od->gc; purple_debug_info("oscar", "Accepting connection on listener socket.\n"); conn->fd = accept(conn->listenerfd, &addr, &addrlen); if (conn->fd < 0) { if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) /* No connection yet--no worries */ /* TODO: Hmm, but they SHOULD be connected if we're here, right? */ return; peer_connection_trynext(conn); return; } if ((addr.sa_family != PF_INET) && (addr.sa_family != PF_INET6)) { /* Invalid connection type?! Continue waiting. */ close(conn->fd); return; } fcntl(conn->fd, F_SETFL, O_NONBLOCK); purple_input_remove(conn->watcher_incoming); peer_connection_finalize_connection(conn);}/** * We've just opened a listener socket, so we send the remote * user an ICBM and ask them to connect to us. */static voidpeer_connection_establish_listener_cb(int listenerfd, gpointer data){ PeerConnection *conn; OscarData *od; PurpleConnection *gc; PurpleAccount *account; PurpleConversation *conv; char *tmp; FlapConnection *bos_conn; const char *listener_ip; unsigned short listener_port; conn = data; conn->listen_data = NULL; if (listenerfd < 0) { /* Could not open listener socket */ peer_connection_trynext(conn); return; } od = conn->od; gc = od->gc; account = purple_connection_get_account(gc); conn->listenerfd = listenerfd; /* Send the "please connect to me!" ICBM */ bos_conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICBM); if (bos_conn == NULL) { /* Not good */ peer_connection_trynext(conn); return; } listener_ip = purple_network_get_my_ip(bos_conn->fd); listener_port = purple_network_get_port_from_fd(conn->listenerfd); if (conn->type == OSCAR_CAPABILITY_DIRECTIM) { aim_im_sendch2_odc_requestdirect(od, conn->cookie, conn->sn, purple_network_ip_atoi(listener_ip), listener_port, ++conn->lastrequestnumber); /* Print a message to a local conversation window */ conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, conn->sn); tmp = g_strdup_printf(_("Asking %s to connect to us at %s:%hu for " "Direct IM."), conn->sn, listener_ip, listener_port); purple_conversation_write(conv, NULL, tmp, PURPLE_MESSAGE_SYSTEM, time(NULL)); g_free(tmp); } else if (conn->type == OSCAR_CAPABILITY_SENDFILE) { aim_im_sendch2_sendfile_requestdirect(od, conn->cookie, conn->sn, purple_network_ip_atoi(listener_ip), listener_port, ++conn->lastrequestnumber, (const gchar *)conn->xferdata.name, conn->xferdata.size, conn->xferdata.totfiles); }}/** * This is a callback function used when we're connecting to a peer * using either the client IP or the verified IP and the connection * took longer than 5 seconds to complete. We do this because * waiting for the OS to time out the connection attempt is not * practical--the default timeout on many OSes can be 3 minutes or * more, and users are impatient. * * Worst case scenario: the user is connected to the Internet using * a modem with severe lag. The peer connections fail and Purple falls * back to using a proxied connection. The lower bandwidth * limitations imposed by the proxied connection won't matter because * the user is using a modem. * * I suppose this line of thinking is discriminatory against people * with very high lag but decent throughput who are transferring * large files. But we don't care about those people. * * I (Sean) changed the timeout from 15 to 5 seconds, as 60 seconds is * too long for a user to wait to send a file. I'm also parallelizing * requests when possible. The longest we should have to wait now is 10 * seconds. We shouldn't make it shorter than this. */static gbooleanpeer_connection_tooktoolong(gpointer data){ PeerConnection *conn; conn = data; purple_debug_info("oscar", "Peer connection timed out after 5 seconds. " "Trying next method...\n"); peer_connection_trynext(conn);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -