Changeset 2530:921f7ac0be31 in roaraudio


Ignore:
Timestamp:
09/02/09 00:50:34 (15 years ago)
Author:
phi
Branch:
default
Phase:
public
Message:

added support for multi homed server

Files:
7 edited

Legend:

Unmodified
Added
Removed
  • plugins/roard/protocol-esound.c

    r2529 r2530  
    7373 int i; 
    7474 
     75 ROAR_DBG("emul_esd_exec_command(*) = ?"); 
     76 
    7577 if ( client == -1 || cmd < ESD_PROTO_CONNECT || cmd > ESD_PROTO_MAX || vio == NULL ) 
    7678  return -1; 
     79 
     80 ROAR_DBG("emul_esd_exec_command(*) = ?"); 
    7781 
    7882 for (i = 0; (cur = &(g_emul_esd_commands[i]))->cmd != -1; i++) { 
  • roard/include/network.h

    r668 r2530  
    3030int net_check_listen  (void); 
    3131 
    32 int net_get_new_client (void); 
     32int net_get_new_client (int sock, int proto); 
    3333 
    3434#endif 
  • roard/include/roard.h

    r2519 r2530  
    7878#define _64BIT 8 
    7979 
     80// listeing code: 
     81#define ROAR_MAX_LISTEN_SOCKETS  8 
     82 
    8083//#include "buffer.h" 
    8184#include "codecfilter.h" 
     
    120123 
    121124#ifdef ROAR_SUPPORT_LISTEN 
    122 int g_listen_socket; 
     125int g_listen_socket[ROAR_MAX_LISTEN_SOCKETS]; 
     126int g_listen_proto[ROAR_MAX_LISTEN_SOCKETS]; 
    123127#endif 
    124128 
  • roard/lib.c

    r2500 r2530  
    5252 
    5353#ifdef ROAR_SUPPORT_LISTEN 
    54  close(g_listen_socket); // listen socket. 
     54 for (i = 0; i < ROAR_MAX_LISTEN_SOCKETS; i++) 
     55  if ( g_listen_socket[i] != -1 ) 
     56   close(g_listen_socket[i]); // listen socket. 
    5557#endif 
    5658 
  • roard/loop.c

    r2500 r2530  
    3434 float  freq; 
    3535#endif 
     36#ifdef ROAR_SUPPORT_LISTEN 
     37 int i; 
     38 int have_listen; 
     39#endif 
    3640#ifdef MONITOR_LATENCY 
    3741 long int ans_1last = 0, ans_2last = 0, ans_3last = 0; 
     
    5963 
    6064#ifdef ROAR_SUPPORT_LISTEN 
    61   if ( g_listen_socket != -1 ) { 
     65  have_listen = 0; 
     66  for (i = 0; i < ROAR_MAX_LISTEN_SOCKETS; i++) { 
     67   if ( g_listen_socket[i] != -1 ) { 
     68    have_listen = 1; 
     69    break; 
     70   } 
     71  } 
     72 
     73  if ( have_listen ) { 
    6274   ROAR_DBG("main_loop(*): check for new clients..."); 
    6375   net_check_listen(); 
     
    6779  ROAR_DBG("main_loop(*): check for new data..."); 
    6880#ifdef ROAR_SUPPORT_LISTEN 
    69   if ( clients_check_all() == 0 && g_terminate && g_listen_socket == -1 ) { 
     81  if ( clients_check_all() == 0 && g_terminate && !have_listen ) { 
    7082#else 
    7183  if ( clients_check_all() == 0 && g_terminate ) { 
  • roard/network.c

    r2529 r2530  
    4040 fd_set sl; 
    4141 struct timeval tv; 
     42 int i; 
     43 int max_fh = -1; 
    4244 
    4345 FD_ZERO(&sl); 
    44  FD_SET(g_listen_socket, &sl); 
     46 
     47 for (i = 0; i < ROAR_MAX_LISTEN_SOCKETS; i++) { 
     48  if ( g_listen_socket[i] != -1 ) { 
     49   if ( g_listen_socket[i] > max_fh ) 
     50    max_fh = g_listen_socket[i]; 
     51 
     52   FD_SET(g_listen_socket[i], &sl); 
     53  } 
     54 } 
     55 
     56 if ( max_fh == -1 ) 
     57  return 0; 
    4558 
    4659 tv.tv_sec  = 0; 
    4760 tv.tv_usec = 1; 
    4861 
    49  if ((r = select(g_listen_socket + 1, &sl, NULL, NULL, &tv)) > 0) { 
     62 if ((r = select(max_fh + 1, &sl, NULL, NULL, &tv)) > 0) { 
    5063  ROAR_DBG("net_check_listen(void): We have a connection!"); 
    51   return net_get_new_client(); 
     64  for (i = 0; i < ROAR_MAX_LISTEN_SOCKETS; i++) { 
     65   if ( g_listen_socket[i] != -1 ) { 
     66    if ( FD_ISSET(g_listen_socket[i], &sl) ) { 
     67     if ( net_get_new_client(g_listen_socket[i], g_listen_proto[i]) == -1 ) 
     68      return -1; 
     69    } 
     70   } 
     71  } 
    5272 } 
    5373 
     
    5979 
    6080#ifdef _CAN_OPERATE 
    61 int net_get_new_client (void) { 
     81int net_get_new_client (int sock, int proto) { 
    6282 int fh; 
    6383 int client; 
     
    7191 struct roar_vio_calls vio; 
    7292 
    73  fh = accept(g_listen_socket, NULL, NULL); 
     93 fh = accept(sock, NULL, NULL); 
    7494 
    7595 ROAR_DBG("net_get_new_client(void): fh = %i", fh); 
     
    107127#endif 
    108128 
    109  if ( clients_set_proto(client, ROAR_PROTO_ESOUND) == -1 ) 
     129 ROAR_DBG("net_get_new_client(*): proto=0x%.4x", proto); 
     130 
     131 if ( clients_set_proto(client, proto) == -1 ) 
    110132  return -1; 
    111133 
    112  if ( roar_vio_open_fh(&vio, fh) == -1 ) 
    113   return -1; 
     134 switch (proto) { 
     135  case ROAR_PROTO_ESOUND: 
     136    if ( roar_vio_open_fh(&vio, fh) == -1 ) 
     137     return -1; 
    114138 
    115  if ( emul_esd_exec_command(client, ESD_PROTO_CONNECT, &vio) == -1 ) 
    116   return -1; 
     139    if ( emul_esd_exec_command(client, ESD_PROTO_CONNECT, &vio) == -1 ) 
     140     return -1; 
     141   break; 
     142 } 
    117143 
    118144// close(fh); 
  • roard/roard.c

    r2511 r2530  
    2626 
    2727#ifdef ROAR_SUPPORT_LISTEN 
    28 char * server = ROAR_DEFAULT_SOCK_GLOBAL; // global server address 
     28char * server[ROAR_MAX_LISTEN_SOCKETS]; 
    2929#endif 
    3030 
     
    3232#define SUPPORT_PIDFILE 
    3333char * pidfile = NULL; 
     34#endif 
     35 
     36#if defined(ROAR_HAVE_SETGID) || defined(ROAR_HAVE_SETUID) 
     37 int    setids    = 0; 
    3438#endif 
    3539 
     
    137141        " -b  --bind            - IP/Hostname to bind to\n" 
    138142        "     --sock            - Filename for UNIX Domain Socket\n" 
     143        "     --proto PROTO     - Use PROTO as protocol on Socket\n" 
     144        "     --new-sock        - Parameters for new socket follows\n" 
    139145#ifdef ROAR_HAVE_LIBSLP 
    140146        "     --slp             - Enable OpenSLP support\n" 
     
    232238} 
    233239 
     240#ifdef ROAR_SUPPORT_LISTEN 
     241int init_listening (void) { 
     242 int i; 
     243 
     244 for (i = 0; i < ROAR_MAX_LISTEN_SOCKETS; i++) { 
     245  g_listen_socket[i] = -1; 
     246  g_listen_proto[i]  = ROAR_PROTO_ROARAUDIO; 
     247  server[i]          = NULL; 
     248 } 
     249 
     250 return 0; 
     251} 
     252 
     253int get_proto  (char * proto) { 
     254 if ( !strcasecmp(proto, "roar") ) { 
     255  return ROAR_PROTO_ROARAUDIO; 
     256 } else if ( !strcasecmp(proto, "roaraudio") ) { 
     257  return ROAR_PROTO_ROARAUDIO; 
     258 } else if ( !strcasecmp(proto, "esd") ) { 
     259  return ROAR_PROTO_ESOUND; 
     260 } else if ( !strcasecmp(proto, "esound") ) { 
     261  return ROAR_PROTO_ESOUND; 
     262 } 
     263 
     264 return -1; 
     265} 
     266 
     267int add_listen (char * addr, int port, int sock_type, char * user, char * group, int proto) { 
     268#if defined(ROAR_HAVE_SETGID) && defined(ROAR_HAVE_IO_POSIX) 
     269 struct group   * grp  = NULL; 
     270#endif 
     271#if defined(ROAR_HAVE_SETUID) && defined(ROAR_HAVE_IO_POSIX) 
     272 struct passwd  * pwd  = NULL; 
     273#endif 
     274#ifdef ROAR_HAVE_UNIX 
     275 char * env_roar_proxy_backup; 
     276#endif 
     277 int    sockid = -1; 
     278 int    sock; 
     279 int    i; 
     280 
     281 if ( *addr != 0 ) { 
     282  for (i = 0; i < ROAR_MAX_LISTEN_SOCKETS; i++) { 
     283   if ( g_listen_socket[i] == -1 ) { 
     284    sockid = i; 
     285    break; 
     286   } 
     287  } 
     288 
     289  if ( sockid == -1 ) 
     290   return -1; 
     291 
     292  g_listen_proto[sockid] = proto; 
     293 
     294  ROAR_DBG("add_listen(*): proto=0x%.4x", proto); 
     295 
     296  if ( (g_listen_socket[sockid] = roar_socket_listen(sock_type, addr, port)) == -1 ) { 
     297#ifdef ROAR_HAVE_UNIX 
     298   if ( *addr == '/' ) { 
     299    if ( (env_roar_proxy_backup = getenv("ROAR_PROXY")) != NULL ) { 
     300     env_roar_proxy_backup = strdup(env_roar_proxy_backup); 
     301     unsetenv("ROAR_PROXY"); 
     302    } 
     303    if ( (sock = roar_socket_connect(addr, port)) != -1 ) { 
     304     close(sock); 
     305     ROAR_ERR("Can not open listen socket!"); 
     306     return 1; 
     307    } else { 
     308     unlink(addr); 
     309     if ( (g_listen_socket[sockid] = roar_socket_listen(sock_type, addr, port)) == -1 ) { 
     310      ROAR_ERR("Can not open listen socket!"); 
     311      return 1; 
     312     } 
     313    } 
     314    if ( env_roar_proxy_backup != NULL ) { 
     315     setenv("ROAR_PROXY", env_roar_proxy_backup, 0); 
     316     free(env_roar_proxy_backup); 
     317    } 
     318#else 
     319   if (0) { // noop 
     320#endif 
     321   } else { 
     322    ROAR_ERR("Can not open listen socket!"); 
     323    return 1; 
     324   } 
     325  } 
     326 
     327#if defined(ROAR_HAVE_SETGID) && defined(ROAR_HAVE_IO_POSIX) 
     328  if ( (grp = getgrnam(group)) == NULL ) { 
     329   ROAR_ERR("Can not get GID for group %s: %s", group, strerror(errno)); 
     330  } 
     331#endif 
     332#if defined(ROAR_HAVE_SETUID) && defined(ROAR_HAVE_IO_POSIX) 
     333  if ( user || (setids & R_SETUID) ) { 
     334   if ( (pwd = getpwnam(user)) == NULL ) { 
     335    ROAR_ERR("Can not get UID for user %s: %s", user, strerror(errno)); 
     336   } 
     337  } 
     338#endif 
     339 
     340#if defined(ROAR_HAVE_IO_POSIX) && defined(ROAR_HAVE_UNIX) 
     341  if ( *addr == '/' ) { 
     342   if ( grp ) { 
     343    if ( pwd ) { 
     344     if ( chown(addr, pwd->pw_uid, grp->gr_gid) == -1 ) 
     345      return 1; 
     346    } else { 
     347     if ( chown(addr, -1, grp->gr_gid) == -1 ) 
     348      return 1; 
     349    } 
     350#ifdef ROAR_HAVE_GETUID 
     351    if ( getuid() == 0 ) 
     352     if ( chmod(addr, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1 ) 
     353      return 1; 
     354#endif 
     355   } 
     356  } 
     357#endif 
     358 } 
     359 
     360 return 0; 
     361} 
     362#endif 
     363 
    234364int update_stream_flags (char * str) { 
    235365 int    dir; 
     
    686816// char * server = ROAR_DEFAULT_SOCK_GLOBAL; 
    687817#ifdef ROAR_SUPPORT_LISTEN 
    688  int      port    = ROAR_DEFAULT_PORT; 
     818 int    port       = ROAR_DEFAULT_PORT; 
     819 char * sock_addr  = NULL; 
     820 int    sock_proto = ROAR_PROTO_ROARAUDIO; 
    689821#endif 
    690822 int               drvid; 
     
    715847 char * chrootdir = NULL; 
    716848#endif 
    717 #if defined(ROAR_HAVE_SETGID) || defined(ROAR_HAVE_SETUID) 
    718  int    setids    = 0; 
    719 #endif 
    720 #ifdef ROAR_HAVE_UNIX 
    721  char * env_roar_proxy_backup; 
    722 #endif 
    723849#if defined(ROAR_HAVE_SETGID) && defined(ROAR_HAVE_IO_POSIX) 
    724850 struct group   * grp  = NULL; 
     
    744870#ifdef ROAR_SUPPORT_LISTEN 
    745871 g_no_listen     =  0; 
    746  g_listen_socket = -1; 
    747872#else 
    748873 g_terminate     =  1; 
     
    766891 } 
    767892 
     893#ifdef ROAR_SUPPORT_LISTEN 
     894 if ( init_listening() == -1 ) { 
     895  ROAR_ERR("Can not init listening sockets!"); 
     896  return 1; 
     897 } 
     898#endif 
     899 
    768900#ifndef ROAR_WITHOUT_DCOMP_MIDI 
    769901 if ( midi_init_config() == -1 ) { 
     
    781913 
    782914#ifdef ROAR_SUPPORT_LISTEN 
     915 sock_addr = ROAR_DEFAULT_SOCK_GLOBAL; 
    783916#ifdef ROAR_HAVE_GETUID 
    784917 if ( getuid() != 0 && getenv("HOME") != NULL ) { 
    785918  snprintf(user_sock, 79, "%s/%s", (char*)getenv("HOME"), ROAR_DEFAULT_SOCK_USER); 
    786   server = user_sock; 
     919  sock_addr = user_sock; 
    787920 } 
    788921#endif 
    789922 
    790923 if ( getenv("ROAR_SERVER") != NULL ) 
    791   server = getenv("ROAR_SERVER"); 
     924  sock_addr = getenv("ROAR_SERVER"); 
    792925#endif 
    793926 
     
    831964  } else if ( strcmp(k, "--restart") == 0 ) { 
    832965#ifdef ROAR_SUPPORT_LISTEN 
    833    if ( restart_server(server, 1) == -1 ) { 
    834     ROAR_WARN("Can not terminate old server (not running at %s?), tring to continue anyway", server); 
     966   if ( restart_server(sock_addr, 1) == -1 ) { 
     967    ROAR_WARN("Can not terminate old server (not running at %s?), tring to continue anyway", sock_addr); 
    835968   } 
    836969#else 
     
    839972  } else if ( strcmp(k, "--shutdown") == 0 ) { 
    840973#ifdef ROAR_SUPPORT_LISTEN 
    841    if ( restart_server(server, 1) == -1 ) { 
    842     ROAR_WARN("Can not terminate old server (not running at %s?)", server); 
     974   if ( restart_server(sock_addr, 1) == -1 ) { 
     975    ROAR_WARN("Can not terminate old server (not running at %s?)", sock_addr); 
    843976    return 1; 
    844977   } 
     
    850983  } else if ( strcmp(k, "--stop") == 0 ) { 
    851984#ifdef ROAR_SUPPORT_LISTEN 
    852    if ( restart_server(server, 0) == -1 ) { 
    853     ROAR_WARN("Can not stop old server (not running at %s?)", server); 
     985   if ( restart_server(sock_addr, 0) == -1 ) { 
     986    ROAR_WARN("Can not stop old server (not running at %s?)", sock_addr); 
    854987    return 1; 
    855988   } 
     
    10421175   // This is only usefull in INET not UNIX mode. 
    10431176#ifdef ROAR_SUPPORT_LISTEN 
    1044    if ( *server == '/' ) 
    1045     server = ROAR_DEFAULT_HOST; 
     1177   if ( *sock_addr == '/' ) 
     1178    sock_addr = ROAR_DEFAULT_HOST; 
    10461179 
    10471180   errno = 0; 
     
    10641197  } else if ( strcmp(k, "-b") == 0 || strcmp(k, "--bind") == 0 || strcmp(k, "--sock") == 0 ) { 
    10651198#ifdef ROAR_SUPPORT_LISTEN 
    1066    server = argv[++i]; 
     1199   sock_addr = argv[++i]; 
     1200#endif 
     1201 
     1202  } else if ( strcmp(k, "--proto") == 0 ) { 
     1203#ifdef ROAR_SUPPORT_LISTEN 
     1204   if ( (sock_proto = get_proto(argv[++i])) == -1 ) { 
     1205    ROAR_ERR("Unknown protocol: %s", argv[i]); 
     1206    return 1; 
     1207   } 
    10671208#endif 
    10681209 
     
    10721213    sock_type = ROAR_SOCKET_TYPE_TCP; 
    10731214 
    1074    if ( *server == '/' ) 
    1075     server = ROAR_DEFAULT_HOST; 
     1215   if ( *sock_addr == '/' ) 
     1216    sock_addr = ROAR_DEFAULT_HOST; 
    10761217#endif 
    10771218 
     
    10791220#ifdef ROAR_SUPPORT_LISTEN 
    10801221   sock_type = ROAR_SOCKET_TYPE_TCP; 
    1081    if ( *server == '/' ) 
    1082     server = ROAR_DEFAULT_HOST; 
     1222   if ( *sock_addr == '/' ) 
     1223    sock_addr = ROAR_DEFAULT_HOST; 
    10831224#endif 
    10841225  } else if ( strcmp(k, "-6") == 0 ) { 
     
    10861227#ifdef PF_INET6 
    10871228   sock_type = ROAR_SOCKET_TYPE_TCP6; 
    1088    if ( *server == '/' ) 
    1089     server = ROAR_DEFAULT_HOST; 
     1229   if ( *sock_addr == '/' ) 
     1230    sock_addr = ROAR_DEFAULT_HOST; 
    10901231#else 
    10911232    ROAR_ERR("No IPv6 support compiled in!"); 
     
    11051246    port   = ROAR_DEFAULT_NUM; 
    11061247    strcpy(decnethost, ROAR_DEFAULT_LISTEN_OBJECT); 
    1107     server = decnethost; 
     1248    sock_addr = decnethost; 
    11081249    sock_type = ROAR_SOCKET_TYPE_DECNET; 
    11091250#else 
     
    11111252    return 1; 
    11121253#endif 
     1254#endif 
     1255  } else if ( strcmp(k, "--new-sock") == 0 ) { 
     1256#ifdef ROAR_SUPPORT_LISTEN 
     1257   if ( add_listen(sock_addr, port, sock_type, sock_user, sock_grp, sock_proto) != 0 ) { 
     1258    ROAR_ERR("Can not open listen socket!"); 
     1259    return 1; 
     1260   } 
    11131261#endif 
    11141262 
     
    11281276  } else if ( strcmp(k, "--no-listen") == 0 ) { 
    11291277#ifdef ROAR_SUPPORT_LISTEN 
    1130    server      = ""; 
     1278   sock_addr   = ""; 
    11311279   g_terminate = 1; 
    11321280   g_no_listen = 1; 
     
    11881336 
    11891337#ifdef ROAR_SUPPORT_LISTEN 
    1190  if ( *server != 0 ) { 
    1191   if ( (g_listen_socket = roar_socket_listen(sock_type, server, port)) == -1 ) { 
    1192 #ifdef ROAR_HAVE_UNIX 
    1193    if ( *server == '/' ) { 
    1194     if ( (env_roar_proxy_backup = getenv("ROAR_PROXY")) != NULL ) { 
    1195      env_roar_proxy_backup = strdup(env_roar_proxy_backup); 
    1196      unsetenv("ROAR_PROXY"); 
    1197     } 
    1198     if ( (i = roar_socket_connect(server, port)) != -1 ) { 
    1199      close(i); 
    1200      ROAR_ERR("Can not open listen socket!"); 
    1201      return 1; 
    1202     } else { 
    1203      unlink(server); 
    1204      if ( (g_listen_socket = roar_socket_listen(sock_type, server, port)) == -1 ) { 
    1205       ROAR_ERR("Can not open listen socket!"); 
    1206       return 1; 
    1207      } 
    1208     } 
    1209     if ( env_roar_proxy_backup != NULL ) { 
    1210      setenv("ROAR_PROXY", env_roar_proxy_backup, 0); 
    1211      free(env_roar_proxy_backup); 
    1212     } 
    1213 #else 
    1214    if (0) { // noop 
    1215 #endif 
    1216    } else { 
    1217     ROAR_ERR("Can not open listen socket!"); 
    1218     return 1; 
    1219    } 
    1220   } 
    1221  
    1222 #if defined(ROAR_HAVE_SETGID) && defined(ROAR_HAVE_IO_POSIX) 
    1223   if ( (grp = getgrnam(sock_grp)) == NULL ) { 
    1224    ROAR_ERR("Can not get GID for group %s: %s", sock_grp, strerror(errno)); 
    1225   } 
    1226 #endif 
    1227 #if defined(ROAR_HAVE_SETUID) && defined(ROAR_HAVE_IO_POSIX) 
    1228   if ( sock_user || (setids & R_SETUID) ) { 
    1229    if ( (pwd = getpwnam(sock_user)) == NULL ) { 
    1230     ROAR_ERR("Can not get UID for user %s: %s", sock_user, strerror(errno)); 
    1231    } 
    1232   } 
    1233 #endif 
    1234  
    1235 #if defined(ROAR_HAVE_IO_POSIX) && defined(ROAR_HAVE_UNIX) 
    1236   if ( *server == '/' ) { 
    1237    if ( grp ) { 
    1238     if ( pwd ) { 
    1239      if ( chown(server, pwd->pw_uid, grp->gr_gid) == -1 ) 
    1240       return 1; 
    1241     } else { 
    1242      if ( chown(server, -1, grp->gr_gid) == -1 ) 
    1243       return 1; 
    1244     } 
    1245 #ifdef ROAR_HAVE_GETUID 
    1246     if ( getuid() == 0 ) 
    1247      if ( chmod(server, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1 ) 
    1248       return 1; 
    1249 #endif 
    1250    } 
    1251   } 
    1252 #endif 
     1338 if ( add_listen(sock_addr, port, sock_type, sock_user, sock_grp, sock_proto) != 0 ) { 
     1339  ROAR_ERR("Can not open listen socket!"); 
     1340  return 1; 
    12531341 } 
    12541342#endif 
     
    13891477#ifdef ROAR_HAVE_LIBSLP 
    13901478 if ( reg_slp ) { 
    1391   register_slp(0, server); 
     1479  register_slp(0, sock_addr); 
    13921480 } 
    13931481#endif 
     
    14051493 
    14061494void cleanup_listen_socket (int terminate) { 
     1495 int i; 
     1496 
    14071497 // Deregister from SLP: 
    14081498#ifdef ROAR_HAVE_LIBSLP 
     
    14111501 
    14121502#ifdef ROAR_SUPPORT_LISTEN 
    1413  if ( g_listen_socket != -1 ) { 
     1503 for (i = 0; i < ROAR_MAX_LISTEN_SOCKETS; i++) { 
     1504  if ( g_listen_socket[i] != -1 ) { 
    14141505#ifdef ROAR_HAVE_IO_POSIX 
    1415   close(g_listen_socket); 
     1506   close(g_listen_socket[i]); 
    14161507#endif // #else is useless because we are in void context. 
    14171508 
    1418   g_listen_socket = -1; 
     1509   g_listen_socket[i] = -1; 
    14191510 
    14201511#ifdef ROAR_HAVE_UNIX 
    1421   if ( *server == '/' ) 
    1422    unlink(server); 
    1423 #endif 
     1512   if ( server[i] != NULL ) 
     1513    if ( *(server[i]) == '/' ) 
     1514     unlink(server[i]); 
     1515#endif 
     1516  } 
    14241517 } 
    14251518 
Note: See TracChangeset for help on using the changeset viewer.