Beispiel #1
0
/**
 * Allocates space for a new socket structure
 * @return Pointer to the allocated structure or NULL on failure
 */
comms_socket_t *comms_sock_new(void)
{
    comms_socket_t *sock;

    sock = (comms_socket_t *) calloc(1, sizeof(struct comms_socket));
    if (!sock) return NULL;

    log_enter();

    sock->can_read = false;
    sock->can_write = false;
    sock->have_exception = false;
    sock->poll_handle = NULL;
    sock->state = NETSOCK_STATE_NONE;
    sock->fd = INVALID_SOCK;
    sock->last_errno = -1;
    sock->is_socket = true;
    sock->in_buffer = netbuf_new(1, 4 * 1024 * 1024);
    if (!sock->in_buffer) {
        BLAST_SAFE_FREE(sock);
        blast_err("Could not allocate in_buffer");
        return NULL;
    }
    sock->out_buffer = netbuf_new(1, 1024 * 1024);
    if (!sock->out_buffer) {
        netbuf_free(sock->in_buffer);
        BLAST_SAFE_FREE(sock);
        log_leave("Could not allocate out_buffer");
        return NULL;
    }

    log_leave();
    return sock;
}
Beispiel #2
0
/**
 * Retrieves the address info structure for the given hostname:port combination.  This assumes a TCP/IP
 * connection
 * @param m_hostname Destination hostname in either DNS or xx.xx.xx.xx format
 * @param m_port Port number for the service
 * @param m_udp True if the port is a UDP port
 * @param m_ai Double pointer that will be allocated by by getaddrinfo()
 * @return return code from getaddrinfo
 */
static int comms_sock_get_addrinfo(const char *m_hostname, uint32_t m_port, bool m_udp, struct addrinfo **m_ai)
{
    char *service = NULL;
    struct addrinfo request = { 0 };
    int retval = 0;

    log_enter();

    if (!m_udp) {
        request.ai_protocol = IPPROTO_TCP;
        request.ai_socktype = SOCK_STREAM;
    } else {
        request.ai_protocol = IPPROTO_UDP;
        request.ai_socktype = SOCK_DGRAM;
    }

    request.ai_family = PF_UNSPEC;
    request.ai_flags = AI_PASSIVE;
    if (m_port) {
        blast_tmp_sprintf(service, "%hu", m_port);
        request.ai_flags = AI_NUMERICSERV;
    }
    retval = getaddrinfo(m_hostname, service, &request, m_ai);
    log_leave();

    return retval;
}
Beispiel #3
0
void *thread_func_aew(void *arg)
{
        struct env_aew          *env = arg;
        void                    *status = THREAD_SUCCESS;
        struct image_buffer_description *image = NULL;

        log_enter();
        log_dbg("meet\n");
        Rendezvous_meet(env->rendezvous_init);

        while (!gblGetQuit()) {
                usleep(10000);

                if (fifo_get(env->fifo_aew, &image) == FIFO_FAILURE) {
                        breakLoop(THREAD_FAILURE);
                }

                if (image == NULL) { //阻塞FIFO,只有FIFO中有消息才会执行下去
                        breakLoop(THREAD_SUCCESS);
                }
  
                capture_buffer_put(image);
        }

        Rendezvous_force(env->rendezvous_init);
        Rendezvous_meet(env->rendezvous_deinit);
        log("exit aew thread\n");
        log_exit();

        return status;
}
Beispiel #4
0
/**
 * Sets up a multicast listening port.
 * @param m_sock Allocated socket
 * @param m_hostname Should be "224.0.0.x" where x is between 0 and 255
 * @param m_port Multicast port number
 * @return NETSOCK_OK on success, NETSOCK_ERR on failure
 */
int comms_sock_multicast_listen(comms_socket_t *m_sock, const char *m_hostname, uint32_t m_port)
{
    socket_t fd;
    in_addr_t group;
    int loop = 0;
    log_enter();

    if (!m_sock || m_sock->state != NETSOCK_STATE_NONE) return NETSOCK_ERR;
    fd = comms_sock_bind("0.0.0.0", m_port, true);
    if (fd == INVALID_SOCK) return NETSOCK_ERR;

    comms_sock_set_fd(m_sock, fd);
    if ((group = inet_addr(m_hostname)) == INADDR_NONE) return NETSOCK_ERR;

    if (comms_sock_join_mcast(m_sock, group) == NETSOCK_ERR) return NETSOCK_ERR;

    setsockopt(m_sock->fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop));

    BLAST_SAFE_FREE(m_sock->host);

    m_sock->addr.sin_family = AF_INET;
    m_sock->addr.sin_addr.s_addr = group;
    m_sock->addr.sin_port = htons(m_port);
    m_sock->addrlen = sizeof(m_sock->addr);

    m_sock->host = strdup(m_hostname);
    m_sock->port = m_port;
    m_sock->udp = 1;

    m_sock->state = NETSOCK_STATE_CONNECTING;

    comms_net_async_set_events(comms_sock_get_poll_handle(m_sock), POLLOUT);
    log_leave();
    return NETSOCK_OK;
}
Beispiel #5
0
/**
 * Connects an allocated socket to a given remote host:port combination
 * @param m_hostname
 * @param m_port
 * @return
 */
static socket_t comms_sock_connect_fd(const char *m_hostname, uint32_t m_port, bool m_udp)
{
    socket_t sock = -1;
    int retval;
    struct addrinfo *addrinfo_group;
    struct addrinfo *ai;

    log_enter();

    retval = comms_sock_get_addrinfo(m_hostname, m_port, m_udp, &addrinfo_group);
    if (retval != 0) {
        blast_err("Failed to resolve hostname %s (%s)", m_hostname, gai_strerror(retval));
        log_leave();
        return NETSOCK_ERR;
    }

    for (ai = addrinfo_group; ai != NULL; ai = ai->ai_next) {
        /* create socket */
        sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
        if (sock < 0) {
            blast_err("Socket create failed: %s", strerror(errno));
            continue;
        }

        fcntl(sock, F_SETFL, O_NONBLOCK);

        if (!m_udp) connect(sock, ai->ai_addr, ai->ai_addrlen);
        break;
    }

    freeaddrinfo(addrinfo_group);
    log_leave();

    return sock;
}
Beispiel #6
0
static int comms_sock_raw_read(comms_socket_t *m_sock, void *m_buf, size_t m_len)
{
    int retval = NETSOCK_ERR;

    log_enter();
    if (m_sock->have_exception) {
        log_leave();
        return NETSOCK_ERR;
    }
    if (m_sock->is_socket) {
        m_sock->addrlen = sizeof(m_sock->addr);
        retval = recvfrom(m_sock->fd, m_buf, m_len, 0, &m_sock->addr, &m_sock->addrlen);
    } else {
        retval = read(m_sock->fd, m_buf, m_len);
    }

    m_sock->last_errno = errno;
    m_sock->can_read = false;

    if (retval < 0) {
        m_sock->have_exception = true;
    }

    log_leave();
    return retval;
}
Beispiel #7
0
static int comms_sock_raw_write(comms_socket_t *m_sock, const void *m_buf, size_t m_len)
{
    ssize_t retval = NETSOCK_ERR;

    log_enter();
    if (m_sock->have_exception) {
        log_leave();
        return NETSOCK_ERR;
    }

    if (m_sock->is_socket) {
        if (m_sock->udp) {
            retval = sendto(m_sock->fd, m_buf, m_len, m_sock->flags, &m_sock->addr, m_sock->addrlen);
        } else {
            /// Cap the maximum we send at any given point to the default segment size for TCP
            m_len = min(m_len, DEFAULT_MTU);
            retval = send(m_sock->fd, m_buf, m_len, m_sock->flags);
        }
    } else {
        retval = write(m_sock->fd, m_buf, m_len);
    }

    m_sock->last_errno = errno;

    if (m_sock->poll_handle) {
        comms_net_async_add_events(m_sock->poll_handle, POLLOUT);
    }
    if (retval < 0) {
        m_sock->have_exception = true;
    }

    log_leave();
    return retval;
}
Beispiel #8
0
comms_net_async_handle_t *comms_sock_get_poll_handle(comms_socket_t *m_sock)
{
    log_enter();
    if (!m_sock->poll_handle) {
        m_sock->poll_handle = comms_net_async_handler_new(m_sock->fd, 0, comms_sock_poll, m_sock);
    }log_leave();
    return m_sock->poll_handle;
}
Beispiel #9
0
void comms_sock_set_fd(comms_socket_t *m_sock, socket_t m_fd)
{
    log_enter();
    m_sock->fd = m_fd;
    if (m_sock->poll_handle) {
        comms_net_async_set_sock(m_sock->poll_handle, m_fd);
    }

    log_leave();
}
Beispiel #10
0
/*
 * Set the fields in the 'target' clone to the specified values.
 * Then, look at all clones to determine which message types are
 * currently active and which clone is the primary console queue.
 * If the primary console queue changes to or from the backlog
 * queue, copy all messages from backlog to primary or vice versa.
 */
void
log_update(log_t *target, queue_t *q, short flags, log_filter_t *filter)
{
	log_t *lp;
	short active = SL_CONSOLE;
	zone_t *zptr = NULL;
	log_zone_t *lzp;
	zoneid_t zoneid = target->log_zoneid;
	int i;

	log_enter();

	if (q != NULL)
		target->log_q = q;
	target->log_wanted = filter;
	target->log_flags = flags;
	target->log_overflow = 0;

	/*
	 * Need to special case the global zone here since this may be
	 * called before zone_init.
	 */
	if (zoneid == GLOBAL_ZONEID) {
		lzp = &log_global;
	} else if ((zptr = zone_find_by_id(zoneid)) == NULL) {
		log_exit();
		return;		/* zone is being destroyed, ignore update */
	} else {
		lzp = zone_getspecific(log_zone_key, zptr);
	}
	ASSERT(lzp != NULL);
	for (i = LOG_LOGMAXIDX; i >= LOG_LOGMINIDX; i--) {
		lp = &lzp->lz_clones[i];
		if (zoneid == GLOBAL_ZONEID && (lp->log_flags & SL_CONSOLE))
			log_consq = lp->log_q;
		active |= lp->log_flags;
	}
	lzp->lz_active = active;

	if (zptr)
		zone_rele(zptr);

	if (log_consq == target->log_q) {
		if (flags & SL_CONSOLE)
			log_conswitch(&log_backlog, target);
		else
			log_conswitch(target, &log_backlog);
	}
	target->log_q = q;

	log_exit();
}
Beispiel #11
0
int comms_sock_flush(comms_socket_t *m_sock)
{
    uint32_t len;
    int retval;

    log_enter();

    if (!comms_sock_is_open(m_sock)) {
        blast_err("Could not write to closed socket %s", m_sock->host ? m_sock->host : "(Unknown host)");

        log_leave();
        return NETSOCK_ERR;
    }

    len = netbuf_bytes_available(m_sock->out_buffer);
    if (m_sock->poll_handle && len > 0) {
        if (!__sync_lock_test_and_set(&m_sock->can_write, false)) {
            comms_net_async_add_events(m_sock->poll_handle, POLLOUT);
            log_leave();
            return NETSOCK_AGAIN;
        }

        void *data;
        len = netbuf_peek(m_sock->out_buffer, &data);

        if (len) {
            retval = comms_sock_raw_write(m_sock, data, len);
            free(data);
            if (retval < 0) {
                comms_sock_close(m_sock);
                blast_err("Could not write socket: %s", strerror(m_sock->last_errno));
                log_leave();
                return NETSOCK_ERR;
            }
            netbuf_eat(m_sock->out_buffer, retval);
        }
    }

    /**
     * If we have data left to write to the socket, then we force the POLLOUT event to allow
     * our async handler to catch and process the data in the next poll call.
     */
    len = netbuf_bytes_available(m_sock->out_buffer);
    if (m_sock->poll_handle && len > 0) {
        comms_net_async_add_events(m_sock->poll_handle, POLLOUT);
        log_leave();
        return NETSOCK_AGAIN;
    }

    log_leave();
    return NETSOCK_OK;
}
Beispiel #12
0
void comms_sock_close(comms_socket_t *m_sock)
{
    log_enter();
    if (comms_sock_is_open(m_sock)) {
        if (close(m_sock->fd) == -1) m_sock->last_errno = errno;

        m_sock->fd = INVALID_SOCK;
        m_sock->state = NETSOCK_STATE_CLOSED;
    }
    if (m_sock->poll_handle) {
        comms_net_async_handler_free(m_sock->poll_handle);
        m_sock->poll_handle = NULL;
    }log_leave("Closed");
}
Beispiel #13
0
/**
 * Binds a socket structure to a specific host:port combination.
 * @param m_hostname
 * @param m_port Port number to connect
 * @param m_udp If false, build a stream-based tcp connection
 * @return
 */
static socket_t comms_sock_bind(const char *m_hostname, uint32_t m_port, bool m_udp)
{
    socket_t sock = -1;
    int retval;
    struct addrinfo *addrinfo_group;
    struct addrinfo *ai;
    int sock_opt = 1;

    log_enter();

    retval = comms_sock_get_addrinfo(m_hostname, m_port, m_udp, &addrinfo_group);
    if (retval != 0) {
        blast_err("Failed to resolve hostname %s (%s)", m_hostname, gai_strerror(retval));
        log_leave();
        return NETSOCK_ERR;
    }

    for (ai = addrinfo_group; ai != NULL; ai = ai->ai_next) {
        /* create socket */
        sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
        if (sock < 0) {
            blast_err("Socket create failed: %s", strerror(errno));
            continue;
        }

        if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &sock_opt, sizeof(sock_opt)) < 0) {
            freeaddrinfo(addrinfo_group);
            close(sock);
            log_leave();
            blast_err("Couldn't reuse socket for port %d", m_port);
            return NETSOCK_ERR;
        }

        if (bind(sock, ai->ai_addr, ai->ai_addrlen)) {
            freeaddrinfo(addrinfo_group);
            close(sock);
            log_leave();
            blast_err("Couldn't bind to socket for port %d", m_port);
            return NETSOCK_ERR;
        }

        break;
    }

    freeaddrinfo(addrinfo_group);
    log_leave();

    return sock;
}
Beispiel #14
0
void comms_sock_free(comms_socket_t *m_sock)
{
    log_enter();
    if (!m_sock) {
        log_leave("No socket");
        return;
    }

    comms_sock_close(m_sock);
    netbuf_free(m_sock->in_buffer);
    netbuf_free(m_sock->out_buffer);
    BLAST_SAFE_FREE(m_sock->host);
    BLAST_SAFE_FREE(m_sock);
    log_leave("Freed");
}
Beispiel #15
0
static int comms_sock_connect_generic(comms_socket_t *m_sock, const char *m_hostname, uint32_t m_port, bool m_udp)
{
    socket_t fd;
    log_enter();

    if (!m_sock || m_sock->state != NETSOCK_STATE_NONE) return NETSOCK_ERR;
    fd = comms_sock_connect_fd(m_hostname, m_port, m_udp);

    if (fd == INVALID_SOCK) return NETSOCK_ERR;
    comms_sock_set_fd(m_sock, fd);

    BLAST_SAFE_FREE(m_sock->host);
    m_sock->host = strdup(m_hostname);
    m_sock->port = m_port;
    m_sock->udp = m_udp;

    m_sock->state = NETSOCK_STATE_CONNECTING;

    comms_net_async_set_events(comms_sock_get_poll_handle(m_sock), POLLOUT);
    log_leave();
    return NETSOCK_OK;
}
Beispiel #16
0
/**
 * Takes a double-pointer to a socket and ensures that it is in a pristine state, ready for a new connection.
 * @param m_sock Double pointer to a socket
 */
void comms_sock_reset(comms_socket_t **m_sock)
{
    log_enter();
    if (!(*m_sock)) {
        *m_sock = comms_sock_new();
        return;
    }
    comms_sock_close(*m_sock);

    (*m_sock)->fd = INVALID_SOCK;
    (*m_sock)->last_errno = -1;
    (*m_sock)->is_socket = true;
    netbuf_reinit((*m_sock)->in_buffer);
    netbuf_reinit((*m_sock)->out_buffer);
    (*m_sock)->can_read = false;
    (*m_sock)->can_write = false;
    (*m_sock)->have_exception = false;
    BLAST_ZERO((*m_sock)->callbacks);
    (*m_sock)->poll_handle = comms_sock_get_poll_handle(*m_sock);
    (*m_sock)->state = NETSOCK_STATE_NONE;
    (*m_sock)->flags = 0;
    log_leave();
}
Beispiel #17
0
void
log_sendmsg(mblk_t *mp, zoneid_t zoneid)
{
	log_t *lp;
	char *src, *dst;
	mblk_t *mp2 = mp->b_cont;
	log_ctl_t *lc = (log_ctl_t *)mp->b_rptr;
	int flags, fac;
	off_t facility = 0;
	off_t body = 0;
	zone_t *zptr = NULL;
	log_zone_t *lzp;
	int i;
	int backlog;

	/*
	 * Need to special case the global zone here since this may be
	 * called before zone_init.
	 */
	if (zoneid == GLOBAL_ZONEID) {
		lzp = &log_global;
	} else if ((zptr = zone_find_by_id(zoneid)) == NULL) {
		/* specified zone doesn't exist, free message and return */
		log_freemsg(mp);
		return;
	} else {
		lzp = zone_getspecific(log_zone_key, zptr);
	}
	ASSERT(lzp != NULL);

	if ((lc->flags & lzp->lz_active) == 0) {
		if (zptr)
			zone_rele(zptr);
		log_freemsg(mp);
		return;
	}

	if (panicstr) {
		/*
		 * Raise the console queue's q_hiwat to ensure that we
		 * capture all panic messages.
		 */
		log_consq->q_hiwat = 2 * LOG_HIWAT;
		log_consq->q_flag &= ~QFULL;

		/* Message was created while panicking. */
		lc->flags |= SL_PANICMSG;
	}

	src = (char *)mp2->b_rptr;
	dst = strstr(src, "FACILITY_AND_PRIORITY] ");
	if (dst != NULL) {
		facility = dst - src;
		body = facility + 23; /* strlen("FACILITY_AND_PRIORITY] ") */
	}

	log_enter();

	/*
	 * In the early boot phase hrestime is invalid, then timechanged is 0.
	 * If hrestime is not valid, the ttime is set to 0 here and the correct
	 * ttime is calculated in log_conswitch() later. The log_conswitch()
	 * calculation to determine the correct ttime does not use ttime data
	 * from these log_ctl_t structures; it only uses ttime from log_ctl_t's
	 * that contain good data.
	 *
	 */
	lc->ltime = ddi_get_lbolt();
	if (timechanged) {
		lc->ttime = gethrestime_sec();
	} else {
		lc->ttime = 0;
	}

	flags = lc->flags & lzp->lz_active;
	log_seq_no[flags & SL_ERROR]++;
	log_seq_no[flags & SL_TRACE]++;
	log_seq_no[flags & SL_CONSOLE]++;

	/*
	 * If this is in the global zone, start with the backlog, then
	 * walk through the clone logs.  If not, just do the clone logs.
	 */
	backlog = (zoneid == GLOBAL_ZONEID);
	i = LOG_LOGMINIDX;
	while (i <= LOG_LOGMAXIDX) {
		if (backlog) {
			/*
			 * Do the backlog this time, then start on the
			 * others.
			 */
			backlog = 0;
			lp = &log_backlog;
		} else {
			lp = &lzp->lz_clones[i++];
		}

		if ((lp->log_flags & flags) && lp->log_wanted(lp, lc)) {
			if (canput(lp->log_q)) {
				lp->log_overflow = 0;
				lc->seq_no = log_seq_no[lp->log_flags];
				if ((mp2 = copymsg(mp)) == NULL)
					break;
				if (facility != 0) {
					src = (char *)mp2->b_cont->b_rptr;
					dst = src + facility;
					fac = (lc->pri & LOG_FACMASK) >> 3;
					dst += snprintf(dst,
					    LOG_FACSIZE + LOG_PRISIZE, "%s.%s",
					    log_fac[MIN(fac, LOG_NFACILITIES)],
					    log_pri[lc->pri & LOG_PRIMASK]);
					src += body - 2; /* copy "] " too */
					while (*src != '\0')
						*dst++ = *src++;
					*dst++ = '\0';
					mp2->b_cont->b_wptr = (uchar_t *)dst;
				}
				(void) putq(lp->log_q, mp2);
			} else if (++lp->log_overflow == 1) {
Beispiel #18
0
/**
 * Main routine providing callback handling for asynchronous socket connections.
 * @param m_handle Pointer to the asynchronous handler
 * @param m_fd File descriptor for the network socket
 * @param m_events Received events flags
 * @param m_sock Pointer to the comms_socket structure
 * @return NETSOCK_OK on success, NETSOCK_ERR on failure
 */
static int comms_sock_poll(comms_net_async_handle_t *m_handle, socket_t m_fd, uint16_t m_events, void *m_sock)
{
    comms_socket_t *sock = (comms_socket_t*) m_sock;
    char buffer[COMMS_NETSOCK_BUF_SIZE];
    int retval = 0;
    socklen_t errlen = sizeof(sock->last_errno);

    log_enter();
    if (!comms_sock_is_open(sock)) {
        log_leave();
        return NETSOCK_ERR;
    }

    if (m_events & POLLERR) {
        /**
         * If we catch an error while connecting, we use getsockopt to try and determine the cause of the error.
         * The connected callback in then fired with NETSOCK_ERR
         */
        if (sock->state == NETSOCK_STATE_CONNECTING) {
            sock->state = NETSOCK_STATE_ERROR;
            blast_err("Got error while connecting to %s", sock->host);
            if (sock->is_socket) getsockopt(m_fd, SOL_SOCKET, SO_ERROR, (void *) &sock->last_errno, &errlen);

            comms_sock_close(sock);
            if (sock->callbacks.connected) {
                sock->callbacks.connected(NETSOCK_ERR, sock->last_errno, sock->callbacks.priv);
            }log_leave();
            return NETSOCK_ERR;
        }
        /**
         * If we catch an error and we are not trying to connect, then we fall through to the POLLIN handler to
         * process the error
         */

        comms_net_async_del_events(m_handle, POLLERR);
        m_events |= POLLIN;
    }
    if (m_events & (POLLIN | POLLPRI)) {
        sock->can_read = true;
        retval = comms_sock_raw_read(sock, buffer, sizeof(buffer));
        /**
         * Caught an error.  Likely broken pipe.  Errno is stored in the sock struct.
         */
        if (retval < 0) {
            retval = -1;
            if (m_handle) {
                comms_net_async_del_events(m_handle, POLLIN | POLLERR);
            }
            if (sock->callbacks.error) {
                sock->callbacks.error(sock->last_errno, sock->callbacks.priv);
            }
        }

        /**
         * No more data are available.  This is the EOF condition
         */
        if (retval == 0) {
            comms_net_async_del_events(m_handle, POLLIN);
            m_events |= POLLHUP;
        }

        /**
         * Got actual data.  Buffer it and pass on to the user callback function
         */
        if (retval > 0) {
            size_t written = netbuf_write(sock->in_buffer, buffer, retval);
            size_t to_write = retval - written;
            if (sock->callbacks.data) {
                void *data;
                size_t len = netbuf_peek(sock->in_buffer, &data);

                if (len) {
                    retval = sock->callbacks.data(data, len, sock->callbacks.priv);

                    if (retval > 0) netbuf_eat(sock->in_buffer, retval);

                    if (netbuf_bytes_available(sock->in_buffer)) comms_net_async_add_events(m_handle, POLLIN);
                    free(data);
                }
            }
            /// If we didn't get everything in, try one more time
            if (to_write) {
                if (netbuf_write(sock->in_buffer, buffer + written, to_write)) blast_warn(
                        "Discarding data due to overfull in_buffer on %s", sock->host ? sock->host : "(NULL)");
            }
        }
    }
    if (m_events & POLLHUP) {
        if (sock->callbacks.finished) {
            void *data;
            size_t len = netbuf_peek(sock->in_buffer, &data);

            if (len) {
                sock->callbacks.finished(data, len, sock->callbacks.priv);
                if (sock->in_buffer) netbuf_eat(sock->in_buffer, len);
                free(data);
            }
            sock->state = NETSOCK_STATE_CLOSED;
        }log_leave();
        return NETSOCK_OK;
    }
    if (m_events & POLLOUT) {
        if (sock->state == NETSOCK_STATE_CONNECTING) {
            sock->state = NETSOCK_STATE_CONNECTED;
            comms_net_async_set_events(m_handle, POLLPRI | POLLIN | POLLOUT);
            fcntl(sock->fd, F_SETFL, 0);

            if (sock->callbacks.connected) {
                sock->callbacks.connected(NETSOCK_OK, 0, sock->callbacks.priv);
            }

            log_leave();
            return NETSOCK_OK;
        }

        sock->can_write = true;
        comms_net_async_del_events(m_handle, POLLOUT);

        if (netbuf_bytes_available(sock->out_buffer)) {
            comms_sock_flush(sock);
        } else if (sock->callbacks.control) {
            sock->callbacks.control(NETSOCK_WRITABLE, sock->callbacks.priv);
        }
    }

    log_leave();
    return retval;
}