static void _handle_stream_start(char *name, char **attrs, void * const userdata) { xmpp_conn_t *conn = (xmpp_conn_t *)userdata; char *id; if (strcmp(name, "stream:stream") != 0) { printf("name = %s\n", name); xmpp_error(conn->ctx, "conn", "Server did not open valid stream."); conn_disconnect(conn); } else { _log_open_tag(conn, attrs); if (conn->stream_id) xmpp_free(conn->ctx, conn->stream_id); id = _get_stream_attribute(attrs, "id"); if (id) conn->stream_id = xmpp_strdup(conn->ctx, id); if (!conn->stream_id) { xmpp_error(conn->ctx, "conn", "Memory allocation failed."); conn_disconnect(conn); } } /* call stream open handler */ conn->open_handler(conn); }
int conn_init( conn_t *conn ) { char *proxy = conn->conf->http_proxy, *host = conn->conf->no_proxy; int i; if( *conn->conf->http_proxy == 0 ) { proxy = NULL; } else if( *conn->conf->no_proxy != 0 ) { for( i = 0; ; i ++ ) if( conn->conf->no_proxy[i] == 0 ) { if( strstr( conn->host, host ) != NULL ) proxy = NULL; host = &conn->conf->no_proxy[i+1]; if( conn->conf->no_proxy[i+1] == 0 ) break; } } conn->proxy = proxy != NULL; if( conn->proto == PROTO_FTP && !conn->proxy ) { conn->ftp->local_if = conn->local_if; conn->ftp->ftp_mode = FTP_PASSIVE; if( !ftp_connect( conn->ftp, conn->host, conn->port, conn->user, conn->pass ) ) { conn->message = conn->ftp->message; conn_disconnect( conn ); return( 0 ); } conn->message = conn->ftp->message; if( !ftp_cwd( conn->ftp, conn->dir ) ) { conn_disconnect( conn ); return( 0 ); } } else { conn->http->local_if = conn->local_if; if( !http_connect( conn->http, conn->proto, proxy, conn->host, conn->port, conn->user, conn->pass ) ) { conn->message = conn->http->headers; conn_disconnect( conn ); return( 0 ); } conn->message = conn->http->headers; conn->fd = conn->http->fd; } return( 1 ); }
void *search_speedtest( void *r ) { struct sigaction actions; memset(&actions, 0, sizeof(actions)); sigemptyset(&actions.sa_mask); actions.sa_flags = 0; actions.sa_handler = thread_exit_handler; sigaction(SIGUSR1,&actions,NULL); search_t *results = r; conn_t conn[1]; // int oldstate; /* Allow this thread to be killed at any time. */ // pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, &oldstate ); // pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate ); memset( conn, 0, sizeof( conn_t ) ); conn->conf = results->conf; if( !conn_set( conn, results->url ) ) results->speed = SPEED_ERROR; else if( !conn_init( conn ) ) results->speed = SPEED_ERROR; else if( !conn_info( conn ) ) results->speed = SPEED_ERROR; else if( conn->size == results->size ) /* Add one because it mustn't be zero */ results->speed = 1 + 1000 * ( gettime() - results->speed_start_time ); else results->speed = SPEED_ERROR; conn_disconnect( conn ); return( NULL ); }
void *search_speedtest( void *r ) { search_t *results = r; conn_t conn[1]; int oldstate; /* Allow this thread to be killed at any time. */ pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, &oldstate ); pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate ); memset( conn, 0, sizeof( conn_t ) ); conn->conf = results->conf; if( !conn_set( conn, results->url ) ) results->speed = SPEED_ERROR; else if( !conn_init( conn ) ) results->speed = SPEED_ERROR; else if( !conn_info( conn ) ) results->speed = SPEED_ERROR; else if( conn->size == results->size ) /* Add one because it mustn't be zero */ results->speed = 1 + 1000 * ( gettime() - results->speed_start_time ); else results->speed = SPEED_ERROR; conn_disconnect( conn ); return( NULL ); }
/** Cleanly disconnect the connection. * This function is only called by the stream parser when </stream:stream> * is received, and it not intended to be called by code outside of Strophe. * * @param conn a Strophe connection object */ void conn_disconnect_clean(xmpp_conn_t * const conn) { /* remove the timed handler */ xmpp_timed_handler_delete(conn, _disconnect_cleanup); conn_disconnect(conn); }
/* Thread used to set up a connection */ void *setup_thread( void *c ) { conn_t *conn = c; int oldstate; /* Allow this thread to be killed at any time. */ pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, &oldstate ); pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate ); if( conn_setup( conn ) ) { conn->last_transfer = gettime(); if( conn_exec( conn ) ) { conn->last_transfer = gettime(); conn->enabled = 1; conn->state = 0; return( NULL ); } } conn_disconnect( conn ); conn->state = 0; return( NULL ); }
/* Close an axel connection */ void axel_close(axel_t *axel) { int i; message_t *m; /* Terminate any thread still running */ for (i = 0; i < axel->conf->num_connections; i++) { /* don't try to kill non existing thread */ #if WIN32 if (NULL != axel->conn[i].setup_thread) { TerminateThread(axel->conn[i].setup_thread, 0); CloseHandle(axel->conn[i].setup_thread); } #else if (*axel->conn[i].setup_thread != 0) { pthread_cancel(*axel->conn[i].setup_thread); } #endif } /* Delete state file if necessary */ if (1 == axel->ready) { snprintf(buffer, MAX_STRING, "%s.st", axel->filename); unlink(buffer); } /* Else: Create it.. */ else if(axel->bytes_done > 0) { save_state(axel); } /* Delete any message not processed yet */ while (axel->message) { m = axel->message; axel->message = axel->message->next; free(m); } /* Close all connections and local file */ #if WIN32 CloseHandle(axel->outfd); #else close(axel->outfd); #endif for (i = 0; i < axel->conf->num_connections; i++) { conn_disconnect(&axel->conn[i]); } free(axel->conn); free(axel); #if WIN32 WSACleanup(); #endif }
/* timed handler for cleanup if normal disconnect procedure takes too long */ static int _disconnect_cleanup(xmpp_conn_t * const conn, void * const userdata) { xmpp_debug(conn->ctx, "xmpp", "disconnection forced by cleanup timeout"); conn_disconnect(conn); return 0; }
void __connmgr_remove_connection_at(struct conn_manager* self, size_t i) { conn_disconnect(self->conns[i]); conn_free(self->conns[i]), free(self->conns[i]); size_t j; for (j = i + 1; j < connmgr_size(self); j ++) { self->conns[j - 1] = self->conns[j]; } self->num_conns --; }
void connmgr_free(struct conn_manager* self) { size_t i; for (i = 0; i < connmgr_size(self); i ++) { conn_disconnect(self->conns[i]); conn_free(self->conns[i]), free(self->conns[i]); } free(self->conns); memset(self, 0, sizeof(*self)); }
int netserver_drop(NETSERVER *s, int client_id, const char *reason) { /* TODO: insert lots of checks here */ NETADDR addr; netserver_client_addr(s, client_id, &addr); dbg_msg("net_server", "client dropped. cid=%d ip=%d.%d.%d.%d reason=\"%s\"", client_id, addr.ip[0], addr.ip[1], addr.ip[2], addr.ip[3], reason ); conn_disconnect(&s->slots[client_id].conn, reason); if(s->del_client) s->del_client(client_id, s->user_ptr); return 0; }
/* Called when tcp connection is established. */ void conn_established(xmpp_conn_t * const conn) { if (conn->tls_legacy_ssl && !conn->is_raw) { xmpp_debug(conn->ctx, "xmpp", "using legacy SSL connection"); if (conn_tls_start(conn) != 0) { conn_disconnect(conn); return; } } if (conn->is_raw) { handler_reset_timed(conn, 0); /* we skip authentication for a "raw" connection, but the event loop ignores user's handlers when conn->authenticated is not set. */ conn->authenticated = 1; conn->conn_handler(conn, XMPP_CONN_RAW_CONNECT, 0, NULL, conn->userdata); } else { /* send stream init */ conn_open_stream(conn); } }
int netserver_drop(NETSERVER *s, int client_id, const char *reason) { /* TODO: insert lots of checks here */ NETADDR addr; netserver_client_addr(s, client_id, &addr); dbg_msg("Client", "Player: %s Disconnected.",server_clientname(client_id)); dbg_msg("Client", "Cid: %d Disconnected. IP: %d.%d.%d.%d reason: \"%s\"", client_id, addr.ip[0], addr.ip[1], addr.ip[2], addr.ip[3], reason ); if(s->del_client) s->del_client(client_id, s->user_ptr); conn_disconnect(&s->slots[client_id].conn, reason); return 0; }
void *setup_thread_cb( void *c ) #endif { conn_t *conn = c; int oldstate; /* Allow this thread to be killed at any time. */ #if !WIN32 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate); #endif if (conn_setup(conn)) { conn->last_transfer = gettime(); if (conn_exec(conn)) { conn->last_transfer = gettime(); conn->enabled = 1; conn->state = 0; #if WIN32 return 0; #else return NULL; #endif } } conn_disconnect(conn); conn->state = 0; #if WIN32 return 0; #else return NULL; #endif }
int search_makelist( search_t *results, char *url ) { int i, size = 8192, j = 0; char *s, *s1, *s2, *s3; conn_t conn[1]; double t; memset( conn, 0, sizeof( conn_t ) ); conn->conf = results->conf; t = gettime(); if( !conn_set( conn, url ) ) return( -1 ); if( !conn_init( conn ) ) return( -1 ); if( !conn_info( conn ) ) return( -1 ); strcpy( results[0].url, url ); results[0].speed = 1 + 1000 * ( gettime() - t ); results[0].size = conn->size; s = malloc( size ); sprintf( s, "http://www.filesearching.com/cgi-bin/s?q=%s&w=a&l=en&" "t=f&e=on&m=%i&o=n&s1=%lld&s2=%lld&x=15&y=15", conn->file, results->conf->search_amount, conn->size, conn->size ); conn_disconnect( conn ); memset( conn, 0, sizeof( conn_t ) ); conn->conf = results->conf; if( !conn_set( conn, s ) ) { free( s ); return( 1 ); } if( !conn_setup( conn ) ) { free( s ); return( 1 ); } if( !conn_exec( conn ) ) { free( s ); return( 1 ); } while( ( i = read( conn->fd, s + j, size - j ) ) > 0 ) { j += i; if( j + 10 >= size ) { size *= 2; s = realloc( s, size ); memset( s + size / 2, 0, size / 2 ); } } conn_disconnect( conn ); s1 = strstr( s, "<pre class=list" ); s1 = strchr( s1, '\n' ) + 1; if( strstr( s1, "</pre>" ) == NULL ) { /* Incomplete list */ free( s ); return( 1 ); } for( i = 1; strncmp( s1, "</pre>", 6 ) && i < results->conf->search_amount && *s1; i ++ ) { s3 = strchr( s1, '\n' ); *s3 = 0; s2 = strrstr( s1, "<a href=" ) + 8; *s3 = '\n'; s3 = strchr( s2, ' ' ); *s3 = 0; if( strcmp( results[0].url, s2 ) ) { strncpy( results[i].url, s2, MAX_STRING ); results[i].size = results[0].size; results[i].conf = results->conf; } else { /* The original URL might show up */ i --; } for( s1 = s3; *s1 != '\n'; s1 ++ ); s1 ++; } free( s ); return( i ); }
/* authenticate the connection * this may get called multiple times. if any auth method fails, * this will get called again until one auth method succeeds or every * method fails */ static void _auth(xmpp_conn_t * const conn) { xmpp_stanza_t *auth, *authdata, *query, *child, *iq; char *str, *authid; char *scram_init; int anonjid; /* if there is no node in conn->jid, we assume anonymous connect */ str = xmpp_jid_node(conn->ctx, conn->jid); if (str == NULL) { anonjid = 1; } else { xmpp_free(conn->ctx, str); anonjid = 0; } if (conn->tls_support) { tls_t *tls = tls_new(conn->ctx, conn->sock, conn->certfail_handler, conn->tls_cert_path); /* If we couldn't init tls, it isn't there, so go on */ if (!tls) { conn->tls_support = 0; _auth(conn); return; } else { tls_free(tls); } auth = _make_starttls(conn); if (!auth) { disconnect_mem_error(conn); return; } handler_add(conn, _handle_proceedtls_default, XMPP_NS_TLS, NULL, NULL, NULL); xmpp_send(conn, auth); xmpp_stanza_release(auth); /* TLS was tried, unset flag */ conn->tls_support = 0; /* _auth() will be called later */ return; } if (conn->tls_mandatory && !xmpp_conn_is_secured(conn)) { xmpp_error(conn->ctx, "xmpp", "TLS is not supported, but set as " "mandatory for this connection"); conn_disconnect(conn); return; } if (anonjid && conn->sasl_support & SASL_MASK_ANONYMOUS) { /* some crap here */ auth = _make_sasl_auth(conn, "ANONYMOUS"); if (!auth) { disconnect_mem_error(conn); return; } handler_add(conn, _handle_sasl_result, XMPP_NS_SASL, NULL, NULL, "ANONYMOUS"); xmpp_send(conn, auth); xmpp_stanza_release(auth); /* SASL ANONYMOUS was tried, unset flag */ conn->sasl_support &= ~SASL_MASK_ANONYMOUS; } else if (anonjid) { xmpp_error(conn->ctx, "auth", "No node in JID, and SASL ANONYMOUS unsupported."); xmpp_disconnect(conn); } else if (conn->sasl_support & SASL_MASK_SCRAMSHA1) { auth = _make_sasl_auth(conn, "SCRAM-SHA-1"); if (!auth) { disconnect_mem_error(conn); return; } /* don't free scram_init on success */ scram_init = _make_scram_sha1_init_msg(conn); if (!scram_init) { xmpp_stanza_release(auth); disconnect_mem_error(conn); return; } str = xmpp_base64_encode(conn->ctx, (unsigned char *)scram_init, strlen(scram_init)); if (!str) { xmpp_free(conn->ctx, scram_init); xmpp_stanza_release(auth); disconnect_mem_error(conn); return; } authdata = xmpp_stanza_new(conn->ctx); if (!authdata) { xmpp_free(conn->ctx, str); xmpp_free(conn->ctx, scram_init); xmpp_stanza_release(auth); disconnect_mem_error(conn); return; } xmpp_stanza_set_text(authdata, str); xmpp_free(conn->ctx, str); xmpp_stanza_add_child(auth, authdata); xmpp_stanza_release(authdata); handler_add(conn, _handle_scram_sha1_challenge, XMPP_NS_SASL, NULL, NULL, (void *)scram_init); xmpp_send(conn, auth); xmpp_stanza_release(auth); /* SASL SCRAM-SHA-1 was tried, unset flag */ conn->sasl_support &= ~SASL_MASK_SCRAMSHA1; } else if (conn->sasl_support & SASL_MASK_DIGESTMD5) { auth = _make_sasl_auth(conn, "DIGEST-MD5"); if (!auth) { disconnect_mem_error(conn); return; } handler_add(conn, _handle_digestmd5_challenge, XMPP_NS_SASL, NULL, NULL, NULL); xmpp_send(conn, auth); xmpp_stanza_release(auth); /* SASL DIGEST-MD5 was tried, unset flag */ conn->sasl_support &= ~SASL_MASK_DIGESTMD5; } else if (conn->sasl_support & SASL_MASK_PLAIN) { auth = _make_sasl_auth(conn, "PLAIN"); if (!auth) { disconnect_mem_error(conn); return; } authdata = xmpp_stanza_new(conn->ctx); if (!authdata) { disconnect_mem_error(conn); return; } authid = _get_authid(conn); if (!authid) { disconnect_mem_error(conn); return; } str = sasl_plain(conn->ctx, authid, conn->pass); if (!str) { disconnect_mem_error(conn); return; } xmpp_stanza_set_text(authdata, str); xmpp_free(conn->ctx, str); xmpp_free(conn->ctx, authid); xmpp_stanza_add_child(auth, authdata); xmpp_stanza_release(authdata); handler_add(conn, _handle_sasl_result, XMPP_NS_SASL, NULL, NULL, "PLAIN"); xmpp_send(conn, auth); xmpp_stanza_release(auth); /* SASL PLAIN was tried */ conn->sasl_support &= ~SASL_MASK_PLAIN; } else if (conn->type == XMPP_CLIENT) { /* legacy client authentication */ iq = xmpp_stanza_new(conn->ctx); if (!iq) { disconnect_mem_error(conn); return; } xmpp_stanza_set_name(iq, "iq"); xmpp_stanza_set_type(iq, "set"); xmpp_stanza_set_id(iq, "_xmpp_auth1"); query = xmpp_stanza_new(conn->ctx); if (!query) { xmpp_stanza_release(iq); disconnect_mem_error(conn); return; } xmpp_stanza_set_name(query, "query"); xmpp_stanza_set_ns(query, XMPP_NS_AUTH); xmpp_stanza_add_child(iq, query); xmpp_stanza_release(query); child = xmpp_stanza_new(conn->ctx); if (!child) { xmpp_stanza_release(iq); disconnect_mem_error(conn); return; } xmpp_stanza_set_name(child, "username"); xmpp_stanza_add_child(query, child); xmpp_stanza_release(child); authdata = xmpp_stanza_new(conn->ctx); if (!authdata) { xmpp_stanza_release(iq); disconnect_mem_error(conn); return; } str = xmpp_jid_node(conn->ctx, conn->jid); xmpp_stanza_set_text(authdata, str); xmpp_free(conn->ctx, str); xmpp_stanza_add_child(child, authdata); xmpp_stanza_release(authdata); child = xmpp_stanza_new(conn->ctx); if (!child) { xmpp_stanza_release(iq); disconnect_mem_error(conn); return; } xmpp_stanza_set_name(child, "password"); xmpp_stanza_add_child(query, child); xmpp_stanza_release(child); authdata = xmpp_stanza_new(conn->ctx); if (!authdata) { xmpp_stanza_release(iq); disconnect_mem_error(conn); return; } xmpp_stanza_set_text(authdata, conn->pass); xmpp_stanza_add_child(child, authdata); xmpp_stanza_release(authdata); child = xmpp_stanza_new(conn->ctx); if (!child) { xmpp_stanza_release(iq); disconnect_mem_error(conn); return; } xmpp_stanza_set_name(child, "resource"); xmpp_stanza_add_child(query, child); xmpp_stanza_release(child); authdata = xmpp_stanza_new(conn->ctx); if (!authdata) { xmpp_stanza_release(iq); disconnect_mem_error(conn); return; } str = xmpp_jid_resource(conn->ctx, conn->jid); if (str) { xmpp_stanza_set_text(authdata, str); xmpp_free(conn->ctx, str); } else { xmpp_stanza_release(authdata); xmpp_stanza_release(iq); xmpp_error(conn->ctx, "auth", "Cannot authenticate without resource"); xmpp_disconnect(conn); return; } xmpp_stanza_add_child(child, authdata); xmpp_stanza_release(authdata); handler_add_id(conn, _handle_legacy, "_xmpp_auth1", NULL); handler_add_timed(conn, _handle_missing_legacy, LEGACY_TIMEOUT, NULL); xmpp_send(conn, iq); xmpp_stanza_release(iq); } }
/* Get file size and other information */ int conn_info( conn_t *conn ) { /* It's all a bit messed up.. But it works. */ if( conn->proto == PROTO_FTP && !conn->proxy ) { ftp_command( conn->ftp, "REST %lld", 1 ); if( ftp_wait( conn->ftp ) / 100 == 3 || conn->ftp->status / 100 == 2 ) { conn->supported = 1; ftp_command( conn->ftp, "REST %lld", 0 ); ftp_wait( conn->ftp ); } else { conn->supported = 0; } if( !ftp_cwd( conn->ftp, conn->dir ) ) return( 0 ); conn->size = ftp_size( conn->ftp, conn->file, MAX_REDIR ); if( conn->size < 0 ) conn->supported = 0; if( conn->size == -1 ) return( 0 ); else if( conn->size == -2 ) conn->size = INT_MAX; } else { char s[MAX_STRING], *t; long long int i = 0; do { conn->currentbyte = 1; if( !conn_setup( conn ) ) return( 0 ); conn_exec( conn ); conn_disconnect( conn ); /* Code 3xx == redirect */ if( conn->http->status / 100 != 3 ) break; if( ( t = http_header( conn->http, "location:" ) ) == NULL ) return( 0 ); sscanf( t, "%1023s", s ); // Warning: truncating to MAX_STRING if( strstr( s, "://" ) == NULL) { sprintf( conn->http->headers, "%s%s", conn_url( conn ), s ); strncpy( s, conn->http->headers, MAX_STRING ); } else if( s[0] == '/' ) { sprintf( conn->http->headers, "http://%s:%i%s", conn->host, conn->port, s ); strncpy( s, conn->http->headers, MAX_STRING ); } conn_set( conn, s ); i ++; } while( conn->http->status / 100 == 3 && i < MAX_REDIR ); if( i == MAX_REDIR ) { sprintf( conn->message, _("Too many redirects.\n") ); return( 0 ); } conn->size = http_size( conn->http ); if( conn->http->status == 206 && conn->size >= 0 ) { conn->supported = 1; conn->size ++; } else if( conn->http->status == 200 || conn->http->status == 206 ) { conn->supported = 0; conn->size = INT_MAX; } else { t = strchr( conn->message, '\n' ); if( t == NULL ) sprintf( conn->message, _("Unknown HTTP error.\n") ); else *t = 0; return( 0 ); } } return( 1 ); }
/* Main 'loop' */ void axel_do( axel_t *axel ) { fd_set fds[1]; int hifd, i, j; long long int size; struct timeval timeval[1]; /* Create statefile if necessary */ if( gettime() > axel->next_state ) { save_state( axel ); axel->next_state = gettime() + axel->conf->save_state_interval; } /* Wait for data on (one of) the connections */ FD_ZERO( fds ); hifd = 0; for( i = 0; i < axel->conf->num_connections; i ++ ) { if( axel->conn[i].enabled ) FD_SET( axel->conn[i].fd, fds ); hifd = max( hifd, axel->conn[i].fd ); } if( hifd == 0 ) { /* No connections yet. Wait... */ usleep( 100000 ); goto conn_check; } else { timeval->tv_sec = 0; timeval->tv_usec = 100000; /* A select() error probably means it was interrupted by a signal, or that something else's very wrong... */ if( select( hifd + 1, fds, NULL, NULL, timeval ) == -1 ) { axel->ready = -1; return; } } /* Handle connections which need attention */ for( i = 0; i < axel->conf->num_connections; i ++ ) if( axel->conn[i].enabled ) { if( FD_ISSET( axel->conn[i].fd, fds ) ) { axel->conn[i].last_transfer = gettime(); size = read( axel->conn[i].fd, buffer, axel->conf->buffer_size ); if( size == -1 ) { if( axel->conf->verbose ) { axel_message( axel, _("Error on connection %i! " "Connection closed"), i ); } axel->conn[i].enabled = 0; conn_disconnect( &axel->conn[i] ); continue; } else if( size == 0 ) { if( axel->conf->verbose ) { /* Only abnormal behaviour if: */ if( axel->conn[i].currentbyte < axel->conn[i].lastbyte && axel->size != INT_MAX ) { axel_message( axel, _("Connection %i unexpectedly closed"), i ); } else { axel_message( axel, _("Connection %i finished"), i ); } } if( !axel->conn[0].supported ) { axel->ready = 1; } axel->conn[i].enabled = 0; conn_disconnect( &axel->conn[i] ); continue; } /* j == Bytes to go */ j = axel->conn[i].lastbyte - axel->conn[i].currentbyte + 1; if( j < size ) { if( axel->conf->verbose ) { axel_message( axel, _("Connection %i finished"), i ); } axel->conn[i].enabled = 0; conn_disconnect( &axel->conn[i] ); size = j; /* Don't terminate, still stuff to write! */ } /* This should always succeed.. */ lseek( axel->outfd, axel->conn[i].currentbyte, SEEK_SET ); if( write( axel->outfd, buffer, size ) != size ) { axel_message( axel, _("Write error!") ); axel->ready = -1; return; } axel->conn[i].currentbyte += size; axel->bytes_done += size; } else { if( gettime() > axel->conn[i].last_transfer + axel->conf->connection_timeout ) { if( axel->conf->verbose ) axel_message( axel, _("Connection %i timed out"), i ); conn_disconnect( &axel->conn[i] ); axel->conn[i].enabled = 0; } } } if( axel->ready ) return; conn_check: /* Look for aborted connections and attempt to restart them. */ for( i = 0; i < axel->conf->num_connections; i ++ ) { if( !axel->conn[i].enabled && axel->conn[i].currentbyte < axel->conn[i].lastbyte ) { if( axel->conn[i].state == 0 ) { conn_set( &axel->conn[i], axel->url->text ); axel->url = axel->url->next; /* axel->conn[i].local_if = axel->conf->interfaces->text; axel->conf->interfaces = axel->conf->interfaces->next; */ if( axel->conf->verbose >= 2 ) axel_message( axel, _("Connection %i downloading from %s:%i using interface %s"), i, axel->conn[i].host, axel->conn[i].port, axel->conn[i].local_if ); if( pthread_create( axel->conn[i].setup_thread, NULL, setup_thread, &axel->conn[i] ) == 0 ) { axel->conn[i].state = 1; axel->conn[i].last_transfer = gettime(); } else { axel_message( axel, _("pthread error!!!") ); axel->ready = -1; } } else { if( gettime() > axel->conn[i].last_transfer + axel->conf->reconnect_delay ) { pthread_cancel( *axel->conn[i].setup_thread ); axel->conn[i].state = 0; } } } } /* Calculate current average speed and finish_time */ axel->bytes_per_second = (int) ( (double) ( axel->bytes_done - axel->start_byte ) / ( gettime() - axel->start_time ) ); axel->finish_time = (int) ( axel->start_time + (double) ( axel->size - axel->start_byte ) / axel->bytes_per_second ); /* Check speed. If too high, delay for some time to slow things down a bit. I think a 5% deviation should be acceptable. */ if( axel->conf->max_speed > 0 ) { if( (float) axel->bytes_per_second / axel->conf->max_speed > 1.05 ) axel->delay_time += 10000; else if( ( (float) axel->bytes_per_second / axel->conf->max_speed < 0.95 ) && ( axel->delay_time >= 10000 ) ) axel->delay_time -= 10000; else if( ( (float) axel->bytes_per_second / axel->conf->max_speed < 0.95 ) ) axel->delay_time = 0; usleep( axel->delay_time ); } /* Ready? */ if( axel->bytes_done == axel->size ) axel->ready = 1; }
/** Run the event loop once. * This function will run send any data that has been queued by * xmpp_send and related functions and run through the Strophe even * loop a single time, and will not wait more than timeout * milliseconds for events. This is provided to support integration * with event loops outside the library, and if used, should be * called regularly to achieve low latency event handling. * * @param ctx a Strophe context object * @param timeout time to wait for events in milliseconds * * @ingroup EventLoop */ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout) { xmpp_connlist_t *connitem; xmpp_conn_t *conn; fd_set rfds, wfds; sock_t max = 0; int ret; struct timeval tv; xmpp_send_queue_t *sq, *tsq; int towrite; char buf[4096]; uint64_t next; long usec; int tls_read_bytes = 0; if (ctx->loop_status == XMPP_LOOP_QUIT) return; ctx->loop_status = XMPP_LOOP_RUNNING; /* send queued data */ connitem = ctx->connlist; while (connitem) { conn = connitem->conn; if (conn->state != XMPP_STATE_CONNECTED) { connitem = connitem->next; continue; } /* if we're running tls, there may be some remaining data waiting to * be sent, so push that out */ if (conn->tls) { ret = tls_clear_pending_write(conn->tls); if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls))) { /* an error occured */ xmpp_debug(ctx, "xmpp", "Send error occured, disconnecting."); conn->error = ECONNABORTED; conn_disconnect(conn); } } /* write all data from the send queue to the socket */ sq = conn->send_queue_head; while (sq) { towrite = sq->len - sq->written; if (conn->tls) { ret = tls_write(conn->tls, &sq->data[sq->written], towrite); if (ret < 0 && !tls_is_recoverable(tls_error(conn->tls))) { /* an error occured */ conn->error = tls_error(conn->tls); break; } else if (ret < towrite) { /* not all data could be sent now */ if (ret >= 0) sq->written += ret; break; } } else { ret = sock_write(conn->sock, &sq->data[sq->written], towrite); if (ret < 0 && !sock_is_recoverable(sock_error())) { /* an error occured */ conn->error = sock_error(); break; } else if (ret < towrite) { /* not all data could be sent now */ if (ret >= 0) sq->written += ret; break; } } /* all data for this queue item written, delete and move on */ xmpp_free(ctx, sq->data); tsq = sq; sq = sq->next; xmpp_free(ctx, tsq); /* pop the top item */ conn->send_queue_head = sq; /* if we've sent everything update the tail */ if (!sq) conn->send_queue_tail = NULL; } /* tear down connection on error */ if (conn->error) { /* FIXME: need to tear down send queues and random other things * maybe this should be abstracted */ xmpp_debug(ctx, "xmpp", "Send error occured, disconnecting."); conn->error = ECONNABORTED; conn_disconnect(conn); } connitem = connitem->next; } /* reset parsers if needed */ for (connitem = ctx->connlist; connitem; connitem = connitem->next) { if (connitem->conn->reset_parser) conn_parser_reset(connitem->conn); } /* fire any ready timed handlers, then make sure we don't wait past the time when timed handlers need to be called */ next = handler_fire_timed(ctx); usec = ((next < timeout) ? next : timeout) * 1000; tv.tv_sec = usec / 1000000; tv.tv_usec = usec % 1000000; FD_ZERO(&rfds); FD_ZERO(&wfds); /* find events to watch */ connitem = ctx->connlist; while (connitem) { conn = connitem->conn; switch (conn->state) { case XMPP_STATE_CONNECTING: /* connect has been called and we're waiting for it to complete */ /* connection will give us write or error events */ /* make sure the timeout hasn't expired */ if (time_elapsed(conn->timeout_stamp, time_stamp()) <= conn->connect_timeout) FD_SET(conn->sock, &wfds); else { conn->error = ETIMEDOUT; xmpp_info(ctx, "xmpp", "Connection attempt timed out."); conn_disconnect(conn); } break; case XMPP_STATE_CONNECTED: FD_SET(conn->sock, &rfds); break; case XMPP_STATE_DISCONNECTED: /* do nothing */ default: break; } /* Check if there is something in the SSL buffer. */ if (conn->tls) { tls_read_bytes += tls_pending(conn->tls); } if (conn->state != XMPP_STATE_DISCONNECTED && conn->sock > max) max = conn->sock; connitem = connitem->next; } /* check for events */ if (max > 0) ret = select(max + 1, &rfds, &wfds, NULL, &tv); else { if (timeout > 0) _sleep(timeout); return; } /* select errored */ if (ret < 0) { if (!sock_is_recoverable(sock_error())) xmpp_error(ctx, "xmpp", "event watcher internal error %d", sock_error()); return; } /* no events happened */ if (ret == 0 && tls_read_bytes == 0) return; /* process events */ connitem = ctx->connlist; while (connitem) { conn = connitem->conn; switch (conn->state) { case XMPP_STATE_CONNECTING: if (FD_ISSET(conn->sock, &wfds)) { /* connection complete */ /* check for error */ ret = sock_connect_error(conn->sock); if (ret != 0) { /* connection failed */ xmpp_debug(ctx, "xmpp", "connection failed, error %d", ret); conn_disconnect(conn); break; } conn->state = XMPP_STATE_CONNECTED; xmpp_debug(ctx, "xmpp", "connection successful"); if (conn->tls_legacy_ssl) { xmpp_debug(ctx, "xmpp", "using legacy SSL connection"); ret = conn_tls_start(conn); if (ret != 0) { conn_disconnect(conn); break; } } /* send stream init */ conn_open_stream(conn); } break; case XMPP_STATE_CONNECTED: if (FD_ISSET(conn->sock, &rfds) || (conn->tls && tls_pending(conn->tls))) { if (conn->tls) { ret = tls_read(conn->tls, buf, 4096); } else { ret = sock_read(conn->sock, buf, 4096); } if (ret > 0) { ret = parser_feed(conn->parser, buf, ret); if (!ret) { /* parse error, we need to shut down */ /* FIXME */ xmpp_debug(ctx, "xmpp", "parse error, disconnecting"); conn_disconnect(conn); } } else { if (conn->tls) { if (!tls_is_recoverable(tls_error(conn->tls))) { xmpp_debug(ctx, "xmpp", "Unrecoverable TLS error, %d.", tls_error(conn->tls)); conn->error = tls_error(conn->tls); conn_disconnect(conn); } } else { /* return of 0 means socket closed by server */ xmpp_debug(ctx, "xmpp", "Socket closed by remote host."); conn->error = ECONNRESET; conn_disconnect(conn); } } } break; case XMPP_STATE_DISCONNECTED: /* do nothing */ default: break; } connitem = connitem->next; } /* fire any ready handlers */ handler_fire_timed(ctx); }
/* Main 'loop' */ void axel_do(axel_t *axel) { #if WIN32 WSAEVENT hEventObject = WSACreateEvent(); DWORD byte; #else fd_set fds[1]; struct timeval timeval[1]; int hifd; #endif int i; long long int remaining, size; /* Create statefile if necessary */ if (axel->next_state < gettime()) { save_state(axel); axel->next_state = gettime() + axel->conf->save_state_interval; } /* Wait for data on (one of) the connections */ #if !WIN32 FD_ZERO(fds); hifd = 0; for (i = 0; i < axel->conf->num_connections; i++) { if (axel->conn[i].enabled) { FD_SET(axel->conn[i].fd, fds); } hifd = max(hifd, axel->conn[i].fd); } if (0 == hifd) { #ifdef DEBUG printf("DEBUG no connection yet. Wait...\n"); #endif /* No connections yet. Wait... */ usleep(100000); goto conn_check; } else { timeval->tv_sec = 0; timeval->tv_usec = 100000; /* A select() error probably means it was interrupted by a signal, or that something else's very wrong... */ if (-1 == select(hifd + 1, fds, NULL, NULL, timeval)) { axel->ready = -1; return; } } #endif /* Handle connections which need attention */ for (i = 0; i < axel->conf->num_connections; i++) { if (axel->conn[i].enabled) { #if WIN32 if (is_readable(axel, axel->conn[i].fd, hEventObject)) #else if (FD_ISSET(axel->conn[i].fd, fds)) #endif { axel->conn[i].last_transfer = gettime(); #if WIN32 memset(buffer, 0, max(MAX_STRING, axel->conf->buffer_size)); size = recv(axel->conn[i].fd, buffer, axel->conf->buffer_size, 0); #else size = read(axel->conn[i].fd, buffer, axel->conf->buffer_size); #endif #if WIN32 if (SOCKET_ERROR == size) #else if (-1 == size) #endif { #if !WIN32 if (axel->conf->verbose) { axel_message( axel, _("Error on connection %i! " "Connection closed"), i ); } #endif axel->conn[i].enabled = 0; conn_disconnect(&axel->conn[i]); continue; } else if (0 == size) { if (axel->conf->verbose) { /* Only abnormal behaviour if: */ if (axel->conn[i].currentbyte < axel->conn[i].lastbyte && axel->size != INT_MAX) { axel_message(axel, _("Connection %i unexpectedly closed"), i); } else { axel_message(axel, _("Connection %i finished"), i); } } if (!axel->conn[0].supported) { axel->ready = 1; } axel->conn[i].enabled = 0; conn_disconnect(&axel->conn[i]); continue; } /* remaining == Bytes to go */ remaining = axel->conn[i].lastbyte - axel->conn[i].currentbyte + 1; if (remaining < size) { if (axel->conf->verbose) { axel_message(axel, _("Connection %i finished"), i); } axel->conn[i].enabled = 0; conn_disconnect(&axel->conn[i]); size = remaining; /* Don't terminate, still stuff to write! */ } /* This should always succeed.. */ #if WIN32 SetFilePointer(axel->outfd, axel->conn[i].currentbyte, NULL, FILE_BEGIN); if (0 == WriteFile(axel->outfd, buffer, size, &byte, NULL)) #else lseek(axel->outfd, axel->conn[i].currentbyte, SEEK_SET); if (write(axel->outfd, buffer, size) != size) #endif { axel_message(axel, _("Write error!")); axel->ready = -1; return; } axel->conn[i].currentbyte += size; axel->bytes_done += size; } else { if (gettime() > axel->conn[i].last_transfer + axel->conf->connection_timeout) { if (axel->conf->verbose) { axel_message(axel, _("Connection %i timed out"), i); } conn_disconnect(&axel->conn[i]); axel->conn[i].enabled = 0; } } } } if (axel->ready) { return; } conn_check: /* Look for aborted connections and attempt to restart them. */ for (i = 0; i < axel->conf->num_connections; i++) { if (!axel->conn[i].enabled && axel->conn[i].currentbyte < axel->conn[i].lastbyte) { if (0 == axel->conn[i].state) { // Wait for termination of this thread #if WIN32 WaitForSingleObject(axel->conn[i].setup_thread, INFINITE); CloseHandle(axel->conn[i].setup_thread); #else pthread_join(*(axel->conn[i].setup_thread), NULL); #endif conn_set(&axel->conn[i], axel->url->text); axel->url = axel->url->next; if (axel->conf->verbose >= 2) { axel_message(axel, _("Connection %i downloading from %s:%i using interface %s"), i, axel->conn[i].host, axel->conn[i].port, axel->conn[i].local_if); } axel->conn[i].state = 1; #if WIN32 axel->conn[i].setup_thread = CreateThread(NULL, 0, setup_thread_cb, &axel->conn[i], 0, NULL); if (NULL != axel->conn[i].setup_thread) #else if (pthread_create(axel->conn[i].setup_thread, NULL, setup_thread_cb, &axel->conn[i]) == 0) #endif { axel->conn[i].last_transfer = gettime(); } else { axel_message(axel, _("thread error in axel_do!!!")); axel->ready = -1; } } else { if (gettime() > axel->conn[i].last_transfer + axel->conf->reconnect_delay) { #if WIN32 TerminateThread(axel->conn[i].setup_thread, 0); CloseHandle(axel->conn[i].setup_thread); #else pthread_cancel(*axel->conn[i].setup_thread); #endif axel->conn[i].state = 0; } } } } /* Calculate current average speed and finish_time */ axel->bytes_per_second = (int)((double)(axel->bytes_done - axel->start_byte) / (gettime() - axel->start_time)); axel->finish_time = (int)(axel->start_time + (double)(axel->size - axel->start_byte) / axel->bytes_per_second); /* Check speed. If too high, delay for some time to slow things down a bit. I think a 5% deviation should be acceptable. */ if (0 < axel->conf->max_speed) { if (1.05 < (float) axel->bytes_per_second / axel->conf->max_speed) { axel->delay_time += 10000; } else if (((float)axel->bytes_per_second / axel->conf->max_speed < 0.95) && 10000 <= (axel->delay_time)) { axel->delay_time -= 10000; } else if (((float)axel->bytes_per_second / axel->conf->max_speed < 0.95)) { axel->delay_time = 0; } usleep(axel->delay_time); } /* Ready? */ if (axel->bytes_done == axel->size) { axel->ready = 1; } }