Index: ChangeLog
===================================================================
--- ChangeLog	(revision 5022)
+++ ChangeLog	(revision 5031)
@@ -5,4 +5,5 @@
 	* Updated drivers to use new sync stream selection logic correctly (Closes: #136)
 	* Converted most roarclients to to use VS API (See: #87)
+	* Added support for ROAR_CMD_GETTIMEOFDAY
 
 v. 0.4beta6 - Mon May 23 2011 19:49 CEST
Index: include/libroar/libroar.h
===================================================================
--- include/libroar/libroar.h	(revision 5010)
+++ include/libroar/libroar.h	(revision 5031)
@@ -167,4 +167,5 @@
 #include "ctl.h"
 #include "caps.h"
+#include "roartime.h"
 #include "meta.h"
 #include "file.h"
Index: include/libroar/roartime.h
===================================================================
--- include/libroar/roartime.h	(revision 5031)
+++ include/libroar/roartime.h	(revision 5031)
@@ -0,0 +1,55 @@
+//time.h:
+
+/*
+ *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010-2011
+ *
+ *  This file is part of libroar a part of RoarAudio,
+ *  a cross-platform sound system for both, home and professional use.
+ *  See README for details.
+ *
+ *  This file is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 3
+ *  as published by the Free Software Foundation.
+ *
+ *  libroar is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301, USA.
+ *
+ *  NOTE for everyone want's to change something and send patches:
+ *  read README and HACKING! There a addition information on
+ *  the license of this document you need to read before you send
+ *  any patches.
+ *
+ *  NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc
+ *  or libpulse*:
+ *  The libs libroaresd, libroararts and libroarpulse link this lib
+ *  and are therefore GPL. Because of this it may be illigal to use
+ *  them with any software that uses libesd, libartsc or libpulse*.
+ */
+
+#ifndef _LIBROARTIME_H_
+#define _LIBROARTIME_H_
+
+#include "libroar.h"
+
+struct roar_time {
+ int64_t  t_sec;   // secund part of system time
+ uint64_t t_ssec;  // sub secs in 2^-64sec units.
+ uint64_t c_freq;  // clock freq in nHz. (use zero for unknown/undefined)
+ uint64_t c_drift; // clock drift in 2^-64sec per sec. (use zero for unknown/undefined)
+};
+
+int roar_time_to_msg(struct roar_message * mes,  struct roar_time    * time);
+int roar_time_from_msg(struct roar_time  * time, struct roar_message * mes);
+
+int roar_get_time  (struct roar_connection * con, struct roar_time * time);
+
+#endif
+
+//ll
Index: include/roaraudio/proto.h
===================================================================
--- include/roaraudio/proto.h	(revision 5029)
+++ include/roaraudio/proto.h	(revision 5031)
@@ -195,4 +195,5 @@
 #define ROAR_ITST_UIURL             10
 
+// old: do not use.
 struct roar_timeofday {
  int64_t  t_sec;   // secund part of system time
Index: libroar/Makefile
===================================================================
--- libroar/Makefile	(revision 4958)
+++ libroar/Makefile	(revision 5031)
@@ -11,5 +11,5 @@
 PASSWORD=passwordapi.o pinentry.o sshaskpass.o
 CRYPTO=crypto.o random.o $(HASHES) crc.o
-OBJS=libroar.o config.o debug.o error.o basic.o stream.o client.o simple.o auth.o socket.o ctl.o buffer.o meta.o file.o acl.o cdrom.o $(PASSWORD) $(VIO) stack.o slp.o nnode.o roardl.o roarx11.o beep.o proto.o env.o keyval.o vs.o ltm.o notify.o notify_proxy.o asyncctl.o enumdev.o serverinfo.o $(CRYPTO) authfile.o caps.o roarfloat.o base64.o trap.o memmgr.o
+OBJS=libroar.o config.o debug.o error.o basic.o stream.o client.o simple.o auth.o socket.o ctl.o buffer.o meta.o file.o acl.o cdrom.o $(PASSWORD) $(VIO) stack.o slp.o nnode.o roardl.o roarx11.o beep.o proto.o env.o keyval.o vs.o ltm.o notify.o notify_proxy.o asyncctl.o enumdev.o serverinfo.o $(CRYPTO) authfile.o caps.o roarfloat.o base64.o trap.o memmgr.o time.o
 
 #DEFINES        = -DDEBUG
Index: libroar/time.c
===================================================================
--- libroar/time.c	(revision 5031)
+++ libroar/time.c	(revision 5031)
@@ -0,0 +1,142 @@
+//time.c:
+
+/*
+ *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010-2011
+ *
+ *  This file is part of libroar a part of RoarAudio,
+ *  a cross-platform sound system for both, home and professional use.
+ *  See README for details.
+ *
+ *  This file is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 3
+ *  as published by the Free Software Foundation.
+ *
+ *  libroar is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301, USA.
+ *
+ *  NOTE for everyone want's to change something and send patches:
+ *  read README and HACKING! There a addition information on
+ *  the license of this document you need to read before you send
+ *  any patches.
+ *
+ *  NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc
+ *  or libpulse*:
+ *  The libs libroaresd, libroararts and libroarpulse link this lib
+ *  and are therefore GPL. Because of this it may be illigal to use
+ *  them with any software that uses libesd, libartsc or libpulse*.
+ */
+
+#include "libroar.h"
+
+int roar_time_to_msg(struct roar_message * mes,  struct roar_time    * time) {
+ uint64_t * data;
+
+ if ( mes == NULL || time == NULL ) {
+  roar_err_set(ROAR_ERROR_FAULT);
+  return -1;
+ }
+
+ memset(mes, 0, sizeof(struct roar_message));
+
+ data = (uint64_t*)mes->data;
+
+ data[0] = ROAR_HOST2NET64(0);
+ data[1] = ROAR_HOST2NET64(time->t_sec);
+ data[2] = ROAR_HOST2NET64(time->t_ssec);
+ data[3] = ROAR_HOST2NET64(time->c_freq);
+ data[4] = ROAR_HOST2NET64(time->c_drift);
+
+ mes->datalen = 5*8;
+
+ if ( time->c_drift == 0 ) {
+  mes->datalen -= 4;
+  if ( time->c_freq == 0 ) {
+   mes->datalen -= 4;
+   if ( time->t_ssec == 0 ) {
+    mes->datalen -= 4;
+   }
+  }
+ }
+
+ return 0;
+}
+
+int roar_time_from_msg(struct roar_time  * time, struct roar_message * mes) {
+ uint64_t * data;
+
+ if ( mes == NULL || time == NULL ) {
+  roar_err_set(ROAR_ERROR_FAULT);
+  return -1;
+ }
+
+ data = (uint64_t*)mes->data;
+
+ if ( mes->datalen < 8 ) {
+  roar_err_set(ROAR_ERROR_BADMSG);
+  return -1;
+ }
+
+ if ( mes->datalen % 8 ) {
+  roar_err_set(ROAR_ERROR_BADMSG);
+  return -1;
+ }
+
+ if ( ROAR_NET2HOST64(data[0]) != 0 ) {
+  roar_err_set(ROAR_ERROR_NSVERSION);
+  return -1;
+ }
+
+ memset(time, 0, sizeof(struct roar_time));
+
+ if ( mes->datalen >= 16 ) {
+  time->t_sec = ROAR_NET2HOST64(data[1]);
+  if ( mes->datalen >= 24 ) {
+   time->t_ssec = ROAR_NET2HOST64(data[2]);
+   if ( mes->datalen >= 32 ) {
+    time->c_freq = ROAR_NET2HOST64(data[3]);
+    if ( mes->datalen >= 40 ) {
+     time->c_drift = ROAR_NET2HOST64(data[4]);
+    }
+   }
+  }
+ }
+
+ return 0;
+}
+
+int roar_get_time  (struct roar_connection * con, struct roar_time * time) {
+ struct roar_message mes;
+
+ if ( con == NULL || time == NULL ) {
+  roar_err_set(ROAR_ERROR_FAULT);
+  return -1;
+ }
+
+ memset(&mes, 0, sizeof(mes));
+
+ mes.cmd     = ROAR_CMD_GETTIMEOFDAY;
+ mes.stream  = -1;
+ mes.datalen = 8; /* 64 bit */
+ // mes.data is already cleared.
+
+ if ( roar_req(con, &mes, NULL) == -1 )
+  return -1;
+
+ if ( mes.cmd != ROAR_CMD_OK ) {
+  return -1;
+ }
+
+ if ( roar_time_from_msg(time, &mes) == -1 )
+  return -1;
+
+ return 0;
+}
+
+//ll
Index: roarclients/roarctl.c
===================================================================
--- roarclients/roarctl.c	(revision 5005)
+++ roarclients/roarctl.c	(revision 5031)
@@ -123,4 +123,5 @@
         "\n"
         "  serverinfo              - Gets general information about the server\n"
+        "  servertime              - Gets server's time\n"
         "  serveroinfo             - Gets Information about server output\n"
         "  serveroinfo2 DIR        - Gets Information about server output for stream direction dir\n"
@@ -243,4 +244,29 @@
 }
 #undef _pm
+
+void server_time (struct roar_connection * con) {
+ struct roar_time time;
+
+ if ( roar_get_time(con, &time) == -1 ) {
+  fprintf(stderr, "Error: can not get server time\n");
+  return;
+ }
+
+ if ( g_verbose ) {
+  printf("Server time           : %llu.%06llu [+%llu/2^64] sec\n",
+         (long long unsigned int)time.t_sec,
+         (long long unsigned int) time.t_ssec / 18446744073709LLU,
+         (long long unsigned int) time.t_ssec);
+ } else {
+  printf("Server time           : %llu.%06llu sec\n",
+         (long long unsigned int)time.t_sec,
+         (long long unsigned int) time.t_ssec / 18446744073709LLU);
+ }
+ if ( time.c_freq )
+  printf("Server clock frequency: %f Hz\n", (float)time.c_freq / 1000000000.f);
+ if ( time.c_drift )
+  printf("Server clock drift    : %llu:2^64 (~10^%f)\n",
+         (long long unsigned int)time.c_drift, logf((float)time.c_drift)/2.302585f);
+}
 
 void server_oinfo (struct roar_connection * con, int dir) {
@@ -1141,4 +1167,6 @@
   } else if ( !strcmp(k, "serverinfo") ) {
    server_info(&con);
+  } else if ( !strcmp(k, "servertime") ) {
+   server_time(&con);
   } else if ( !strcmp(k, "serveroinfo") ) {
    server_oinfo(&con, -1);
Index: roard/commands.c
===================================================================
--- roard/commands.c	(revision 4781)
+++ roard/commands.c	(revision 5031)
@@ -53,4 +53,5 @@
   {ROAR_CMD_PASSFH,       _NAME("PASSFH"),       req_on_passfh,       ACCLEV_PWRUSER},
 
+  {ROAR_CMD_GETTIMEOFDAY, _NAME("GETTIMEOFDAY"), req_on_gettimeofday, ACCLEV_NONE},
   {ROAR_CMD_SERVER_INFO,  _NAME("SERVER_INFO"),  req_on_server_info,  ACCLEV_NONE},    // allow this early so the client
                                                                                        // can device ealry if this server
Index: roard/include/req.h
===================================================================
--- roard/include/req.h	(revision 4708)
+++ roard/include/req.h	(revision 5031)
@@ -52,4 +52,5 @@
 int req_on_exit        (int client, struct roar_message * mes, char ** data, uint32_t flags[2]);
 
+int req_on_gettimeofday(int client, struct roar_message * mes, char ** data, uint32_t flags[2]);
 int req_on_server_info (int client, struct roar_message * mes, char ** data, uint32_t flags[2]);
 
Index: roard/req.c
===================================================================
--- roard/req.c	(revision 4949)
+++ roard/req.c	(revision 5031)
@@ -682,4 +682,59 @@
 #endif
 
+int req_on_gettimeofday (int client, struct roar_message * mes, char ** data, uint32_t flags[2]) {
+#if defined(ROAR_HAVE_GETTIMEOFDAY) || defined(ROAR_HAVE_TIME)
+ struct roar_time curtime;
+#ifdef ROAR_HAVE_GETTIMEOFDAY
+ struct timeval tv;
+#elif defined(ROAR_HAVE_TIME)
+ time_t now = time(NULL);
+#endif
+
+ ROAR_DBG("req_on_gettimeofday(client=%i, mes=%p, data=%p, flags=%p) = ?", client, mes, data, flags);
+
+ if ( *data != NULL ) {
+  return -1;
+ }
+
+ ROAR_DBG("req_on_gettimeofday(client=%i, mes=%p, data=%p, flags=%p) = ?", client, mes, data, flags);
+
+ if ( mes->datalen && mes->datalen < 8 ) {
+  return -1;
+ }
+
+ ROAR_DBG("req_on_gettimeofday(client=%i, mes=%p, data=%p, flags=%p) = ?", client, mes, data, flags);
+
+ if ( mes->datalen >= 8 ) {
+  if ( *(uint64_t *)mes->data != 0 ) {
+   return -1;
+  }
+ }
+
+ ROAR_DBG("req_on_gettimeofday(client=%i, mes=%p, data=%p, flags=%p) = ?", client, mes, data, flags);
+
+ memset(&curtime, 0, sizeof(curtime));
+
+#ifdef ROAR_HAVE_GETTIMEOFDAY
+ if ( gettimeofday(&tv, NULL) == -1 )
+  return -1;
+ curtime.t_sec  = tv.tv_sec;
+ curtime.t_ssec = (uint64_t)tv.tv_usec * (uint64_t)18446744073709ULL;
+#elif defined(ROAR_HAVE_TIME)
+ curtime.t_sec = now;
+#endif
+
+ if ( roar_time_to_msg(mes, &curtime) == -1 )
+  return -1;
+
+ mes->cmd = ROAR_CMD_OK;
+
+ ROAR_DBG("req_on_gettimeofday(client=%i, mes=%p, data=%p, flags=%p) = ?", client, mes, data, flags);
+
+ return 0;
+#else
+ return -1;
+#endif
+}
+
 int req_on_server_info (int client, struct roar_message * mes, char ** data, uint32_t flags[2]) {
 #ifdef ROAR_HAVE_UNAME
