void *update_ipc(void *data) { char *socket_path = getenv("I3SOCK"); char *i3_default_sock_path = "/tmp/i3-ipc.sock"; main_loop = ev_default_loop(0); if (socket_path == NULL) { ELOG("No Socket Path Specified, default to %s\n", i3_default_sock_path); socket_path = i3_default_sock_path; } if (init_connection(socket_path)) { /* We subscribe to the i3-events we need */ subscribe_events(); /* Get current workspaces from i3. */ i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); } ev_loop(main_loop, 0); }
int main(int argc, char* argv[]) { signal( SIGTRAP, SIG_IGN ); params p = get_params( argc, argv ); unistd::addrinfo hint = addrinfo{ 0, AF_INET6, SOCK_SEQPACKET, IPPROTO_SCTP, 0, nullptr, nullptr, nullptr }; std::vector<unistd::addrinfo> addrs = unistd::getaddrinfo( p.hostname, p.port, hint ); const unistd::addrinfo& addr = addrs.at( 0 ); unistd::fd sock = unistd::socket( addr ); subscribe_events( sock ); if ( 0 != p.sndbuf ) unistd::setsockopt( sock, SOL_SOCKET, SO_SNDBUF, p.sndbuf ); if ( 0 != p.mtu ) { unistd::setsockopt( sock, IPPROTO_IPV6, IPV6_MTU_DISCOVER, IP_PMTUDISC_DONT ); unistd::setsockopt( sock, IPPROTO_IPV6, IPV6_MTU, p.mtu ); } if ( p.nodelay ) unistd::setsockopt( sock, SOL_SCTP, SCTP_NODELAY, 1 ); if ( 0 != p.max_burst ) unistd::setsockopt( sock, SOL_SCTP, SCTP_MAX_BURST, p.max_burst ); if ( 0 != p.maxseg ) unistd::setsockopt( sock, SOL_SCTP, SCTP_MAXSEG, p.maxseg ); int sndbuf = 0; socklen_t len = sizeof(sndbuf); getsockopt( sock, SOL_SOCKET, SO_SNDBUF, &sndbuf, &len ); fprintf( stderr, "sndbuf: set=%d get=%d\n", p.sndbuf, sndbuf ); if ( 0 != p.rcvbuf ) unistd::setsockopt( sock, SOL_SOCKET, SO_RCVBUF, p.rcvbuf ); sctp_initmsg init_params; memset( &init_params, 0, sizeof(init_params) ); init_params.sinit_num_ostreams = 1; init_params.sinit_max_instreams = 1; init_params.sinit_max_attempts = 3; init_params.sinit_max_init_timeo = 100; unistd::setsockopt( sock, SOL_SCTP, SCTP_INITMSG, init_params ); unistd::connect( sock, addr ); sctp_assoc_t assoc_id = 0; while ( assoc_id == 0 ) { std::vector<char> cmsg_buff( CMSG_SPACE( sizeof( sctp_sndrcvinfo ) ) ); std::vector<char> msg_buff( 8192 ); //TODO: struct iovec iov; memset( &iov, 0, sizeof(iov) ); iov.iov_base = msg_buff.data(); iov.iov_len = msg_buff.size(); struct msghdr hdr; memset( &hdr, 0, sizeof(hdr) ); hdr.msg_name = nullptr; hdr.msg_namelen = 0; hdr.msg_iov = &iov; hdr.msg_iovlen = 1; hdr.msg_control = cmsg_buff.data(); hdr.msg_controllen = cmsg_buff.size(); hdr.msg_flags = 0; ssize_t nrecv = 0; TEMP_FAILURE_RETRY( nrecv = recvmsg( sock, &hdr, 0 ) ); if ( 0 == nrecv ) raise( SIGTRAP ); if ( -1 == nrecv ) raise( SIGTRAP ); if ( hdr.msg_flags & MSG_NOTIFICATION ) { const sctp_notification& notify = *reinterpret_cast<const sctp_notification*>( hdr.msg_iov[0].iov_base ); switch ( notify.sn_header.sn_type ) { case SCTP_ASSOC_CHANGE: { const auto& sac = notify.sn_assoc_change; std::cout << " assoc_id=" << sac.sac_assoc_id << " error=" << sac.sac_error << " in=" << sac.sac_inbound_streams << " out=" << sac.sac_outbound_streams << std::endl; assoc_id = sac.sac_assoc_id; break; } case SCTP_REMOTE_ERROR: { const auto& sre = notify.sn_remote_error; printf( "^^^ remote_error: err=%hu len=%hu\n", ntohs(sre.sre_error), ntohs(sre.sre_length) ); return EXIT_FAILURE; } case SCTP_SHUTDOWN_EVENT: { printf( "^^^ SCTP_SHUTDOWN_EVENT\n" ); return EXIT_FAILURE; } } } } //int flags = fcntl( sock, F_GETFL, 0 ); //fcntl( sock, F_SETFL, flags | O_NONBLOCK ); const std::vector<char> msg = generate_message( p.msgsize ); struct iovec iov; iov.iov_base = const_cast<char*>( msg.data() ); iov.iov_len = msg.size(); std::vector<char> cmsg_buff( CMSG_SPACE( sizeof( sctp_sndrcvinfo ) ) ); struct mmsghdr mhdr; memset( &mhdr, 0, sizeof(mhdr) ); struct msghdr& hdr = mhdr.msg_hdr; hdr.msg_name = nullptr; hdr.msg_namelen = 0; hdr.msg_iov = &iov; hdr.msg_iovlen = 1; hdr.msg_flags = 0; hdr.msg_control = cmsg_buff.data(); hdr.msg_controllen = cmsg_buff.size(); cmsghdr* cmsg = CMSG_FIRSTHDR( &hdr ); cmsg->cmsg_level = IPPROTO_SCTP; cmsg->cmsg_type = SCTP_SNDRCV; cmsg->cmsg_len = CMSG_LEN( sizeof( sctp_sndrcvinfo ) ); sctp_sndrcvinfo& cmsg_data = *reinterpret_cast<sctp_sndrcvinfo*>( CMSG_DATA( cmsg ) ); cmsg_data.sinfo_stream = 0; cmsg_data.sinfo_ssn = 0; //ignored cmsg_data.sinfo_flags = SCTP_UNORDERED; cmsg_data.sinfo_ppid = 31337; cmsg_data.sinfo_context = 123456; cmsg_data.sinfo_timetolive = 0; cmsg_data.sinfo_tsn = 0; //ignored cmsg_data.sinfo_cumtsn = 0; //ignored cmsg_data.sinfo_assoc_id = assoc_id; std::vector<mmsghdr> mhdrs( p.batch, mhdr ); while ( p.count ) { const ssize_t count = std::min<uint64_t>( p.batch, p.count ); ssize_t nsend = 0; TEMP_FAILURE_RETRY( nsend = sendmmsg( sock, mhdrs.data(), count, 0 ) ); if ( 0 == nsend ) raise( SIGTRAP ); if ( -1 == nsend ) raise( SIGTRAP ); if ( count != nsend ) raise( SIGTRAP ); p.count -= count; } //raise( SIGTRAP ); sock.close(); return EXIT_SUCCESS; }
int main(int argc, char **argv) { int opt; int option_index = 0; char *socket_path = getenv("I3SOCK"); char *command = NULL; char *fontname = NULL; char *i3_default_sock_path = "/tmp/i3-ipc.sock"; struct xcb_color_strings_t colors = { NULL, }; /* Definition of the standard-config */ config.hide_on_modifier = 0; config.dockpos = DOCKPOS_NONE; config.disable_ws = 0; static struct option long_opt[] = { { "socket", required_argument, 0, 's' }, { "command", required_argument, 0, 'c' }, { "hide", no_argument, 0, 'm' }, { "dock", optional_argument, 0, 'd' }, { "font", required_argument, 0, 'f' }, { "nows", no_argument, 0, 'w' }, { "help", no_argument, 0, 'h' }, { "version", no_argument, 0, 'v' }, { "verbose", no_argument, 0, 'V' }, { "color-bar-fg", required_argument, 0, 'A' }, { "color-bar-bg", required_argument, 0, 'B' }, { "color-active-ws-fg", required_argument, 0, 'C' }, { "color-active-ws-bg", required_argument, 0, 'D' }, { "color-inactive-ws-fg", required_argument, 0, 'E' }, { "color-inactive-ws-bg", required_argument, 0, 'F' }, { "color-urgent-ws-bg", required_argument, 0, 'G' }, { "color-urgent-ws-fg", required_argument, 0, 'H' }, { "color-focus-ws-bg", required_argument, 0, 'I' }, { "color-focus-ws-fg", required_argument, 0, 'J' }, { NULL, 0, 0, 0} }; while ((opt = getopt_long(argc, argv, "s:c:d::mf:whvVA:B:C:D:E:F:G:H:I:J:", long_opt, &option_index)) != -1) { switch (opt) { case 's': socket_path = expand_path(optarg); break; case 'c': command = strdup(optarg); break; case 'm': config.hide_on_modifier = 1; break; case 'd': config.hide_on_modifier = 0; if (optarg == NULL) { config.dockpos = DOCKPOS_BOT; break; } if (!strcmp(optarg, "top")) { config.dockpos = DOCKPOS_TOP; } else if (!strcmp(optarg, "bottom")) { config.dockpos = DOCKPOS_BOT; } else { print_usage(argv[0]); exit(EXIT_FAILURE); } break; case 'f': fontname = strdup(optarg); break; case 'w': config.disable_ws = 1; break; case 'v': printf("i3bar version " I3_VERSION " © 2010-2011 Axel Wagner and contributors\n"); exit(EXIT_SUCCESS); break; case 'V': config.verbose = 1; break; case 'A': read_color(&colors.bar_fg); break; case 'B': read_color(&colors.bar_bg); break; case 'C': read_color(&colors.active_ws_fg); break; case 'D': read_color(&colors.active_ws_bg); break; case 'E': read_color(&colors.inactive_ws_fg); break; case 'F': read_color(&colors.inactive_ws_bg); break; case 'G': read_color(&colors.urgent_ws_bg); break; case 'H': read_color(&colors.urgent_ws_fg); break; case 'I': read_color(&colors.focus_ws_bg); break; case 'J': read_color(&colors.focus_ws_fg); break; default: print_usage(argv[0]); exit(EXIT_SUCCESS); break; } } if (fontname == NULL) { /* This is a very restrictive default. More sensefull would be something like * "-misc-*-*-*-*--*-*-*-*-*-*-*-*". But since that produces very ugly results * on my machine, let's stick with this until we have a configfile */ fontname = "-misc-fixed-medium-r-semicondensed--12-110-75-75-c-60-iso10646-1"; } if (config.dockpos != DOCKPOS_NONE) { if (config.hide_on_modifier) { ELOG("--dock and --hide are mutually exclusive!\n"); exit(EXIT_FAILURE); } } else { config.hide_on_modifier = 1; } main_loop = ev_default_loop(0); init_colors(&colors); char *atom_sock_path = init_xcb(fontname); if (socket_path == NULL) { socket_path = atom_sock_path; } if (socket_path == NULL) { ELOG("No Socket Path Specified, default to %s\n", i3_default_sock_path); socket_path = expand_path(i3_default_sock_path); } free_colors(&colors); init_outputs(); if (init_connection(socket_path)) { /* We subscribe to the i3-events we need */ subscribe_events(); /* We initiate the main-function by requesting infos about the outputs and * workspaces. Everything else (creating the bars, showing the right workspace- * buttons and more) is taken care of by the event-driveniness of the code */ i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_OUTPUTS, NULL); if (!config.disable_ws) { i3_send_msg(I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); } } /* The name of this function is actually misleading. Even if no -c is specified, * this function initiates the watchers to listen on stdin and react accordingly */ start_child(command); FREE(command); /* We listen to SIGTERM/QUIT/INT and try to exit cleanly, by stopping the main-loop. * We only need those watchers on the stack, so putting them on the stack saves us * some calls to free() */ ev_signal *sig_term = malloc(sizeof(ev_signal)); ev_signal *sig_int = malloc(sizeof(ev_signal)); ev_signal *sig_hup = malloc(sizeof(ev_signal)); if (sig_term == NULL || sig_int == NULL || sig_hup == NULL) { ELOG("malloc() failed: %s\n", strerror(errno)); exit(EXIT_FAILURE); } ev_signal_init(sig_term, &sig_cb, SIGTERM); ev_signal_init(sig_int, &sig_cb, SIGINT); ev_signal_init(sig_hup, &sig_cb, SIGHUP); ev_signal_start(main_loop, sig_term); ev_signal_start(main_loop, sig_int); ev_signal_start(main_loop, sig_hup); /* From here on everything should run smooth for itself, just start listening for * events. We stop simply stop the event-loop, when we are finished */ ev_loop(main_loop, 0); kill_child(); FREE(statusline_buffer); clean_xcb(); ev_default_destroy(); free_workspaces(); return 0; }