📄 conn.c
字号:
return conn_open_tcp_nb_with_port(host, port, 0, our_host);}Connection *conn_open_tcp_nb_with_port(Octstr *host, int port, int our_port, Octstr *our_host){ int sockfd; int done = -1; Connection *c; sockfd = tcpip_connect_nb_to_server_with_port(octstr_get_cstr(host), port, our_port, our_host == NULL ? NULL : octstr_get_cstr(our_host), &done); if (sockfd < 0) return NULL; c = conn_wrap_fd(sockfd, 0); if (done != 0) { c->connected = no; } return c;}int conn_is_connected(Connection *conn){ if (conn->connected == yes) return 0; return -1;}int conn_get_connect_result(Connection *conn){ int err,len; len = sizeof(len); if (getsockopt(conn->fd, SOL_SOCKET, SO_ERROR, &err, &len) < 0) { return -1; } if (err) { return -1; } conn->connected = yes; return 0;}Connection *conn_open_tcp_with_port(Octstr *host, int port, int our_port, Octstr *our_host){ int sockfd; sockfd = tcpip_connect_to_server_with_port(octstr_get_cstr(host), port, our_port, our_host == NULL ? NULL : octstr_get_cstr(our_host)); if (sockfd < 0) return NULL; return conn_wrap_fd(sockfd, 0);}Connection *conn_wrap_fd(int fd, int ssl){ Connection *conn; if (socket_set_blocking(fd, 0) < 0) return NULL; conn = gw_malloc(sizeof(*conn)); conn->inlock = mutex_create(); conn->outlock = mutex_create(); conn->claimed = 0; conn->outbuf = octstr_create(""); conn->outbufpos = 0; conn->inbuf = octstr_create(""); conn->inbufpos = 0; conn->fd = fd; conn->connected = yes; conn->read_eof = 0; conn->io_error = 0; conn->output_buffering = DEFAULT_OUTPUT_BUFFERING; conn->registered = NULL; conn->callback = NULL; conn->callback_data = NULL; conn->listening_pollin = 0; conn->listening_pollout = 0;#ifdef HAVE_LIBSSL /* * do all the SSL magic for this connection */ if (ssl) { conn->ssl = SSL_new(global_server_ssl_context); conn->peer_certificate = NULL; /* SSL_set_fd can fail, so check it */ if (SSL_set_fd(conn->ssl, conn->fd) == 0) { /* SSL_set_fd failed, log error and return NULL */ error(errno, "SSL: OpenSSL: %.256s", ERR_error_string(ERR_get_error(), NULL)); conn_destroy(conn); return NULL; } /* SSL_set_verify(conn->ssl, 0, NULL); */ /* set read/write BIO layer to non-blocking mode */ BIO_set_nbio(SSL_get_rbio(conn->ssl), 1); BIO_set_nbio(SSL_get_wbio(conn->ssl), 1); /* set accept state , SSL-Handshake will be handled transparent while SSL_[read|write] */ SSL_set_accept_state(conn->ssl); } else { conn->ssl = NULL; conn->peer_certificate = NULL; }#endif /* HAVE_LIBSSL */ return conn;}void conn_destroy(Connection *conn){ int ret; if (conn == NULL) return; /* No locking done here. conn_destroy should not be called * if any thread might still be interested in the connection. */ if (conn->registered) fdset_unregister(conn->registered, conn->fd); if (conn->fd >= 0) { /* Try to flush any remaining data */ unlocked_try_write(conn);#ifdef HAVE_LIBSSL if (conn->ssl != NULL) { SSL_smart_shutdown(conn->ssl); SSL_free(conn->ssl); if (conn->peer_certificate != NULL) X509_free(conn->peer_certificate); }#endif /* HAVE_LIBSSL */ ret = close(conn->fd); if (ret < 0) error(errno, "conn_destroy: error on close"); conn->fd = -1; } octstr_destroy(conn->outbuf); octstr_destroy(conn->inbuf); mutex_destroy(conn->inlock); mutex_destroy(conn->outlock); gw_free(conn);}void conn_claim(Connection *conn){ gw_assert(conn != NULL); if (conn->claimed) panic(0, "Connection is being claimed twice!"); conn->claimed = 1;#ifndef NO_GWASSERT conn->claiming_thread = gwthread_self();#endif}long conn_outbuf_len(Connection *conn){ long len; lock_out(conn); len = unlocked_outbuf_len(conn); unlock_out(conn); return len;}long conn_inbuf_len(Connection *conn){ long len; lock_in(conn); len = unlocked_inbuf_len(conn); unlock_in(conn); return len;}int conn_eof(Connection *conn){ int eof; lock_in(conn); eof = conn->read_eof; unlock_in(conn); return eof;}int conn_error(Connection *conn){ int err; lock_in(conn); lock_out(conn); err = conn->io_error; unlock_in(conn); unlock_out(conn); return err;}void conn_set_output_buffering(Connection *conn, unsigned int size){ lock_out(conn); conn->output_buffering = size; /* If the buffer size is smaller, we may have to write immediately. */ unlocked_try_write(conn); unlock_out(conn);}static void poll_callback(int fd, int revents, void *data){ Connection *conn; int do_callback = 0; conn = data; if (conn == NULL) { error(0, "poll_callback called with NULL connection."); return; } if (conn->fd != fd) { error(0, "poll_callback called on wrong connection."); return; } /* Get result of nonblocking connect, before any reads and writes * we must check result (it must be handled in initial callback) */ if (conn->connected == no) { if (conn->callback) conn->callback(conn, conn->callback_data); return; } /* If got POLLERR or POLHUP, then unregister the descriptor from the * fdset and set the error condition variable to let the upper layer * close and destroy the connection. */ if (revents & (POLLERR|POLLHUP)) { lock_in(conn); lock_out(conn); if (conn->listening_pollin) unlocked_register_pollin(conn, 0); if (conn->listening_pollout) unlocked_register_pollout(conn, 0); conn->io_error = 1; unlock_in(conn); unlock_out(conn); do_callback = 1; } /* If unlocked_write manages to write all pending data, it will * tell the fdset to stop listening for POLLOUT. */ if (revents & POLLOUT) { lock_out(conn); unlocked_write(conn); if (unlocked_outbuf_len(conn) == 0) do_callback = 1; unlock_out(conn); } /* We read only in unlocked_read in we received POLLIN, cause the * descriptor is already broken and of no use anymore. */ if (revents & POLLIN) { lock_in(conn); unlocked_read(conn); unlock_in(conn); do_callback = 1; } if (do_callback && conn->callback) conn->callback(conn, conn->callback_data);}int conn_register(Connection *conn, FDSet *fdset, conn_callback_t callback, void *data){ int events; int result = 0; gw_assert(conn != NULL); if (conn->fd < 0) return -1; /* We need both locks if we want to update the registration * information. */ lock_out(conn); lock_in(conn); if (conn->registered == fdset) { /* Re-registering. Change only the callback info. */ conn->callback = callback; conn->callback_data = data; result = 0; } else if (conn->registered) { /* Already registered to a different fdset. */ result = -1; } else { events = 0; /* For nonconnected socket we must lesten both directions */ if (conn->connected == yes) { if (conn->read_eof == 0 && conn->io_error == 0) events |= POLLIN; if (unlocked_outbuf_len(conn) > 0) events |= POLLOUT; } else { events |= POLLIN | POLLOUT; } conn->registered = fdset; conn->callback = callback; conn->callback_data = data; conn->listening_pollin = (events & POLLIN) != 0; conn->listening_pollout = (events & POLLOUT) != 0; fdset_register(fdset, conn->fd, events, poll_callback, conn); result = 0; } unlock_out(conn); unlock_in(conn); return result;}void conn_unregister(Connection *conn){ gw_assert(conn != NULL); if (conn->fd < 0) return; /* We need both locks to update the registration information */ lock_out(conn); lock_in(conn); if (conn->registered) { fdset_unregister(conn->registered, conn->fd); conn->registered = NULL; conn->callback = NULL; conn->callback_data = NULL; conn->listening_pollin = 0; conn->listening_pollout = 0; } unlock_in(conn); unlock_out(conn);}int conn_wait(Connection *conn, double seconds){ int events; int ret; int fd; lock_out(conn); /* Try to write any data that might still be waiting to be sent */ ret = unlocked_write(conn); if (ret < 0) { unlock_out(conn); return -1; } if (ret > 0) { /* We did something useful. No need to poll or wait now. */ unlock_out(conn); return 0; } fd = conn->fd; /* Normally, we block until there is more data available. But * if any data still needs to be sent, we block until we can * send it (or there is more data available). We always block * for reading, unless we know there is no more data coming. * (Because in that case, poll will keep reporting POLLIN to * signal the end of the file). If the caller explicitly wants * to wait even though there is no data to write and we're at * end of file, then poll for new data anyway because the caller * apparently doesn't trust eof. */ events = 0; if (unlocked_outbuf_len(conn) > 0) events |= POLLOUT; /* Don't keep the connection locked while we wait */ unlock_out(conn); /* We need the in lock to query read_eof */ lock_in(conn); if ((conn->read_eof == 0 && conn->io_error == 0) || events == 0) events |= POLLIN; unlock_in(conn); ret = gwthread_pollfd(fd, events, seconds); if (ret < 0) { if (errno == EINTR) return 0; error(0, "conn_wait: poll failed on fd %d:", fd); return -1; } if (ret == 0) return 1; if (ret & POLLNVAL) { error(0, "conn_wait: fd %d not open.", fd); return -1; } if (ret & (POLLERR | POLLHUP)) { /* Call unlocked_read to report the specific error, * and handle the results of the error. We can't be * certain that the error still exists, because we * released the lock for a while. */ lock_in(conn); unlocked_read(conn); unlock_in(conn); return -1; } /* If POLLOUT is on, then we must have wanted * to write something. */ if (ret & POLLOUT) { lock_out(conn); unlocked_write(conn); unlock_out(conn); } /* Since we normally select for reading, we must * try to read here. Otherwise, if the caller loops * around conn_wait without making conn_read* calls * in between, we will keep polling this same data. */ if (ret & POLLIN) { lock_in(conn); unlocked_read(conn); unlock_in(conn); } return 0;}int conn_flush(Connection *conn){ int ret; int revents; int fd; lock_out(conn); ret = unlocked_write(conn); if (ret < 0) { unlock_out(conn); return -1; } while (unlocked_outbuf_len(conn) != 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -