#include "conversation.h" #include "cc_interface.h" /* --- begin constant definitions --- */ #define NETWORK_TIMEOUT_DELAY 40 /* in ms */ #define MAX_ACCEPT_CHECKS 1000 /* --- begin type declarations --- */ struct sock_accept_args { struct cc_session *session; /* --- begin function prototypes --- */ * Creates a server socket and sends a response to the peer. * @param account the gaim account sending the ready msg * @param session the peer CrazyChat session static void cc_net_send_ready(GaimAccount *account, struct cc_session *session); * Handles responses from the CrazyChat session invite dialog box. * @param dialog the dialog box * @param response the dialog box button response * @param args account, crazychat global data, peer name static void invite_handler(GtkDialog *dialog, gint response, struct accept_args *args); * Periodically checks the server socket for peer's connection. Gives up * after a set number of checks. * @param args peer session and account * @return TRUE to continue checking, FALSE to stop static gboolean accept_cb(struct sock_accept_args *args); * Initialize CrazyChat network session. Sets up the UDP socket and port. * @param account the account the session is part of * @param session the CrazyChat network session static void init_cc_net_session(GaimAccount *account, struct cc_session *session); * Handles checking the network for new feature data and sending out the * @param session the session we're checking for network traffic static gboolean network_cb(struct cc_session *session); * Generates random bytes in the user specified byte buffer. * @param buf the byte buffer * @param len length of the byte buffer static void generate_randomness(uint8_t buf[], unsigned int len); * Sends data over a socket. * @param s socket file descriptor * @param len data buffer length * @return number of bytes sent or -1 if an error occurred static int __send(int s, char *buf, int len); /* --- begin function definitions --- */ void cc_net_send_invite(struct crazychat *cc, char *name, GaimAccount *account) struct cc_session *session; session = cc_find_session(cc, name); if (session) return; /* already have a session with this guy */ session = cc_add_session(cc, name); conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_ANY, name, account); conv = gaim_conversation_new(GAIM_CONV_TYPE_IM, account, name); im = gaim_conversation_get_im_data(conv); snprintf(buf, BUFSIZ, "%s%s!%d", CRAZYCHAT_INVITE_CODE, gaim_network_get_my_ip(-1), cc->tcp_port); Debug("Sent invite to %s for port: %d\n", name, cc->tcp_port); gaim_conv_im_send(im, buf); void cc_net_recv_invite(GaimAccount *account, struct crazychat *cc, char *name, const char *peer_ip, const char *peer_port) struct cc_session *session; struct accept_args *args; Debug("Received a CrazyChat session invite from %s on port %s!\n", session = cc_find_session(cc, name); Debug("Creating a CrazyChat session invite dialog box!\n"); conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_ANY, name, account); if (conv) convwin = gaim_conversation_get_window(conv); /* pop gtk window asking if want to accept */ gtk_dialog_new_with_buttons("CrazyChat Session Invite", GTK_DIALOG_DESTROY_WITH_PARENT, snprintf(buf, BUFSIZ, "Would you like to CRaZYchAT with %s?", name); GtkWidget *label = gtk_label_new(buf); gtk_container_add(GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), args = (struct accept_args*)malloc(sizeof(*args)); args->name = strdup(name); assert(inet_aton(peer_ip, (struct in_addr*)&args->peer_ip)); args->peer_port = atoi(peer_port); g_signal_connect(GTK_OBJECT(dialog), "response", G_CALLBACK(invite_handler), args); gtk_widget_show_all(dialog); void cc_net_recv_accept(GaimAccount *account, struct crazychat *cc, char *name, struct cc_session *session; struct in_addr peer_addr; Debug("Received a CrazyChat session accept!\n"); session = cc_find_session(cc, name); if (session && session->state == INVITE) { session->state = ACCEPTED; assert(inet_aton(peer_ip, &peer_addr)); session->peer_ip = peer_addr.s_addr; cc_net_send_ready(account, session); static void cc_net_send_ready(GaimAccount *account, struct cc_session *session) struct sock_accept_args *args; Debug("Initializing the server socket and sending ready message\n"); /* create the server socket */ session->tcp_sock = socket(AF_INET, SOCK_STREAM, 0); assert(session->tcp_sock != -1); assert(setsockopt(session->tcp_sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int)) != -1); struct sockaddr_in my_addr; my_addr.sin_family = AF_INET; my_addr.sin_port = htons(session->cc->tcp_port); assert(inet_aton(gaim_network_get_my_ip(-1), memset(&my_addr.sin_zero, 0, sizeof(my_addr.sin_zero)); assert(bind(session->tcp_sock, (struct sockaddr*)&my_addr, Debug("Listening on port: %d\n", my_addr.sin_port); assert(listen(session->tcp_sock, 1) != -1); /* socket created, send the ready message */ conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_ANY, session->name, account); conv = gaim_conversation_new(GAIM_CONV_TYPE_IM, account, im = gaim_conversation_get_im_data(conv); gaim_conv_im_send(im, CRAZYCHAT_READY_CODE); /* register timer callback for checking socket connection */ args = (struct sock_accept_args*)malloc(sizeof(*args)); session->udp_sock = MAX_ACCEPT_CHECKS; session->timer_id = g_timeout_add(NETWORK_TIMEOUT_DELAY, (GSourceFunc)accept_cb, args); void cc_net_recv_ready(GaimAccount *account, struct crazychat *cc, char *name) struct cc_session *session; struct sockaddr_in server_addr, my_addr; Debug("Received a CrazyChat session ready!\n"); session = cc_find_session(cc, name); if (session && session->state == ACCEPTED) { session->tcp_sock = socket(AF_INET, SOCK_STREAM, 0); assert(session->tcp_sock != -1); server_addr.sin_family = AF_INET; server_addr.sin_port = session->peer_port; server_addr.sin_addr.s_addr = session->peer_ip; memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero)); assert(connect(session->tcp_sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) != -1); Debug("Connecting to peer on port %d\n", session->peer_port); session->state = CONNECTED; init_cc_net_session(account, session); static void invite_handler(GtkDialog *dialog, gint response, struct accept_args *args) struct cc_session *session; if (response == GTK_RESPONSE_ACCEPT) { session = cc_find_session(args->cc, args->name); session = cc_add_session(args->cc, args->name); session->state = ACCEPTED; session->peer_ip = args->peer_ip; session->peer_port = args->peer_port; snprintf(buf, BUFSIZ, "%s%s", CRAZYCHAT_ACCEPT_CODE, gaim_network_get_my_ip(-1)); conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_ANY, args->name, conv = gaim_conversation_new(GAIM_CONV_TYPE_IM, args->account, args->name); im = gaim_conversation_get_im_data(conv); gaim_conv_im_send(im, buf); gtk_widget_destroy(GTK_WIDGET(dialog)); static gboolean accept_cb(struct sock_accept_args *args) struct cc_session *session; /* set select to check on our tcp socket */ FD_SET(session->tcp_sock, &fds); memset(&zero, 0, sizeof(zero)); ret = select(session->tcp_sock+1,&fds, NULL, NULL, &zero); if (ret) { /* got something to check */ Debug("Checking pending connection\n"); struct sockaddr_in client_addr; sin_size = sizeof(client_addr); sock = accept(session->tcp_sock, (struct sockaddr*)&client_addr, &sin_size); /* check if it's a match */ if (client_addr.sin_addr.s_addr == session->peer_ip) { Debug("Accepted tcp connect from %s\n", session->name); close(session->tcp_sock); session->tcp_sock = sock; session->state = CONNECTED; init_cc_net_session(account, session); Debug("Will start sending to port %d\n", if (!session->udp_sock) { /* timed out */ /* remove session from session list */ cc_remove_session(session->cc, session); static void init_cc_net_session(GaimAccount *account, struct cc_session *session) struct sockaddr_in my_addr; struct sockaddr_in peer_addr; /* send/obtain the udp port information */ assert(__send(session->tcp_sock, (char*)&session->cc->udp_port, sizeof(session->cc->udp_port)) == sizeof(session->cc->udp_port)); assert(recv(session->tcp_sock, (char*)&session->peer_port, sizeof(session->peer_port), 0) == sizeof(session->peer_port)); Debug("Established a CrazyChat session with %s!\n", session->name); /* connect the udp sockets */ session->udp_sock = socket(AF_INET, SOCK_DGRAM, 0); assert(!setsockopt(session->udp_sock, SOL_SOCKET, SO_REUSEADDR, my_addr.sin_family = AF_INET; my_addr.sin_port = htons(session->cc->udp_port); assert(inet_aton(gaim_network_get_my_ip(-1), memset(my_addr.sin_zero, 0, sizeof(my_addr.sin_zero)); assert(!bind(session->udp_sock, (struct sockaddr*)&my_addr, session->peer.sin_family = AF_INET; session->peer.sin_port = htons(session->peer_port); session->peer.sin_addr.s_addr = session->peer_ip; memset(&session->peer.sin_zero, 0, sizeof(session->peer.sin_zero)); Debug("Bound udp sock to port %d, connecting to port %d\n", session->cc->udp_port, session->peer_port); memset(&session->features, 0, sizeof(session->features)); session->output = init_output(&session->features, session); session->filter = Filter_Initialize(); /* initialize timer callback */ session->timer_id = g_timeout_add(NETWORK_TIMEOUT_DELAY, (GSourceFunc)network_cb, session); /* initialize input subsystem if not initialized */ if (!session->cc->features_state) { session->cc->input_data = init_input(session->cc); session->cc->features_state = 1; static gboolean network_cb(struct cc_session *session) struct cc_features *features; Debug("Checking for data\n"); /* set select to check on our tcp socket */ FD_SET(session->tcp_sock, &fds); memset(&zero, 0, sizeof(zero)); ret = select(session->tcp_sock+1, &fds, NULL, NULL, &zero); ret = recv(session->tcp_sock, &command, sizeof(command), 0); /* tcp connection closed, destroy connection */ gtk_widget_destroy(session->output->widget); assert(ret == sizeof(command)); FD_SET(session->tcp_sock, &fds); ret = select(session->tcp_sock+1, &fds, NULL, NULL, &zero); /* set select to check on our udp socket */ FD_SET(session->udp_sock, &fds); memset(&zero, 0, sizeof(zero)); ret = select(session->udp_sock+1, &fds, NULL, NULL, &zero); features = &session->features; while (ret) { /* have data, let's copy it for output */ ret = recvfrom(session->udp_sock, &session->features, sizeof(session->features), 0, (struct sockaddr*)&from, &fromlen); Debug("Received %d bytes from port %d\n", ret, filter(features, session->filter); Debug("\thead size: %d\n", features->head_size); Debug("\topen: left(%s), right(%s), mouth(%s)\n", features->left_eye_open ? "yes" : "no", features->right_eye_open ? "yes" : "no", features->mouth_open ? "yes" : "no"); Debug("\thead rotation: x(%d), y(%d), z(%d)\n", features->head_x_rot, features->head_y_rot, Debug("\tx(%d), y(%d)\n", features->x, features->y); FD_SET(session->udp_sock, &fds); ret = select(session->udp_sock+1, &fds, NULL, NULL, &zero); struct cc_features bogus; generate_randomness((uint8_t*)features, sizeof(*features)); features = &session->cc->input_data->face; assert(sendto(session->udp_sock, (char*)features, sizeof(*features), 0, (struct sockaddr*)&session->peer, sizeof(session->peer)) == sizeof(*features)); Debug("Sent %d bytes\n", sizeof(*features)); Debug("\thead size: %d\n", features->head_size); Debug("\topen: left(%s), right(%s), mouth(%s)\n", features->left_eye_open ? "yes" : "no", features->right_eye_open ? "yes" : "no", features->mouth_open ? "yes" : "no"); Debug("\thead rotation: x(%d), y(%d), z(%d)\n", features->head_x_rot, features->head_y_rot, Debug("\tx(%d), y(%d)\n", features->x, features->y); static void generate_randomness(uint8_t buf[], unsigned int len) fd = open("/dev/random", O_RDONLY); assert(read(fd, buf, len) == len); static int __send(int s, char *buf, int len) int total = 0; /* how many bytes we've sent */ int bytesleft = len; /* how many we have left to send */ n = send(s, buf + total, bytesleft, 0); Debug("ERROR: %s\n", strerror(errno));