Пример #1
0
/* dSfree() assumes links has been decremented and tested by Stringfree() */
void dSfree(String *str, const char *file, int line)
{
    if (str->links < 0) {
	/* While it would be useful to print str->file, it may have been
	 * clobbered the first time str was freed, so is unsafe. */
        internal_error(file, line,
	    "dSfree: links==%d, data=\"%.32b\"", str->links, '\"', str->data);
        core("dSfree: links==%d", file, line, str->links);
    }

    if (str->charattrs) Sfree(str, str->charattrs);
    if (str->dynamic_data && str->data)
        Sfree(str, str->data);

    str->size = -42;  /* break lcheck if str is reused without dSinit */
    str->len = 0;
    if (str->dynamic_struct) {
        if (!str->dynamic_data)	/* str and data were alloced together */
            Sfree(str, str);
#if USE_MMALLOC
        else if (str->md)
            Sfree(str, str);
#endif
        else
            pfree_fl(str, Stringpool, data, file, line);
    }
}
Пример #2
0
/*=========================================================================*\
  Get HTTP log info
    this includes a corresponding HTTP header
    returns an allocated string (caller must free) or NULL on error
\*=========================================================================*/
char *_ickP2pGetLogFile( ickP2pContext_t *ictx, const char *uri )
{
  int          level = 7;
  char        *logContent;
  int          dlen, hlen;
  char        *message;
  char         header[512];

  debug( "_ickP2pGetLogFile (%p): \"%s\"", ictx, uri );

/*------------------------------------------------------------------------*\
    Get minimum log level from path
\*------------------------------------------------------------------------*/
  if( strlen(uri)>strlen(ICK_P2PLOGURI) ) {
    const char *ptr = uri + strlen(ICK_P2PLOGURI);
    char       *eptr;
    if( *ptr!='/' )
      return strdup( HTTP_404 );
    ptr++;
    level = (int) strtol( ptr, &eptr, 10 );
    while( isspace(*eptr) )
      eptr++;
    if( *eptr ) {
      logwarn("_ickP2pGetLogFile (%p): Requested minimum level is not a number (%s)", ictx, ptr );
      return strdup( HTTP_404 );
    }
  }

/*------------------------------------------------------------------------*\
    Get debug info
\*------------------------------------------------------------------------*/
  logContent = ickP2pGetLogContent( level );
  if( !logContent )
    return strdup( HTTP_404 );

/*------------------------------------------------------------------------*\
  Construct header
\*------------------------------------------------------------------------*/
  dlen = strlen( logContent);
  hlen = sprintf( header, HTTP_200, "text/plain", (long)dlen );

/*------------------------------------------------------------------------*\
  Merge header and payload
\*------------------------------------------------------------------------*/
  message = malloc( hlen+dlen+1 );
  if( !message ) {
    Sfree( logContent );
    logerr( "_ickP2pGetLogFile: out of memory" );
    return NULL;
  }
  strcpy( message, header );
  strcpy( message+hlen, logContent );
  Sfree( logContent );

/*------------------------------------------------------------------------*\
  That's all
\*------------------------------------------------------------------------*/
  return message;
}
Пример #3
0
/*=========================================================================*\
  Get HTTP debug info
    this includes a corresponding HTTP header
    will lock the device list
    returns an allocated string (caller must free) or NULL on error
\*=========================================================================*/
char *_ickP2pGetDebugFile( ickP2pContext_t *ictx, const char *uri )
{
  const char  *uuid = NULL;
  int          dlen, hlen;
  char        *debugContent = NULL;
  char        *message;
  char         header[512];

  debug( "_ickP2pGetDebugFile (%p): \"%s\"", ictx, uri );

/*------------------------------------------------------------------------*\
    Get device info from path
\*------------------------------------------------------------------------*/
  if( strlen(uri)>strlen(ICK_P2PDEBUGURI) ) {
    uuid = uri + strlen(ICK_P2PDEBUGURI);
    if( *uuid!='/' )
      return strdup( HTTP_404 );
    uuid++;
  }

/*------------------------------------------------------------------------*\
    Get debug info
\*------------------------------------------------------------------------*/
  debugContent = ickP2pGetDebugInfo( ictx, uuid );

/*------------------------------------------------------------------------*\
    Not found or error?
\*------------------------------------------------------------------------*/
  if( !debugContent )
    return strdup( HTTP_404 );

/*------------------------------------------------------------------------*\
  Construct header
\*------------------------------------------------------------------------*/
  dlen = strlen( debugContent);
  hlen = sprintf( header, HTTP_200, "application/json", (long)dlen );

/*------------------------------------------------------------------------*\
  Merge header and payload
\*------------------------------------------------------------------------*/
  message = malloc( hlen+dlen+1 );
  if( !message ) {
    Sfree( debugContent );
    logerr( "_ickP2pGetDebugFile: out of memory" );
    return NULL;
  }
  strcpy( message, header );
  strcpy( message+hlen, debugContent );
  Sfree( debugContent );

/*------------------------------------------------------------------------*\
  That's all
\*------------------------------------------------------------------------*/
  return message;
}
Пример #4
0
/*=========================================================================*\
  Free a message container
\*=========================================================================*/
void _ickDeviceFreeMessage( ickMessage_t *message )
{
  debug( "_ickDeviceFreeMessage: message %p (%ld bytes)",
         message, message->size );

/*------------------------------------------------------------------------*\
    Free payload and descriptor
\*------------------------------------------------------------------------*/
  Sfree( message->payload );
  Sfree( message );

/*------------------------------------------------------------------------*\
    That's all
\*------------------------------------------------------------------------*/
}
Пример #5
0
/*=========================================================================*\
      Set Filename to store repository 
        An existing repository is not cleared...
\*=========================================================================*/
int persistSetFilename( const char *name )
{
  struct stat buf;
  
  DBGMSG( "persistSetFilename: \"%s\"", name ); 
  
/*------------------------------------------------------------------------*\
    Defensively dump to an existing file name
\*------------------------------------------------------------------------*/
  if( repositoryFileName && jRepository )
    _dumpRepository( repositoryFileName );

/*------------------------------------------------------------------------*\
    Try to read content from existing file
\*------------------------------------------------------------------------*/
  if( !stat(name,&buf) && _readRepository(name) )
    return -1;

/*------------------------------------------------------------------------*\
    Create empty repository if necessary
\*------------------------------------------------------------------------*/
  if( !jRepository )
    jRepository = json_object();
  if( !jRepository ) {
    logerr( "Could not create repository object." );
    return -1;
  }
  
/*------------------------------------------------------------------------*\
    Save new name
\*------------------------------------------------------------------------*/
  Sfree( repositoryFileName );
  repositoryFileName = strdup( name );
  return 0;    
}
Пример #6
0
/*=========================================================================*\
  Set device name, uses uuid if name is NULL
    caller should lock the device
\*=========================================================================*/
ickErrcode_t _ickDeviceSetName( ickDevice_t *device, const char *name )
{
  char *str = name ? strdup(name) : strdup(device->uuid);
  if( !str ) {
    logerr( "_ickDeviceSetLocation: out of memory" );
    return ICKERR_NOMEM;
  }
  Sfree( device->friendlyName );
  device->friendlyName = str;
  return ICKERR_SUCCESS;
}
Пример #7
0
String *dScpy(String *dest, const char *src, const char *file, int line)
{
    dest->len = strlen(src);
    if (dest->charattrs) {
        Sfree(dest, dest->charattrs);
        dest->charattrs = NULL;
    }
    lcheck(dest, file, line);
    memcpy(dest->data, src, dest->len + 1);
    return dest;
}
Пример #8
0
/*=========================================================================*\
  Free memory for a device descriptor
    this does no unlinking or timer deletion
    caller should lock device
\*=========================================================================*/
void _ickDeviceFree( ickDevice_t *device )
{
  debug( "_ickDeviceFree: uuid=\"%s\"", device->uuid );

/*------------------------------------------------------------------------*\
    Delete mutex
\*------------------------------------------------------------------------*/
  pthread_mutex_destroy( &device->mutex );

/*------------------------------------------------------------------------*\
    Clean up message queues
\*------------------------------------------------------------------------*/
  _ickDevicePurgeMessages( device );

/*------------------------------------------------------------------------*\
    Free memory
\*------------------------------------------------------------------------*/
  Sfree( device->uuid );
  Sfree( device->location );
  Sfree( device->friendlyName );
  Sfree( device );
}
Пример #9
0
/*=========================================================================*\
  Clean up message queues
\*=========================================================================*/
void _ickDevicePurgeMessages( ickDevice_t *device )
{
  ickMessage_t *msg, *next;
  int           num;

  debug( "_ickDevicePurgeMessages: uuid=\"%s\"", device->uuid );

/*------------------------------------------------------------------------*\
    Delete unsent messages
\*------------------------------------------------------------------------*/
  if( device->outQueue ) {
    for( num=0,msg=device->outQueue; msg; msg=next ) {
      next = msg->next;
      Sfree( msg->payload );
      Sfree( msg )
      num++;
    }
    device->outQueue = NULL;
    loginfo( "_ickDevicePurgeMessages: Deleted %d unsent messages in outQueue.", num );
  }

/*------------------------------------------------------------------------*\
    Delete undelivered messages
\*------------------------------------------------------------------------*/
  if( device->inQueue ) {
    for( num=0,msg=device->inQueue; msg; msg=next ) {
      next = msg->next;
      Sfree( msg->payload );
      Sfree( msg )
      num++;
    }
    device->inQueue = NULL;
    loginfo( "_ickDevicePurgeMessages: Deleted %d undelivered messages in inQueue.", num );
  }

/*------------------------------------------------------------------------*\
    That's it
\*------------------------------------------------------------------------*/
}
Пример #10
0
/*=========================================================================*\
  Set device location string
    caller should lock the device
\*=========================================================================*/
ickErrcode_t _ickDeviceSetLocation( ickDevice_t *device, const char *location )
{
  char *str = NULL;
  if( location ) {
    str = strdup( location );
    if( !str ) {
      logerr( "_ickDeviceSetLocation: out of memory" );
      return ICKERR_NOMEM;
    }
  }
  Sfree( device->location );
  device->location = str;
  return ICKERR_SUCCESS;
}
Пример #11
0
String *dSScpy(String *dest, const conString *src, const char *file, int line)
{
    if (dest->charattrs && !src->charattrs) {
        Sfree(dest, dest->charattrs);
        dest->charattrs = NULL;
    }
    dest->len = src->len;
    lcheck(dest, file, line);
    memcpy(dest->data, src->data ? src->data : "", src->len+1);
    if (src->charattrs) {
        check_charattrs(dest, 0, 0, file, line);
        memcpy(dest->charattrs, src->charattrs, sizeof(cattr_t) * (src->len+1));
    }
    dest->attrs = src->attrs;
    return dest;
}
Пример #12
0
String *dSncpy(String *dest, const char *src, int n, const char *file, int line)
{
    int len = strlen(src);

    if (n < 0) core("dSncpy: n==%ld", file, line, (long)n);
    if (n > len) n = len;
    dest->len = n;
    if (dest->charattrs) {
        Sfree(dest, dest->charattrs);
        dest->charattrs = NULL;
    }
    lcheck(dest, file, line);
    memcpy(dest->data, src, n);
    dest->data[n] = '\0';
    return dest;
}
Пример #13
0
/*=========================================================================*\
    Dereference an item URI using the service hints
      returns an allocated string (called needs to free that) or NULL on error
\*=========================================================================*/
char *ickServiceResolveURI( const char* uri, const char* type )
{
  ServiceListItem *service;
  char            *serviceId;
  char            *urlStub;

  DBGMSG( "ickServiceResolveURI: \"%s\" type=\"%s\".", uri, type?type:"(no type)" );

/*------------------------------------------------------------------------*\
    No service prefix ?
\*------------------------------------------------------------------------*/
  if( strncasecmp(uri,IckServiceSchemePrefix,strlen(IckServiceSchemePrefix)) )
    return strdup( uri );

/*------------------------------------------------------------------------*\
    Get service id
\*------------------------------------------------------------------------*/
  serviceId = strdup( uri+strlen(IckServiceSchemePrefix) );
  urlStub   = strchr( serviceId, '/' );
  if( urlStub )
    *(urlStub++) = 0; 

/*------------------------------------------------------------------------*\
    Look up service by id and (optionally) type
\*------------------------------------------------------------------------*/
  pthread_mutex_lock( &serviceListMutex );
  service = _getService( NULL, serviceId, type, 0 );

/*------------------------------------------------------------------------*\
    Build result
\*------------------------------------------------------------------------*/
  char *retval = NULL;
  if( service  && service->serviceUrl ) {
    retval = malloc( strlen(service->serviceUrl) + strlen(urlStub) + 2 );
    strcpy( retval, service->serviceUrl );
    strcat( retval, "/" );
    strcat( retval, urlStub );
  }
  pthread_mutex_unlock( &serviceListMutex );

/*------------------------------------------------------------------------*\
    That's all: clean up
\*------------------------------------------------------------------------*/
  DBGMSG( "ickServiceResolveURI (%s): \"%s\".", uri, retval );
  Sfree( serviceId );
  return retval;
}
Пример #14
0
/*=========================================================================*\
      Shutdown module, Free all memory
\*=========================================================================*/
void persistShutdown( void )
{
  loginfo( "Shutting down persistency module..." ); 

/*------------------------------------------------------------------------*\
    Dump to file a last time
\*------------------------------------------------------------------------*/
  if( repositoryFileName && jRepository )
    _dumpRepository( repositoryFileName );
  
/*------------------------------------------------------------------------*\
    Free filename
\*------------------------------------------------------------------------*/
  Sfree( repositoryFileName ); 

/*------------------------------------------------------------------------*\
    Free JSON repository in memory
\*------------------------------------------------------------------------*/
  _freeRepository();

/*------------------------------------------------------------------------*\
    That's all
\*------------------------------------------------------------------------*/
}
Пример #15
0
/*=========================================================================*\
    Remove and free a service from list
      Does not lock the list, so caller needs to set mutex!
\*=========================================================================*/
static void _removeService( ServiceListItem *item ) 
{
  DBGMSG( "_removeService (%s): (%s:%s).", item->id, item->type, item->name );

/*------------------------------------------------------------------------*\
    Search for entry 
\*------------------------------------------------------------------------*/
  ServiceListItem *prevElement = NULL;
  ServiceListItem *element     = serviceList;
  while( element ) {
    if( element==item )
      break;
    prevElement = element;
    element = element->next;
  }

/*------------------------------------------------------------------------*\
    Not found 
\*------------------------------------------------------------------------*/
  if( !element )
    return;

/*------------------------------------------------------------------------*\
    Unlink element 
\*------------------------------------------------------------------------*/
  if( !prevElement )    // replace list root
    serviceList = element->next;
  else
    prevElement->next = element->next;

/*------------------------------------------------------------------------*\
    Free resources 
\*------------------------------------------------------------------------*/
  json_decref( element->jItem );
  Sfree( element );
}
Пример #16
0
/*=========================================================================*\
    Add a new service
      jService is the result part of a getServiceInformation answer
\*=========================================================================*/
int ickServiceAdd( json_t *jService, ServiceOrigin origin )
{
  ServiceListItem *item;
  json_t          *jObj;

/*------------------------------------------------------------------------*\
    Allocate header
\*------------------------------------------------------------------------*/
  item = calloc( 1, sizeof(ServiceListItem) );
  if( !item ) {
    logerr( "ickServiceAdd: out of memory!" );
    return -1;
  }
  item->origin = origin;
  item->jItem  = json_incref( jService );

/*------------------------------------------------------------------------*\
    Extract id for quick access (weak ref.)
\*------------------------------------------------------------------------*/
  jObj = json_object_get( jService, "id" );
  if( !jObj || !json_is_string(jObj) ) {
    logerr( "ickServiceAdd: Missing field \"id\"!" );
    Sfree( item );
    json_decref( jService );
    return -1; 
  }
  item->id = json_string_value( jObj );

/*------------------------------------------------------------------------*\
    Extract name for quick access (weak ref.)
\*------------------------------------------------------------------------*/
  jObj = json_object_get( jService, "name" );
  if( !jObj || !json_is_string(jObj) ) {
    logerr( "ickServiceAdd (%s): Missing field \"name\"!", item->id );
    Sfree( item );
    json_decref( jService );
    return -1; 
  }
  item->name = json_string_value( jObj );   

/*------------------------------------------------------------------------*\
    Extract type for quick access (weak ref.)
\*------------------------------------------------------------------------*/
  jObj = json_object_get( jService, "type" );
  if( !jObj || !json_is_string(jObj) ) {
    logerr( "ickServiceAdd (%s): Missing field \"type\"!", item->id );
    Sfree( item );
    json_decref( jService );
    return -1; 
  }
  item->type = json_string_value( jObj );

/*------------------------------------------------------------------------*\
    Extract url for quick access (optional, weak ref.)
\*------------------------------------------------------------------------*/
  jObj = json_object_get( jService, "url" );
  if( jObj ) 
    item->url = json_string_value( jObj );   

/*------------------------------------------------------------------------*\
    Extract service url for quick access (optional, weak ref.)
\*------------------------------------------------------------------------*/
  jObj = json_object_get( jService, "serviceUrl" );
  if( jObj ) 
    item->serviceUrl = json_string_value( jObj );   

/*------------------------------------------------------------------------*\
    Insert or replace item
\*------------------------------------------------------------------------*/
  pthread_mutex_lock( &serviceListMutex );

  // Check for duplicates
  ServiceListItem *oldItem = _getService( NULL, item->id, item->type, origin );
  if( oldItem ) {
     DBGMSG( "ickServiceAdd (%s): Replacing service (%s:%s).",
                            item->id, item->type, item->name );
    _removeService( oldItem );
  }

  // Insert new item in list
  item->next = serviceList;
  serviceList = item;
  pthread_mutex_unlock( &serviceListMutex );

/*------------------------------------------------------------------------*\
    Be verbose
\*------------------------------------------------------------------------*/
  DBGMSG( "ickServiceAdd (%s): Added (%s:%s), origin %d.",
                     item->id, item->type, item->name, item->origin );

/*------------------------------------------------------------------------*\
    That's it
\*------------------------------------------------------------------------*/
  return 0;
}
Пример #17
0
/*=========================================================================*\
    Parse HTTP header, will write all icy-*, ice-* plus some relevant HTTP
    elements to a JSON object. Type detection is done to identify numbers.
    Returns NULL on error or an object with key-value pairs for identified
    fields
\*=========================================================================*/
json_t *icyExtractHeaders( const char *httpHeader )
{
  json_t     *jObj;
  const char *keyPtr;

  DBGMSG( "icyExtractHeaders: \"%s\".", httpHeader );

/*------------------------------------------------------------------------*\
    Create result container
\*------------------------------------------------------------------------*/
  jObj = json_object();
  if( !jObj ) {
    logerr( "icyExtractHeaders: Out of memory." );
    return NULL;
  }
  json_object_set( jObj, "timestamp", json_real(srvtime()) );

/*------------------------------------------------------------------------*\
    Loop over all lines
\*------------------------------------------------------------------------*/
  for( keyPtr=httpHeader; keyPtr&&*keyPtr; keyPtr++ ) {
    const char *linePtr = strpbrk( keyPtr, "\n\r" );
    char *key           = NULL;
    const char *valPtr;
    json_t     *jVal = NULL;

    // Skip white spaces and line feeds
    if( *keyPtr=='\r' || *keyPtr=='\n' || *keyPtr==' ' || *keyPtr=='\t' )
      continue;

    // Get key name separator within this line, ignore lines without separator
    valPtr = strchr( keyPtr, ':' );
    if( !valPtr || valPtr>linePtr ) {
      keyPtr = linePtr;
      continue;
    }

    // Only consider header elements of interest
    if( strcmpprefix(keyPtr,"icy-") &&
        strcmpprefix(keyPtr,"ice-") &&
        strcmpprefix(keyPtr,"Content-Type:") &&
        strcmpprefix(keyPtr,"Server:") ) {
      keyPtr = linePtr;
      continue;
    }
    key = strndup( keyPtr, valPtr-keyPtr );

    // Skip separator and leading white spaces in value
    do
      valPtr++;
    while( *valPtr && (*valPtr==' ' || *valPtr=='\t') );

    // Special treatment for ice tag
    if( !strcmp(key,"ice-audio-info") ) {
      if( _segmentKeyValList(valPtr,jObj,linePtr)<0 ) {
        DBGMSG( "icyExtractHeaders: Cannot code entries for key \"%s\": \"%.*s\"",
                 key, linePtr-valPtr, valPtr );
      }
      goto next;
    }

    // No value
    if( !*valPtr || valPtr==linePtr )
      jVal = json_null();

    // Type detection of value: try integer
    if( !jVal )
      jVal =_getInteger( valPtr, linePtr );

    // Try float
    if( !jVal )
      jVal =_getReal( valPtr, linePtr );

    // Use string as it is, convert to UTF8
    if( !jVal )
      jVal = json_mkstring( valPtr, linePtr-valPtr );

    // Could not code this?
    if( !jVal ) {
      DBGMSG( "icyExtractHeaders: Cannot code entry for key \"%s\": \"%.*s\"",
               key, linePtr-valPtr, valPtr );
    }

    // Set value in target
    else {
      if( jVal && json_object_set(jObj,key,jVal) ) {
        logerr( "icyExtractHeaders: Cannot insert/set JSON for key \"%s\" in target.", key );
        Sfree( key );
        json_decref( jObj );
        return NULL;
      }
      DBGMSG( "icyExtractHeaders: Set entry for key \"%s\": \"%.*s\"", key, linePtr-valPtr, valPtr );
    }

    // Clean up and set pointer to next line separator
next:
    Sfree( key );
    keyPtr = linePtr;
  }

/*------------------------------------------------------------------------*\
    That's it
\*------------------------------------------------------------------------*/
  return jObj;
}
Пример #18
0
/*=========================================================================*\
    Interpret a string of the form "key1=va11;...;keyn=valn[;]" up to
      (excluding) pbrk and insert JSON elements to jObj. Type detection is
      done to identify numbers. Existing elements are overwritten.
    Returns -1 on error or the number of elements processed
\*=========================================================================*/
static int _segmentKeyValList( const char *str, json_t *jObj, const char *pbrk )
{
  int     retval = 0;

  // Loop over string (range)
  while( str && *str && (!pbrk || str<pbrk) ) {
    const char *valPtr;
    char       *key;
    json_t     *jVal = NULL;

    // Get key name
    valPtr = strchr( str, '=' );
    if( !valPtr )
      break;
    key = strndup( str, valPtr-str );

    // Skip separator (equal sign) and leading white spaces in value
    do
      valPtr++;
    while( *valPtr && (*valPtr==' ' || *valPtr=='\t') );

    // No value
    if( !*valPtr || *valPtr== ';' ) {
      str = *valPtr ? valPtr+1 : valPtr;
      jVal = json_null();
    }

    // Value is of string type
    else if( *valPtr=='\'' ) {
      // there seems to be no escape mechanism for single quotes...
      str = strchr( ++valPtr, '\'' );
      if( !str || (pbrk && str>pbrk) ) {
        logwarn( "_segmentKeyValList: unterminated string fragment \"%s\".", valPtr );
        if( pbrk )
          str = pbrk;
      }
      if( !str )
        str = strchr( valPtr, 0 );
      jVal = json_mkstring( valPtr, str-valPtr );
    }

    // O.k. - this should be a number...
    else {
      str = strchr( valPtr, ';' );
      if( pbrk && (!str || str>pbrk) )
        str = pbrk;
      if( !str )
        str = strchr( valPtr, 0 );
      jVal = _getInteger( valPtr, str );
      if( !jVal )
        jVal = _getReal( valPtr, str );
      if( !jVal )
        logwarn( "_segmentKeyValList: Expected number, but got \"%.*s\" (key: \"%s\"",
                 str-valPtr, valPtr, key );
    }

    // Store JSON element
    if( jVal && json_object_set(jObj,key,jVal) ) {
      logerr( "_segmentKeyValList: Cannot insert/set JSON for key \"%s\" in target.", key );
      Sfree( key );
      return -1;
    }
    if( jVal ) {
      retval++;
      DBGMSG( "_segmentKeyValList: Set entry for key \"%s\": \"%.*s\"",
               key, str-valPtr, valPtr );
    }
    else {
      DBGMSG( "_segmentKeyValList: Cannot code entry for key \"%s\": \"%.*s\"",
              key, str-valPtr, valPtr );
    }

    // Clean up and skip separator
    Sfree( key );
    while( str && *str==';' )
      str++;
  }

  // Return number of elements
  return retval;
}
Пример #19
0
/*=========================================================================*\
  Get device info as allocated JSON object string
    (no unicode escaping of strings)
    caller must free result and should lock the device
    returns NULL on error
\*=========================================================================*/
static char *_ickDeviceStateJson( ickDevice_t *device, int indent )
{
  int   rc;
  char *result;
  char *wsi;
  char *message;
  debug( "_ickDeviceStateJson: %s", device->uuid );
  indent += JSON_INDENT;

/*------------------------------------------------------------------------*\
    Empty data?
\*------------------------------------------------------------------------*/
  if( !device )
    return strdup( "null" );

/*------------------------------------------------------------------------*\
    Create websocket information (if any)
\*------------------------------------------------------------------------*/
  /* fixme
  psd  = // no way to get user data from a wsi outside a lws callback scope
  jWsi = _ickWsiStateJson( psd );
  */
  wsi = strdup( JSON_BOOL(device->wsi) );
  if( !wsi ) {
    logerr( "_ickDeviceStateJson: out of memory" );
    return NULL;
  }

/*------------------------------------------------------------------------*\
    Create message information (if any)
\*------------------------------------------------------------------------*/
  message = _ickMessageStateJson( device->outQueue, indent+JSON_INDENT );
  if( !message ) {
    Sfree( wsi );
    logerr( "_ickDeviceStateJson: out of memory" );
    return NULL;
  }

/*------------------------------------------------------------------------*\
    Compile all debug info
\*------------------------------------------------------------------------*/
  rc = asprintf( &result,
                  "{\n"
                  "%*s\"name\": \"%s\",\n"
                  "%*s\"tCreation\": %f,\n"
                  "%*s\"UUID\": \"%s\",\n"
                  "%*s\"location\": \"%s\",\n"
                  "%*s\"upnpVersion\": %d,\n"
                  "%*s\"p2pLevel\": %d,\n"
                  "%*s\"lifetime\": %d,\n"
                  "%*s\"services\": %d,\n"
                  "%*s\"getXml\": \"%s\",\n"
                  "%*s\"doConnect\": %s,\n"
                  "%*s\"ssdpState\": \"%s\",\n"
                  "%*s\"bootId\": \"%ld\",\n"
                  "%*s\"configId\": \"%ld\",\n"
                  "%*s\"connectionState\": \"%s\",\n"
                  "%*s\"tXmlComplete\": %f,\n"
                  "%*s\"tConnect\": %f,\n"
                  "%*s\"tDisconnect\": %f,\n"
                  "%*s\"rx\": %d,\n"
                  "%*s\"rxSegmented\": %d,\n"
                  "%*s\"rxPending\": %d,\n"
                  "%*s\"tx\": %d,\n"
                  "%*s\"txPending\": %d,\n"
                  "%*s\"rxLast\": %f,\n"
                  "%*s\"txLast\": %f,\n"
                  "%*s\"wsi\": %s,\n"
                  "%*s\"message\": %s\n"
                  "%*s}",
                  indent, "", JSON_STRING( device->friendlyName ),
                  indent, "", JSON_REAL( device->tCreation ),
                  indent, "", JSON_STRING( device->uuid ),
                  indent, "", JSON_STRING( device->location ),
                  indent, "", JSON_INTEGER( device->ickUpnpVersion ),
                  indent, "", JSON_INTEGER( device->ickP2pLevel ),
                  indent, "", JSON_INTEGER( device->lifetime ),
                  indent, "", JSON_INTEGER( device->services ),
                  indent, "", JSON_STRING( device->wget?_ickWGetUri(device->wget) : NULL ),
                  indent, "", JSON_BOOL( device->doConnect ),
                  indent, "", JSON_STRING( _ickDeviceSsdpState2Str(device->ssdpState) ),
                  indent, "", JSON_LONG( device->ssdpBootId ),
                  indent, "", JSON_LONG( device->ssdpConfigId ),
                  indent, "", JSON_STRING( _ickDeviceConnState2Str(device->connectionState) ),
                  indent, "", JSON_REAL( device->tXmlComplete ),
                  indent, "", JSON_REAL( device->tConnect ),
                  indent, "", JSON_REAL( device->tDisconnect ),
                  indent, "", JSON_INTEGER( device->nRx ),
                  indent, "", JSON_INTEGER( device->nRxSegmented ),
                  indent, "", JSON_INTEGER( _ickDevicePendingInMessages(device) ),
                  indent, "", JSON_INTEGER( device->nTx ),
                  indent, "", JSON_INTEGER( _ickDevicePendingOutMessages(device) ),
                  indent, "", JSON_REAL( device->tLastRx ),
                  indent, "", JSON_REAL( device->tLastTx ),
                  indent, "", JSON_OBJECT( wsi ),
                  indent, "", JSON_OBJECT( message ),
                  indent-JSON_INDENT, ""
                );
  Sfree( wsi );
  Sfree( message );

/*------------------------------------------------------------------------*\
    Error
\*------------------------------------------------------------------------*/
  if( rc<0 ) {
    logerr( "_ickDeviceStateJson: out of memory" );
    return NULL;
  }

/*------------------------------------------------------------------------*\
    Return result
\*------------------------------------------------------------------------*/
  return result;
}
Пример #20
0
/*=========================================================================*\
  Get context info as allocated JSON object string including device list
    (no unicode escaping of strings)
    caller must free result
    returns NULL on error
\*=========================================================================*/
static char *_ickContextStateJson( ickP2pContext_t *ictx, int indent )
{
  ickDevice_t    *device;
  char           *devices    = NULL;
  ickInterface_t *interface;
  char           *interfaces = NULL;
  int             i;
  int             rc;
  char           *result;
  debug( "_ickContextStateJson (%p): %s", ictx, ictx->deviceUuid );
  indent += JSON_INDENT;

/*------------------------------------------------------------------------*\
    Compile array of interfaces
\*------------------------------------------------------------------------*/
  _ickLibInterfaceListLock( ictx );
  interfaces = strdup( "[" );
  for( i=0,interface=ictx->interfaces; interface&&interfaces; i++,interface=interface->next ) {
    char *interfaceInfo;

    // Get debug info
    interfaceInfo = _ickInterfaceStateJson( interface, indent+JSON_INDENT );
    if( !interfaceInfo ) {
      Sfree( interfaces );
      break;
    }

    // Add to list
    rc = asprintf( &result, "%s%s\n%*s%s", interfaces, i?",":"", indent+JSON_INDENT, "", interfaceInfo );
    Sfree( interfaces );
    Sfree( interfaceInfo );
    if( rc<0 )
      break;
    else
      interfaces = result;
  }
  _ickLibInterfaceListUnlock( ictx );

  // Close list
  if( interfaces ) {
    rc = asprintf( &result, "%s\n%*s]", interfaces, indent, "" );
    Sfree( interfaces );
    if( rc>0 )
      interfaces = result;
  }

  // Error ?
  if( !interfaces ) {
    logerr( "_ickContextStateJson: out of memory" );
    return NULL;
  }

/*------------------------------------------------------------------------*\
    Compile array of devices
\*------------------------------------------------------------------------*/
  _ickLibDeviceListLock( ictx );
  devices = strdup( "[" );
  for( i=0,device=ictx->deviceList; device&&devices; i++,device=device->next ) {
    char *deviceInfo;

    // Get debug info
    deviceInfo = _ickDeviceStateJson( device, indent+JSON_INDENT );
    if( !deviceInfo ) {
      Sfree( devices );
      break;
    }

    // Add to list
    rc = asprintf( &result, "%s%s\n%*s%s", devices, i?",":"", indent+JSON_INDENT, "", deviceInfo );
    Sfree( devices );
    Sfree( deviceInfo );
    if( rc<0 )
      break;
    else
      devices = result;

  }
  _ickLibDeviceListUnlock( ictx );

  // Close list
  if( devices ) {
    rc = asprintf( &result, "%s\n%*s]", devices, indent, "" );
    Sfree( devices );
    if( rc>0 )
      devices = result;
  }

  // Error ?
  if( !devices ) {
    Sfree( interfaces );
    logerr( "_ickContextStateJson: out of memory" );
    return NULL;
  }

/*------------------------------------------------------------------------*\
    Compile all context debug info
\*------------------------------------------------------------------------*/
  rc = asprintf( &result,
                  "{\n"
                  "%*s\"pid\": %d,\n"
                  "%*s\"uuid\": \"%s\",\n"
                  "%*s\"name\": \"%s\",\n"
                  "%*s\"services\": %d,\n"
                  "%*s\"upnpListenerPort\": %d,\n"
                  "%*s\"wsPort\": %d,\n"
                  "%*s\"folder\": \"%s\",\n"
                  "%*s\"lifetime\": %d,\n"
                  "%*s\"state\": \"%s\",\n"
                  "%*s\"loopback\": %s,\n"
                  "%*s\"customConnectMatrix\": %s,\n"
                  "%*s\"tCreation\": %f,\n"
                  "%*s\"tResume\": %f,\n"
                  "%*s\"osName\": \"%s\",\n"
                  "%*s\"p2pVersion\": \"%s\",\n"
                  "%*s\"p2pLevel\": %d,\n"
                  "%*s\"lwsVersion\": \"%s\",\n"
                  "%*s\"bootId\": %ld,\n"
                  "%*s\"configId\": %ld,\n"
                  "%*s\"interfaces\": %s\n"
                  "%*s\"devices\": %s\n"
                        "%*s}\n",
                  indent, "", JSON_INTEGER( getpid() ),
                  indent, "", JSON_STRING( ictx->deviceUuid ),
                  indent, "", JSON_STRING( ictx->deviceName ),
                  indent, "", JSON_INTEGER( ictx->ickServices ),
                  indent, "", JSON_INTEGER( ictx->upnpListenerPort ),
                  indent, "", JSON_INTEGER( ictx->lwsPort ),
                  indent, "", JSON_STRING( ictx->upnpFolder),
                  indent, "", JSON_INTEGER( ictx->lifetime ),
                  indent, "", JSON_STRING( ickLibState2Str(ictx->state) ),
                  indent, "", JSON_BOOL( ictx->upnpLoopback ),
                  indent, "", JSON_BOOL( ictx->lwsConnectMatrixCb==ickP2pDefaultConnectMatrixCb ),
                  indent, "", JSON_REAL( ictx->tCreation ),
                  indent, "", JSON_REAL( ictx->tResume ),
                  indent, "", JSON_STRING( ictx->osName ),
                  indent, "", JSON_STRING( ickP2pGetVersion(NULL,NULL) ),
                  indent, "", JSON_INTEGER( ICKP2PLEVEL_SUPPORTED ),
                  indent, "", JSON_STRING( lws_get_library_version() ),
                  indent, "", JSON_LONG( ictx->upnpBootId ),
                  indent, "", JSON_LONG( ictx->upnpConfigId ),
                  indent, "", JSON_OBJECT( interfaces ),
                  indent, "", JSON_OBJECT( devices ),
                  indent-JSON_INDENT, ""
                );
  Sfree( devices );
  Sfree( interfaces );

/*------------------------------------------------------------------------*\
    Error
\*------------------------------------------------------------------------*/
  if( rc<0 ) {
    logerr( "_ickContextStateJson: out of memory" );
    return NULL;
  }

/*------------------------------------------------------------------------*\
    Return result
\*------------------------------------------------------------------------*/
  return result;
}
Пример #21
0
/*=========================================================================*\
    Get streaming reference for an item from cloud
      item - the item to be resolved
      returns a json list containing one element
              (equivalent to streamingRefs feature of items)
      returns NULL on error
\*=========================================================================*/
json_t *ickServiceGetStreamingRef( PlaylistItem *item )
{
  const char      *token;
  char            *sid;
  ServiceListItem *service;
  json_t          *jParams;
  json_t          *jResult;
  json_t          *jObj;
  json_t          *jStreamingRefs;

  DBGMSG( "ickServiceGetStreamingRef: Item \"%s\" (%s)",
      playlistItemGetText(item), playlistItemGetId(item) );

/*------------------------------------------------------------------------*\
    Need token for cloud access...
\*------------------------------------------------------------------------*/
  token = ickCloudGetAccessToken();
  if( !token ) {
    logwarn( "ickServiceGetStreamingRef: Device not registered (no access token)." );
    return NULL;
  }

/*------------------------------------------------------------------------*\
  Get service id from item id
\*------------------------------------------------------------------------*/
  if( !playlistItemGetId(item) ) {
    playlistItemLock( item );
    logwarn( "ickServiceGetStreamingRef (%s): Item contains no id!",
             playlistItemGetText(item) );
    playlistItemUnlock( item );
    return NULL;
  }
  sid = strdup( playlistItemGetId(item) );
  if( !sid ) {
    logwarn( "ickServiceGetStreamingRef: out of memory!" );
    return NULL;
  }
  if( !strchr(sid,':') ) {
    playlistItemLock( item );
    logwarn( "ickServiceGetStreamingRef (%s,%s): Malformed id (missing ':')!",
            playlistItemGetText(item), playlistItemGetId(item) );
    playlistItemUnlock( item );
    Sfree ( sid );
    return NULL;
  }
  *strchr( sid, ':' ) = 0;

/*------------------------------------------------------------------------*\
  Find service descriptor
\*------------------------------------------------------------------------*/
  service = ickServiceFind( NULL, sid, NULL, ServiceCloud );
  if( !service ) {
    playlistItemLock( item );
    logwarn( "ickServiceGetStreamingRef (%s,%s): No such service \"%s\"!",
            playlistItemGetText(item), playlistItemGetId(item), sid );
    playlistItemUnlock( item );
    Sfree ( sid );
    return NULL;
  }
  Sfree ( sid );
  DBGMSG( "ickServiceGetStreamingRef (%s,%s): using service \"%s\" (%s)",
          playlistItemGetText(item), playlistItemGetId(item),
          service->name, service->type );

/*------------------------------------------------------------------------*\
    Collect parameters
\*------------------------------------------------------------------------*/
  jParams = json_object();
  json_object_set_new( jParams, "itemId", json_string(playlistItemGetId(item)) );
  //Fixme: collect supported formats

/*------------------------------------------------------------------------*\
    Interact with cloud
\*------------------------------------------------------------------------*/
  jResult = ickCloudRequestSync( service->url, token, "getItemStreamingRef", jParams, NULL );
  json_decref( jParams );
  if( !jResult ) {
    logwarn( "ickServiceGetStreamingRef: No answer from cloud." );
    return NULL;
  }

/*------------------------------------------------------------------------*\
    Server indicated error?
\*------------------------------------------------------------------------*/
  jObj = json_object_get( jResult, "error" );
  if( jObj ) {
    logwarn( "ickServiceGetStreamingRef: Error %s.", json_rpcerrstr(jObj) );
    json_decref( jResult );
    return NULL;
  }

/*------------------------------------------------------------------------*\
    Get result
\*------------------------------------------------------------------------*/
  jObj = json_object_get( jResult, "result" );
  if( !jObj ) {
    logerr( "ickServiceGetStreamingRef: No \"result\" object in answer." );
    json_decref( jResult );
    return NULL;
  }

/*------------------------------------------------------------------------*\
    Convert to list to be compatible with streamingRefs feature of items
\*------------------------------------------------------------------------*/
  jStreamingRefs = json_array();
  if( !jObj ) {
    logerr( "ickServiceGetStreamingRef: out of memory!" );
    json_decref( jResult );
    return NULL;
  }
  if( json_array_append(jStreamingRefs,jObj) ) {
    logerr( "ickServiceGetStreamingRef: json_arry_append() failed." );
    json_decref( jResult );
    return NULL;
  }

/*------------------------------------------------------------------------*\
    That's it
\*------------------------------------------------------------------------*/
  json_decref( jResult );
  return jStreamingRefs;
}
Пример #22
0
/*=========================================================================*\
  Get address and network mask of an interface
    ifname  - be interface name or address
    addr    - pointer to addr of interface (might be NULL)
    netmask - pointer to network mask of interface (might be NULL)
    name    - pointer to name of interface, will be an allocated string (might be NULL)
    *addr and *netmask are in network byte order
    return 0 on success or error code
\*=========================================================================*/
ickErrcode_t _ickIpGetIfAddr( const char *ifname, in_addr_t *addr, in_addr_t *netmask, char **name )
{
  char          *buffer;
  struct ifconf  ifc;
  size_t         pos;
  in_addr_t      ifaddr;
  int            sd;
  int            rc;
  ickErrcode_t   irc = ICKERR_NOINTERFACE;

/*------------------------------------------------------------------------*\
    Create virtual socket
\*------------------------------------------------------------------------*/
  sd = socket( PF_INET, SOCK_DGRAM, 0 );
  if( sd<0 ) {
    logerr( "_ickIpGetIfAddr: could not get socket (%s)", strerror(errno) );
    return ICKERR_NOSOCKET;
  }

/*------------------------------------------------------------------------*\
    Is this already a valid IP address?
\*------------------------------------------------------------------------*/
  ifaddr = inet_addr( ifname );

/*------------------------------------------------------------------------*\
    Allocate buffer
\*------------------------------------------------------------------------*/
  buffer = calloc( 1, ICK_IFRBUFFERSIZE );

/*------------------------------------------------------------------------*\
    Get all known interfaces
\*------------------------------------------------------------------------*/
  ifc.ifc_len = ICK_IFRBUFFERSIZE;
  ifc.ifc_req = (struct ifreq *)buffer;
  if( ioctl(sd,SIOCGIFCONF,&ifc)<0 ) {
    close( sd );
    logerr( "_ickIpGetIfAddr: ioctl(SIOCGIFCONF) failed (%s)", strerror(errno) );
    return ICKERR_NOSOCKET;
  }

/*------------------------------------------------------------------------*\
    Loop over interface list
\*------------------------------------------------------------------------*/
  size_t len;
  for( pos=0; pos<ifc.ifc_len; pos+=len ) {

    // Get current interface descriptor
    struct ifreq *ifr= (struct ifreq *)(buffer + pos );
    debug( "_ickIpGetIfAddr: testing interface \"%s\"", ifr->ifr_name );

    // Get actual size of interface descriptor
#ifdef linux
    len = sizeof( struct ifreq );
#else
    len = IFNAMSIZ + ifr->ifr_addr.sa_len;
#endif

    // We are looking for an internet interface
    if( ifr->ifr_addr.sa_family!=AF_INET )
      continue;

    // If ifname is no address the interface name must match
    if( ifaddr==INADDR_NONE && strcasecmp(ifname,ifr->ifr_name) )
      continue;

    // Get interface address
    rc = ioctl( sd, SIOCGIFADDR, ifr );
    if( rc<0 ) {
      logerr( "_ickIpGetIfAddr: ioctl(SIOCGIFADDR) failed (%s)", strerror(errno) );
      irc = ICKERR_NOINTERFACE;
      break;
    }

    // If ifname is an address it must match
    if( ifaddr!=INADDR_NONE && ifaddr!=((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr.s_addr )
      continue;

    // Store address
    if( addr )
      *addr = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr.s_addr;

    // Get and store interface network mask
    if( netmask ) {
      rc = ioctl( sd, SIOCGIFNETMASK, ifr );
      if( rc<0 ) {
        logerr( "_ickIpGetIfAddr: ioctl(SIOCGIFNETMASK) failed (%s)", strerror(errno) );
        irc = ICKERR_NOINTERFACE;
        break;
      }
      *netmask = ((struct sockaddr_in *)(&ifr->ifr_addr))->sin_addr.s_addr;
    }

    // Duplicate real interface name
    if( name ) {
      *name = strdup( ifr->ifr_name );
      if( !*name ) {
        logerr( "_ickIpGetIfAddr: out of memory" );
        irc = ICKERR_NOMEM;
        break;
      }
    }

    // Found it!
    debug( "_ickIpGetIfAddr (%s): found interface \"%s\"", ifname, ifr->ifr_name );
    irc = ICKERR_SUCCESS;
    break;
  }

/*------------------------------------------------------------------------*\
    Clean up and return result
\*------------------------------------------------------------------------*/
  Sfree( buffer );
  close( sd );
  return irc;
}