/** * Run a SOCKS5 handshake on an open but unused TCP connection. * * @param ih SOCKS5 handshake, consumed here. * @param c open unused connection, consumed here. * @return Connection handle that becomes usable when the SOCKS5 handshake completes. */ struct GNUNET_CONNECTION_Handle * GNUNET_SOCKS_run_handshake(struct GNUNET_SOCKS_Handshake *ih, struct GNUNET_CONNECTION_Handle *c) { ih->socks5_connection=c; ih->target_connection = GNUNET_CONNECTION_create_proxied_from_handshake (c); register_sender (ih); return ih->target_connection; }
/** * Register SOCKS5 handshake sender * * @param cls closure (SOCKS handshake) * @param size number of bytes available in @a buf * @param buf where the callee should write the message * @return number of bytes written to @a buf */ size_t transmit_ready (void *cls, size_t size, void *buf) { struct GNUNET_SOCKS_Handshake * ih = cls; /* connection.c has many routines that call us with buf == NULL : * signal_transmit_error() - DNS, etc. active * connect_fail_continuation() * connect_probe_continuation() - timeout * try_connect_using_address() - DNS failure/timeout * transmit_timeout() - retry failed? * GNUNET_CONNECTION_notify_transmit_ready() can schedule : * transmit_timeout() - DNS still working * connect_error() - DNS done but no socket? * transmit_ready() - scheduler shutdown or timeout, or signal_transmit_error() * We'd need to dig into the scheduler to guess at the reason, as * connection.c tells us nothing itself, but mostly its timouts. * Initially, we'll simply ignore this and leave massive timeouts, but * maybe that should change for error handling pruposes. It appears that * successful operations, including DNS resolution, do not use this. */ if (NULL == buf) { if (0 == ih->step) { LOG (GNUNET_ERROR_TYPE_WARNING, "Timeout contacting SOCKS server, retrying indefinitely, but probably hopeless.\n"); register_sender (ih); } else { LOG (GNUNET_ERROR_TYPE_ERROR, "Timeout during mid SOCKS handshake (step %u), probably not a SOCKS server.\n", ih->step); GNUNET_break (0); } return 0; } GNUNET_assert (1024 >= size && size > 0); GNUNET_assert (SOCKS5_step_done > ih->step && ih->step >= 0); unsigned char * b = ih->outstep[ih->step]; unsigned char * e = ih->outstep[ih->step+1]; GNUNET_assert (e <= &ih->outbuf[1024]); unsigned l = e - b; GNUNET_assert (size >= l && l >= 0); GNUNET_memcpy(buf, b, l); register_reciever (ih, register_reciever_wants(ih)); return l; }
vrpn_File_Connection::vrpn_File_Connection (const char * station_name, const char * local_in_logfile_name, const char * local_out_logfile_name) : vrpn_Connection (local_in_logfile_name, local_out_logfile_name, NULL, NULL), d_controllerId (register_sender("vrpn File Controller")), d_set_replay_rate_type(register_message_type("vrpn_File set_replay_rate")), d_reset_type (register_message_type("vrpn_File reset")), d_play_to_time_type (register_message_type("vrpn_File play_to_time")), d_fileName (NULL), d_file (NULL), d_logHead (NULL), d_logTail (NULL), d_currentLogEntry (NULL), d_preload(vrpn_FILE_CONNECTIONS_SHOULD_PRELOAD), d_accumulate(vrpn_FILE_CONNECTIONS_SHOULD_ACCUMULATE) { // Because we are a file connection, our status should be CONNECTED // Later set this to BROKEN if there is a problem opening/reading the file. if (d_endpoints[0] == NULL) { fprintf(stderr,"vrpn_File_Connection::vrpn_File_Connection(): NULL zeroeth endpoint\n"); } else { connectionStatus = CONNECTED; d_endpoints[0]->status = CONNECTED; } // If we are preloading, then we must accumulate messages. if (d_preload) { d_accumulate = true; } // These are handlers for messages that may be sent from a // vrpn_File_Controller object that may attach itself to us. register_handler(d_set_replay_rate_type, handle_set_replay_rate, this, d_controllerId); register_handler(d_reset_type, handle_reset, this, d_controllerId); register_handler(d_play_to_time_type, handle_play_to_time, this, d_controllerId); // necessary to initialize properly in mainloop() d_last_time.tv_usec = d_last_time.tv_sec = 0; d_fileName = vrpn_copy_file_name(station_name); if (!d_fileName) { fprintf(stderr, "vrpn_File_Connection: Out of memory!\n"); connectionStatus = BROKEN; return; } d_file = fopen(d_fileName, "rb"); if (!d_file) { fprintf(stderr, "vrpn_File_Connection: " "Could not open file \"%s\".\n", d_fileName); connectionStatus = BROKEN; return; } // Read the cookie from the file. It will print an error message if it // can't read it, so we just pass the broken status on up the chain. if (read_cookie() < 0) { connectionStatus = BROKEN; return; } // If we are supposed to preload the entire file into memory buffers, // then keep reading until we get to the end. Otherwise, just read the // first message to get things going. if (d_preload) { while (!read_entry()) { } } else { read_entry(); } // Initialize the "current message" pointer to the first log-file // entry that was read, and set the start time for the file and // the current time to the one in this message. if (d_logHead) { d_currentLogEntry = d_logHead; d_startEntry = d_logHead; d_start_time = d_startEntry->data.msg_time; d_time = d_start_time; d_earliest_user_time.tv_sec = d_earliest_user_time.tv_usec = 0; d_earliest_user_time_valid = false; d_highest_user_time.tv_sec = d_highest_user_time.tv_usec = 0; d_highest_user_time_valid = false; } else { fprintf(stderr, "vrpn_File_Connection: Can't read first message\n"); connectionStatus = BROKEN; return; } // This is useful to play the initial system messages // (the sender/type ones) automatically. These might not be // time synched so if we don't play them automatically they // can mess up playback if their timestamps are later then // the first user message. if (vrpn_FILE_CONNECTIONS_SHOULD_SKIP_TO_USER_MESSAGES) { play_to_user_message(); if (d_currentLogEntry) { d_start_time = d_currentLogEntry->data.msg_time; d_time = d_start_time; } } // Add this to the list of known connections. vrpn_ConnectionManager::instance().addConnection(this, station_name); }
/** * Read one step in the SOCKS5 handshake. * * @param ih SOCKS5 Handshake */ void SOCKS5_handshake_step (struct GNUNET_SOCKS_Handshake *ih) { unsigned char * b = ih->instart; size_t available = ih->inend - b; int want = register_reciever_wants(ih); if (available < want) { register_reciever (ih, want - available); return; } GNUNET_assert (SOCKS5_step_done > ih->step && ih->step >= 0); switch (ih->step) { case SOCKS5_step_greet: /* SOCKS5 server's greeting */ if (b[0] != 5) { LOG (GNUNET_ERROR_TYPE_ERROR, "Not a SOCKS5 server\n"); GNUNET_assert (0); } switch (b[1]) { case SOCKS5_AUTH_NOAUTH: ih->step=SOCKS5_step_cmd; /* no authentication to do */ break; case SOCKS5_AUTH_USERPASS: ih->step=SOCKS5_step_auth; break; case SOCKS5_AUTH_REJECT: LOG (GNUNET_ERROR_TYPE_ERROR, "No authentication method accepted\n"); return; default: LOG (GNUNET_ERROR_TYPE_ERROR, "Not a SOCKS5 server / Nonsensical authentication\n"); return; } b += 2; break; case SOCKS5_step_auth: /* SOCKS5 server's responce to authentication */ if (b[1] != 0) { LOG (GNUNET_ERROR_TYPE_ERROR, "SOCKS5 authentication failed\n"); GNUNET_assert (0); } ih->step=SOCKS5_step_cmd; b += 2; break; case SOCKS5_step_cmd: /* SOCKS5 server's responce to command */ if (b[0] != 5) { LOG (GNUNET_ERROR_TYPE_ERROR, "SOCKS5 protocol error\n"); GNUNET_assert (0); } if (0 != b[1]) { LOG (GNUNET_ERROR_TYPE_ERROR, "SOCKS5 connection error : %s\n", SOCKS5_REP_names(b[1])); return; } b += 3; /* There is no reason to verify host and port afaik. */ switch (*(b++)) { case 1: /* IPv4 */ b += sizeof(struct in_addr); /* 4 */ break; case 4: /* IPv6 */ b += sizeof(struct in6_addr); /* 16 */ break; case 3: /* hostname */ b += *b; break; } b += 2; /* port */ if (b > ih->inend) { register_reciever (ih, b - ih->inend); return; } ih->step = SOCKS5_step_done; LOG (GNUNET_ERROR_TYPE_DEBUG, "SOCKS5 server : %s\n", SOCKS5_REP_names(b[1])); ih->instart = b; SOCKS5_handshake_done (ih); return; case SOCKS5_step_done: GNUNET_assert (0); } ih->instart = b; /* Do not reschedule the sender unless we're done reading. * I imagine this lets us avoid ever cancelling the transmit handle. */ register_sender (ih); }