/** * g_socket_listener_add_address: * @listener: a #GSocketListener * @address: a #GSocketAddress * @type: a #GSocketType * @protocol: a #GSocketProtocol * @source_object: (allow-none): Optional #GObject identifying this source * @effective_address: (out) (allow-none): location to store the address that was bound to, or %NULL. * @error: #GError for error reporting, or %NULL to ignore. * * Creates a socket of type @type and protocol @protocol, binds * it to @address and adds it to the set of sockets we're accepting * sockets from. * * Note that adding an IPv6 address, depending on the platform, * may or may not result in a listener that also accepts IPv4 * connections. For more deterministic behavior, see * g_socket_listener_add_inet_port(). * * @source_object will be passed out in the various calls * to accept to identify this particular source, which is * useful if you're listening on multiple addresses and do * different things depending on what address is connected to. * * If successful and @effective_address is non-%NULL then it will * be set to the address that the binding actually occurred at. This * is helpful for determining the port number that was used for when * requesting a binding to port 0 (ie: "any port"). This address, if * requested, belongs to the caller and must be freed. * * Returns: %TRUE on success, %FALSE on error. * * Since: 2.22 */ gboolean g_socket_listener_add_address (GSocketListener *listener, GSocketAddress *address, GSocketType type, GSocketProtocol protocol, GObject *source_object, GSocketAddress **effective_address, GError **error) { GSocketAddress *local_address; GSocketFamily family; GSocket *socket; if (!check_listener (listener, error)) return FALSE; family = g_socket_address_get_family (address); socket = g_socket_new (family, type, protocol, error); if (socket == NULL) return FALSE; g_socket_set_listen_backlog (socket, listener->priv->listen_backlog); if (!g_socket_bind (socket, address, TRUE, error) || !g_socket_listen (socket, error)) { g_object_unref (socket); return FALSE; } local_address = NULL; if (effective_address) { local_address = g_socket_get_local_address (socket, error); if (local_address == NULL) { g_object_unref (socket); return FALSE; } } if (!g_socket_listener_add_socket (listener, socket, source_object, error)) { if (local_address) g_object_unref (local_address); g_object_unref (socket); return FALSE; } if (effective_address) *effective_address = local_address; g_object_unref (socket); /* add_socket refs this */ return TRUE; }
GInetAddress * xdmcp_client_get_local_address (XDMCPClient *client) { if (!client->priv->socket) return NULL; GSocketAddress *socket_address = g_socket_get_local_address (client->priv->socket, NULL); return g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (socket_address)); }
GStrv _client_create_exec_args (GSocket *socket, const gchar *contact_id, const gchar *username, gchar **ssh_opts) { GPtrArray *args; GSocketAddress *socket_address; GInetAddress *inet_address; guint16 port; gchar *host; gchar *str; gchar **opt; /* Get the local host and port on which sshd is running */ socket_address = g_socket_get_local_address (socket, NULL); inet_address = g_inet_socket_address_get_address ( G_INET_SOCKET_ADDRESS (socket_address)); port = g_inet_socket_address_get_port ( G_INET_SOCKET_ADDRESS (socket_address)); host = g_inet_address_to_string (inet_address); /* Create ssh client args */ args = g_ptr_array_new_with_free_func (g_free); g_ptr_array_add (args, g_strdup ("ssh")); g_ptr_array_add (args, host); g_ptr_array_add (args, g_strdup ("-p")); str = g_strdup_printf ("%d", port); g_ptr_array_add (args, str); if (contact_id != NULL) { str = g_strdup_printf ("-oHostKeyAlias=%s", contact_id); g_ptr_array_add (args, str); } if (!tp_str_empty (username)) { g_ptr_array_add (args, g_strdup ("-l")); g_ptr_array_add (args, g_strdup (username)); } if (ssh_opts != NULL) { for (opt = ssh_opts; *opt != NULL; opt++) { g_ptr_array_add (args, g_strdup (*opt)); } } g_ptr_array_add (args, NULL); return (gchar **) g_ptr_array_free (args, FALSE); }
guint16 arv_gv_stream_get_port (ArvGvStream *gv_stream) { GInetSocketAddress *local_address; guint16 port; g_return_val_if_fail (ARV_IS_GV_STREAM (gv_stream), 0); local_address = G_INET_SOCKET_ADDRESS (g_socket_get_local_address (gv_stream->socket, NULL)); port = g_inet_socket_address_get_port (local_address); g_object_unref (local_address); return port; }
int kms_sctp_connection_get_bound_port (KmsSCTPConnection * conn) { GSocketAddress *addr; gint bound_port = -1; g_return_val_if_fail (conn != NULL, bound_port); addr = g_socket_get_local_address (conn->socket, NULL); if (addr != NULL) { bound_port = g_inet_socket_address_get_port ((GInetSocketAddress *) addr); g_object_unref (addr); } return bound_port; }
/** * g_vfs_ftp_connection_listen_data_connection: * @conn: a connection * @error: %NULL or location to take potential errors * * Initiates a listening socket that the FTP server can connect to. To accept * connections and initialize data transfers, use * g_vfs_ftp_connection_accept_data_connection(). * This function supports what is known as "active FTP", while * g_vfs_ftp_connection_open_data_connection() is to be used for "passive FTP". * * Returns: the actual address the socket is listening on or %NULL on error **/ GSocketAddress * g_vfs_ftp_connection_listen_data_connection (GVfsFtpConnection *conn, GError ** error) { GSocketAddress *local, *addr; g_return_val_if_fail (conn != NULL, NULL); g_return_val_if_fail (conn->data == NULL, NULL); g_vfs_ftp_connection_stop_listening (conn); local = g_socket_connection_get_local_address (conn->connection, error); if (local == NULL) return NULL; conn->listen_socket = g_socket_new (g_socket_address_get_family (local), G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_TCP, error); if (conn->listen_socket == NULL) return NULL; g_assert (G_IS_INET_SOCKET_ADDRESS (local)); addr = g_inet_socket_address_new (g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (local)), 0); g_object_unref (local); if (!g_socket_bind (conn->listen_socket, addr, TRUE, error) || !g_socket_listen (conn->listen_socket, error) || !(local = g_socket_get_local_address (conn->listen_socket, error))) { g_object_unref (addr); g_vfs_ftp_connection_stop_listening (conn); return NULL; } g_object_unref (addr); return local; }
static gboolean run (int argc, char **argv, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; g_autoptr(GOptionContext) context = NULL; const char *dirpath; OtTrivialHttpd appstruct = { 0, }; OtTrivialHttpd *app = &appstruct; glnx_unref_object SoupServer *server = NULL; g_autoptr(GFileMonitor) dirmon = NULL; context = g_option_context_new ("[DIR] - Simple webserver"); g_option_context_add_main_entries (context, options, NULL); app->root_dfd = -1; if (!g_option_context_parse (context, &argc, &argv, error)) goto out; if (argc > 1) dirpath = argv[1]; else dirpath = "."; if (!glnx_opendirat (AT_FDCWD, dirpath, TRUE, &app->root_dfd, error)) goto out; if (!(opt_random_500s_percentage >= 0 && opt_random_500s_percentage <= 99)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Invalid --random-500s=%u", opt_random_500s_percentage); goto out; } if (opt_log) { GOutputStream *stream = NULL; if (g_strcmp0 (opt_log, "-") == 0) { if (opt_daemonize) { ot_util_usage_error (context, "Cannot use --log-file=- and --daemonize at the same time", error); goto out; } stream = G_OUTPUT_STREAM (g_unix_output_stream_new (STDOUT_FILENO, FALSE)); } else { g_autoptr(GFile) log_file = NULL; GFileOutputStream* log_stream; log_file = g_file_new_for_path (opt_log); log_stream = g_file_create (log_file, G_FILE_CREATE_PRIVATE, cancellable, error); if (!log_stream) goto out; stream = G_OUTPUT_STREAM (log_stream); } app->log = stream; } #if SOUP_CHECK_VERSION(2, 48, 0) server = soup_server_new (SOUP_SERVER_SERVER_HEADER, "ostree-httpd ", NULL); if (!soup_server_listen_all (server, opt_port, 0, error)) goto out; #else server = soup_server_new (SOUP_SERVER_PORT, opt_port, SOUP_SERVER_SERVER_HEADER, "ostree-httpd ", NULL); #endif soup_server_add_handler (server, NULL, httpd_callback, app, NULL); if (opt_port_file) { g_autofree char *portstr = NULL; #if SOUP_CHECK_VERSION(2, 48, 0) GSList *listeners = soup_server_get_listeners (server); g_autoptr(GSocket) listener = NULL; g_autoptr(GSocketAddress) addr = NULL; g_assert (listeners); listener = g_object_ref (listeners->data); g_slist_free (listeners); listeners = NULL; addr = g_socket_get_local_address (listener, error); if (!addr) goto out; g_assert (G_IS_INET_SOCKET_ADDRESS (addr)); portstr = g_strdup_printf ("%u\n", g_inet_socket_address_get_port ((GInetSocketAddress*)addr)); #else portstr = g_strdup_printf ("%u\n", soup_server_get_port (server)); #endif if (g_strcmp0 ("-", opt_port_file) == 0) { fputs (portstr, stdout); // not g_print - this must go to stdout, not a handler fflush (stdout); } else if (!g_file_set_contents (opt_port_file, portstr, strlen (portstr), error)) goto out; } #if !SOUP_CHECK_VERSION(2, 48, 0) soup_server_run_async (server); #endif if (opt_daemonize) { pid_t pid = fork(); if (pid == -1) { int errsv = errno; g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errsv), g_strerror (errsv)); goto out; } else if (pid > 0) { ret = TRUE; goto out; } /* Child, continue */ if (setsid () < 0) err (1, "setsid"); /* Daemonising: close stdout/stderr so $() et al work on us */ if (freopen("/dev/null", "r", stdin) == NULL) err (1, "freopen"); if (freopen("/dev/null", "w", stdout) == NULL) err (1, "freopen"); if (freopen("/dev/null", "w", stderr) == NULL) err (1, "freopen"); } else { /* Since we're used for testing purposes, let's just do this by * default. This ensures we exit when our parent does. */ if (prctl (PR_SET_PDEATHSIG, SIGTERM) != 0) { if (errno != ENOSYS) { glnx_set_error_from_errno (error); goto out; } } } app->running = TRUE; if (opt_autoexit) { gboolean is_symlink = FALSE; g_autoptr(GFile) root = NULL; g_autoptr(GFileInfo) info = NULL; root = g_file_new_for_path (dirpath); info = g_file_query_info (root, G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, cancellable, error); if (!info) goto out; is_symlink = g_file_info_get_is_symlink (info); if (is_symlink) dirmon = g_file_monitor_file (root, 0, cancellable, error); else dirmon = g_file_monitor_directory (root, 0, cancellable, error); if (!dirmon) goto out; g_signal_connect (dirmon, "changed", G_CALLBACK (on_dir_changed), app); } httpd_log (app, "serving at root %s\n", dirpath); while (app->running) g_main_context_iteration (NULL, TRUE); ret = TRUE; out: if (app->root_dfd != -1) (void) close (app->root_dfd); g_clear_object (&app->log); return ret; }
NiceSocket * nice_tcp_bsd_socket_new (GMainContext *ctx, NiceAddress *addr) { union { struct sockaddr_storage storage; struct sockaddr addr; } name; NiceSocket *sock; TcpPriv *priv; GSocket *gsock = NULL; GError *gerr = NULL; gboolean gret = FALSE; GSocketAddress *gaddr; if (addr == NULL) { /* We can't connect a tcp socket with no destination address */ return NULL; } sock = g_slice_new0 (NiceSocket); nice_address_copy_to_sockaddr (addr, &name.addr); if (name.storage.ss_family == AF_UNSPEC || name.storage.ss_family == AF_INET) { gsock = g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_TCP, NULL); name.storage.ss_family = AF_INET; #ifdef HAVE_SA_LEN name.storage.ss_len = sizeof (struct sockaddr_in); #endif } else if (name.storage.ss_family == AF_INET6) { gsock = g_socket_new (G_SOCKET_FAMILY_IPV6, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_TCP, NULL); name.storage.ss_family = AF_INET6; #ifdef HAVE_SA_LEN name.storage.ss_len = sizeof (struct sockaddr_in6); #endif } if (gsock == NULL) { g_slice_free (NiceSocket, sock); return NULL; } gaddr = g_socket_address_new_from_native (&name.addr, sizeof (name)); if (gaddr == NULL) { g_object_unref (gsock); g_slice_free (NiceSocket, sock); return NULL; } /* GSocket: All socket file descriptors are set to be close-on-exec. */ g_socket_set_blocking (gsock, false); gret = g_socket_connect (gsock, gaddr, NULL, &gerr); g_object_unref (gaddr); if (gret == FALSE) { if (g_error_matches (gerr, G_IO_ERROR, G_IO_ERROR_PENDING) == FALSE) { g_error_free (gerr); g_socket_close (gsock, NULL); g_object_unref (gsock); g_slice_free (NiceSocket, sock); return NULL; } g_error_free (gerr); } gaddr = g_socket_get_local_address (gsock, NULL); if (gaddr == NULL || !g_socket_address_to_native (gaddr, &name.addr, sizeof (name), NULL)) { g_slice_free (NiceSocket, sock); g_socket_close (gsock, NULL); g_object_unref (gsock); return NULL; } g_object_unref (gaddr); nice_address_set_from_sockaddr (&sock->addr, &name.addr); sock->priv = priv = g_slice_new0 (TcpPriv); if (ctx == NULL) ctx = g_main_context_default (); priv->context = g_main_context_ref (ctx); priv->server_addr = *addr; priv->error = FALSE; sock->fileno = gsock; sock->send_messages = socket_send_messages; sock->recv_messages = socket_recv_messages; sock->is_reliable = socket_is_reliable; sock->close = socket_close; return sock; }
static gboolean gst_tcp_mix_src_listen (GstTCPMixSrc * src, GstTCPMixSrcPad * pad) { GError *err = NULL; GInetAddress *addr; GSocketAddress *saddr; GResolver *resolver; gint bound_port = 0; gchar *ip; /* look up name if we need to */ addr = g_inet_address_new_from_string (src->host); if (!addr) { GList *results; resolver = g_resolver_get_default (); results = g_resolver_lookup_by_name (resolver, src->host, src->cancellable, &err); if (!results) goto resolve_no_name; addr = G_INET_ADDRESS (g_object_ref (results->data)); g_resolver_free_addresses (results); g_object_unref (resolver); } /* get IP address */ ip = g_inet_address_to_string (addr); saddr = g_inet_socket_address_new (addr, src->server_port); g_object_unref (addr); /* create the server listener socket */ src->server_socket = g_socket_new (g_socket_address_get_family (saddr), G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_TCP, &err); if (!src->server_socket) goto socket_new_failed; /* bind it */ if (!g_socket_bind (src->server_socket, saddr, TRUE, &err)) goto socket_bind_failed; g_object_unref (saddr); g_socket_set_listen_backlog (src->server_socket, TCP_BACKLOG); if (!g_socket_listen (src->server_socket, &err)) goto socket_listen_failed; GST_OBJECT_FLAG_SET (src, GST_TCP_MIX_SRC_OPEN); if (src->server_port == 0) { saddr = g_socket_get_local_address (src->server_socket, NULL); bound_port = g_inet_socket_address_get_port ((GInetSocketAddress *) saddr); g_object_unref (saddr); } else { bound_port = src->server_port; } GST_DEBUG_OBJECT (src, "Listening on %s (%s:%d)", src->host, ip, bound_port); g_free (ip); g_atomic_int_set (&src->bound_port, bound_port); g_object_notify (G_OBJECT (src), "bound-port"); return TRUE; /* Handling Errors */ resolve_no_name: { if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { GST_DEBUG_OBJECT (src, "Cancelled name resolval"); } else { GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), ("Failed to resolve host '%s': %s", src->host, err->message)); } g_clear_error (&err); g_object_unref (resolver); return FALSE; } socket_new_failed: { GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), ("Failed to create socket: %s", err->message)); g_clear_error (&err); g_object_unref (saddr); return FALSE; } socket_bind_failed: { if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { GST_DEBUG_OBJECT (src, "Cancelled binding"); } else { GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), ("Failed to bind on host '%s:%d': %s", src->host, src->server_port, err->message)); } g_clear_error (&err); g_object_unref (saddr); gst_tcp_mix_src_stop (src, pad); return FALSE; } socket_listen_failed: { if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { GST_DEBUG_OBJECT (src, "Cancelled listening"); } else { GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), ("Failed to listen on host '%s:%d': %s", src->host, src->server_port, err->message)); } g_clear_error (&err); gst_tcp_mix_src_stop (src, pad); return FALSE; } }
static gboolean gst_net_client_clock_start (GstNetClientClock * self) { GSocketAddress *servaddr; GSocketAddress *myaddr; GInetAddress *inetaddr; GSocket *socket; GError *error = NULL; g_return_val_if_fail (self->priv->address != NULL, FALSE); g_return_val_if_fail (self->priv->servaddr == NULL, FALSE); socket = g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &error); if (socket == NULL) goto no_socket; /* check address we're bound to, mostly for debugging purposes */ myaddr = g_socket_get_local_address (socket, &error); if (myaddr == NULL) goto getsockname_error; GST_DEBUG_OBJECT (self, "socket opened on UDP port %hd", g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (myaddr))); g_object_unref (myaddr); /* create target address */ inetaddr = g_inet_address_new_from_string (self->priv->address); if (inetaddr == NULL) goto bad_address; servaddr = g_inet_socket_address_new (inetaddr, self->priv->port); g_object_unref (inetaddr); g_assert (servaddr != NULL); GST_DEBUG_OBJECT (self, "will communicate with %s:%d", self->priv->address, self->priv->port); self->priv->cancel = g_cancellable_new (); self->priv->socket = socket; self->priv->servaddr = G_SOCKET_ADDRESS (servaddr); self->priv->thread = g_thread_try_new ("GstNetClientClock", gst_net_client_clock_thread, self, &error); if (error != NULL) goto no_thread; return TRUE; /* ERRORS */ no_socket: { GST_ERROR_OBJECT (self, "socket_new() failed: %s", error->message); g_error_free (error); return FALSE; } getsockname_error: { GST_ERROR_OBJECT (self, "get_local_address() failed: %s", error->message); g_error_free (error); g_object_unref (socket); return FALSE; } bad_address: { GST_ERROR_OBJECT (self, "inet_address_new_from_string('%s') failed", self->priv->address); g_object_unref (socket); return FALSE; } no_thread: { GST_ERROR_OBJECT (self, "could not create thread: %s", error->message); g_object_unref (self->priv->servaddr); self->priv->servaddr = NULL; g_object_unref (self->priv->socket); self->priv->socket = NULL; g_error_free (error); return FALSE; } }
/* create a socket for sending to remote machine */ static gboolean gst_udpsrc_start (GstBaseSrc * bsrc) { GstUDPSrc *src; GInetAddress *addr, *bind_addr; GSocketAddress *bind_saddr; GResolver *resolver; GError *err = NULL; src = GST_UDPSRC (bsrc); if (src->socket == NULL) { /* need to allocate a socket */ GST_DEBUG_OBJECT (src, "allocating socket for %s:%d", src->host, src->port); addr = g_inet_address_new_from_string (src->host); if (!addr) { GList *results; GST_DEBUG_OBJECT (src, "resolving IP address for host %s", src->host); resolver = g_resolver_get_default (); results = g_resolver_lookup_by_name (resolver, src->host, src->cancellable, &err); if (!results) goto name_resolve; addr = G_INET_ADDRESS (g_object_ref (results->data)); g_resolver_free_addresses (results); g_object_unref (resolver); } #ifndef GST_DISABLE_GST_DEBUG { gchar *ip = g_inet_address_to_string (addr); GST_DEBUG_OBJECT (src, "IP address for host %s is %s", src->host, ip); g_free (ip); } #endif if ((src->used_socket = g_socket_new (g_inet_address_get_family (addr), G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &err)) == NULL) goto no_socket; src->external_socket = FALSE; GST_DEBUG_OBJECT (src, "got socket %p", src->used_socket); if (src->addr) g_object_unref (src->addr); src->addr = G_INET_SOCKET_ADDRESS (g_inet_socket_address_new (addr, src->port)); GST_DEBUG_OBJECT (src, "binding on port %d", src->port); if (g_inet_address_get_is_multicast (addr)) bind_addr = g_inet_address_new_any (g_inet_address_get_family (addr)); else bind_addr = G_INET_ADDRESS (g_object_ref (addr)); g_object_unref (addr); bind_saddr = g_inet_socket_address_new (bind_addr, src->port); g_object_unref (bind_addr); if (!g_socket_bind (src->used_socket, bind_saddr, src->reuse, &err)) goto bind_error; g_object_unref (bind_saddr); } else { GST_DEBUG_OBJECT (src, "using provided socket %p", src->socket); /* we use the configured socket, try to get some info about it */ src->used_socket = G_SOCKET (g_object_ref (src->socket)); src->external_socket = TRUE; if (src->addr) g_object_unref (src->addr); src->addr = G_INET_SOCKET_ADDRESS (g_socket_get_local_address (src->used_socket, &err)); if (!src->addr) goto getsockname_error; } #if GLIB_CHECK_VERSION (2, 35, 7) { gint val = 0; if (src->buffer_size != 0) { GError *opt_err = NULL; GST_INFO_OBJECT (src, "setting udp buffer of %d bytes", src->buffer_size); /* set buffer size, Note that on Linux this is typically limited to a * maximum of around 100K. Also a minimum of 128 bytes is required on * Linux. */ if (!g_socket_set_option (src->used_socket, SOL_SOCKET, SO_RCVBUF, src->buffer_size, &opt_err)) { GST_ELEMENT_WARNING (src, RESOURCE, SETTINGS, (NULL), ("Could not create a buffer of requested %d bytes: %s", src->buffer_size, opt_err->message)); g_error_free (opt_err); opt_err = NULL; } } /* read the value of the receive buffer. Note that on linux this returns * 2x the value we set because the kernel allocates extra memory for * metadata. The default on Linux is about 100K (which is about 50K * without metadata) */ if (g_socket_get_option (src->used_socket, SOL_SOCKET, SO_RCVBUF, &val, NULL)) { GST_INFO_OBJECT (src, "have udp buffer of %d bytes", val); } else { GST_DEBUG_OBJECT (src, "could not get udp buffer size"); } } #elif defined (SO_RCVBUF) { gint rcvsize, ret; socklen_t len; len = sizeof (rcvsize); if (src->buffer_size != 0) { rcvsize = src->buffer_size; GST_DEBUG_OBJECT (src, "setting udp buffer of %d bytes", rcvsize); /* set buffer size, Note that on Linux this is typically limited to a * maximum of around 100K. Also a minimum of 128 bytes is required on * Linux. */ ret = setsockopt (g_socket_get_fd (src->used_socket), SOL_SOCKET, SO_RCVBUF, (void *) &rcvsize, len); if (ret != 0) { GST_ELEMENT_WARNING (src, RESOURCE, SETTINGS, (NULL), ("Could not create a buffer of requested %d bytes, %d: %s (%d)", rcvsize, ret, g_strerror (errno), errno)); } } /* read the value of the receive buffer. Note that on linux this returns 2x the * value we set because the kernel allocates extra memory for metadata. * The default on Linux is about 100K (which is about 50K without metadata) */ ret = getsockopt (g_socket_get_fd (src->used_socket), SOL_SOCKET, SO_RCVBUF, (void *) &rcvsize, &len); if (ret == 0) GST_DEBUG_OBJECT (src, "have udp buffer of %d bytes", rcvsize); else GST_DEBUG_OBJECT (src, "could not get udp buffer size"); } #else if (src->buffer_size != 0) { GST_WARNING_OBJECT (src, "don't know how to set udp buffer size on this " "OS. Consider upgrading your GLib to >= 2.35.7 and re-compiling the " "GStreamer udp plugin"); } #endif g_socket_set_broadcast (src->used_socket, TRUE); if (src->auto_multicast && g_inet_address_get_is_multicast (g_inet_socket_address_get_address (src->addr))) { GST_DEBUG_OBJECT (src, "joining multicast group %s", src->host); if (!g_socket_join_multicast_group (src->used_socket, g_inet_socket_address_get_address (src->addr), FALSE, src->multi_iface, &err)) goto membership; } /* NOTE: sockaddr_in.sin_port works for ipv4 and ipv6 because sin_port * follows ss_family on both */ { GInetSocketAddress *addr; guint16 port; addr = G_INET_SOCKET_ADDRESS (g_socket_get_local_address (src->used_socket, &err)); if (!addr) goto getsockname_error; port = g_inet_socket_address_get_port (addr); GST_DEBUG_OBJECT (src, "bound, on port %d", port); if (port != src->port) { src->port = port; GST_DEBUG_OBJECT (src, "notifying port %d", port); g_object_notify (G_OBJECT (src), "port"); } g_object_unref (addr); } return TRUE; /* ERRORS */ name_resolve: { GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL), ("Name resolval failed: %s", err->message)); g_clear_error (&err); g_object_unref (resolver); return FALSE; } no_socket: { GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), ("no socket error: %s", err->message)); g_clear_error (&err); g_object_unref (addr); return FALSE; } bind_error: { GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL), ("bind failed: %s", err->message)); g_clear_error (&err); g_object_unref (bind_saddr); gst_udpsrc_stop (GST_BASE_SRC (src)); return FALSE; } membership: { GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL), ("could add membership: %s", err->message)); g_clear_error (&err); gst_udpsrc_stop (GST_BASE_SRC (src)); return FALSE; } getsockname_error: { GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL), ("getsockname failed: %s", err->message)); g_clear_error (&err); gst_udpsrc_stop (GST_BASE_SRC (src)); return FALSE; } }
/* create a socket for sending to remote machine */ static gboolean gst_udpsrc_open (GstUDPSrc * src) { GInetAddress *addr, *bind_addr; GSocketAddress *bind_saddr; GError *err = NULL; if (src->socket == NULL) { /* need to allocate a socket */ GST_DEBUG_OBJECT (src, "allocating socket for %s:%d", src->address, src->port); addr = gst_udpsrc_resolve (src, src->address); if (!addr) goto name_resolve; if ((src->used_socket = g_socket_new (g_inet_address_get_family (addr), G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &err)) == NULL) goto no_socket; src->external_socket = FALSE; GST_DEBUG_OBJECT (src, "got socket %p", src->used_socket); if (src->addr) g_object_unref (src->addr); src->addr = G_INET_SOCKET_ADDRESS (g_inet_socket_address_new (addr, src->port)); GST_DEBUG_OBJECT (src, "binding on port %d", src->port); /* On Windows it's not possible to bind to a multicast address * but the OS will make sure to filter out all packets that * arrive not for the multicast address the socket joined. * * On Linux and others it is necessary to bind to a multicast * address to let the OS filter out all packets that are received * on the same port but for different addresses than the multicast * address */ #ifdef G_OS_WIN32 if (g_inet_address_get_is_multicast (addr)) bind_addr = g_inet_address_new_any (g_inet_address_get_family (addr)); else #endif bind_addr = G_INET_ADDRESS (g_object_ref (addr)); g_object_unref (addr); bind_saddr = g_inet_socket_address_new (bind_addr, src->port); g_object_unref (bind_addr); if (!g_socket_bind (src->used_socket, bind_saddr, src->reuse, &err)) goto bind_error; g_object_unref (bind_saddr); } else { GST_DEBUG_OBJECT (src, "using provided socket %p", src->socket); /* we use the configured socket, try to get some info about it */ src->used_socket = G_SOCKET (g_object_ref (src->socket)); src->external_socket = TRUE; if (src->addr) g_object_unref (src->addr); src->addr = G_INET_SOCKET_ADDRESS (g_socket_get_local_address (src->used_socket, &err)); if (!src->addr) goto getsockname_error; } #if GLIB_CHECK_VERSION (2, 35, 7) { gint val = 0; if (src->buffer_size != 0) { GError *opt_err = NULL; GST_INFO_OBJECT (src, "setting udp buffer of %d bytes", src->buffer_size); /* set buffer size, Note that on Linux this is typically limited to a * maximum of around 100K. Also a minimum of 128 bytes is required on * Linux. */ if (!g_socket_set_option (src->used_socket, SOL_SOCKET, SO_RCVBUF, src->buffer_size, &opt_err)) { GST_ELEMENT_WARNING (src, RESOURCE, SETTINGS, (NULL), ("Could not create a buffer of requested %d bytes: %s", src->buffer_size, opt_err->message)); g_error_free (opt_err); opt_err = NULL; } } /* read the value of the receive buffer. Note that on linux this returns * 2x the value we set because the kernel allocates extra memory for * metadata. The default on Linux is about 100K (which is about 50K * without metadata) */ if (g_socket_get_option (src->used_socket, SOL_SOCKET, SO_RCVBUF, &val, NULL)) { GST_INFO_OBJECT (src, "have udp buffer of %d bytes", val); } else { GST_DEBUG_OBJECT (src, "could not get udp buffer size"); } } #elif defined (SO_RCVBUF) { gint rcvsize, ret; socklen_t len; len = sizeof (rcvsize); if (src->buffer_size != 0) { rcvsize = src->buffer_size; GST_DEBUG_OBJECT (src, "setting udp buffer of %d bytes", rcvsize); /* set buffer size, Note that on Linux this is typically limited to a * maximum of around 100K. Also a minimum of 128 bytes is required on * Linux. */ ret = setsockopt (g_socket_get_fd (src->used_socket), SOL_SOCKET, SO_RCVBUF, (void *) &rcvsize, len); if (ret != 0) { GST_ELEMENT_WARNING (src, RESOURCE, SETTINGS, (NULL), ("Could not create a buffer of requested %d bytes, %d: %s (%d)", rcvsize, ret, g_strerror (errno), errno)); } } /* read the value of the receive buffer. Note that on linux this returns 2x the * value we set because the kernel allocates extra memory for metadata. * The default on Linux is about 100K (which is about 50K without metadata) */ ret = getsockopt (g_socket_get_fd (src->used_socket), SOL_SOCKET, SO_RCVBUF, (void *) &rcvsize, &len); if (ret == 0) GST_DEBUG_OBJECT (src, "have udp buffer of %d bytes", rcvsize); else GST_DEBUG_OBJECT (src, "could not get udp buffer size"); } #else if (src->buffer_size != 0) { GST_WARNING_OBJECT (src, "don't know how to set udp buffer size on this " "OS. Consider upgrading your GLib to >= 2.35.7 and re-compiling the " "GStreamer udp plugin"); } #endif g_socket_set_broadcast (src->used_socket, TRUE); if (src->auto_multicast && g_inet_address_get_is_multicast (g_inet_socket_address_get_address (src->addr))) { GST_DEBUG_OBJECT (src, "joining multicast group %s", src->address); if (!g_socket_join_multicast_group (src->used_socket, g_inet_socket_address_get_address (src->addr), FALSE, src->multi_iface, &err)) goto membership; } /* NOTE: sockaddr_in.sin_port works for ipv4 and ipv6 because sin_port * follows ss_family on both */ { GInetSocketAddress *addr; guint16 port; addr = G_INET_SOCKET_ADDRESS (g_socket_get_local_address (src->used_socket, &err)); if (!addr) goto getsockname_error; port = g_inet_socket_address_get_port (addr); GST_DEBUG_OBJECT (src, "bound, on port %d", port); if (port != src->port) { src->port = port; GST_DEBUG_OBJECT (src, "notifying port %d", port); g_object_notify (G_OBJECT (src), "port"); } g_object_unref (addr); } src->allocator = NULL; gst_allocation_params_init (&src->params); src->max_size = 0; return TRUE; /* ERRORS */ name_resolve: { return FALSE; } no_socket: { GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), ("no socket error: %s", err->message)); g_clear_error (&err); g_object_unref (addr); return FALSE; } bind_error: { GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL), ("bind failed: %s", err->message)); g_clear_error (&err); g_object_unref (bind_saddr); gst_udpsrc_close (src); return FALSE; } membership: { GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL), ("could add membership: %s", err->message)); g_clear_error (&err); gst_udpsrc_close (src); return FALSE; } getsockname_error: { GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL), ("getsockname failed: %s", err->message)); g_clear_error (&err); gst_udpsrc_close (src); return FALSE; } }
/** * g_socket_listener_add_any_inet_port: * @listener: a #GSocketListener * @source_object: (allow-none): Optional #GObject identifying this source * @error: a #GError location to store the error occurring, or %NULL to * ignore. * * Listens for TCP connections on any available port number for both * IPv6 and IPv4 (if each is available). * * This is useful if you need to have a socket for incoming connections * but don't care about the specific port number. * * @source_object will be passed out in the various calls * to accept to identify this particular source, which is * useful if you're listening on multiple addresses and do * different things depending on what address is connected to. * * Returns: the port number, or 0 in case of failure. * * Since: 2.24 **/ guint16 g_socket_listener_add_any_inet_port (GSocketListener *listener, GObject *source_object, GError **error) { GSList *sockets_to_close = NULL; guint16 candidate_port = 0; GSocket *socket6 = NULL; GSocket *socket4 = NULL; gint attempts = 37; /* * multi-step process: * - first, create an IPv6 socket. * - if that fails, create an IPv4 socket and bind it to port 0 and * that's it. no retries if that fails (why would it?). * - if our IPv6 socket also speaks IPv4 then we are done. * - if not, then we need to create a IPv4 socket with the same port * number. this might fail, of course. so we try this a bunch of * times -- leaving the old IPv6 sockets open so that we get a * different port number to try each time. * - if all that fails then just give up. */ while (attempts--) { GInetAddress *inet_address; GSocketAddress *address; gboolean result; g_assert (socket6 == NULL); socket6 = g_socket_new (G_SOCKET_FAMILY_IPV6, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, NULL); if (socket6 != NULL) { inet_address = g_inet_address_new_any (G_SOCKET_FAMILY_IPV6); address = g_inet_socket_address_new (inet_address, 0); g_object_unref (inet_address); result = g_socket_bind (socket6, address, TRUE, error); g_object_unref (address); if (!result || !(address = g_socket_get_local_address (socket6, error))) { g_object_unref (socket6); socket6 = NULL; break; } g_assert (G_IS_INET_SOCKET_ADDRESS (address)); candidate_port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (address)); g_assert (candidate_port != 0); g_object_unref (address); if (g_socket_speaks_ipv4 (socket6)) break; } g_assert (socket4 == NULL); socket4 = g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, socket6 ? NULL : error); if (socket4 == NULL) /* IPv4 not supported. * if IPv6 is supported then candidate_port will be non-zero * (and the error parameter above will have been NULL) * if IPv6 is unsupported then candidate_port will be zero * (and error will have been set by the above call) */ break; inet_address = g_inet_address_new_any (G_SOCKET_FAMILY_IPV4); address = g_inet_socket_address_new (inet_address, candidate_port); g_object_unref (inet_address); /* a note on the 'error' clause below: * * if candidate_port is 0 then we report the error right away * since it is strange that this binding would fail at all. * otherwise, we ignore the error message (ie: NULL). * * the exception to this rule is the last time through the loop * (ie: attempts == 0) in which case we want to set the error * because failure here means that the entire call will fail and * we need something to show to the user. * * an english summary of the situation: "if we gave a candidate * port number AND we have more attempts to try, then ignore the * error for now". */ result = g_socket_bind (socket4, address, TRUE, (candidate_port && attempts) ? NULL : error); g_object_unref (address); if (candidate_port) { g_assert (socket6 != NULL); if (result) /* got our candidate port successfully */ break; else /* we failed to bind to the specified port. try again. */ { g_object_unref (socket4); socket4 = NULL; /* keep this open so we get a different port number */ sockets_to_close = g_slist_prepend (sockets_to_close, socket6); candidate_port = 0; socket6 = NULL; } } else /* we didn't tell it a port. this means two things. * - if we failed, then something really bad happened. * - if we succeeded, then we need to find out the port number. */ { g_assert (socket6 == NULL); if (!result || !(address = g_socket_get_local_address (socket4, error))) { g_object_unref (socket4); socket4 = NULL; break; } g_assert (G_IS_INET_SOCKET_ADDRESS (address)); candidate_port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (address)); g_assert (candidate_port != 0); g_object_unref (address); break; } } /* should only be non-zero if we have a socket */ g_assert ((candidate_port != 0) == (socket4 || socket6)); while (sockets_to_close) { g_object_unref (sockets_to_close->data); sockets_to_close = g_slist_delete_link (sockets_to_close, sockets_to_close); } /* now we actually listen() the sockets and add them to the listener */ if (socket6 != NULL) { g_socket_set_listen_backlog (socket6, listener->priv->listen_backlog); if (!g_socket_listen (socket6, error)) { g_object_unref (socket6); if (socket4) g_object_unref (socket4); return 0; } if (source_object) g_object_set_qdata_full (G_OBJECT (socket6), source_quark, g_object_ref (source_object), g_object_unref); g_ptr_array_add (listener->priv->sockets, socket6); } if (socket4 != NULL) { g_socket_set_listen_backlog (socket4, listener->priv->listen_backlog); if (!g_socket_listen (socket4, error)) { g_object_unref (socket4); if (socket6) g_object_unref (socket6); return 0; } if (source_object) g_object_set_qdata_full (G_OBJECT (socket4), source_quark, g_object_ref (source_object), g_object_unref); g_ptr_array_add (listener->priv->sockets, socket4); } if ((socket4 != NULL || socket6 != NULL) && G_SOCKET_LISTENER_GET_CLASS (listener)->changed) G_SOCKET_LISTENER_GET_CLASS (listener)->changed (listener); return candidate_port; }
static GSocket * gst_switch_server_listen (GstSwitchServer *srv, gint port, gint *bound_port) { GError *err = NULL; GInetAddress *addr; GSocket *socket = NULL; GSocketAddress *saddr; GResolver *resolver; gchar *ip; *bound_port = 0; /* look up name if we need to */ addr = g_inet_address_new_from_string (srv->host); if (!addr) { GList *results; resolver = g_resolver_get_default (); results = g_resolver_lookup_by_name (resolver, srv->host, srv->cancellable, &err); if (!results) goto resolve_no_name; addr = G_INET_ADDRESS (g_object_ref (results->data)); g_resolver_free_addresses (results); g_object_unref (resolver); } ip = g_inet_address_to_string (addr); saddr = g_inet_socket_address_new (addr, port); g_object_unref (addr); /* create the server listener socket */ socket = g_socket_new (g_socket_address_get_family (saddr), G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_TCP, &err); if (!socket) goto socket_new_failed; /* bind it */ if (!g_socket_bind (socket, saddr, TRUE, &err)) goto socket_bind_failed; g_object_unref (saddr); /* listen on the socket */ g_socket_set_listen_backlog (socket, GST_SWITCH_SERVER_LISTEN_BACKLOG); if (!g_socket_listen (socket, &err)) goto socket_listen_failed; if (port == 0) { saddr = g_socket_get_local_address (socket, NULL); *bound_port = g_inet_socket_address_get_port ((GInetSocketAddress *) saddr); g_object_unref (saddr); } else { *bound_port = port; } INFO ("Listening on %s (%s:%d)", srv->host, ip, *bound_port); g_free (ip); //g_atomic_int_set (&srv->bound_port, bound_port); //g_object_notify (G_OBJECT (src), "bound-port"); return socket; /* Errors Handling */ resolve_no_name: { ERROR ("resolve: %s", err->message); g_object_unref (resolver); g_object_unref (addr); return NULL; } socket_new_failed: { ERROR ("new socket: %s", err->message); g_clear_error (&err); g_object_unref (saddr); g_free (ip); return NULL; } socket_bind_failed: { ERROR ("bind socket: %s", err->message); g_clear_error (&err); g_object_unref (saddr); g_free (ip); return NULL; } socket_listen_failed: { ERROR ("listen socket: %s", err->message); g_clear_error (&err); g_object_unref (saddr); g_free (ip); return NULL; } }
int main (int argc, char *argv[]) { GSocket *socket; GSocketAddress *src_address; GSocketAddress *address; GSocketType socket_type; GSocketFamily socket_family; GError *error = NULL; GOptionContext *context; GCancellable *cancellable; GSocketAddressEnumerator *enumerator; GSocketConnectable *connectable; g_thread_init (NULL); g_type_init (); context = g_option_context_new (" <hostname>[:port] - Test GSocket client stuff"); g_option_context_add_main_entries (context, cmd_entries, NULL); if (!g_option_context_parse (context, &argc, &argv, &error)) { g_printerr ("%s: %s\n", argv[0], error->message); return 1; } if (argc != 2) { g_printerr ("%s: %s\n", argv[0], "Need to specify hostname / unix socket name"); return 1; } if (cancel_timeout) { cancellable = g_cancellable_new (); g_thread_create (cancel_thread, cancellable, FALSE, NULL); } else { cancellable = NULL; } loop = g_main_loop_new (NULL, FALSE); if (use_udp) socket_type = G_SOCKET_TYPE_DATAGRAM; else socket_type = G_SOCKET_TYPE_STREAM; if (unix_socket) socket_family = G_SOCKET_FAMILY_UNIX; else socket_family = G_SOCKET_FAMILY_IPV4; socket = g_socket_new (socket_family, socket_type, 0, &error); if (socket == NULL) { g_printerr ("%s: %s\n", argv[0], error->message); return 1; } if (read_timeout) g_socket_set_timeout (socket, read_timeout); if (unix_socket) { GSocketAddress *addr; addr = socket_address_from_string (argv[1]); if (addr == NULL) { g_printerr ("%s: Could not parse '%s' as unix socket name\n", argv[0], argv[1]); return 1; } connectable = G_SOCKET_CONNECTABLE (addr); } else { connectable = g_network_address_parse (argv[1], 7777, &error); if (connectable == NULL) { g_printerr ("%s: %s\n", argv[0], error->message); return 1; } } enumerator = g_socket_connectable_enumerate (connectable); while (TRUE) { address = g_socket_address_enumerator_next (enumerator, cancellable, &error); if (address == NULL) { if (error == NULL) g_printerr ("%s: No more addresses to try\n", argv[0]); else g_printerr ("%s: %s\n", argv[0], error->message); return 1; } if (g_socket_connect (socket, address, cancellable, &error)) break; g_printerr ("%s: Connection to %s failed: %s, trying next\n", argv[0], socket_address_to_string (address), error->message); g_error_free (error); error = NULL; g_object_unref (address); } g_object_unref (enumerator); g_object_unref (connectable); g_print ("Connected to %s\n", socket_address_to_string (address)); /* TODO: Test non-blocking connect */ if (non_blocking) g_socket_set_blocking (socket, FALSE); src_address = g_socket_get_local_address (socket, &error); if (!src_address) { g_printerr ("Error getting local address: %s\n", error->message); return 1; } g_print ("local address: %s\n", socket_address_to_string (src_address)); g_object_unref (src_address); while (TRUE) { gchar buffer[4096]; gssize size; gsize to_send; if (fgets (buffer, sizeof buffer, stdin) == NULL) break; to_send = strlen (buffer); while (to_send > 0) { ensure_condition (socket, "send", cancellable, G_IO_OUT); if (use_udp) size = g_socket_send_to (socket, address, buffer, to_send, cancellable, &error); else size = g_socket_send (socket, buffer, to_send, cancellable, &error); if (size < 0) { if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { g_print ("socket send would block, handling\n"); g_error_free (error); error = NULL; continue; } else { g_printerr ("Error sending to socket: %s\n", error->message); return 1; } } g_print ("sent %" G_GSSIZE_FORMAT " bytes of data\n", size); if (size == 0) { g_printerr ("Unexpected short write\n"); return 1; } to_send -= size; } ensure_condition (socket, "receive", cancellable, G_IO_IN); if (use_udp) size = g_socket_receive_from (socket, &src_address, buffer, sizeof buffer, cancellable, &error); else size = g_socket_receive (socket, buffer, sizeof buffer, cancellable, &error); if (size < 0) { g_printerr ("Error receiving from socket: %s\n", error->message); return 1; } if (size == 0) break; g_print ("received %" G_GSSIZE_FORMAT " bytes of data", size); if (use_udp) g_print (" from %s", socket_address_to_string (src_address)); g_print ("\n"); if (verbose) g_print ("-------------------------\n" "%.*s" "-------------------------\n", (int)size, buffer); } g_print ("closing socket\n"); if (!g_socket_close (socket, &error)) { g_printerr ("Error closing master socket: %s\n", error->message); return 1; } g_object_unref (G_OBJECT (socket)); g_object_unref (G_OBJECT (address)); return 0; }
static gboolean gst_net_client_internal_clock_start (GstNetClientInternalClock * self) { GSocketAddress *servaddr; GSocketAddress *myaddr; GSocketAddress *anyaddr; GInetAddress *inetaddr; GSocket *socket; GError *error = NULL; GSocketFamily family; GPollFD dummy_pollfd; GResolver *resolver = NULL; GError *err = NULL; g_return_val_if_fail (self->address != NULL, FALSE); g_return_val_if_fail (self->servaddr == NULL, FALSE); /* create target address */ inetaddr = g_inet_address_new_from_string (self->address); if (inetaddr == NULL) { GList *results; resolver = g_resolver_get_default (); results = g_resolver_lookup_by_name (resolver, self->address, NULL, &err); if (!results) goto failed_to_resolve; inetaddr = G_INET_ADDRESS (g_object_ref (results->data)); g_resolver_free_addresses (results); g_object_unref (resolver); } family = g_inet_address_get_family (inetaddr); servaddr = g_inet_socket_address_new (inetaddr, self->port); g_object_unref (inetaddr); g_assert (servaddr != NULL); GST_DEBUG_OBJECT (self, "will communicate with %s:%d", self->address, self->port); socket = g_socket_new (family, G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &error); if (socket == NULL) goto no_socket; GST_DEBUG_OBJECT (self, "binding socket"); inetaddr = g_inet_address_new_any (family); anyaddr = g_inet_socket_address_new (inetaddr, 0); g_socket_bind (socket, anyaddr, TRUE, &error); g_object_unref (anyaddr); g_object_unref (inetaddr); if (error != NULL) goto bind_error; /* check address we're bound to, mostly for debugging purposes */ myaddr = g_socket_get_local_address (socket, &error); if (myaddr == NULL) goto getsockname_error; GST_DEBUG_OBJECT (self, "socket opened on UDP port %d", g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (myaddr))); g_object_unref (myaddr); self->cancel = g_cancellable_new (); self->made_cancel_fd = g_cancellable_make_pollfd (self->cancel, &dummy_pollfd); self->socket = socket; self->servaddr = G_SOCKET_ADDRESS (servaddr); self->thread = g_thread_try_new ("GstNetClientInternalClock", gst_net_client_internal_clock_thread, self, &error); if (error != NULL) goto no_thread; return TRUE; /* ERRORS */ no_socket: { GST_ERROR_OBJECT (self, "socket_new() failed: %s", error->message); g_error_free (error); return FALSE; } bind_error: { GST_ERROR_OBJECT (self, "bind failed: %s", error->message); g_error_free (error); g_object_unref (socket); return FALSE; } getsockname_error: { GST_ERROR_OBJECT (self, "get_local_address() failed: %s", error->message); g_error_free (error); g_object_unref (socket); return FALSE; } failed_to_resolve: { GST_ERROR_OBJECT (self, "resolving '%s' failed: %s", self->address, err->message); g_clear_error (&err); g_object_unref (resolver); return FALSE; } no_thread: { GST_ERROR_OBJECT (self, "could not create thread: %s", error->message); g_object_unref (self->servaddr); self->servaddr = NULL; g_object_unref (self->socket); self->socket = NULL; g_error_free (error); return FALSE; } }
NiceSocket * nice_tcp_passive_socket_new (GMainContext *ctx, NiceAddress *addr) { union { struct sockaddr_storage storage; struct sockaddr addr; } name; NiceSocket *sock; TcpPassivePriv *priv; GSocket *gsock = NULL; gboolean gret = FALSE; GSocketAddress *gaddr; if (addr != NULL) { nice_address_copy_to_sockaddr(addr, &name.addr); } else { memset (&name, 0, sizeof (name)); name.storage.ss_family = AF_UNSPEC; } if (name.storage.ss_family == AF_UNSPEC || name.storage.ss_family == AF_INET) { gsock = g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_TCP, NULL); name.storage.ss_family = AF_INET; #ifdef HAVE_SA_LEN name.storage.ss_len = sizeof (struct sockaddr_in); #endif } else if (name.storage.ss_family == AF_INET6) { gsock = g_socket_new (G_SOCKET_FAMILY_IPV6, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_TCP, NULL); name.storage.ss_family = AF_INET6; #ifdef HAVE_SA_LEN name.storage.ss_len = sizeof (struct sockaddr_in6); #endif } if (gsock == NULL) { return NULL; } gaddr = g_socket_address_new_from_native (&name.addr, sizeof (name)); if (gaddr == NULL) { g_object_unref (gsock); return NULL; } /* GSocket: All socket file descriptors are set to be close-on-exec. */ g_socket_set_blocking (gsock, false); gret = g_socket_bind (gsock, gaddr, FALSE, NULL) && g_socket_listen (gsock, NULL); g_object_unref (gaddr); if (gret == FALSE) { g_socket_close (gsock, NULL); g_object_unref (gsock); return NULL; } gaddr = g_socket_get_local_address (gsock, NULL); if (gaddr == NULL || !g_socket_address_to_native (gaddr, &name.addr, sizeof (name), NULL)) { g_socket_close (gsock, NULL); g_object_unref (gsock); return NULL; } g_object_unref (gaddr); if (ctx == NULL) { ctx = g_main_context_default (); } sock = g_slice_new0 (NiceSocket); nice_address_set_from_sockaddr (&sock->addr, &name.addr); sock->priv = priv = g_slice_new0 (TcpPassivePriv); priv->context = g_main_context_ref (ctx); priv->connections = g_hash_table_new_full ((GHashFunc) nice_address_hash, (GEqualFunc) nice_address_equal, ( GDestroyNotify) nice_address_free, NULL); priv->writable_cb = NULL; priv->writable_data = NULL; sock->type = NICE_SOCKET_TYPE_TCP_PASSIVE; sock->fileno = gsock; sock->send_messages = socket_send_messages; sock->send_messages_reliable = socket_send_messages_reliable; sock->recv_messages = socket_recv_messages; sock->is_reliable = socket_is_reliable; sock->can_send = socket_can_send; sock->set_writable_callback = socket_set_writable_callback; sock->close = socket_close; return sock; }
static gboolean make_connection (const char *argument, GTlsCertificate *certificate, GCancellable *cancellable, GSocket **socket, GSocketAddress **address, GIOStream **connection, GInputStream **istream, GOutputStream **ostream, GError **error) { GSocketType socket_type; GSocketFamily socket_family; GSocketAddressEnumerator *enumerator; GSocketConnectable *connectable; GSocketAddress *src_address; GTlsInteraction *interaction; GError *err = NULL; if (use_udp) socket_type = G_SOCKET_TYPE_DATAGRAM; else socket_type = G_SOCKET_TYPE_STREAM; if (unix_socket) socket_family = G_SOCKET_FAMILY_UNIX; else socket_family = G_SOCKET_FAMILY_IPV4; *socket = g_socket_new (socket_family, socket_type, 0, error); if (*socket == NULL) return FALSE; if (read_timeout) g_socket_set_timeout (*socket, read_timeout); if (unix_socket) { GSocketAddress *addr; addr = socket_address_from_string (argument); if (addr == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Could not parse '%s' as unix socket name", argument); return FALSE; } connectable = G_SOCKET_CONNECTABLE (addr); } else { connectable = g_network_address_parse (argument, 7777, error); if (connectable == NULL) return FALSE; } enumerator = g_socket_connectable_enumerate (connectable); while (TRUE) { *address = g_socket_address_enumerator_next (enumerator, cancellable, error); if (*address == NULL) { if (error != NULL && *error == NULL) g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, "No more addresses to try"); return FALSE; } if (g_socket_connect (*socket, *address, cancellable, &err)) break; g_message ("Connection to %s failed: %s, trying next", socket_address_to_string (*address), err->message); g_clear_error (&err); g_object_unref (*address); } g_object_unref (enumerator); g_print ("Connected to %s\n", socket_address_to_string (*address)); src_address = g_socket_get_local_address (*socket, error); if (!src_address) { g_prefix_error (error, "Error getting local address: "); return FALSE; } g_print ("local address: %s\n", socket_address_to_string (src_address)); g_object_unref (src_address); if (use_udp) { *connection = NULL; *istream = NULL; *ostream = NULL; } else *connection = G_IO_STREAM (g_socket_connection_factory_create_connection (*socket)); if (tls) { GIOStream *tls_conn; tls_conn = g_tls_client_connection_new (*connection, connectable, error); if (!tls_conn) { g_prefix_error (error, "Could not create TLS connection: "); return FALSE; } g_signal_connect (tls_conn, "accept-certificate", G_CALLBACK (accept_certificate), NULL); interaction = g_tls_console_interaction_new (); g_tls_connection_set_interaction (G_TLS_CONNECTION (tls_conn), interaction); g_object_unref (interaction); if (certificate) g_tls_connection_set_certificate (G_TLS_CONNECTION (tls_conn), certificate); g_object_unref (*connection); *connection = G_IO_STREAM (tls_conn); if (!g_tls_connection_handshake (G_TLS_CONNECTION (tls_conn), cancellable, error)) { g_prefix_error (error, "Error during TLS handshake: "); return FALSE; } } g_object_unref (connectable); if (*connection) { *istream = g_io_stream_get_input_stream (*connection); *ostream = g_io_stream_get_output_stream (*connection); } return TRUE; }
/** * tp_stream_tube_channel_accept_async: * @self: an incoming #TpStreamTubeChannel * @callback: a callback to call when the tube has been accepted * @user_data: data to pass to @callback * * Accept an incoming stream tube. When the tube has been accepted, @callback * will be called. You can then call tp_stream_tube_channel_accept_finish() * to get a #TpStreamTubeConnection connected to the tube. * * Since: 0.13.2 */ void tp_stream_tube_channel_accept_async (TpStreamTubeChannel *self, GAsyncReadyCallback callback, gpointer user_data) { GHashTable *properties; GHashTable *supported_sockets; GError *error = NULL; g_return_if_fail (TP_IS_STREAM_TUBE_CHANNEL (self)); g_return_if_fail (self->priv->result == NULL); if (self->priv->access_control_param != NULL) { g_simple_async_report_error_in_idle (G_OBJECT (self), callback, user_data, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Tube has already be accepted"); return; } self->priv->result = g_simple_async_result_new (G_OBJECT (self), callback, user_data, tp_stream_tube_channel_accept_async); properties = _tp_channel_get_immutable_properties (TP_CHANNEL (self)); supported_sockets = tp_asv_get_boxed (properties, TP_PROP_CHANNEL_TYPE_STREAM_TUBE_SUPPORTED_SOCKET_TYPES, TP_HASH_TYPE_SUPPORTED_SOCKET_MAP); if (!_tp_set_socket_address_type_and_access_control_type (supported_sockets, &self->priv->socket_type, &self->priv->access_control, &error)) { operation_failed (self, error); g_clear_error (&error); return; } DEBUG ("Using socket type %u with access control %u", self->priv->socket_type, self->priv->access_control); self->priv->client_socket = _tp_create_client_socket (self->priv->socket_type, &error); if (error != NULL) { DEBUG ("Failed to create socket: %s", error->message); operation_failed (self, error); g_clear_error (&error); return; } switch (self->priv->access_control) { case TP_SOCKET_ACCESS_CONTROL_LOCALHOST: /* Put a dummy value */ self->priv->access_control_param = tp_g_value_slice_new_uint (0); break; case TP_SOCKET_ACCESS_CONTROL_PORT: { GSocketAddress *addr; guint16 port; addr = g_socket_get_local_address (self->priv->client_socket, &error); if (addr == NULL) { DEBUG ("Failed to get local address of client socket: %s", error->message); operation_failed (self, error); g_error_free (error); return; } port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr)); self->priv->access_control_param = tp_g_value_slice_new_uint (port); g_object_unref (addr); } break; case TP_SOCKET_ACCESS_CONTROL_CREDENTIALS: self->priv->access_control_param = tp_g_value_slice_new_byte ( g_random_int_range (0, G_MAXUINT8)); break; default: g_assert_not_reached (); } /* Call Accept */ tp_cli_channel_type_stream_tube_call_accept (TP_CHANNEL (self), -1, self->priv->socket_type, self->priv->access_control, self->priv->access_control_param, _channel_accepted, NULL, NULL, G_OBJECT (self)); }
int main (int argc, char *argv[]) { GSocket *socket, *new_socket, *recv_socket; GSocketAddress *src_address; GSocketAddress *address; GSocketType socket_type; GSocketFamily socket_family; GError *error = NULL; GOptionContext *context; GCancellable *cancellable; char *display_addr; GTlsCertificate *tlscert = NULL; GIOStream *connection; GInputStream *istream; GOutputStream *ostream; g_type_init (); context = g_option_context_new (" - Test GSocket server stuff"); g_option_context_add_main_entries (context, cmd_entries, NULL); if (!g_option_context_parse (context, &argc, &argv, &error)) { g_printerr ("%s: %s\n", argv[0], error->message); return 1; } if (unix_socket && argc != 2) { g_printerr ("%s: %s\n", argv[0], "Need to specify unix socket name"); return 1; } if (cancel_timeout) { GThread *thread; cancellable = g_cancellable_new (); thread = g_thread_new ("cancel", cancel_thread, cancellable); g_thread_unref (thread); } else { cancellable = NULL; } if (tls_cert_file) { if (use_udp) { g_printerr ("DTLS (TLS over UDP) is not supported"); return 1; } tlscert = g_tls_certificate_new_from_file (tls_cert_file, &error); if (!tlscert) { g_printerr ("Could not read server certificate '%s': %s\n", tls_cert_file, error->message); return 1; } } loop = g_main_loop_new (NULL, FALSE); if (use_udp) socket_type = G_SOCKET_TYPE_DATAGRAM; else socket_type = G_SOCKET_TYPE_STREAM; if (unix_socket) socket_family = G_SOCKET_FAMILY_UNIX; else socket_family = G_SOCKET_FAMILY_IPV4; socket = g_socket_new (socket_family, socket_type, 0, &error); if (socket == NULL) { g_printerr ("%s: %s\n", argv[0], error->message); return 1; } if (non_blocking) g_socket_set_blocking (socket, FALSE); if (unix_socket) { src_address = socket_address_from_string (argv[1]); if (src_address == NULL) { g_printerr ("%s: Could not parse '%s' as unix socket name\n", argv[0], argv[1]); return 1; } } else { src_address = g_inet_socket_address_new (g_inet_address_new_any (G_SOCKET_FAMILY_IPV4), port); } if (!g_socket_bind (socket, src_address, !dont_reuse_address, &error)) { g_printerr ("Can't bind socket: %s\n", error->message); return 1; } g_object_unref (src_address); if (!use_udp) { if (!g_socket_listen (socket, &error)) { g_printerr ("Can't listen on socket: %s\n", error->message); return 1; } address = g_socket_get_local_address (socket, &error); if (!address) { g_printerr ("Error getting local address: %s\n", error->message); return 1; } display_addr = socket_address_to_string (address); g_print ("listening on %s...\n", display_addr); g_free (display_addr); ensure_socket_condition (socket, G_IO_IN, cancellable); new_socket = g_socket_accept (socket, cancellable, &error); if (!new_socket) { g_printerr ("Error accepting socket: %s\n", error->message); return 1; } if (non_blocking) g_socket_set_blocking (new_socket, FALSE); if (read_timeout) g_socket_set_timeout (new_socket, read_timeout); address = g_socket_get_remote_address (new_socket, &error); if (!address) { g_printerr ("Error getting remote address: %s\n", error->message); return 1; } display_addr = socket_address_to_string (address); g_print ("got a new connection from %s\n", display_addr); g_free(display_addr); g_object_unref (address); recv_socket = new_socket; connection = G_IO_STREAM (g_socket_connection_factory_create_connection (recv_socket)); g_object_unref (new_socket); } else { recv_socket = socket; connection = NULL; } if (tlscert) { GIOStream *tls_conn; tls_conn = g_tls_server_connection_new (connection, tlscert, &error); if (!tls_conn) { g_printerr ("Could not create TLS connection: %s\n", error->message); return 1; } if (!g_tls_connection_handshake (G_TLS_CONNECTION (tls_conn), cancellable, &error)) { g_printerr ("Error during TLS handshake: %s\n", error->message); return 1; } g_object_unref (connection); connection = tls_conn; } if (connection) { istream = g_io_stream_get_input_stream (connection); ostream = g_io_stream_get_output_stream (connection); } else { g_assert (use_udp); istream = NULL; ostream = NULL; } while (TRUE) { gchar buffer[4096]; gssize size; gsize to_send; if (use_udp) { ensure_socket_condition (recv_socket, G_IO_IN, cancellable); size = g_socket_receive_from (recv_socket, &address, buffer, sizeof buffer, cancellable, &error); } else { ensure_connection_condition (connection, G_IO_IN, cancellable); size = g_input_stream_read (istream, buffer, sizeof buffer, cancellable, &error); } if (size < 0) { g_printerr ("Error receiving from socket: %s\n", error->message); return 1; } if (size == 0) break; g_print ("received %" G_GSSIZE_FORMAT " bytes of data", size); if (use_udp) g_print (" from %s", socket_address_to_string (address)); g_print ("\n"); if (verbose) g_print ("-------------------------\n" "%.*s\n" "-------------------------\n", (int)size, buffer); to_send = size; #ifdef __QNXNTO__ if (delay_) #else if (delay) #endif { #ifdef __QNXNTO__ if (verbose) g_print ("delaying %d seconds before response\n", delay_); g_usleep (1000 * 1000 * delay_); #else if (verbose) g_print ("delaying %d seconds before response\n", delay); g_usleep (1000 * 1000 * delay); #endif } while (to_send > 0) { if (use_udp) { ensure_socket_condition (recv_socket, G_IO_OUT, cancellable); size = g_socket_send_to (recv_socket, address, buffer, to_send, cancellable, &error); } else { ensure_connection_condition (connection, G_IO_OUT, cancellable); size = g_output_stream_write (ostream, buffer, to_send, cancellable, &error); } if (size < 0) { if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { g_print ("socket send would block, handling\n"); g_error_free (error); error = NULL; continue; } else { g_printerr ("Error sending to socket: %s\n", error->message); return 1; } } g_print ("sent %" G_GSSIZE_FORMAT " bytes of data\n", size); if (size == 0) { g_printerr ("Unexpected short write\n"); return 1; } to_send -= size; } } g_print ("connection closed\n"); if (connection) { if (!g_io_stream_close (connection, NULL, &error)) { g_printerr ("Error closing connection stream: %s\n", error->message); return 1; } g_object_unref (connection); } if (!g_socket_close (socket, &error)) { g_printerr ("Error closing master socket: %s\n", error->message); return 1; } g_object_unref (socket); return 0; }
/* create a socket for sending to remote machine */ static gboolean gst_udpsrc_open (GstUDPSrc * src) { GInetAddress *addr, *bind_addr; GSocketAddress *bind_saddr; GError *err = NULL; gst_udpsrc_create_cancellable (src); if (src->socket == NULL) { /* need to allocate a socket */ GST_DEBUG_OBJECT (src, "allocating socket for %s:%d", src->address, src->port); addr = gst_udpsrc_resolve (src, src->address); if (!addr) goto name_resolve; if ((src->used_socket = g_socket_new (g_inet_address_get_family (addr), G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &err)) == NULL) goto no_socket; src->external_socket = FALSE; GST_DEBUG_OBJECT (src, "got socket %p", src->used_socket); if (src->addr) g_object_unref (src->addr); src->addr = G_INET_SOCKET_ADDRESS (g_inet_socket_address_new (addr, src->port)); GST_DEBUG_OBJECT (src, "binding on port %d", src->port); /* On Windows it's not possible to bind to a multicast address * but the OS will make sure to filter out all packets that * arrive not for the multicast address the socket joined. * * On Linux and others it is necessary to bind to a multicast * address to let the OS filter out all packets that are received * on the same port but for different addresses than the multicast * address */ #ifdef G_OS_WIN32 if (g_inet_address_get_is_multicast (addr)) bind_addr = g_inet_address_new_any (g_inet_address_get_family (addr)); else #endif bind_addr = G_INET_ADDRESS (g_object_ref (addr)); g_object_unref (addr); bind_saddr = g_inet_socket_address_new (bind_addr, src->port); g_object_unref (bind_addr); if (!g_socket_bind (src->used_socket, bind_saddr, src->reuse, &err)) goto bind_error; g_object_unref (bind_saddr); g_socket_set_multicast_loopback (src->used_socket, src->loop); } else { GInetSocketAddress *local_addr; GST_DEBUG_OBJECT (src, "using provided socket %p", src->socket); /* we use the configured socket, try to get some info about it */ src->used_socket = G_SOCKET (g_object_ref (src->socket)); src->external_socket = TRUE; local_addr = G_INET_SOCKET_ADDRESS (g_socket_get_local_address (src->used_socket, &err)); if (!local_addr) goto getsockname_error; /* See above for the reasons. Without this we would behave different on * Windows and Linux, joining multicast groups below for provided sockets * on Linux but not on Windows */ #ifdef G_OS_WIN32 addr = gst_udpsrc_resolve (src, src->address); if (!addr) goto name_resolve; if (!src->auto_multicast || !g_inet_address_get_is_any (g_inet_socket_address_get_address (local_addr)) || !g_inet_address_get_is_multicast (addr)) { g_object_unref (addr); #endif if (src->addr) g_object_unref (src->addr); src->addr = local_addr; #ifdef G_OS_WIN32 } else { g_object_unref (local_addr); if (src->addr) g_object_unref (src->addr); src->addr = G_INET_SOCKET_ADDRESS (g_inet_socket_address_new (addr, src->port)); g_object_unref (addr); } #endif } { gint val = 0; if (src->buffer_size != 0) { GError *opt_err = NULL; GST_INFO_OBJECT (src, "setting udp buffer of %d bytes", src->buffer_size); /* set buffer size, Note that on Linux this is typically limited to a * maximum of around 100K. Also a minimum of 128 bytes is required on * Linux. */ if (!g_socket_set_option (src->used_socket, SOL_SOCKET, SO_RCVBUF, src->buffer_size, &opt_err)) { GST_ELEMENT_WARNING (src, RESOURCE, SETTINGS, (NULL), ("Could not create a buffer of requested %d bytes: %s", src->buffer_size, opt_err->message)); g_error_free (opt_err); opt_err = NULL; } } /* read the value of the receive buffer. Note that on linux this returns * 2x the value we set because the kernel allocates extra memory for * metadata. The default on Linux is about 100K (which is about 50K * without metadata) */ if (g_socket_get_option (src->used_socket, SOL_SOCKET, SO_RCVBUF, &val, NULL)) { GST_INFO_OBJECT (src, "have udp buffer of %d bytes", val); } else { GST_DEBUG_OBJECT (src, "could not get udp buffer size"); } } g_socket_set_broadcast (src->used_socket, TRUE); if (src->auto_multicast && g_inet_address_get_is_multicast (g_inet_socket_address_get_address (src->addr))) { GST_DEBUG_OBJECT (src, "joining multicast group %s", src->address); if (!g_socket_join_multicast_group (src->used_socket, g_inet_socket_address_get_address (src->addr), FALSE, src->multi_iface, &err)) goto membership; } /* NOTE: sockaddr_in.sin_port works for ipv4 and ipv6 because sin_port * follows ss_family on both */ { GInetSocketAddress *addr; guint16 port; addr = G_INET_SOCKET_ADDRESS (g_socket_get_local_address (src->used_socket, &err)); if (!addr) goto getsockname_error; port = g_inet_socket_address_get_port (addr); GST_DEBUG_OBJECT (src, "bound, on port %d", port); if (port != src->port) { src->port = port; GST_DEBUG_OBJECT (src, "notifying port %d", port); g_object_notify (G_OBJECT (src), "port"); } g_object_unref (addr); } src->allocator = NULL; gst_allocation_params_init (&src->params); src->max_size = 0; return TRUE; /* ERRORS */ name_resolve: { return FALSE; } no_socket: { GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), ("no socket error: %s", err->message)); g_clear_error (&err); g_object_unref (addr); return FALSE; } bind_error: { GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL), ("bind failed: %s", err->message)); g_clear_error (&err); g_object_unref (bind_saddr); gst_udpsrc_close (src); return FALSE; } membership: { GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL), ("could add membership: %s", err->message)); g_clear_error (&err); gst_udpsrc_close (src); return FALSE; } getsockname_error: { GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL), ("getsockname failed: %s", err->message)); g_clear_error (&err); gst_udpsrc_close (src); return FALSE; } }