+ return retval;
+}
+
+static void ustcomm_fini_server(struct ustcomm_server *server, int keep_socket_file)
+{
+ int result;
+ struct stat st;
+
+ if(!keep_socket_file) {
+ /* Destroy socket */
+ result = stat(server->socketpath, &st);
+ if(result == -1) {
+ PERROR("stat (%s)", server->socketpath);
+ return;
+ }
+
+ /* Paranoid check before deleting. */
+ result = S_ISSOCK(st.st_mode);
+ if(!result) {
+ ERR("The socket we are about to delete is not a socket.");
+ return;
+ }
+
+ result = unlink(server->socketpath);
+ if(result == -1) {
+ PERROR("unlink");
+ }
+ }
+
+ free(server->socketpath);
+
+ result = close(server->listen_fd);
+ if(result == -1) {
+ PERROR("close");
+ return;
+ }
+}
+
+/* Free a traceable application server */
+
+void ustcomm_fini_app(struct ustcomm_app *handle, int keep_socket_file)
+{
+ ustcomm_fini_server(&handle->server, keep_socket_file);
+}
+
+/* Free a ustd server */
+
+void ustcomm_fini_ustd(struct ustcomm_ustd *handle)
+{
+ ustcomm_fini_server(&handle->server, 0);
+}
+
+static const char *find_tok(const char *str)
+{
+ while(*str == ' ') {
+ str++;
+
+ if(*str == 0)
+ return NULL;
+ }
+
+ return str;
+}
+
+static const char *find_sep(const char *str)
+{
+ while(*str != ' ') {
+ str++;
+
+ if(*str == 0)
+ break;
+ }
+
+ return str;
+}
+
+int nth_token_is(const char *str, const char *token, int tok_no)
+{
+ int i;
+ const char *start;
+ const char *end;
+
+ for(i=0; i<=tok_no; i++) {
+ str = find_tok(str);
+ if(str == NULL)
+ return -1;
+
+ start = str;
+
+ str = find_sep(str);
+ if(str == NULL)
+ return -1;
+
+ end = str;
+ }
+
+ if(end-start != strlen(token))
+ return 0;
+
+ if(strncmp(start, token, end-start))
+ return 0;
+
+ return 1;
+}
+
+char *nth_token(const char *str, int tok_no)
+{
+ static char *retval = NULL;
+ int i;
+ const char *start;
+ const char *end;
+
+ for(i=0; i<=tok_no; i++) {
+ str = find_tok(str);
+ if(str == NULL)
+ return NULL;
+
+ start = str;
+
+ str = find_sep(str);
+ if(str == NULL)
+ return NULL;
+
+ end = str;
+ }
+
+ if(retval) {
+ free(retval);
+ retval = NULL;
+ }
+
+ asprintf(&retval, "%.*s", (int)(end-start), start);
+
+ return retval;
+}
+
+/* Callback from multipoll.
+ * Receive a new connection on the listening socket.
+ */
+
+static int process_mp_incoming_conn(void *priv, int fd, short events)
+{
+ struct ustcomm_connection *newconn;
+ struct ustcomm_server *server = (struct ustcomm_server *) priv;
+ int newfd;
+ int result;
+
+ result = newfd = accept(server->listen_fd, NULL, NULL);
+ if(result == -1) {
+ PERROR("accept");
+ return -1;
+ }
+
+ newconn = (struct ustcomm_connection *) malloc(sizeof(struct ustcomm_connection));
+ if(newconn == NULL) {
+ ERR("malloc returned NULL");
+ return -1;
+ }
+
+ ustcomm_init_connection(newconn);
+ newconn->fd = newfd;
+
+ list_add(&newconn->list, &server->connections);
+
+ return 0;
+}
+
+/* Callback from multipoll.
+ * Receive a message on an existing connection.
+ */
+
+static int process_mp_conn_msg(void *priv, int fd, short revents)
+{
+ struct ustcomm_multipoll_conn_info *mpinfo = (struct ustcomm_multipoll_conn_info *) priv;
+ int result;
+ char *msg;
+ struct ustcomm_source src;
+
+ if(revents) {
+ src.fd = fd;
+
+ result = recv_message_conn(mpinfo->conn, &msg);
+ if(result == -1) {
+ ERR("error in recv_message_conn");
+ }
+
+ else if(result == 0) {
+ /* connection finished */
+ ustcomm_close_app(mpinfo->conn);
+ list_del(&mpinfo->conn->list);
+ free(mpinfo->conn);
+ }
+ else {
+ mpinfo->cb(msg, &src);
+ free(msg);
+ }
+ }
+
+ return 0;
+}
+
+int free_ustcomm_client_poll(void *data)
+{
+ free(data);