/* This one is actually pretty simple... Might get more calls if we can't write the whole request at once. */ static gboolean http_connected( gpointer data, int source, b_input_condition cond ) { struct http_request *req = data; int st; if( source < 0 ) goto error; if( req->inpa > 0 ) b_event_remove( req->inpa ); sock_make_nonblocking( req->fd ); if( req->ssl ) { st = ssl_write( req->ssl, req->request + req->bytes_written, req->request_length - req->bytes_written ); if( st < 0 ) { if( ssl_errno != SSL_AGAIN ) { ssl_disconnect( req->ssl ); goto error; } } } else { st = write( source, req->request + req->bytes_written, req->request_length - req->bytes_written ); if( st < 0 ) { if( !sockerr_again() ) { closesocket( req->fd ); goto error; } } } if( st > 0 ) req->bytes_written += st; if( req->bytes_written < req->request_length ) req->inpa = b_input_add( source, req->ssl ? ssl_getdirection( req->ssl ) : B_EV_IO_WRITE, http_connected, req ); else req->inpa = b_input_add( source, B_EV_IO_READ, http_incoming_data, req ); return FALSE; error: if( req->status_string == NULL ) req->status_string = g_strdup( "Error while writing HTTP request" ); req->func( req ); http_free( req ); return FALSE; }
static void s5_sendconnect(gpointer data, gint source) { unsigned char buf[512]; struct PHB *phb = data; int hlen = strlen(phb->host); buf[0] = 0x05; buf[1] = 0x01; /* CONNECT */ buf[2] = 0x00; /* reserved */ buf[3] = 0x03; /* address type -- host name */ buf[4] = hlen; memcpy(buf + 5, phb->host, hlen); buf[5 + strlen(phb->host)] = phb->port >> 8; buf[5 + strlen(phb->host) + 1] = phb->port & 0xff; if (write(source, buf, (5 + strlen(phb->host) + 2)) < (5 + strlen(phb->host) + 2)) { close(source); phb->func(phb->data, -1, GAIM_INPUT_READ); g_free(phb->host); g_free(phb); return; } phb->inpa = b_input_add(source, GAIM_INPUT_READ, s5_canread_again, phb); }
static gboolean s5_canread(gpointer data, gint source, b_input_condition cond) { unsigned char buf[512]; struct PHB *phb = data; b_event_remove(phb->inpa); if (read(source, buf, 2) < 2) { return phb_free(phb, FALSE); } if ((buf[0] != 0x05) || (buf[1] == 0xff)) { return phb_free(phb, FALSE); } if (buf[1] == 0x02) { unsigned int i = strlen(proxyuser), j = strlen(proxypass); buf[0] = 0x01; /* version 1 */ buf[1] = i; memcpy(buf + 2, proxyuser, i); buf[2 + i] = j; memcpy(buf + 2 + i + 1, proxypass, j); if (write(source, buf, 3 + i + j) < 3 + i + j) { return phb_free(phb, FALSE); } phb->inpa = b_input_add(source, B_EV_IO_READ, s5_readauth, phb); } else { s5_sendconnect(phb, source); } return FALSE; }
gboolean Skype_begin (im_connection* connection) { SkypeData* skype = connection->proto_data; int result; if (!skype) { return FALSE; } skype->bfd = b_input_add(skype->fd, B_EV_IO_READ, Skype_loop, connection); /* Identifying */ Skype_printf(connection, "USERNAME %s\n", connection->acc->user); Skype_printf(connection, "PASSWORD %s\n", connection->acc->pass); result = Skype_printf(connection, "SEARCH FRIENDS\n"); Skype_printf(connection, "SET USERSTATUS ONLINE\n"); if (set_getbool(&connection->acc->set, "auto_join")) { Skype_printf(connection, "SEARCH BOOKMRKEDCHATS\n"); } return result; }
static gboolean http_canwrite(gpointer data, gint source, b_input_condition cond) { char cmd[384]; struct PHB *phb = data; unsigned int len; int error = ETIMEDOUT; if (phb->inpa > 0) b_event_remove(phb->inpa); len = sizeof(error); if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { close(source); phb->func(phb->data, -1, GAIM_INPUT_READ); g_free(phb->host); g_free(phb); return FALSE; } sock_make_blocking(source); g_snprintf(cmd, sizeof(cmd), "CONNECT %s:%d HTTP/1.1\r\nHost: %s:%d\r\n", phb->host, phb->port, phb->host, phb->port); if (send(source, cmd, strlen(cmd), 0) < 0) { close(source); phb->func(phb->data, -1, GAIM_INPUT_READ); g_free(phb->host); g_free(phb); return FALSE; } if (strlen(proxyuser) > 0) { char *t1, *t2; t1 = g_strdup_printf("%s:%s", proxyuser, proxypass); t2 = tobase64(t1); g_free(t1); g_snprintf(cmd, sizeof(cmd), "Proxy-Authorization: Basic %s\r\n", t2); g_free(t2); if (send(source, cmd, strlen(cmd), 0) < 0) { close(source); phb->func(phb->data, -1, GAIM_INPUT_READ); g_free(phb->host); g_free(phb); return FALSE; } } g_snprintf(cmd, sizeof(cmd), "\r\n"); if (send(source, cmd, strlen(cmd), 0) < 0) { close(source); phb->func(phb->data, -1, GAIM_INPUT_READ); g_free(phb->host); g_free(phb); return FALSE; } phb->inpa = b_input_add(source, GAIM_INPUT_READ, http_canread, phb); return FALSE; }
static gboolean s4_canwrite(gpointer data, gint source, b_input_condition cond) { unsigned char packet[12]; struct hostent *hp; struct PHB *phb = data; socklen_t len; int error = ETIMEDOUT; gboolean is_socks4a = (proxytype == PROXY_SOCKS4A); if (phb->inpa > 0) { b_event_remove(phb->inpa); } len = sizeof(error); if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { return phb_free(phb, FALSE); } sock_make_blocking(source); if (!is_socks4a && !(hp = gethostbyname(phb->host))) { return phb_free(phb, FALSE); } packet[0] = 4; packet[1] = 1; packet[2] = phb->port >> 8; packet[3] = phb->port & 0xff; if (is_socks4a) { packet[4] = 0; packet[5] = 0; packet[6] = 0; packet[7] = 1; } else { packet[4] = (unsigned char) (hp->h_addr_list[0])[0]; packet[5] = (unsigned char) (hp->h_addr_list[0])[1]; packet[6] = (unsigned char) (hp->h_addr_list[0])[2]; packet[7] = (unsigned char) (hp->h_addr_list[0])[3]; } packet[8] = 0; if (write(source, packet, 9) != 9) { return phb_free(phb, FALSE); } if (is_socks4a) { size_t host_len = strlen(phb->host) + 1; /* include the \0 */ if (write(source, phb->host, host_len) != host_len) { return phb_free(phb, FALSE); } } phb->inpa = b_input_add(source, B_EV_IO_READ, s4_canread, phb); return FALSE; }
static gboolean s4_canwrite(gpointer data, gint source, b_input_condition cond) { unsigned char packet[12]; struct hostent *hp; struct PHB *phb = data; unsigned int len; int error = ETIMEDOUT; if (phb->inpa > 0) b_event_remove(phb->inpa); len = sizeof(error); if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { close(source); phb->func(phb->data, -1, GAIM_INPUT_READ); g_free(phb->host); g_free(phb); return FALSE; } sock_make_blocking(source); /* XXX does socks4 not support host name lookups by the proxy? */ if (!(hp = gethostbyname(phb->host))) { close(source); phb->func(phb->data, -1, GAIM_INPUT_READ); g_free(phb->host); g_free(phb); return FALSE; } packet[0] = 4; packet[1] = 1; packet[2] = phb->port >> 8; packet[3] = phb->port & 0xff; packet[4] = (unsigned char)(hp->h_addr_list[0])[0]; packet[5] = (unsigned char)(hp->h_addr_list[0])[1]; packet[6] = (unsigned char)(hp->h_addr_list[0])[2]; packet[7] = (unsigned char)(hp->h_addr_list[0])[3]; packet[8] = 0; if (write(source, packet, 9) != 9) { close(source); phb->func(phb->data, -1, GAIM_INPUT_READ); g_free(phb->host); g_free(phb); return FALSE; } phb->inpa = b_input_add(source, GAIM_INPUT_READ, s4_canread, phb); return FALSE; }
static gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ) { struct msn_handler_data *handler = data; struct im_connection *ic = handler->data; struct msn_data *md; if( !g_slist_find( msn_connections, ic ) ) return FALSE; md = ic->proto_data; if( source == -1 ) { imcb_error( ic, "Could not connect to server" ); imc_logout( ic, TRUE ); return FALSE; } g_free( handler->rxq ); handler->rxlen = 0; handler->rxq = g_new0( char, 1 ); if( md->uuid == NULL ) { struct utsname name; sha1_state_t sha[1]; /* UUID == SHA1("BitlBee" + my hostname + MSN username) */ sha1_init( sha ); sha1_append( sha, (void*) "BitlBee", 7 ); if( uname( &name ) == 0 ) { sha1_append( sha, (void*) name.nodename, strlen( name.nodename ) ); } sha1_append( sha, (void*) ic->acc->user, strlen( ic->acc->user ) ); md->uuid = sha1_random_uuid( sha ); memcpy( md->uuid, "b171be3e", 8 ); /* :-P */ } if( msn_ns_write( ic, source, "VER %d %s CVR0\r\n", ++md->trId, MSNP_VER ) ) { handler->inpa = b_input_add( handler->fd, B_EV_IO_READ, msn_ns_callback, handler ); imcb_log( ic, "Connected to server, waiting for reply" ); } return FALSE; }
int ipc_master_load_state( char *statefile ) { struct bitlbee_child *child; FILE *fp; int i, n; if( statefile == NULL ) return 0; fp = fopen( statefile, "r" ); unlink( statefile ); /* Why do it later? :-) */ if( fp == NULL ) return 0; if( fscanf( fp, "%d", &n ) != 1 ) { log_message( LOGLVL_WARNING, "Could not import state information for child processes." ); fclose( fp ); return 0; } log_message( LOGLVL_INFO, "Importing information for %d child processes.", n ); for( i = 0; i < n; i ++ ) { child = g_new0( struct bitlbee_child, 1 ); if( fscanf( fp, "%d %d", (int *) &child->pid, &child->ipc_fd ) != 2 ) { log_message( LOGLVL_WARNING, "Unexpected end of file: Only processed %d clients.", i ); g_free( child ); fclose( fp ); return 0; } child->ipc_inpa = b_input_add( child->ipc_fd, B_EV_IO_READ, ipc_master_read, child ); child->to_fd = -1; child_list = g_slist_prepend( child_list, child ); } ipc_to_children_str( "HELLO\r\n" ); ipc_to_children_str( "OPERMSG :New %s master process started (version %s)\r\n", PACKAGE, BITLBEE_VERSION ); fclose( fp ); return 1; }
static gboolean gaim_io_connected(gpointer data, gint source, b_input_condition cond) { struct PHB *phb = data; socklen_t len; int error = ETIMEDOUT; len = sizeof(error); if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0 || error) { if ((phb->gai_cur = phb->gai_cur->ai_next)) { int new_fd; b_event_remove(phb->inpa); if ((new_fd = proxy_connect_none(NULL, 0, phb))) { b_event_remove(phb->inpa); closesocket(source); dup2(new_fd, source); closesocket(new_fd); phb->inpa = b_input_add(source, B_EV_IO_WRITE, gaim_io_connected, phb); return FALSE; } } freeaddrinfo(phb->gai); closesocket(source); b_event_remove(phb->inpa); phb->inpa = 0; if( phb->proxy_func ) phb->proxy_func(phb->proxy_data, -1, B_EV_IO_READ); else { phb->func(phb->data, -1, B_EV_IO_READ); g_free(phb); } return FALSE; } freeaddrinfo(phb->gai); sock_make_blocking(source); b_event_remove(phb->inpa); phb->inpa = 0; if( phb->proxy_func ) phb->proxy_func(phb->proxy_data, source, B_EV_IO_READ); else { phb->func(phb->data, source, B_EV_IO_READ); g_free(phb); } return FALSE; }
static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond ) { struct scd *conn = data; int st, stver; if( ( st = gnutls_handshake( conn->session ) ) < 0 ) { if( st == GNUTLS_E_AGAIN || st == GNUTLS_E_INTERRUPTED ) { conn->inpa = b_input_add( conn->fd, ssl_getdirection( conn ), ssl_handshake, data ); } else { conn->func( conn->data, 0, NULL, cond ); gnutls_deinit( conn->session ); closesocket( conn->fd ); g_free( conn ); } } else { if( conn->verify && ( stver = verify_certificate_callback( conn->session ) ) != 0 ) { conn->func( conn->data, stver, NULL, cond ); gnutls_deinit( conn->session ); closesocket( conn->fd ); g_free( conn ); } else { /* For now we can't handle non-blocking perfectly everywhere... */ sock_make_blocking( conn->fd ); conn->established = TRUE; conn->func( conn->data, 0, conn, cond ); } } return FALSE; }
static gboolean new_ipc_client( gpointer data, gint serversock, b_input_condition cond ) { struct bitlbee_child *child = g_new0( struct bitlbee_child, 1 ); child->to_fd = -1; child->ipc_fd = accept( serversock, NULL, 0 ); if( child->ipc_fd == -1 ) { log_message( LOGLVL_WARNING, "Unable to accept connection on UNIX domain socket: %s", strerror(errno) ); return TRUE; } child->ipc_inpa = b_input_add( child->ipc_fd, B_EV_IO_READ, ipc_master_read, child ); child_list = g_slist_prepend( child_list, child ); return TRUE; }
/** * Implemented #ssl_input_function for the connection of #fb_mqtt->ssl. * * @param data The user defined data, which is #fb_mqtt. * @param error The SSL error. (0 on success) * @param ssl The SSL source. * @param cond The #b_input_condition. * * @return TRUE for continued event handling, otherwise FALSE. **/ static gboolean fb_mqtt_cb_open(gpointer data, gint error, gpointer ssl, b_input_condition cond) { fb_mqtt_t *mqtt = data; gint fd; if ((ssl == NULL) || (error != SSL_OK)) { fb_mqtt_error(mqtt, FB_MQTT_ERROR_GENERAL, "Failed to connect"); return FALSE; } fb_mqtt_timeout_clear(mqtt); fd = ssl_getfd(mqtt->ssl); mqtt->rev = b_input_add(fd, B_EV_IO_READ, fb_mqtt_cb_read, mqtt); FB_MQTT_FUNC(mqtt, open); return FALSE; }
static gboolean s5_canwrite(gpointer data, gint source, b_input_condition cond) { unsigned char buf[512]; int i; struct PHB *phb = data; unsigned int len; int error = ETIMEDOUT; if (phb->inpa > 0) b_event_remove(phb->inpa); len = sizeof(error); if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { close(source); phb->func(phb->data, -1, GAIM_INPUT_READ); g_free(phb->host); g_free(phb); return FALSE; } sock_make_blocking(source); i = 0; buf[0] = 0x05; /* SOCKS version 5 */ if (proxyuser[0]) { buf[1] = 0x02; /* two methods */ buf[2] = 0x00; /* no authentication */ buf[3] = 0x02; /* username/password authentication */ i = 4; } else { buf[1] = 0x01; buf[2] = 0x00; i = 3; } if (write(source, buf, i) < i) { close(source); phb->func(phb->data, -1, GAIM_INPUT_READ); g_free(phb->host); g_free(phb); return FALSE; } phb->inpa = b_input_add(source, GAIM_INPUT_READ, s5_canread, phb); return FALSE; }
int jabber_write( struct im_connection *ic, char *buf, int len ) { struct jabber_data *jd = ic->proto_data; gboolean ret; if( jd->flags & JFLAG_XMLCONSOLE ) { char *msg; msg = g_strdup_printf( "TX: %s", buf ); imcb_buddy_msg( ic, JABBER_XMLCONSOLE_HANDLE, msg, 0, 0 ); g_free( msg ); } if( jd->tx_len == 0 ) { /* If the queue is empty, allocate a new buffer. */ jd->tx_len = len; jd->txq = g_memdup( buf, len ); /* Try if we can write it immediately so we don't have to do it via the event handler. If not, add the handler. (In most cases it probably won't be necessary.) */ if( ( ret = jabber_write_queue( ic ) ) && jd->tx_len > 0 ) jd->w_inpa = b_input_add( jd->fd, GAIM_INPUT_WRITE, jabber_write_callback, ic ); } else { /* Just add it to the buffer if it's already filled. The event handler is already set. */ jd->txq = g_renew( char, jd->txq, jd->tx_len + len ); memcpy( jd->txq + jd->tx_len, buf, len ); jd->tx_len += len; /* The return value for write() doesn't necessarily mean that everything got sent, it mainly means that the connection (officially) still exists and can still be accessed without hitting SIGSEGV. IOW: */ ret = TRUE; } return ret; }
static int proxy_connect_none(const char *host, unsigned short port, struct PHB *phb) { struct sockaddr_in *sin; struct sockaddr_in me; int fd = -1; if (!(sin = gaim_gethostbyname(host, port))) { g_free(phb); return -1; } if ((fd = socket(sin->sin_family, SOCK_STREAM, 0)) < 0) { g_free(phb); return -1; } sock_make_nonblocking(fd); if( global.conf->iface_out ) { me.sin_family = AF_INET; me.sin_port = 0; me.sin_addr.s_addr = inet_addr( global.conf->iface_out ); if( bind( fd, (struct sockaddr *) &me, sizeof( me ) ) != 0 ) event_debug( "bind( %d, \"%s\" ) failure\n", fd, global.conf->iface_out ); } event_debug("proxy_connect_none( \"%s\", %d ) = %d\n", host, port, fd); if (connect(fd, (struct sockaddr *)sin, sizeof(*sin)) < 0 && !sockerr_again()) { closesocket(fd); g_free(phb); return -1; } else { phb->inpa = b_input_add(fd, GAIM_INPUT_WRITE, gaim_io_connected, phb); phb->fd = fd; return fd; } }
static gboolean ssl_handshake(gpointer data, gint source, b_input_condition cond) { struct scd *conn = data; int st; if ((st = SSL_connect(conn->ssl)) < 0) { conn->lasterr = SSL_get_error(conn->ssl, st); if (conn->lasterr != SSL_ERROR_WANT_READ && conn->lasterr != SSL_ERROR_WANT_WRITE) { conn->func(conn->data, 0, NULL, cond); ssl_disconnect(conn); return FALSE; } conn->inpa = b_input_add(conn->fd, ssl_getdirection(conn), ssl_handshake, data); return FALSE; } conn->established = TRUE; sock_make_blocking(conn->fd); /* For now... */ conn->func(conn->data, 0, conn, cond); return FALSE; }
int ipc_master_listen_socket() { struct sockaddr_un un_addr; int serversock; if (!IPCSOCKET || !*IPCSOCKET) return 1; /* Clean up old socket files that were hanging around.. */ if (unlink(IPCSOCKET) == -1 && errno != ENOENT) { log_message( LOGLVL_ERROR, "Could not remove old IPC socket at %s: %s", IPCSOCKET, strerror(errno) ); return 0; } un_addr.sun_family = AF_UNIX; strcpy(un_addr.sun_path, IPCSOCKET); serversock = socket(AF_UNIX, SOCK_STREAM, PF_UNIX); if (serversock == -1) { log_message( LOGLVL_WARNING, "Unable to create UNIX socket: %s", strerror(errno) ); return 0; } if (bind(serversock, (struct sockaddr *)&un_addr, sizeof(un_addr)) == -1) { log_message( LOGLVL_WARNING, "Unable to bind UNIX socket to %s: %s", IPCSOCKET, strerror(errno) ); return 0; } if (listen(serversock, 5) == -1) { log_message( LOGLVL_WARNING, "Unable to listen on UNIX socket: %s", strerror(errno) ); return 0; } b_input_add( serversock, B_EV_IO_READ, new_ipc_client, NULL ); return 1; }
/** * Writes a #fb_mqtt_msg to the #fb_mqtt. * * @param mqtt The #fb_mqtt. * @param msg The #fb_mqtt_msg. **/ void fb_mqtt_write(fb_mqtt_t *mqtt, fb_mqtt_msg_t *msg) { const GByteArray *bytes; gint fd; g_return_if_fail(mqtt != NULL); bytes = fb_mqtt_msg_bytes(msg); if (G_UNLIKELY(bytes == NULL)) { fb_mqtt_error(mqtt, FB_MQTT_ERROR_GENERAL, "Failed to format data"); return; } fb_util_hexdump(bytes, 2, "Writing %d (flags: 0x%0X)", msg->type, msg->flags); fd = ssl_getfd(mqtt->ssl); g_byte_array_append(mqtt->wbuf, bytes->data, bytes->len); if ((mqtt->wev < 1) && fb_mqtt_cb_write(mqtt, fd, B_EV_IO_WRITE)) mqtt->wev = b_input_add(fd, B_EV_IO_WRITE, fb_mqtt_cb_write, mqtt); }
gboolean jabber_start_stream( struct im_connection *ic ) { struct jabber_data *jd = ic->proto_data; int st; char *greet; /* We'll start our stream now, so prepare everything to receive one from the server too. */ xt_free( jd->xt ); /* In case we're RE-starting. */ jd->xt = xt_new( jabber_handlers, ic ); if( jd->r_inpa <= 0 ) jd->r_inpa = b_input_add( jd->fd, GAIM_INPUT_READ, jabber_read_callback, ic ); greet = g_strdup_printf( "<?xml version='1.0' ?>" "<stream:stream to=\"%s\" xmlns=\"jabber:client\" " "xmlns:stream=\"http://etherx.jabber.org/streams\" version=\"1.0\">", jd->server ); st = jabber_write( ic, greet, strlen( greet ) ); g_free( greet ); return st; }
irc_t *irc_new(int fd) { irc_t *irc; struct sockaddr_storage sock; socklen_t socklen = sizeof(sock); char *host = NULL, *myhost = NULL; irc_user_t *iu; GSList *l; set_t *s; bee_t *b; irc = g_new0(irc_t, 1); irc->fd = fd; sock_make_nonblocking(irc->fd); irc->r_watch_source_id = b_input_add(irc->fd, B_EV_IO_READ, bitlbee_io_current_client_read, irc); irc->status = USTATUS_OFFLINE; irc->last_pong = gettime(); irc->nick_user_hash = g_hash_table_new(g_str_hash, g_str_equal); irc->watches = g_hash_table_new(g_str_hash, g_str_equal); irc->iconv = (GIConv) - 1; irc->oconv = (GIConv) - 1; if (global.conf->hostname) { myhost = g_strdup(global.conf->hostname); } else if (getsockname(irc->fd, (struct sockaddr*) &sock, &socklen) == 0) { char buf[NI_MAXHOST + 1]; if (getnameinfo((struct sockaddr *) &sock, socklen, buf, NI_MAXHOST, NULL, 0, 0) == 0) { myhost = g_strdup(ipv6_unwrap(buf)); } } if (getpeername(irc->fd, (struct sockaddr*) &sock, &socklen) == 0) { char buf[NI_MAXHOST + 1]; if (getnameinfo((struct sockaddr *) &sock, socklen, buf, NI_MAXHOST, NULL, 0, 0) == 0) { host = g_strdup(ipv6_unwrap(buf)); } } if (host == NULL) { host = g_strdup("localhost.localdomain"); } if (myhost == NULL) { myhost = g_strdup("localhost.localdomain"); } if (global.conf->ping_interval > 0 && global.conf->ping_timeout > 0) { irc->ping_source_id = b_timeout_add(global.conf->ping_interval * 1000, irc_userping, irc); } irc_connection_list = g_slist_append(irc_connection_list, irc); b = irc->b = bee_new(); b->ui_data = irc; b->ui = &irc_ui_funcs; s = set_add(&b->set, "allow_takeover", "true", set_eval_bool, irc); s = set_add(&b->set, "away_devoice", "true", set_eval_bw_compat, irc); s->flags |= SET_HIDDEN; s = set_add(&b->set, "away_reply_timeout", "3600", set_eval_int, irc); s = set_add(&b->set, "charset", "utf-8", set_eval_charset, irc); s = set_add(&b->set, "default_target", "root", NULL, irc); s = set_add(&b->set, "display_namechanges", "false", set_eval_bool, irc); s = set_add(&b->set, "display_timestamps", "true", set_eval_bool, irc); s = set_add(&b->set, "handle_unknown", "add_channel", NULL, irc); s = set_add(&b->set, "last_version", "0", NULL, irc); s->flags |= SET_HIDDEN; s = set_add(&b->set, "nick_format", "%-@nick", NULL, irc); s = set_add(&b->set, "nick_lowercase", "false", set_eval_bool, irc); s = set_add(&b->set, "nick_underscores", "false", set_eval_bool, irc); s = set_add(&b->set, "offline_user_quits", "true", set_eval_bool, irc); s = set_add(&b->set, "ops", "both", set_eval_irc_channel_ops, irc); s = set_add(&b->set, "paste_buffer", "false", set_eval_bool, irc); s->old_key = g_strdup("buddy_sendbuffer"); s = set_add(&b->set, "paste_buffer_delay", "200", set_eval_int, irc); s->old_key = g_strdup("buddy_sendbuffer_delay"); s = set_add(&b->set, "password", NULL, set_eval_password, irc); s->flags |= SET_NULL_OK | SET_PASSWORD; s = set_add(&b->set, "private", "true", set_eval_bool, irc); s = set_add(&b->set, "query_order", "lifo", NULL, irc); s = set_add(&b->set, "root_nick", ROOT_NICK, set_eval_root_nick, irc); s->flags |= SET_HIDDEN; s = set_add(&b->set, "show_offline", "false", set_eval_bw_compat, irc); s->flags |= SET_HIDDEN; s = set_add(&b->set, "self_messages", "true", set_eval_self_messages, irc); s = set_add(&b->set, "simulate_netsplit", "true", set_eval_bool, irc); s = set_add(&b->set, "timezone", "local", set_eval_timezone, irc); s = set_add(&b->set, "to_char", ": ", set_eval_to_char, irc); s = set_add(&b->set, "typing_notice", "false", set_eval_bool, irc); s = set_add(&b->set, "utf8_nicks", "false", set_eval_utf8_nicks, irc); irc->root = iu = irc_user_new(irc, ROOT_NICK); iu->host = g_strdup(myhost); iu->fullname = g_strdup(ROOT_FN); iu->f = &irc_user_root_funcs; iu = irc_user_new(irc, NS_NICK); iu->host = g_strdup(myhost); iu->fullname = g_strdup(ROOT_FN); iu->f = &irc_user_root_funcs; irc->user = g_new0(irc_user_t, 1); irc->user->host = g_strdup(host); conf_loaddefaults(irc); /* Evaluator sets the iconv/oconv structures. */ set_eval_charset(set_find(&b->set, "charset"), set_getstr(&b->set, "charset")); irc_write(irc, ":%s NOTICE * :%s", irc->root->host, "BitlBee-IRCd initialized, please go on"); if (isatty(irc->fd)) { irc_write(irc, ":%s NOTICE * :%s", irc->root->host, "If you read this, you most likely accidentally " "started BitlBee in inetd mode on the command line. " "You probably want to run it in (Fork)Daemon mode. " "See doc/README for more information."); } g_free(myhost); g_free(host); /* libpurple doesn't like fork()s after initializing itself, so this is the right moment to initialize it. */ #ifdef WITH_PURPLE nogaim_init(); #endif /* SSL library initialization also should be done after the fork, to avoid shared CSPRNG state. This is required by NSS, which refuses to work if a fork is detected */ ssl_init(); for (l = irc_plugins; l; l = l->next) { irc_plugin_t *p = l->data; if (p->irc_new) { p->irc_new(irc); } } return irc; }
static gboolean http_incoming_data( gpointer data, int source, b_input_condition cond ) { struct http_request *req = data; char buffer[4096]; int st; if( req->inpa > 0 ) { b_event_remove( req->inpa ); req->inpa = 0; } if( req->ssl ) { st = ssl_read( req->ssl, buffer, sizeof( buffer ) ); if( st < 0 ) { if( ssl_errno != SSL_AGAIN ) { /* goto cleanup; */ /* YAY! We have to deal with crappy Microsoft servers that LOVE to send invalid TLS packets that abort connections! \o/ */ goto eof; } } else if( st == 0 ) { goto eof; } } else { st = read( req->fd, buffer, sizeof( buffer ) ); if( st < 0 ) { if( !sockerr_again() ) { req->status_string = g_strdup( strerror( errno ) ); goto cleanup; } } else if( st == 0 ) { goto eof; } } if( st > 0 ) { http_ret_t c; if( req->flags & HTTPC_CHUNKED ) c = http_process_chunked_data( req, buffer, st ); else c = http_process_data( req, buffer, st ); if( c == CR_EOF ) goto eof; else if( c == CR_ERROR || c == CR_ABORT ) return FALSE; } if( req->content_length != -1 && req->body_size >= req->content_length ) goto eof; if( ssl_pending( req->ssl ) ) return http_incoming_data( data, source, cond ); /* There will be more! */ req->inpa = b_input_add( req->fd, req->ssl ? ssl_getdirection( req->ssl ) : B_EV_IO_READ, http_incoming_data, req ); return FALSE; eof: req->flags |= HTTPC_EOF; /* Maybe if the webserver is overloaded, or when there's bad SSL support... */ if( req->bytes_read == 0 ) { req->status_string = g_strdup( "Empty HTTP reply" ); goto cleanup; } cleanup: /* Avoid g_source_remove warnings */ req->inpa = 0; if( req->ssl ) ssl_disconnect( req->ssl ); else closesocket( req->fd ); if( req->body_size < req->content_length ) { req->status_code = -1; g_free( req->status_string ); req->status_string = g_strdup( "Response truncated" ); } if( getenv( "BITLBEE_DEBUG" ) && req ) printf( "Finishing HTTP request with status: %s\n", req->status_string ? req->status_string : "NULL" ); req->func( req ); http_free( req ); return FALSE; }
static int proxy_connect_none(const char *host, unsigned short port_, struct PHB *phb) { struct sockaddr_in me; int fd = -1; if (phb->gai_cur == NULL) { int ret; char port[6]; struct addrinfo hints; g_snprintf(port, sizeof(port), "%d", port_); memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV; if (!(ret = getaddrinfo(host, port, &hints, &phb->gai))) phb->gai_cur = phb->gai; else event_debug("gai(): %s\n", gai_strerror(ret)); } for (; phb->gai_cur; phb->gai_cur = phb->gai_cur->ai_next) { if ((fd = socket(phb->gai_cur->ai_family, phb->gai_cur->ai_socktype, phb->gai_cur->ai_protocol)) < 0) { event_debug( "socket failed: %d\n", errno); continue; } sock_make_nonblocking(fd); if (global.conf->iface_out) { me.sin_family = AF_INET; me.sin_port = 0; me.sin_addr.s_addr = inet_addr( global.conf->iface_out ); if (bind(fd, (struct sockaddr *) &me, sizeof(me)) != 0) event_debug("bind( %d, \"%s\" ) failure\n", fd, global.conf->iface_out); } event_debug("proxy_connect_none( \"%s\", %d ) = %d\n", host, port_, fd); if (connect(fd, phb->gai_cur->ai_addr, phb->gai_cur->ai_addrlen) < 0 && !sockerr_again()) { event_debug( "connect failed: %s\n", strerror(errno)); closesocket(fd); fd = -1; continue; } else { phb->inpa = b_input_add(fd, B_EV_IO_WRITE, gaim_io_connected, phb); phb->fd = fd; break; } } if(fd < 0 && host) g_free(phb); return fd; }
static guint prplcb_ev_input_add( int fd, PurpleInputCondition cond, PurpleInputFunction func, gpointer udata ) { return b_input_add( fd, cond | B_EV_FLAG_FORCE_REPEAT, (b_event_handler) func, udata ); }
static gboolean http_incoming_data( gpointer data, int source, b_input_condition cond ) { struct http_request *req = data; int evil_server = 0; char buffer[2048]; char *end1, *end2; int st; if( req->inpa > 0 ) b_event_remove( req->inpa ); if( req->ssl ) { st = ssl_read( req->ssl, buffer, sizeof( buffer ) ); if( st < 0 ) { if( ssl_errno != SSL_AGAIN ) { /* goto cleanup; */ /* YAY! We have to deal with crappy Microsoft servers that LOVE to send invalid TLS packets that abort connections! \o/ */ goto got_reply; } } else if( st == 0 ) { goto got_reply; } } else { st = read( req->fd, buffer, sizeof( buffer ) ); if( st < 0 ) { if( !sockerr_again() ) { req->status_string = g_strdup( strerror( errno ) ); goto cleanup; } } else if( st == 0 ) { goto got_reply; } } if( st > 0 ) { req->reply_headers = g_realloc( req->reply_headers, req->bytes_read + st + 1 ); memcpy( req->reply_headers + req->bytes_read, buffer, st ); req->bytes_read += st; } /* There will be more! */ req->inpa = b_input_add( req->fd, req->ssl ? ssl_getdirection( req->ssl ) : B_EV_IO_READ, http_incoming_data, req ); if( ssl_pending( req->ssl ) ) return http_incoming_data( data, source, cond ); else return FALSE; got_reply: /* Maybe if the webserver is overloaded, or when there's bad SSL support... */ if( req->bytes_read == 0 ) { req->status_string = g_strdup( "Empty HTTP reply" ); goto cleanup; } /* Zero termination is very convenient. */ req->reply_headers[req->bytes_read] = 0; /* Find the separation between headers and body, and keep stupid webservers in mind. */ end1 = strstr( req->reply_headers, "\r\n\r\n" ); end2 = strstr( req->reply_headers, "\n\n" ); if( end2 && end2 < end1 ) { end1 = end2 + 1; evil_server = 1; } else if( end1 ) { end1 += 2; } else { req->status_string = g_strdup( "Malformed HTTP reply" ); goto cleanup; } *end1 = 0; if( getenv( "BITLBEE_DEBUG" ) ) printf( "HTTP response headers:\n%s\n", req->reply_headers ); if( evil_server ) req->reply_body = end1 + 1; else req->reply_body = end1 + 2; req->body_size = req->reply_headers + req->bytes_read - req->reply_body; if( ( end1 = strchr( req->reply_headers, ' ' ) ) != NULL ) { if( sscanf( end1 + 1, "%d", &req->status_code ) != 1 ) { req->status_string = g_strdup( "Can't parse status code" ); req->status_code = -1; } else { char *eol; if( evil_server ) eol = strchr( end1, '\n' ); else eol = strchr( end1, '\r' ); req->status_string = g_strndup( end1 + 1, eol - end1 - 1 ); /* Just to be sure... */ if( ( eol = strchr( req->status_string, '\r' ) ) ) *eol = 0; if( ( eol = strchr( req->status_string, '\n' ) ) ) *eol = 0; } } else { req->status_string = g_strdup( "Can't locate status code" ); req->status_code = -1; } if( ( ( req->status_code >= 301 && req->status_code <= 303 ) || req->status_code == 307 ) && req->redir_ttl-- > 0 ) { char *loc, *new_request, *new_host; int error = 0, new_port, new_proto; /* We might fill it again, so let's not leak any memory. */ g_free( req->status_string ); req->status_string = NULL; loc = strstr( req->reply_headers, "\nLocation: " ); if( loc == NULL ) /* We can't handle this redirect... */ { req->status_string = g_strdup( "Can't locate Location: header" ); goto cleanup; } loc += 11; while( *loc == ' ' ) loc ++; /* TODO/FIXME: Possibly have to handle relative redirections, and rewrite Host: headers. Not necessary for now, it's enough for passport authentication like this. */ if( *loc == '/' ) { /* Just a different pathname... */ /* Since we don't cache the servername, and since we don't need this yet anyway, I won't implement it. */ req->status_string = g_strdup( "Can't handle recursive redirects" ); goto cleanup; } else { /* A whole URL */ url_t *url; char *s; const char *new_method; s = strstr( loc, "\r\n" ); if( s == NULL ) goto cleanup; url = g_new0( url_t, 1 ); *s = 0; if( !url_set( url, loc ) ) { req->status_string = g_strdup( "Malformed redirect URL" ); g_free( url ); goto cleanup; } /* Find all headers and, if necessary, the POST request contents. Skip the old Host: header though. This crappy code here means anything using this http_client MUST put the Host: header at the top. */ if( !( ( s = strstr( req->request, "\r\nHost: " ) ) && ( s = strstr( s + strlen( "\r\nHost: " ), "\r\n" ) ) ) ) { req->status_string = g_strdup( "Error while rebuilding request string" ); g_free( url ); goto cleanup; } /* More or less HTTP/1.0 compliant, from my reading of RFC 2616. Always perform a GET request unless we received a 301. 303 was meant for this but it's HTTP/1.1-only and we're specifically speaking HTTP/1.0. ... Well except someone at identi.ca's didn't bother reading any RFCs and just return HTTP/1.1-specific status codes to HTTP/1.0 requests. Fuckers. So here we are, handle 301..303,307. */ if( strncmp( req->request, "GET", 3 ) == 0 ) /* GETs never become POSTs. */ new_method = "GET"; else if( req->status_code == 302 || req->status_code == 303 ) /* 302 de-facto becomes GET, 303 as specified by RFC 2616#10.3.3 */ new_method = "GET"; else /* 301 de-facto should stay POST, 307 specifally RFC 2616#10.3.8 */ new_method = "POST"; /* Okay, this isn't fun! We have to rebuild the request... :-( */ new_request = g_strdup_printf( "%s %s HTTP/1.0\r\nHost: %s%s", new_method, url->file, url->host, s ); new_host = g_strdup( url->host ); new_port = url->port; new_proto = url->proto; /* If we went from POST to GET, truncate the request content. */ if( new_request[0] != req->request[0] && new_request[0] == 'G' && ( s = strstr( new_request, "\r\n\r\n" ) ) ) s[4] = '\0'; g_free( url ); } if( req->ssl ) ssl_disconnect( req->ssl ); else closesocket( req->fd ); req->fd = -1; req->ssl = NULL; if( getenv( "BITLBEE_DEBUG" ) ) printf( "New headers for redirected HTTP request:\n%s\n", new_request ); if( new_proto == PROTO_HTTPS ) { req->ssl = ssl_connect( new_host, new_port, TRUE, http_ssl_connected, req ); if( req->ssl == NULL ) error = 1; } else { req->fd = proxy_connect( new_host, new_port, http_connected, req ); if( req->fd < 0 ) error = 1; } g_free( new_host ); if( error ) { req->status_string = g_strdup( "Connection problem during redirect" ); g_free( new_request ); goto cleanup; } g_free( req->request ); g_free( req->reply_headers ); req->request = new_request; req->request_length = strlen( new_request ); req->bytes_read = req->bytes_written = req->inpa = 0; req->reply_headers = req->reply_body = NULL; return FALSE; } /* Assume that a closed connection means we're finished, this indeed breaks with keep-alive connections and faulty connections. */ req->finished = 1; cleanup: if( req->ssl ) ssl_disconnect( req->ssl ); else closesocket( req->fd ); if( getenv( "BITLBEE_DEBUG" ) && req ) printf( "Finishing HTTP request with status: %s\n", req->status_string ? req->status_string : "NULL" ); req->func( req ); http_free( req ); return FALSE; }
static int discord_ws_callback(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { struct im_connection *ic = NULL; discord_data *dd = NULL; if (wsi == NULL) { return 0; } struct lws_context *wsctx = lws_get_context(wsi); if (wsctx != NULL) { ic = lws_context_user(wsctx); dd = ic->proto_data; } switch(reason) { case LWS_CALLBACK_CLIENT_ESTABLISHED: dd->state = WS_CONNECTED; lws_callback_on_writable(wsi); break; case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: imcb_error(ic, "Websocket connection error"); if (in != NULL) { imcb_error(ic, in); } b_event_remove(dd->keepalive_loop_id); dd->keepalive_loop_id = 0; dd->state = WS_CLOSING; break; case LWS_CALLBACK_CLIENT_WRITEABLE: if (dd->state == WS_CONNECTED) { GString *buf = g_string_new(""); g_string_printf(buf, "{\"d\":{\"v\":3,\"token\":\"%s\",\"properties\":{\"$referring_domain\":\"\",\"$browser\":\"bitlbee-discord\",\"$device\":\"bitlbee\",\"$referrer\":\"\",\"$os\":\"linux\"}},\"op\":2}", dd->token); discord_ws_send_payload(wsi, buf->str, buf->len); g_string_free(buf, TRUE); } else if (dd->state == WS_READY) { GString *buf = g_string_new(""); g_string_printf(buf, "{\"op\":1,\"d\":%tu}", time(NULL)); discord_ws_send_payload(dd->lws, buf->str, buf->len); g_string_free(buf, TRUE); } else { g_print("%s: Unhandled writable callback\n", __func__); } break; case LWS_CALLBACK_CLIENT_RECEIVE: { size_t rpload = lws_remaining_packet_payload(wsi); if (dd->ws_buf == NULL) { dd->ws_buf = g_string_new(""); } dd->ws_buf = g_string_append(dd->ws_buf, in); if (rpload == 0) { discord_parse_message(ic); g_string_free(dd->ws_buf, TRUE); dd->ws_buf = NULL; } break; } case LWS_CALLBACK_CLOSED: b_event_remove(dd->keepalive_loop_id); dd->keepalive_loop_id = 0; dd->state = WS_CLOSING; lws_cancel_service(dd->lwsctx); break; case LWS_CALLBACK_ADD_POLL_FD: { struct lws_pollargs *pargs = in; dd->main_loop_id = b_input_add(pargs->fd, B_EV_IO_READ, discord_ws_service_loop, ic); break; } case LWS_CALLBACK_DEL_POLL_FD: b_event_remove(dd->main_loop_id); break; case LWS_CALLBACK_CHANGE_MODE_POLL_FD: { struct lws_pollargs *pargs = in; int flags = 0; b_event_remove(dd->main_loop_id); if (pargs->events & POLLIN) { flags |= B_EV_IO_READ; } if (pargs->events & POLLOUT) { flags |= B_EV_IO_WRITE; } dd->main_loop_id = b_input_add(pargs->fd, flags, discord_ws_service_loop, ic); break; } case LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED: case LWS_CALLBACK_GET_THREAD_ID: case LWS_CALLBACK_LOCK_POLL: case LWS_CALLBACK_UNLOCK_POLL: case LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS: case LWS_CALLBACK_PROTOCOL_INIT: case LWS_CALLBACK_PROTOCOL_DESTROY: case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER: case LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH: case LWS_CALLBACK_WSI_CREATE: case LWS_CALLBACK_WSI_DESTROY: // Ignoring these, this block should be removed when defult is set to // stay silent. break; default: g_print("%s: unknown rsn=%d\n", __func__, reason); break; } return 0; }